news 2026/10/5 2:49:31

学Git先掌握这15个核心命令:从安装配置到分支合并一次讲透

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
学Git先掌握这15个核心命令:从安装配置到分支合并一次讲透

有人问我,学 Git 到底先学什么?我的答案一直没变过:先别急着背命令,先把日常开发里最高频的那十几个命令用熟。Git 的命令有上百个,但说实话,你每天真正敲来敲去的,翻来覆去就是那十几个。把这十几个命令的原理、参数、坑搞明白,你就能覆盖日常开发 90% 以上的场景。这篇文章我就把 15 个 Git 核心命令掰开揉碎讲一遍,从安装配置到分支合并,从代码撤销到远程协作,结合我这些年实操中踩过的坑,一次性梳理清楚。

这篇文章适合谁看?刚入门 Git 的新手、在学校只学过 git add/commit 的科班生、以及用了很久 Git 但全靠图形界面点来点去、遇到命令行就发怵的同学。看完这篇文章,你会发现 Git 命令行没那么可怕,而且比图形工具高效得多,尤其是在服务器上操作、批量处理、脚本自动化这些场景,命令行几乎是唯一的选择。

1. 先把 Git 环境收拾利索:安装、配置与 SSH

很多同学抱怨 Git 命令报错,其实八成不是命令本身的问题,是环境没弄对。这部分我按步骤讲,照着做基本不会翻车。

1.1 安装 Git:Windows、macOS、Linux 三种方案

Git 的安装本身不难,但不同系统的安装方式和后续配置路径差别很大。

Windows 用户直接去 Git 官网下载安装包就行,安装时有一个容易忽略的选项:调整 PATH 环境变量。建议选 “Git from the command line and also from 3rd-party software”,这样 Git 命令不光能在自带的 Git Bash 里用,在 CMD、PowerShell 里也能直接识别。安装完成后,右键菜单会多出 “Git Bash Here” 和 “Git GUI Here” 两个选项,日常操作强烈建议用 Git Bash,它的命令语法跟 Linux 完全一致,网上查到的教程命令都能直接用,而 CMD 的语法在一些场景下有差异。

macOS 用户分两种情况:装了 Homebrew 的直接brew install git搞定;没装 Homebrew 的可以去官网下 pkg 安装包,装完在终端里输git --version验证。还有个隐藏方案:macOS 自带的 Command Line Tools 里其实带了 Git,你敲git命令时系统会提示你安装,但版本通常比较旧,建议还是用 Homebrew 装新版。

Linux 用户最简单,Debian/Ubuntu 系执行sudo apt install git,CentOS/RHEL 系执行sudo yum install git。这里有个细节:系统自带的软件源里 Git 版本可能偏低,如果你需要用一些较新的特性(比如git switch命令,2.23 版本才引入),可以考虑加第三方源装新版,不过日常使用系统源版本完全够了。

装完验证一下:

git --version

能看到版本号就说明安装成功了。Windows 用户如果在 PowerShell 里敲完这命令提示找不到命令,大概率是 PATH 没配好,去系统环境变量里把 Git 的安装路径加上,然后重开终端。

1.2 全局配置:user.name 和 user.email 不设置好,提交全是坑

Git 安装完后第一件事不是急着拉代码,而是配置身份信息。这一步要是跳过,你 commit 的时候会提示让你补配置,而且提交记录里的作者信息会变成系统默认的乱码名字,团队协作时根本分不清谁是谁。

git config --global user.name "你的名字" git config --global user.email "你的邮箱"

这里有几个容易忽略的地方。

--global参数表示全局生效,配一次所有仓库都能用。有些场景需要给某个特定仓库配不同的身份,比如公司电脑上同时有个人项目和公司项目,可以在仓库目录下去掉--global重新配置,这样只对当前仓库生效。

邮箱建议用你代码托管平台绑定的那个邮箱,这样你的提交记录能正确关联到你的账号,贡献图才会亮起来。如果你不想暴露真实邮箱,GitHub 提供 noreply 的隐私邮箱,在 GitHub 设置页面能看到,用那个也完全没问题。

配完可以查看确认:

git config --global --list

会列出所有全局配置项,包括 user.name、user.email,还有后面要讲的 color.ui、core.editor 等。

1.3 SSH 密钥配置:一次配置,免除每次输密码的烦恼

很多新手第一次 clone 私有仓库时,被要求输用户名密码,输完发现下次还要输,烦得要命。解决方案是配置 SSH 密钥。

ssh-keygen -t ed25519 -C "你的邮箱"

一路回车就能生成密钥对。这里说明一下:生成过程中会让你输 passphrase,这是给私钥再加一道锁的密码,如果不想每次用都输可以直接回车留空。ed25519是目前推荐的非对称加密算法,比老的 RSA 更安全、密钥更短。如果你的 Git 服务器或托管平台还不支持 ed25519,可以用ssh-keygen -t rsa -b 4096生成 RSA 密钥,兼容性更好。

