1. 项目概述:为什么你需要一份自己的Git指令速查表?
干了这么多年开发,我电脑里一直存着一个自己维护的Git指令速查表。这玩意儿不是什么高深的技术,但绝对是效率神器。你可能会说,网上教程一搜一大把,何必自己整理?但我的经验是,网上的内容要么太零散,要么就是官方文档的翻译,真正贴合你日常工作流、能帮你快速定位和解决问题的“肌肉记忆”指令集,还得靠自己沉淀。
Git作为版本控制的绝对主流,其指令体系庞大而精妙。新手面对git add、git commit、git push三板斧可能觉得够用,但一旦遇到代码冲突、分支管理混乱、误操作需要回滚,或者只是想优雅地整理提交历史时,就会手足无措。这时候,如果你手边有一份根据自己习惯和常见场景分类的速查表,就像老司机手边的扳手套装,哪把工具干什么活,心里门清,拿起来就用。
这份速查表的目的,不是替代官方文档,而是作为官方文档的“快捷方式”和“场景化注解”。它基于我踩过的无数坑、解决过的各种疑难杂症,将最常用、最关键、最容易出错的指令及其组合,按照实际工作场景(如日常提交、分支操作、代码回退、远程协作等)进行归类和解说。我会重点解释每个指令在什么场景下用、为什么这么用、以及用了之后可能会发生什么,附带那些官方手册里不会写的“血泪教训”。
2. Git核心概念与工作流精要
在深入指令之前,我们必须统一对Git核心模型的理解。很多人用不好Git,不是因为命令记不住,而是对工作区、暂存区、本地仓库、远程仓库这几个概念及其之间的关系模糊不清。
2.1 三棵树与一个仓库:Git的底层逻辑
你可以把Git的管理想象成在操作三棵树和一座仓库:
- 工作区 (Working Directory):就是你电脑里能直接看到、编辑的文件夹和文件。这是你的沙盘,所有改动最初发生在这里。
- 暂存区 (Staging Area / Index):这是一个中间缓存区域。你把工作区的改动
git add到这里,相当于把要提交的“快照”准备好。它让你可以精细控制哪些改动进入下一次提交。 - 本地仓库 (Local Repository):执行
git commit后,暂存区的内容就作为一个永久的快照存储在这里。本地仓库包含了项目的完整历史(所有提交记录、分支、标签)。 - 远程仓库 (Remote Repository):如GitHub、GitLab、Gitee上的仓库。用于团队协作和备份,通过
git push和git fetch/git pull与本地仓库同步。
核心心法:几乎所有的Git操作,都是在这四个区域之间移动或操作数据。理解了你当前的操作影响了哪棵树或哪个仓库,很多问题就迎刃而解了。
2.2 主流工作流模型选择
对于团队协作,选择一个清晰的工作流至关重要。这里介绍两种最实用的:
- Git Flow:功能强大,分支模型严格(主分支
master/main、开发分支develop、功能分支feature/*、发布分支release/*、热修复分支hotfix/*)。适合版本发布周期固定、流程规范的中大型项目。但分支较多,略显复杂。 - GitHub Flow / 简化Git Flow:更轻量敏捷。通常只有一个长期存在的
main分支,任何新功能或修复都从main拉取特性分支,开发完成后立即发起Pull Request合并回main。强调持续集成和部署,适合SaaS类产品或迭代快速的团队。
个人建议:对于大多数初创团队或中小项目,强烈推荐从简化版的GitHub Flow开始。它降低了分支管理的认知负担,鼓励小步快跑、频繁集成。等你和团队觉得需要更严格的发布控制时,再平滑过渡到完整的Git Flow也不迟。
3. 日常开发高频指令全解析
这部分是使用Git的“一日三餐”,必须做到条件反射般的熟练。
3.1 仓库初始化与克隆
一切开始于此。
git init:在当前目录初始化一个新的Git仓库。执行后会出现一个隐藏的.git文件夹,所有版本信息都存在这里。git clone <repository_url>:克隆远程仓库到本地。这是获取已有项目代码最标准的方式。repository_url可以是HTTPS或SSH格式。- 实操细节:使用SSH密钥克隆通常更安全便捷,无需每次输入密码。你需要先在本地生成SSH密钥对,并将公钥添加到你的Git托管平台(如GitHub)账户设置中。
3.2 文件状态跟踪与提交
这是最基础的版本控制循环。
git status:查看当前工作区和暂存区的状态。这是你使用频率最高的命令之一,用于确认哪些文件被修改、哪些已暂存、哪些未被跟踪。git add <file>:将工作区中指定文件的改动添加到暂存区。也可以用git add .或git add -A添加所有改动。- 重要区别:
git add .添加当前目录及子目录的所有改动(不包括被删除的文件,除非使用git add -u)。git add -A添加所有改动,包括新增、修改和删除。
- 重要区别:
git commit -m “<commit message>”:将暂存区的内容创建一个新的提交记录到本地仓库。提交信息commit message务必清晰,好的提交信息是 readable history 的基础。- 进阶技巧:
git commit -am “message”可以跳过git add步骤,直接提交所有已跟踪文件的修改(对新创建的文件无效)。这是一个快捷方式,但牺牲了提交的精细度。
- 进阶技巧:
3.3 查看历史与差异
了解过去发生了什么。
git log:查看提交历史。默认展示方式可能信息冗长,试试这些美化参数:git log --oneline:单行显示提交哈希和摘要。git log --graph --oneline --decorate --all:以图形化方式展示所有分支的提交历史,非常直观。
git diff:比较工作区和暂存区的差异(即,你修改了但还没add的内容)。git diff --staged或git diff --cached:比较暂存区和最后一次提交的差异(即,你已经add了,准备提交的内容)。git diff <commit1> <commit2>:比较两个特定提交之间的差异。
4. 分支操作与合并策略实战
分支是Git的杀手锏,但也是混乱之源。管理好分支,就管理好了并行开发。
4.1 分支的创建、切换与查看
git branch:列出所有本地分支,当前分支前会标有*号。git branch <branch_name>:基于当前所在分支,创建一个新的分支。git checkout <branch_name>:切换到指定分支。你的工作区文件会立即变成该分支的最新状态。git checkout -b <branch_name>:创建并立即切换到新分支。这是日常开发中最常用的组合指令。git branch -d <branch_name>:删除一个已合并的分支。git branch -D <branch_name>:强制删除一个分支,即使它还没有被合并。使用时要非常小心。
4.2 合并与变基:理解核心差异与选用场景
这是Git中最容易混淆,也最重要的部分。
合并 (Merge):
git merge <branch_name>- 做了什么:将目标分支
<branch_name>的修改整合到当前分支。Git会创建一个新的“合并提交”,这个提交有两个父提交。 - 优点:保留了完整的历史记录和分支的上下文,是非破坏性操作。
- 缺点:历史记录可能会变得复杂,出现交错的分支线。
- 适用场景:公共分支(如
main)合并特性分支时,或者当你希望保留特性分支的完整开发历史时。
- 做了什么:将目标分支
变基 (Rebase):
git rebase <base_branch>- 做了什么:将当前分支的提交“重新播放”到目标分支
<base_branch>的最新提交之后。相当于把当前分支的基底换成了目标分支的最新点。 - 优点:能产生一条线性的、更整洁的提交历史,便于阅读和追溯。
- 缺点:重写了提交历史,是破坏性操作。绝对不要对已经推送到远程仓库且可能被他人使用的分支执行变基!
- 适用场景:在本地特性分支上,定期同步主分支最新改动时。常用工作流:在
feature分支上,执行git rebase main,将main的新提交作为你新工作的起点,解决可能出现的冲突,然后再合并回main。
- 做了什么:将当前分支的提交“重新播放”到目标分支
黄金法则:只对你本地、未共享的分支进行变基。对于公共分支,永远使用合并。简单记:
rebase用于整理自己的历史,merge用于整合他人的工作。
4.3 解决合并冲突
冲突不可避免,当Git无法自动合并同一文件的同一部分的不同修改时,就会发生冲突。
- 识别冲突:执行
merge或rebase时,Git会提示CONFLICT。git status会显示Unmerged paths。 - 查看冲突文件:打开冲突文件,你会看到类似这样的标记:
<<<<<<< HEAD 这是当前分支的代码 ======= 这是要合并进来的分支的代码 >>>>>>> branch-name - 手动解决:与相关同事沟通,决定保留哪部分代码,或进行整合。删除冲突标记
<<<<<<<,=======,>>>>>>>。 - 标记已解决:解决完所有冲突文件后,用
git add <file>将每个解决后的文件标记为已解决。 - 完成操作:如果是合并冲突,执行
git commit(Git会为你预填合并信息)。如果是变基冲突,执行git rebase --continue。
5. 代码回退与撤销操作指南
误操作是常事,Git提供了多种“后悔药”,但用法各异,吃错药可能更糟。
5.1 撤销工作区的修改(未add)
git checkout -- <file>:丢弃工作区中对某个文件的修改,将其恢复到最近一次git add或git commit时的状态。这是一个危险操作,因为改动将永久丢失。git restore <file>:Git较新版本(2.23+)推荐的命令,作用同git checkout -- <file>,语义更清晰。
5.2 撤销暂存区的修改(已add,未commit)
git reset HEAD <file>:将某个文件从暂存区撤出,放回工作区。文件内容修改还在,但状态变成了“未暂存”。git restore --staged <file>:同上,新版本推荐命令。
5.3 撤销提交(已commit)
这是重灾区,分几种情况:
- 情况一:撤销上一次提交,但保留修改在工作区(相当于重新编辑后再提交):
git reset --soft HEAD~1HEAD~1指向上一个提交。执行后,最新的提交被撤销,但那次提交所做的所有修改都回到了暂存区。
- 情况二:撤销上一次提交,且丢弃修改(完全当作没提交过):
git reset --hard HEAD~1- 警告:这是最危险的命令之一!它不仅撤销提交,还把工作区和暂存区的相关修改全部丢弃,无法轻易恢复。除非你100%确定,否则慎用。
- 情况三:创建一个新的提交来“反做”之前的提交(推荐用于已推送到远程的提交):
git revert <commit_hash>- 这会创建一个新的提交,其内容正好是撤销指定提交的修改。历史记录中会保留原提交和这次撤销提交,是一种安全的、非破坏性的撤销方式,特别适合团队协作。
5.4 储藏临时改动
当你需要临时切换分支,但手头的工作还没完成到可以提交的程度时:
git stash:将当前工作区和暂存区的改动“储藏”起来,让你的工作目录恢复干净。git stash list:查看所有的储藏列表。git stash pop:应用最近一次的储藏,并从储藏列表中删除它。git stash apply stash@{n}:应用指定的储藏(n是列表编号),但不从列表中删除。git stash drop stash@{n}:删除指定的储藏。
6. 远程协作核心指令详解
个人玩转本地仓库只是开始,团队协作才是Git价值的体现。
6.1 关联远程仓库与信息查看
git remote add origin <url>:将本地仓库与一个远程仓库关联,并给这个远程仓库起个别名叫origin(这是约定俗成的名字)。git remote -v:查看已配置的远程仓库地址。git remote show origin:查看远程仓库origin的详细信息,包括分支跟踪关系。
6.2 推送与拉取:理解Fetch, Pull, Push
git fetch origin:从远程仓库origin下载所有最新的提交、分支等信息到你的本地仓库,但不会自动合并到你的工作区。这是一个安全的操作,让你先看看远程发生了什么变化。git pull origin <branch_name>:相当于git fetch+git merge。从远程拉取指定分支的最新改动,并尝试合并到当前本地分支。如果遇到冲突,需要手动解决。git pull --rebase origin <branch_name>:以变基方式拉取。这会使你的本地提交在远程更新之后“重放”,保持历史线性。如果你习惯用rebase整理历史,可以用这个。
git push origin <branch_name>:将本地指定分支的提交推送到远程仓库的同名分支。git push -u origin <branch_name>:在第一次推送分支时使用-u(--set-upstream)参数,建立本地分支与远程分支的跟踪关系。之后在这个分支上直接使用git push即可。git push origin --delete <branch_name>:删除远程分支。
6.3 跟踪分支与上游分支
当你从远程克隆仓库或拉取分支后,本地分支会自动跟踪对应的远程分支。你可以通过git branch -vv查看跟踪关系。如果跟踪关系丢失或错误,可以手动设置:git branch -u origin/<remote_branch> <local_branch>
7. 高级技巧与场景化指令组合
掌握了基础,这些进阶技巧能让你如虎添翼。
7.1 交互式变基:重写提交历史
git rebase -i HEAD~n:交互式地修改最近的n次提交。会打开一个编辑器,你可以:
pick:保留该提交。reword:保留提交但修改提交信息。edit:保留提交,但暂停rebase以便你修改提交内容(比如增删文件)。squash:将该提交合并到前一个提交中,并允许你重新编辑提交信息。fixup:类似squash,但直接使用前一个提交的信息,丢弃本提交信息。drop:丢弃该提交。
这是整理凌乱提交历史的利器,同样只适用于未推送的提交。
7.2 二分查找:定位问题提交
当发现一个bug,但不确定是哪个提交引入的时候:git bisect startgit bisect bad# 标记当前版本为“有问题”git bisect good <commit># 标记一个已知没问题的旧提交 Git会自动切换到中间的一个提交,让你测试。你根据测试结果输入git bisect good或git bisect bad,Git会不断二分查找,直到定位到第一个引入问题的提交。最后用git bisect reset结束。
7.3 子模块:管理项目中的项目
当你的项目需要包含并使用另一个独立的Git项目时:
git submodule add <repository_url> <path>:添加子模块。git clone --recurse-submodules <repository_url>:克隆主项目时同时克隆并初始化所有子模块。- 更新子模块:进入子模块目录,像普通Git仓库一样拉取更新,然后在主项目目录提交子模块指针的变更。
子模块功能强大但管理稍复杂,对于简单的依赖,现在更推荐使用包管理器或直接引用编译产物。
8. 常见疑难杂症排查与解决方案实录
这里记录的都是实战中高频出现的问题和我的解决思路。
8.1 提交到了错误的分支
场景:在feature/login分支上写代码,忘记切换,直接在主分支main上commit了。解决方案:
- 在
main分支上,创建新分支保存这些提交:git branch temp-branch。 - 切换回
main分支,用git reset --hard HEAD~1(如果只有一个错误提交)把main分支硬重置到之前的状态。注意:确保temp-branch已经保存了你的工作。 - 切换到正确的
feature/login分支,然后合并临时分支:git merge temp-branch。 - 删除临时分支:
git branch -d temp-branch。
8.2 提交信息写错了(还未push)
场景:刚执行完git commit -m “fxied typo”,发现信息有拼写错误。解决方案:git commit --amend -m “fixed typo”这个命令会修改最近一次提交的提交信息。如果还想修改提交的文件内容,可以先修改文件,然后git add,再执行上述命令。
8.3 推送被拒绝:非快进式更新
场景:git push时提示! [rejected] main -> main (non-fast-forward)。原因:远程分支有你本地没有的新提交,Git为了保护这些提交,拒绝你的推送。解决方案:
- 首选(推荐):先拉取合并。
git pull origin main。解决可能出现的冲突,提交合并结果,然后再git push。 - 强制推送(危险!):
git push -f或git push --force-with-lease。这会用你的本地分支覆盖远程分支。仅在完全确定远程分支上的新提交无用,且只有你一人在操作该分支时使用。在团队协作中,强制推送是万恶之源。
8.4 想恢复被删除的分支或硬重置丢失的提交
场景:误操作git branch -D或git reset --hard,发现还有代码没保存。解决方案:Git在彻底清理前会保留一段时间的引用。立即使用git reflog命令。它会显示HEAD和分支引用在本地仓库的所有移动记录。找到删除/重置之前的那个提交哈希,然后用git checkout -b <new_branch_name> <commit_hash>在那个提交上创建一个新分支,你的代码就回来了。
8.5.gitignore规则不生效
场景:已经将文件(如logs/目录)加入.gitignore,但它仍然出现在git status中。原因:该文件已经被Git跟踪了。.gitignore只对未被跟踪的文件生效。解决方案:先从Git索引中删除该文件(但保留在本地磁盘):git rm --cached -r logs/然后提交这次删除。之后,该目录下的文件就会被.gitignore规则忽略。
8.6 合并/变基时陷入冲突,想中止
场景:解决冲突到一半,发现太复杂,想先回退到操作前的状态。解决方案:
- 对于合并冲突:
git merge --abort - 对于变基冲突:
git rebase --abort这两个命令能安全地中止当前操作,回到命令执行前的状态。
这份速查表是我多年工作的沉淀,它不是一个静态的文档,而应该随着你的技术栈和工作流演变而不断更新。最好的学习方式就是在实际项目中反复使用这些命令,遇到问题就回来查阅、理解、并记录下你自己的心得。最终,你会形成一套最适合自己的Git操作体系,那才是真正的效率之源。