生成后密钥默认在~/.ssh/目录下,id_ed25519.pub是公钥,id_ed25519是私钥。私钥绝对不能泄露,不能提交到代码仓库,也不能发给别人。公钥内容用下面的命令查看:

cat ~/.ssh/id_ed25519.pub

复制输出的整行内容,粘贴到你的代码托管平台后台。GitHub 在 Settings -> SSH and GPG keys 里添加,GitLab 在 Preferences -> SSH Keys 里添加,Gitee 在设置 -> SSH 公钥里添加。

配置好之后测试一下:

ssh -T git@github.com

如果是 GitHub 会回一句 “Hi xxx! You've successfully authenticated”,看到这句说明 SSH 认证已经通了,以后 clone、push、pull 都不用再输密码了。

ssh -T这条命令经常用到,排查 SSH 认证失败特别管用。常见的失败原因有两个:一是公钥没粘贴正确,多了或少了个字符都不行;二是本机有多个密钥,系统默认用了错误的那个。解决办法是在~/.ssh/config文件里指定:

Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519

这样系统就知道连接 GitHub 时该用哪个私钥了。

2. 拿下一个仓库:clone、init 与状态查看

环境配好之后,开始进入真正的实操环节。第一个要掌握的是怎么把一个仓库弄到本地,以及怎么随时掌握仓库的状态。

2.1 git clone:把远程仓库完整复制到本地

克隆仓库是 Git 里最常见的操作之一。语法很简单:

git clone git@github.com:用户名/仓库名.git

这里我强烈推荐使用 SSH 地址而不是 HTTPS 地址。HTTPS 地址每次 push 都要输账号密码(哪怕配置了缓存也只能管一段时间),SSH 地址按第一部分配置好密钥后完全免密,体验差别很大。

git clone默认会把远程仓库的所有分支历史都拉下来,同时自动建立一个本地分支跟踪远程的默认分支(一般是main或master)。如果你只想克隆最近一次提交的代码、不关心历史记录,可以加--depth 1参数做浅克隆,这在拉取大型仓库时能省不少时间和磁盘空间:

git clone --depth 1 git@github.com:用户名/仓库名.git

还有一个细节容易被忽视:默认克隆下来的仓库目录名是仓库名本身。如果你希望放到别的目录名下,在仓库地址后面加一个空格指定目录名即可:

git clone git@github.com:用户名/仓库名.git 新目录名

这个在团队协作里有实际用途。比如你同时需要拉取同一个仓库的多个分支版本,就可以克隆到不同目录,避免频繁切换分支。

2.2 git init:从零开始初始化一个仓库

新项目还没有纳入版本控制时,用git init在当前目录下初始化一个全新的仓库。

git init

执行后目录下会多出一个.git目录,所有的版本历史、配置信息都存放在这里。如果你不小心把这个目录删了,整个仓库的版本历史就全没了,工作区文件还在,但再也无法回溯历史版本。所以没事别去动.git目录。

有一种情况要特别当心:如果你在一个大的目录结构下执行git init,比如在/Users/username/project下,它会把这个目录和它的所有子目录都纳入版本控制范围(除非被.gitignore排除)。所以初始化前想清楚仓库的边界,别把一个包含大量临时文件、依赖包的目录整个变成仓库,不然后面每次提交都要小心翼翼。

git init还有一个常用变体git init 目录名,会在指定目录创建新项目并初始化仓库,一步到位。

2.3 git status:随时掌握工作区状态

我刚学 Git 时最喜欢敲的命令就是git status,因为它把你当前仓库的状态说得很清楚:哪些文件改了、哪些文件新增还没加入暂存、当前在哪个分支、跟远程仓库差了多少个提交。

git status

输出信息分几个区域:

  • Changes not staged for commit:已跟踪文件被修改了,但还没暂存
  • Changes to be committed:文件已暂存,等待提交
  • Untracked files:新增文件,Git 从未跟踪过

刚接触 Git 的同学第一次看这些输出可能会晕,我提供一个理解方式:Git 的文件状态流转是“工作区 -> 暂存区 -> 版本库”三层结构。工作区就是你实际编辑文件的目录,暂存区是提交前的一个中间缓冲区,版本库保存着每一次提交的历史快照。git status就是告诉你这三层之间当前有哪些差异。

为了方便快速查看更简洁的状态,建议用git status -sb,-s是精简输出,每个文件一行,用字符表示状态;-b同时显示当前分支和与远程分支的领先/落后情况。我自己的习惯是把这个起个别名:

git config --global alias.st "status -sb"

以后敲git st就能看到一行非常清爽的状态概览,效率提升明显。

3. 日常提交的核心链路:add、commit、log

接下来是 Git 使用频率最高的三个命令,也是很多人只知道“怎么用”但没想过“为什么这么用”的三个命令。

3.1 git add:把改动放进暂存区

修改文件之后,第一步是把改动文件加入暂存区:

git add 文件名

如果想一次把所有改动都加入暂存,用:

git add .

这里有个重要提醒:git add .会把当前目录下所有未跟踪的文件和修改文件全部加入暂存。如果你的项目里有些文件本不应该被提交(比如本地的配置文件、密钥文件、依赖包目录),却没在.gitignore里忽略,就会被一起暂存。我见过有人把含有数据库密码的配置文件提交到仓库然后推上远程,酿成安全事故。所以养成好习惯:一个项目开始时就写好.gitignore,提交前用git status或git diff --cached确认一下要提交的文件。

git add还有一个交互模式值得学习:git add -p。这个命令会逐个区块地让你确认是否暂存改动,适合你在一个文件里做了多处修改、但只想提交其中一部分的场景。团队协作中,这种“部分提交”能力很实用,可以让单个提交只包含一个逻辑变更,代码评审的人会感谢你。

3.2 git commit:创建一次提交记录

暂存区准备好后,就该提交了:

git commit -m "提交说明"

提交说明的质量直接影响团队协作效率。我总结的提交信息格式是这样:用一句话说清楚“这次改动做了什么”,动词开头,控制在一行内尽量不超过 50 个字符。比如修复登录页面在 Safari 下样式错乱的问题,比修改了一些bug强一万倍。

很多团队用 Conventional Commits 规范,格式是type(scope): subject:

  • feat(user-service): 新增用户注册接口
  • fix(auth): 修复 token 过期时间计算错误
  • docs(readme): 更新部署步骤说明

如果你提交时忘了写-m参数,Git 会打开默认编辑器让你写提交信息。默认的编辑器通常是你系统里配的vi或vim,新手经常卡在里面不知道怎么退出,直接关掉终端导致提交失败。两个解决办法:一是设置默认编辑器为更友好的工具,比如 VS Code:

git config --global core.editor "code --wait"

二是强制自己每次都用-m参数。

提交之后想修改最近的提交信息,可以用:

git commit --amend -m "新的提交说明"

这会把上一次提交替换掉,相当于改了历史。要注意的是:如果你已经把上次提交推送到了远程,而且有同事基于它做了开发,就不要用 amend,否则会打乱所有人的历史记录。

3.3 git log:查看提交历史,别再用肉眼翻历史了

需要回顾项目演进过程、排查某次提交改了什么,用git log。

git log

默认输出每个提交的哈希值、作者、日期、提交信息。但默认格式信息量太大,看起来特别费劲。我推荐这几个参数组合:

# 一行一提交,只看提交信息和短哈希 git log --oneline # 图形化展示分支结构 git log --graph --oneline --all # 查看具体某个文件的提交历史 git log --oneline -- 文件名

--oneline把每个提交压缩成一行,输出哈希前 7 位和提交信息,扫一眼就能了解整体演进;--graph会把分支合并的分叉线画出来,配合--all能看到所有分支,适合理清复杂的合并关系。

还有一个参数我经常用:git log -p,它会连每个提交的具体改动内容(diff)一起显示,排查某个提交具体改了什么的时候特别有用。不过输出很长,配合--oneline -3限定位数更实用。

3.4 核心原理解读:为什么 Git 要设计“暂存区”这个概念

前面多次提到暂存区,这里有必要深入讲一下。你日常的编辑、查看改动、提交代码,实际上都在跟“工作区和暂存区的关系”“暂存区和版本库的关系”这两组差异打交道。

Git 设计暂存区的核心目的是让你可以精细控制一次提交的内容边界。工作区里可能同时存在多个文件的改动,有些改动属于功能 A,有些属于功能 B。如果不经过暂存区直接提交,你就只能把所有改动打包成一个提交,历史记录的粒度很粗,后续想单独回滚功能 A 就无从下手。

有了暂存区之后,你可以把功能 A 的文件用git add加入暂存,先提交,再把功能 B 的文件加入暂存,再提交。这样一条条提交互相独立,每条提交只做一件事。这个理念在团队协作里特别关键,因为代码评审(Code Review)就是基于提交记录逐个看的。

回到项目实际操作层面,应对“临时要切换分支”这种情况时,暂存区的作用就体现出来了。如果你在工作区改到一半,突然有个紧急 bug 要切到其他分支修复,不处理手头的改动就直接切换会很被动——要么把半成品提交上去污染历史,要么改丢。这就是暂存区和下面要讲的git stash系列命令大显身手的时候。

4. 分支操作:branch、checkout/switch、merge

分支是 Git 最强大的设计,也是对新手最不友好的功能。把它搞明白,你对 Git 的理解就上升了一个台阶。

4.1 git branch:查看、创建、删除分支

分支管理命令的第一条:

# 查看本地所有分支,当前分支前会有星号 git branch # 查看所有分支(包括远程分支) git branch -a # 创建一个新分支 git branch 新分支名 # 删除一个已合并的分支 git branch -d 分支名 # 强制删除分支(即使未合并) git branch -D 分支名

有个概念必须理解透彻:切换到某一分支上的操作,本质上是移动一个指针,并不会改变你工作区的文件;只有当 checkout 或 switch 的时候,Git 才会根据目标分支的内容和当前分支内容的差异来更新工作区文件。这也是为什么切换分支前要求“工作区干净”,不然可能带着未提交的改动进入另一个分支,产生混乱。

4.2 git checkout/switch:切换分支的正确姿势

早期 Git 只有git checkout一个命令,身兼两职:切换分支和恢复工作区文件。命令用是能用,但职责不清晰。Git 2.23 版本引入了git switch专门负责分支切换,职责单一,推荐优先使用:

# 切换到已存在的分支 git switch 分支名 # 创建新分支并切换过去(两步合成一步) git switch -c 新分支名 # 切换回上一个分支 git switch -

如果你还在用旧版的git checkout -b 新分支名,也没有问题,只是注意别跟“用 checkout 恢复文件”混淆。

切换分支前一定要记住:确认当前工作区是干净的。如果你有未提交的改动,可以先 commit 或者 stash,不要直接切换。因为 Git 默认不允许带着会造成冲突的未提交改动切换分支,有时虽然让你切过去了,但改动会带过去,很容易搞乱。

4.3 git merge:合并分支的两种方式与冲突处理

把功能分支的成果合并回主干,用git merge:

# 先切换到要接收合并的目标分支 git switch main # 将 feature 分支合并到 main git merge feature

合并有两种情况:快进合并(Fast-forward)和三方合并(Three-way merge)。

快进合并发生在目标分支自从分支出来以后没有任何新提交,Git 只需要简单地把指针往前移动,历史是一条直线,非常干净。但实际开发中这种情况较少,因为主干通常不断有新提交。

三方合并发生在两个分支都有各自的新提交,Git 需要找两个分支的共同祖先,结合三份内容(共同祖先、当前分支、目标分支)做合并。如果两个分支改动了同一个文件的同一位置,Git 无法自动决定,就会报冲突。

冲突是新手最怕的场景,报错信息长得吓人。实际处理流程其实不超过三步:

  1. 打开提示冲突的文件,搜索<<<<<<<、=======、>>>>>>>标记
  2. 手动保留需要的代码,删掉这些标记
  3. 保存文件后执行git add 文件名,然后git commit完成合并

冲突文件里,<<<<<<< HEAD和=======之间是当前分支(HEAD)的版本,=======和>>>>>>> feature之间是被合并分支的版本。你需要读懂两边代码的意图,决定最终保留哪份,或者融合两边内容。

我的经验是:两段都要的情况远多于二选一,不要在冲突时急着删除另一方的代码,先读懂为什么要两边都改。有些冲突文件很大,处理起来耗神,但这是版本控制里非常正常的一环,处理多了就习惯了。

4.4 分支策略:为什么团队协作中 feature branch 是常态

理解了分支和合并,再聊聊日常开发中用得最多的分支策略。现在大多数团队都采用“主干开发 + 功能分支”的模式:

  • main或master是受保护的主干,永远保持可发布状态
  • 每个功能在一个独立分支上开发,分支名可以是feature/登录功能、fix/修复XXbug
  • 功能完成后通过合并请求(Pull Request / Merge Request)走代码评审流程合入主干

这种做法的价值在于:主干始终处于健康状态,任何时刻都可以部署发版;功能分支隔离了半成品的代码,不会影响其他人的工作;通过代码评审可以在合并前发现潜在问题。

你在本地开发时也建议养成开分支的习惯。一个需求开一个新分支,开发完成合并后删除分支,不要所有改动都堆在主分支上。理由很简单:如果改动做到一半需要去线上修 bug,在干净的主干上开一个hotfix分支修复合入,整个过程不会被半成品功能干扰。

5. 远程协作与撤销:remote、push、pull、fetch、stash、reset

这部分的命令直接关系到多人协作和代码安全,每一个都值得认真掌握。

5.1 git remote:管理远程仓库地址

查看远程仓库地址:

git remote -v

输出会列出origin对应的 URL,origin是 Git 默认给远程仓库起的名字。当你git clone一个仓库时,Git 自动把远程地址命名为origin。

如果你是在本地git init初始化的项目,想要关联一个远程仓库:

git remote add origin git@github.com:用户名/仓库名.git

如果远程地址变了,需要更新:

git remote set-url origin 新的地址

删除远程关联:

git remote remove origin

这块操作不多,但很重要,因为团队协作的一切推送和拉取,都是基于远程仓库来做的。

5.2 git push:把本地提交推送到远程

把本地已提交的内容推送到远程仓库:

git push origin 分支名

第一次推送一个新建的本地分支时,会需要建立与远程分支的关联关系:

git push -u origin 分支名

-u参数不仅推送到远程,还设置当前本地分支跟踪远程同名分支。设置之后,后续只要敲git push就能直接推送,不用再写远程名和分支名了,git pull同理。

推送时有几个常见报错值得提前了解:

“non-fast-forward” 错误:远程分支上已有你本地没有的提交,说明远程被其他人推送过了。解决办法:先git pull(或git fetch+ merge),再推送。

“failed to push some refs”:原因通常同上,或者你没有该分支的写权限。

推送前记得先 pull:我养成的习惯是推送前先git pull --rebase,把远程的新提交拉下来,让自己的提交“叠”在最新代码之上,保持历史线性,然后再 push。这样能减少冲突概率,也让历史记录更清晰。关于--rebase的详细机制,我们在后面章节展开讲。

5.3 git pull 与 git fetch:拉取代码的两种姿势

很多人以为git pull就是 “更新下本地代码”,这句话不准确。git pull其实是两条命令的合体:先执行git fetch拉取远程最新提交到本地一个特殊区域,再执行git merge将这些提交合并进你当前所在的分支。

git fetch单独执行时,只会把远程仓库的最新状态下载到本地,但不会动你当前分支的工作区和历史。你的本地仓库就会保留一份远程更新的引用,用git log FETCH_HEAD可以查看拉取下来的内容,确认无误后再手动决定如何合并。

git pull把 fetch 和 merge 合二为一,操作简洁,但它的合并行为有时会产生不必要的合并提交(merge commit),把历史记录搞得乱七八糟。这种情况下我会用:

git pull --rebase

--rebase方式下,Git 会先把你的本地提交“摘下来”,拉取远程最新提交后,再把你的提交按顺序重放到最新代码之上。最终效果是历史保持线性,没有多余的 merge commit,阅读起来像一条干净的直线。

这里有一个核心注意点:rebase 会改写提交历史,如果你已经把这些提交推送到了远程,并且其他同事基于它们做了工作,就不要再用 rebase 去操作这些提交,否则会把大家的历史搞得一团糟。判断标准很简单:只 rebase 那些“只存在于本地、从未推送过的提交”。

5.4 git stash:临时保存当前工作进度

开发做到一半,突然要切分支修 bug,又不想提交半成品代码,怎么办?git stash就是为了解决这个问题而生。

# 把当前未提交的改动(包括已暂存的和未暂存的)临时保存起来 git stash # 恢复最近一次保存的改动 git stash pop # 查看所有保存过的改动 git stash list # 恢复指定的一次保存(不删除那条记录) git stash apply stash@{1}

一个我特别推荐的习惯:git stash时加上描述信息,方便之后识别:

git stash push -m "登录功能开发到一半"

git stash list就能看到这条描述而不是一堆随机哈希。

什么时候用 stash?典型场景是:你正在开发功能 A,线上突然出了 bug 需要马上修。此时本地改动还没到提交的程度,如果直接切分支,这些半成品改动会跟着工作区走,非常危险。执行git stash后,工作区干净了,切分支修 bug、提交、推送,最后切回来执行git stash pop,你的改动原封不动地回来了。

需要提醒的是:git stash pop如果遇到冲突(因为你改动过的文件在 stash 期间被别人改了),会像 merge 冲突一样要求手动解决。这是 stash 机制的正常行为,按冲突处理的流程走就好。

5.5 git reset 与 git revert:两种撤销方式,别用混了

撤销操作是 Git 里最容易被误用的部分,也是新手事故高发区。先记住一个大原则:尚未推送到远程的提交,用什么方式撤销都行;已经推送到远程的提交,不要用 reset,而应该用 revert。

git reset的作用是把当前分支的 HEAD 指针回退到指定提交,有--soft、--mixed、--hard三个参数,影响范围从轻到重:

# 回退到上一个提交,但保留改动在工作区(改动取消暂存) git reset --soft HEAD~1 # 撤销提交和暂存,但保留所有改动在工作区 git reset --mixed HEAD~1 # 彻底回退,丢弃所有改动 git reset --hard HEAD~1

三个参数整天把新手绕晕,我提供一个简化记忆:--soft只动 HEAD 指针回归;--mixed在--soft基础上还清了暂存区;--hard则放弃所有改动、让工作区回到目标提交状态。

最常见的需求是“我提交了,但提交信息写错了要用git commit --amend”和“我提交了不该提交的文件要用git reset --mixed HEAD~1”。用--hard务必想清楚,它会丢掉无法找回的临时改动。

git revert刚好相反,它不是回退历史,而是创建一个新提交,把某个旧提交的改动反向撤销。这样历史是往前走的,其他人拉取代码时自然就能同步到这次撤销,不会因为各自 rebase 导致历史分叉:

git revert HEAD

执行后 Git 会打开编辑器让你写撤销提交的说明,保存后即完成撤销。

我给你们一个最简单的选择建议:代码还在自己本地没推出去,随便 reset;代码已经推送、或不确定别人是否已经拉取,一律用 revert。这是让团队协作不翻车的基本素养。

6. 高频场景实战:把 15 个命令串起来跑一遍

前面按命令逐个拆解,有朋友可能会问:真实开发中这些命令是怎么组合起来用的?这里以一个典型的功能开发周期为例,把完整的命令流串一遍。

6.1 场景一:新版本功能开发的标准流程

入职一家公司,第一次拿到项目代码,从环境配置到功能开发结束推送到远程,完整流程长这样:

# 1. 配置身份信息(只在全新环境做一次) git config --global user.name "你的名字" git config --global user.email "你的邮箱" # 2. 生成 SSH 密钥并配置到托管平台(只做一次) ssh-keygen -t ed25519 -C "你的邮箱" cat ~/.ssh/id_ed25519.pub # 3. 克隆项目到本地 git clone git@github.com:公司/项目.git # 4. 进入项目目录,为本次需求创建功能分支 cd 项目目录 git switch -c feature/新增用户导出功能 # 5. 开始开发,过程中随时查看状态 git status # 6. 开发完成,暂存改动 git add src/新增的源文件 git add test/对应的测试文件 # 7. 提交,写清说明 git commit -m "feat(user): 新增用户导出功能" # 8. 推送前先拉取最新代码,用 rebase 保持历史线性 git pull --rebase # 9. 推送到远程 git push -u origin feature/新增用户导出功能

这就是一个非常标准的日常开发闭环。第 8 步如果你不做git pull --rebase,而是直接 push 时被告知远程有新提交,那就得停下来做合并;提前 pull 一下,往往能更早发现冲突,冲突处理也更轻松。

如果是开发到一半被紧急任务打断,第 5 步之后实际操作会插一段 stash 操作:

# 紧急任务来了,先把半成品藏起来 git stash push -m "新增用户导出功能开发中" # 切回主干,修复线上 bug git switch main git switch -c hotfix/修复统计页崩溃 ... ... 修复、提交、推送 ... # 回到原功能分支,恢复进度 git switch feature/新增用户导出功能 git stash pop

这套流程跑完,你对 Git 的核心命令基本就形成肌肉记忆了。

6.2 场景二:提交信息写错了、文件加错了的补救

提交后发现把临时文件也包含进去了,或者提交信息写得不清楚,别慌,按下面的方案补救:

# 场景:还没推送,只是想改最近一条提交的说明 git commit --amend -m "更准确的提交说明" # 场景:还没推送,想撤销最近一次提交框架但保留改动 git reset --mixed HEAD~1 # 撤销后重新选择要提交的文件 git add 正确的文件 git commit -m "正确的提交说明"

注意,--mixed HEAD~1不回退工作区,你之前的文件改动都还在,只是暂存区被清空,需要重新 add。

6.3 场景三:线上代码出 bug,紧急回滚

假设功能上线后出现问题,需要立刻回退到上一个稳定版本。分两种状态:

代码还没推送到远程,本地回滚:

git reset --hard HEAD~1

代码已经推送到远程,多人协作环境下的安全操作是 revert:

git revert HEAD git push origin main

这样远程会新增一个“撤销提交”,代码内容回退到上一个版本的最终状态,历史中清楚留痕。后续想再恢复这次的功能,只要找到被 revert 的那个提交,用git revert <revert 提交的哈希>再反向操作一次就行。

7. 常见问题与排查技巧实录

最后把我在实战中遇到的 Git 高频问题做一个整理。这些问题不是冷门角落,而是几乎每个团队都踩过一遍的坑。

7.1 SSH 认证失败的排查步骤

不少同学配置完 SSH 密钥后,执行git clone git@github.com:...收到Permission denied (publickey)。逐条排查:

  1. 确认公钥是否粘贴完整:执行cat ~/.ssh/id_ed25519.pub,从头到尾复制一遍,不要漏字符
  2. 确认粘贴的平台对不对:GitHub 的公钥要加在 GitHub 后台,GitLab 的加在 GitLab 后台,别搞混
  3. 确认本机是否有多个密钥且用的是正确的那一个:查看~/.ssh/config配置,确认IdentityFile指向了正确的私钥路径
  4. 确认私钥权限:私钥文件权限应为 600,可以用chmod 600 ~/.ssh/id_ed25519修正。权限过宽会被 SSH 直接忽略,这是一个防呆设计
  5. 测试认证是否通过:
ssh -T git@github.com

如果显示认证成功,问题就出在 clone 地址写的是 HTTPS 而不是 SSH。这个排查顺序十次有九次能定位问题。

7.2 不小心 commit 了不该提交的文件

最常见的是把密钥文件、.env环境变量文件、大文件等误提交。此时判断是否已推送:

  • 未推送的话:git reset --mixed HEAD~1撤销提交但不丢改动,然后把这些文件加进.gitignore,重新提交
  • 已推送到远程的话:这已经属于需要立即处理的情况,因为文件内容和提交历史都已外泄。在团队协作中应第一时间告知同事,因为这个记录没法通过简单方式彻底抹掉。普通文件误提交可以在远程用 revert 的方式提交一个反向操作,但敏感信息意味着需要重新生成密钥或密码,因为泄露的凭证不能再用了。

避免这件事的最好办法是前置预防:

# 提交前一定会看的内容 git status git diff --cached

git diff --cached专门用来看“将要提交的改动”到底改了什么,把敏感信息拦截在提交之前,成本最低。

7.3 分支合并时冲突处理的心态与技术

面对冲突文件时,最常见的心态问题是慌。事实上冲突只是提示“Git 无法替你决定”,并不代表代码坏了。按我前面的方法打开文件,找到冲突标记区域逐段处理即可。

处理冲突时有一个地方要多问一句:双方代码是否在逻辑上都应该保留?如果一边是重构后的新实现,另一边是 bug 修复,通常应该保留最新的实现并合入修复逻辑;如果两边改了完全不同的模块,只是恰好同一个文件的相邻行,那么两边都要保留。

处理完冲突后,git add 文件然后git commit,合并就完成了。想中途退出合并回到合并前状态,执行:

git merge --abort

7.4 误操作了 git reset --hard 如何抢救

万一你已经执行了git reset --hard,发现文件内容全不对了,先冷静。Git 的 reflog 会记录 HEAD 指针的每一次移动,是 Git 的“后悔药”机制:

# 查看 HEAD 的历史移动记录 git reflog # 找到误操作之前那个提交的哈希 git reset --hard 那个哈希

git reflog的输出会列出所有 HEAD 变化,包括你刚才 reset 产生的记录。只要你的改动在某个提交中存在过,reflog 就能帮你找回。这也是为什么我反复强调“能不 reset --hard 就不 hard”,但真误操作了,补救路径一直是存在的。

7.5 常用命令速查表

把 15 个核心命令的信息汇总成一张速查表,建议收藏:

命令核心作用高频参数适用场景
git config配置身份与全局参数--global, --list新环境初始化
ssh-keygen生成 SSH 密钥对-t ed25519, -C配置免密认证
git clone克隆远程仓库到本地--depth 1首次拉取项目
git init初始化本地仓库目录名新项目起步
git status查看仓库当前状态-s, -b提交前确认
git add暂存文件改动-p, .提交前准备
git commit创建提交记录-m, --amend保存版本快照
git log查看提交历史--oneline, --graph, -p回溯代码演进
git branch管理分支-a, -d, -D分支生命周期管理
git switch切换分支-c分支切换
git merge合并分支--abort功能合入主干
git remote管理远程仓库-v, add, set-url远程协作配置
git push推送提交到远程-u分享代码
git pull拉取并合并远程更新--rebase同步远程最新代码
git fetch仅拉取远程更新而不合并配合 merge 使用查看远程状态后再决定
git stash临时保存工作进度push -m, pop, list切换分支前暂存改动
git reset回退分支历史--soft, --mixed, --hard本地提交撤销
git revert用新提交反向撤销旧提交HEAD远程已推送内容的撤销

这里我实际写了 18 个命令,超过了标题的 15 个。原因是日常开发中这 18 个命令高度协同,单拎出任何一个都会影响其他命令的理解。实际使用中,你会发现真正最核心的就是:config、status、add、commit、log、branch、switch、merge、remote、push、pull、stash、reset、revert、clone 这 15 个,另外几个是根据场景灵活搭配使用的辅助命令,同样建议掌握。

7.6 把 Git 用利索的几个小习惯

最后分享几个我这些年养成的 Git 使用习惯,不需要额外装工具,纯靠改习惯就能让协作体验提升一大截:

第一,每次提交前必须跑一遍git status和git diff --cached。前者看哪些文件会被纳入提交,后者看具体改动内容。这一步能拦截 90% 的误提交。

第二,提交信息遵循固定格式。我日常主力格式是type(module): description,type 用 feat/fix/docs/refactor/test,module 写模块名。这样之后回看历史,或者用工具生成变更日志,都能一目了然。

第三,推送前先git pull --rebase。这个习惯能有效减少冲突出现概率,让团队历史保持线性。不要等到 push 失败才去处理远程差异。

第四,本地功能分支尽量在一两天内完成并合并删除。长期不合并的分支会成为“技术债”,合并时冲突面巨大,且分支上写的内容往往已经跟主干脱节。

第五,不要试图覆盖已推送的历史。已经推送出去的提交,任何人可能在任何时刻拉取过。你本地怎么 reset 都只是你一个人的事,但一旦覆盖了远程历史,整个团队的仓库都会混乱。安全的改写历史方式只有新增提交(包括 revert),不会影响他人的工作副本。

这些习惯挂在嘴边不难,难的是真正执行。一旦它们在团队里形成共识,很多协作中的磕磕绊绊会少很多。

我自己的实际体验是:刚开始学 Git 时总觉得命令太多记不住,尤其是 merge 和 rebase、reset 和 revert 这两组概念绕了很久。后来发现,与其死记硬背,不如把“工作区、暂存区、版本库”三层结构和“提交 = 快照 + 指针移动”这条主线想清楚,所有命令的行为都能推导出来。建议各位在遇到不确定的命令时,先想清楚这一步操作会改变几个区域的状态,再敲回车,基本就不会出大错。Git 的学习曲线确实有点陡,但把它当成肌肉记忆练,一两个星期之后你就能体会到它给开发流程带来的掌控感。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 2:49:31

DeepSeek R1本地部署与知识库搭建:从Ollama到Dify实战指南

简介&#xff1a;PDF教程围绕DeepSeek R1的本地部署展开&#xff0c;面向想摆脱云端依赖、在个人电脑上运行大语言模型的开发者与普通用户。内容从安装Ollama入手&#xff0c;涵盖模型版本选择、命令行验证&#xff0c;再到Cherry-Studio界面化配置与密钥创建&#xff0c;最后讲…

作者头像 李华
网站建设 2026/10/5 2:49:02

SpringBoot实战:NBA数据分析系统开发全解析

带一份 SpringBoot 做数据分析系统&#xff0c;我当初选这个题&#xff0c;就是看中它“能跑通、能讲透、能扩展”。NBA 这个题材在课程设计和毕业设计里都属于讨喜的类型——导师一听就知道你要做什么&#xff0c;不用费劲解释业务背景&#xff1b;评审老师看演示的时候&#…

作者头像 李华
网站建设 2026/10/5 2:49:02

Java程序员转型大模型开发:向量数据库与RAG全攻略

Java程序员这个群体&#xff0c;过去十年被问最多的问题就是“你们到底是不是只会增删改查”&#xff0c;这几年风向又变了&#xff0c;变成“你会不会大模型开发”。我见过太多同事&#xff0c;一边刷着Spring Boot面试题&#xff0c;一边焦虑AI时代自己会不会被优化。其实Jav…

作者头像 李华
网站建设 2026/10/5 2:46:43

JSP+Servlet早餐外卖系统开发实战:从数据库到部署全流程解析

早餐外卖这个场景特别适合JSPServlet这套老牌技术栈来练手&#xff1a;业务链路完整&#xff0c;从前台点餐到后台出餐都有&#xff0c;又不至于复杂到失控。今天把这个基于JavaWeb和MySQL的JSPServlet早餐外卖店管理系统拆开揉碎讲一遍&#xff0c;从数据库设计到前端交互&…

作者头像 李华
网站建设 2026/10/5 2:46:12

内存对齐与缓存友好设计:从结构体布局到多核性能优化

1. 先搞懂内存对齐到底在解决什么问题我平时和人聊性能优化&#xff0c;十个里有八个觉得内存对齐是"编译器自动处理的事"——写几年代码也不见得主动查过某个结构体到底占多少字节&#xff0c;更没想过一个long long摆错位置会让程序慢上一大截。但真正在底层和高性…

作者头像 李华
网站建设 2026/10/5 2:46:12

生成式AI实战:从需求拆解到批量生成电商客服话术全流程

先交代个背景&#xff1a;这个《生成式人工智能实战》系列前四篇&#xff0c;我们聊过环境搭建、模型基础选型、文本生成任务的调参思路&#xff0c;还有多模态模型在图片理解上的坑。不少读者反馈说前面的内容偏“单点”&#xff0c;看完之后能跑通Demo&#xff0c;但一到真实…

作者头像 李华