简介:Git作为分布式版本控制系统的代表,是解决多人协作开发与代码历史管理的常用工具。这份以“最详细、最傻瓜”为卖点的PDF教程,面向零基础开发者,从Git起源讲起,逐步覆盖Windows安装配置、版本库初始化、git add/commit操作、版本回退与重置,并借助工作区、暂存区、master分支和HEAD指针的关系解释提交原理,适合快速建立完整认知后动手实践。资源为单个PDF文件,包体约3.05MB,内容以文字讲解和命令行示例为主,阅读门槛低,可随时查阅命令用法。目前已有10872人学习下载,是入门Git的高热度参考资料。按教程步骤操作,读者可以掌握创建仓库、提交版本、查看日志、回退历史版本等核心技能,同时理解分布式版本控制与集中式控制的区别,为后续使用GitHub协作开发打下扎实基础。
1. Git 到底是什么:一个十四天写出来的分布式版本控制系统
这份 git 使用教程不讲抽象概念,先放一个反直觉的事实:2005 年之前,Linux 内核代码很大程度靠 Linus 手工合并志愿者发来的 diff 补丁。他嫌 CVS、SVN 这类集中式系统速度慢又必须联网,商用方案又违背开源精神,代码库膨胀后手工合并也彻底撑不住了,于是 Linus 用两周时间写了自己的分布式版本控制系统,也就是 Git。它解决的三个核心问题是:多人同时改同一批文件不互相踩踏、任何时刻能回到任意历史版本、本地不联网也能完成提交与查记录。这篇教程从安装配置一路讲到分支合并和冲突处理,适合刚接触 git 想搞懂命令背后逻辑的新手,也适合用过一段时间但遇到 reset、回退、分支冲突就发怵的开发者。
2. 安装配置与仓库初始化:从装好到跑通第一条 git 命令
2.1 Windows 下安装与最小验证
Windows 上装 Git,官方安装包一路 Next,安装位置默认放 C 盘就行,不用刻意改。这里有几个安装界面的细节需要留意:在 Select Components 界面,默认勾选的 Git Bash Here 和 Git GUI Here 别取消,它决定了你在项目目录右键能不能直接开终端;在 Adjusting your PATH 界面,建议选 Git from the command line and also from 3rd-party software,也就是 Git 自带终端和 Windows 系统终端都能调用 git 的模式。选成只从 Git Bash 里调用的话,后面你在 IDE 里内置终端敲 git 会提示找不到命令。
装完之后的最小验证就一行命令:
git --version能输出版本号,说明 PATH 环境变量没问题。常见的翻车现场是:装完 Git 以后,打开的是安装之前就存在的终端窗口,敲 git 报“无法将 git 项识别为 cmdlet、函数、脚本文件或可运行程序的名称”。这不是没装好,而是终端缓存了旧的环境变量,重开一个终端窗口就解决了。还有种情况是安装时 PATH 选了 only use Git Bash,那就在系统环境变量里手动把 C:\Program Files\Git\cmd 加上,记得加完要重开终端。
装好之后,我习惯第一时间补两条全局配置,否则后续 commit 出来的作者信息会是一串从系统主机名猜出来的奇怪名字:
git config --global user.name "你的名字" git config --global user.email "你的邮箱" git config --listuser.name 和 user.email 是全局配置,作用于这台电脑上的所有仓库。git config --list 用来确认配置写进去没有,看到这两项就说明生效了。再补一条 git config --global init.defaultBranch master,把新建仓库的默认分支名统一成 master。Git 新版本默认建 main,如果教程里整天讲 master,你的项目却自动生成了 main,前后对不上就容易懵。
2.2 初始化第一个版本库
配置弄好之后,建一个专门放练习的目录,再初始化仓库:
mkdir git_test cd git_test git initmkdir 创建目录,cd 进去,git init 在当前目录初始化一个空仓库。命令执行完,目录下会多出一个隐藏的 .git 文件夹,Git 的版本库就存在这里面。终端会输出 Initialized empty Git repository 之类的提示,看到这行字才算初始化成功。这里有个容易忽略的点:git init 不是只能用在空目录,它也能在已有大量文件的目录里执行,执行完只是把目录纳入 Git 管理,文件本身还没有被记录,需要用后面的 add 和 commit 真正提交。
很多人喜欢随手在桌面、下载目录这种地方直接 git init,后来发现 git log 报 fatal: not a git repository (or any of the parent directories): .git,原因很简单:git 命令必须在仓库目录或其子目录里执行,它要靠 .git 目录向上逐级找仓库上下文。桌面不是一个仓库,也没有被某个仓库包含,自然什么都查不到。所以规范做法是先建一个专门的 git_test 目录,再初始化,别拿根目录当仓库玩。
另外要分清 git init 和 git clone 的适用场景:git init 是在本地从零建仓库,git clone 是从远程仓库复制整套历史和文件下来。日常接手现成项目,多半用 clone;想亲手理解 Git 内部结构,用 init 更直接。
2.3 认识 .git 目录:黑匣子其实没那么神秘
初始化之后,用 ls -a 看看目录内容:
ls -a cd .git ls -la.git 目录里的核心文件就几个:HEAD 记录当前分支指针指向哪,打开一般是 ref: refs/heads/master 这种内容;config 保存这个仓库的本地配置;objects 目录存所有提交和文件快照;refs 目录存分支和标签的引用。这个目录平时不用手动去改,但是知道它长什么样之后,后面遇到 HEAD detached、分支丢失、reset 误操作这类问题,排查范围会小很多。有一点要特别记住:.git 目录不能随便删,删了整个项目的提交历史就全没了,这不是开玩笑,我见过真的有人拿临时目录做实验,最后把整个 .git 拖进回收站,找都找不回来。
我还会在 init 之后顺手放一个 .gitignore 文件,把 node_modules、target、out、*.log 这类不该进版本库的东西提前排除掉。这不是本教程的核心,但建议在提交第一个版本之前就先写好,避免以后误提交一堆依赖包,到时候再收拾就麻烦了。到这里环境就绪,后面所有操作都在 git_test 目录下演示。
3. 版本创建与回退:add、commit、reset 三条命令的完整链路
3.1 第一个版本的完整链路:add + commit 两步走
先创建文件再提交,这是最标准的入门流程:
echo "this is the first line" > code.txt git add code.txt git commit -m "版本1"echo 后面的 > 表示覆盖写入,如果之前已有内容会被清空,所以第一次创建文件用 > 没问题,后面追加内容就得换 >>。git add 的作用是把文件放进暂存区,git commit 把暂存区的内容固化成一个版本,-m 后面跟的是提交说明。很多新手不理解 add 和 commit 为什么非得拆成两步,一步到位不好吗?这是因为 Git 想让你能控制“哪些修改被纳入这次提交”。你同时改了十个文件,可以只 add 其中三个,再 commit 这三个,剩下的留在暂存区或工作区慢慢处理,这种粒度控制是集中式版本控制很难给的。
3.2 git log 查看版本记录:commit hash 的使用价值
第一次提交之后,查看版本记录:
git log git log --onelinegit log 完整输出里能看到 commit 后跟着一长串 hash 值,还有作者、日期、提交说明。hash 是这个提交的唯一身份证号,后面回退、对比、合并全要依赖它。git log --oneline 是把每条记录压缩成一行显示,左边是 hash 前几位,右边是提交说明,日常看得最多的是这个版本。hash 不用全抄,命令行里一般取前 6 到 8 位就能唯一锁定一个提交。
很多人看 git log 只盯着提交说明,其实 commit hash 的价值远比想象大。比如你想知道两个月前某个功能是在哪个提交里引入的,用 git log --oneline 翻一遍历史,拿到 hash 后 diff 两个版本,就能精确定位改动。这个习惯越早养成越好,后面 reset 和 merge 都用得上。
3.3 版本回退与前进:reset、HEAD 指针与 reflog
现在给 code.txt 追加一行,创建第二个版本:
echo "this is the second line" >> code.txt git add code.txt git commit -m "版本2" git log --oneline这时版本 2 是最新的,内容有两行。想回到版本 1,用 reset 把 HEAD 指针往前拉:
git reset --hard HEAD^ cat code.txtHEAD 永远指向当前版本。HEAD^ 表示前一个版本,HEAD^^ 表示前前一个版本,HEAD~100 表示往前数 100 个版本。命令执行后,工作区文件也恢复到版本 1 的内容,所以 cat code.txt 只能看到第一行。这里的关键点是 --hard:它会同时重置暂存区和工作区,让三者都回到指定提交的状态。如果你只想把指针移动、但保留工作区里的改动,应该用 --soft;只想清空暂存区、保留工作区,用 --mixed。新手阶段先用 --hard,但心里要清楚这是一把重刀子。
更常见的问题是回退完后悔了,想回版本 2,但 git log 里已经看不到版本 2 的 hash 了。这时候用 git reflog:
git reflog git reset --hard <版本号>reflog 记录的是 HEAD 指针所有移动过的痕迹,哪怕你在 reset、checkout、merge 之后看不到某个提交,reflog 里也还留着它的 hash。很多人把 reflog 叫作“后悔药”,就因为它能把那些看起来已经消失的提交重新捞回来。要提醒的是 reflog 记录不是永久保留的,默认保留时间有限,但刚发生几分钟的操作一定还在,越早用越稳妥。
3.4 工作区、暂存区与 HEAD:理解这三者就理解了一半 Git
创建第二个文件 code2.txt,再修改一下 code.txt,然后执行 git status:
echo "second file" > code2.txt echo "this is appended to code.txt" >> code.txt git statusgit status 会把工作区里的变化分成两类:已跟踪文件被修改了(code.txt),和未跟踪的新文件(code2.txt)。到这里,必须把三个概念彻底搞清楚,否则后面的操作全是靠猜。工作区(Working Directory)就是你在电脑里看到的目录,文件都在这里被编辑;版本库(Repository)是 .git 目录,所有历史提交都存在里面;暂存区(Stage/Index)是 add 之后、commit 之前那块中间地带。master 分支是版本库里的主干时间线,HEAD 指针指向当前所在的分支。
git add 做的事情是把工作区的修改搬进暂存区,git commit 做的事情是把暂存区的内容一次性封装成新版本,固化到当前分支里。这也是为什么 Git 能实现一个非常实用的功能:你同时改了几个文件,但可以只提交其中一部分。把 code.txt 和 code2.txt 都 add 进暂存区后再 commit,新版本就包含两个文件的改动,提交完再 git status,工作区就是干净的。
3.5 撤销修改的三个场景:从 checkout 到 reset HEAD
改乱了代码不可怕,可怕的是不知道怎么恢复。先覆盖三种最常见的场景。
场景一:工作区文件改乱了,还没 add。
git checkout -- code.txtgit checkout -- 文件名 的作用是丢弃工作区里对该文件的全部改动,把文件恢复成暂存区或版本库里的状态。这里注意 checkout 和 -- 之间有空格,-- 是告诉 git 后面跟的是文件路径,不是分支名。新版 Git 推荐用 git restore 替代,但 checkout 写法兼容性更好,老的教程和旧版本环境都能跑。
场景二:不但改乱了,还 add 进暂存区了。
git reset HEAD code.txt git checkout -- code.txt第一步把文件从暂存区退回到工作区,相当于取消 add,第二步用 checkout 丢弃工作区改动。两条命令执行完,文件回到干净状态。
场景三:已经 commit 提交到版本库了,才发现改错。这就不是撤销文件,而是回退版本了,用前面讲过的 git reset --hard HEAD^ 把整个项目回到上一个提交。
这三种场景我在实际工作中反复用到,特别是场景一,每次提交前想丢掉临时调试代码,靠的就是这一句。不建议死记命令,记住一条主线就行:改动越晚被 Git 记录,撤销越容易;越往后走,撤销成本越高。
3.6 文件对比与删除恢复:git diff 和 git rm 的边界
先给 code.txt 再加一行,然后看工作区和当前版本的差异:
echo "this is the third line" >> code.txt git diffgit diff 默认比较工作区和暂存区之间的差异,输出里 + 表示新增行,- 表示删除行。如果你只想看两个版本之间的区别,用 git diff HEAD HEAD^,比较当前版本和前一个版本,调换两个参数位置就是反过来比较。这个命令的价值在于,你不需要等到提交完才知道自己改了什么,提交前看一眼 diff,能省掉很多“提交之后才发现多了一行不该有的代码”的尴尬。
删除文件的处理逻辑也需要提前讲清楚。如果确定某文件要从版本库里彻底移除,用 git rm 而不是系统里的 del 或 rm:
git rm code2.txt git commit -m "删除 code2.txt"git rm 会把工作区文件和版本库里的记录一起删掉,并把这个删除动作放进暂存区,紧接着 commit 就生效。如果只是误删了工作区的文件,还没提交删除,直接用 git checkout -- code2.txt 就能恢复。原理是:只要文件之前被提交过,版本库里就有它的快照,恢复工作区只是把快照重新取出来。但你只能恢复成最近一次提交的状态,最后一次提交之后做的修改会丢掉,这一点心里要有数。
这里也顺带澄清一个常被误解的点:git commit 提交的是“暂存区里这个时刻的内容”,而不是整个文件的当前状态。如果你在 add 之后又改了文件,但没有再次 add,那么 commit 带走的是第一次 add 时的内容,后面的修改会继续留在工作区里,显示为未暂存状态。这个坑几乎每个新手都会踩一次,记住它,后面能少翻好多车。
4. 分支管理实战:从创建分支到合并冲突
4.1 分支模型:指针、时间线与平行宇宙
分支是 Git 区别于 SVN 的核心能力之一,理解方式可以很直白:我们每次提交都会在版本库里串成一条时间线,这条时间线就是一个分支。master 指向最新提交,HEAD 指向当前分支。创建新分支,本质上只是新建了一个指针,让它也指向当前的这个提交,同时把 HEAD 挪到新指针上。所以 Git 创建分支极快,改个指针而已,工作区文件一个都不动。
至于什么时候需要分支,用平行宇宙来类比很贴切。你要开发一个新功能,预计两周做完,第一周代码写了一半。直接提交到主分支,不完整的代码会影响别人;憋着不提交,又怕自己电脑出问题把进度全丢了。分支的解法是:开一个 dev 分支,代码想提交就提交,完全不影响 master 上别人干活,功能做完再把 dev 合并回 master。两个分支各自演进,合并的时刻才交汇,这就是分布式版本控制最舒服的地方。
4.2 创建、切换与提交:在新分支上的完整流程
命令行操作按这套命令走:
git branch dev git checkout dev第一行创建 dev 分支,第二行切到 dev。更快的写法是 git checkout -b dev,一步完成创建加切换。在这之后提交的代码都走 dev 这条时间线,master 不会跟着动。验证当前分支用 git branch,不带参数会列出所有分支,带 - 号或星号的就是当前所在分支。
在 dev 分支上做一次提交,然后切回 master:
echo "this is dev line" >> code.txt git add code.txt git commit -m "dev 分支提交" git checkout master cat code.txt切回 master 再看 code.txt,内容里没有 dev 那行,因为那个提交只存在于 dev 分支上,master 的提交点没变。很多人第一次看到这个现象会愣住,以为是文件丢了,其实不是,只是你站到了另一条时间线上。要找回那行内容,把分支切回 dev,或者把它合并到 master。
4.3 合并分支:快进模式与普通合并
dev 分支的工作做完了,合并到 master:
git merge devgit merge 的作用是把指定分支合并到当前分支。如果合并时 master 自创建 dev 之后没有过任何新的提交,Git 会走 fast-forward 模式,直接把 master 指针移到 dev 的当前提交上,合并过程就是一次指针移动,速度飞快。完事后可以安全删除 dev:
git branch -d devgit branch -d 删除分支。这里有个细节:如果 dev 的提交还没有被合并到主分支,-d 会拒绝删除并提示,这是 Git 在保护你。真想强制删,用 -D,但一般在日常开发里用不上,也别轻易用。
4.4 解决冲突:处理 <<<<<<< 标记的手工流程
fast-forward 不是总能成功的。当 master 和 dev 都各自有新提交,并且都改了同一个文件,merge 就会冲突。比如 dev 分支改了 code.txt 的一行并提交,master 也在自己这边改了同一行并提交,这时执行 git merge dev,Git 会告诉你 code.txt 存在冲突,必须手动解决后才能提交。
先看文件内容:
cat code.txt你会看到 Git 在冲突文件里插入的标记:
<<<<<<< HEAD 当前 master 分支的内容 ======= dev 分支的内容 >>>>>>> dev<<<<<<< ======= >>>>>>> 把两边分支的内容分隔开了。处理方式不是命令,而是打开文件人工判断,决定保留哪边内容,或者把两边都改写掉,然后把标记行全部删干净,再重新提交。解决完要执行:
git add code.txt git commit -m "解决 code.txt 冲突"这里特别注意,解决冲突后的提交就是真正的合并提交了,和 fast-forward 不同,它会把两个分支的历史交汇点记录下来。用带参数的 git log 看会更直观:
git log --graph --oneline能看到分支在哪里分叉、在哪里汇合,整个演进过程一目了然。我处理冲突时的习惯是:先 git status 确认哪些文件冲突了,再逐个打开文件看标记,改完就搜索文件里是否还有 <<<<<<< 或 ======= 残留,确认干净了才 add 和 commit。
4.5 分支管理策略:--no-ff 的作用
fast-forward 虽然快,但有一个缺点:删除 dev 分支后,你会在历史里找不到这次合并是从哪个分支来的,分支信息被吞掉了。团队开发时,如果希望历史保留明显的“合并痕迹”,让后面的人能追溯,就得禁用快进模式:
git merge --no-ff -m "合并 dev 分支" dev--no-ff 强制 Git 生成一个新的合并提交,即使可以快速前进也不直接移指针。这样才会在时间线上留下一个明确的“合并节点”,配合 -m 把这次合并说明写清楚。代价是历史会多出一些合并提交,但对多人协作项目来说,可追溯性比一条笔直的提交线更有价值。小项目一个人开发,fast-forward 够用;多人团队一起干活,--no-ff 是更稳妥的默认姿势。
4.6 Bug 分支与 stash:临时保存工作现场
写功能写了一半,突然被告知有个紧急 bug 要马上修复,但 dev 上的代码才写了一半,没法提交。这时候 stash 就派上用场了:
git stash git stash listgit stash 把当前工作区的修改保存到一个临时的“储物间”,工作区瞬间变干净。确认没事之后,在 master 上建一个临时 bug 分支修 bug,修完合并删除,再回到 dev 分支恢复现场:
git stash popgit stash pop 会把最近一次 stash 的内容恢复到工作区,并把它从 stash 列表里移除。如果同一时间存了多个现场,git stash list 可以列出所有记录,配合 git stash apply stash@{0} 选择恢复哪一份。这个方法我在多任务切换时几乎每周都用,比手忙脚乱备份文件靠谱太多。关键点是 stash 不会保存未跟踪的新文件,只保存已经被 Git 跟踪的修改,新建的文件要先 add 进去才能被一起 stash。
5. Git 常见问题排查与避坑指南:五个高频翻车现场
5.1 fatal: not a git repository(在任何父目录中都不是 git 仓库)
现象:执行 git log、git status、git add 时报 fatal: not a git repository (or any of the parent directories): .git,后面跟着一长串提示。
原因:当前目录不在任何 Git 仓库内。Git 命令必须在一个已经初始化的仓库目录或其子目录中执行,它需要向上逐级寻找 .git 文件夹来建立上下文。很多人是在桌面、Downloads 或者一个新建的空白目录里直接敲 git 命令,忘了先 git init,或者忘了 cd 进仓库目录。
解决:先用 pwd 确认当前位置,再用 ls -a 确认当前目录或上级目录是否存在 .git;如果是个新项目,先执行 git init 初始化;如果项目是从远程克隆的,确认 clone 的目录位置。这个报错几乎每个新手都会遇到,看到它第一步别慌,排查目的就是确认有没有进入仓库。
5.2 提交后第二次修改“不见了”:忘了重新 add
现象:同一个文件被编辑了两次,第一次 git add 之后又往里加了内容,然后直接 git commit。提交完成后发现第二次的修改不在提交记录里,git status 还提示 modified。
原因:git add 把文件当时的快照放进了暂存区,之后你再次修改文件,暂存区里的内容并不会自动更新。git commit 提交的是暂存区的内容,不是工作区的当前内容,所以第二次改动根本没有进入这次提交。
解决:提交前先 git status 检查一下有没有漏掉未暂存的修改;有遗漏就把该 add 的文件重新 add 再 commit。追求效率的话,对已跟踪文件可以用 git commit -am "说明",-a 参数会先自动暂存所有已跟踪文件的修改,但新增的未跟踪文件仍然需要手动 add。我的习惯是提交前跑一遍 git status,再跑一遍 git diff 看改动,确认没有遗漏再 commit。
5.3 reset --hard 后工作区改动被清了:反悔要看 reflog
现象:执行 git reset --hard 后,不仅分支指针回到了旧版本,工作区里一堆未提交的改动也全没了,当场傻眼。
原因:--hard 参数会把工作区和暂存区一起重置到指定提交,所以它会覆盖掉所有未提交的修改。很多人只关注了“回退版本”这个行为,忽略了“连同工作区一起重置”的代价。
解决:如果是分支指针已经回退、但提交本身还在仓库里,用 git reflog 查看 HEAD 的移动记录,找到回退之前的那个提交 hash,再 git reset --hard 切回去。问题在于 reflog 只能找回已被提交的版本状态,未提交的工作区改动是真丢了。所以我现在每次执行硬回退之前,都会先 git stash 或者手动备份一份,宁可多一步也别冒这个险。
5.4 远程推送报 ssh 认证失败:URL 和公钥没对上
现象:git clone 或 git push 时出现 Permission denied (publickey)、Could not read from remote repository 这类报错,本地明明已经登录了平台网站,却依然推不上去。
原因:远程仓库地址用了 SSH 格式,但本机没有匹配的 SSH 私钥,或者公钥没有添加到 Git 托管平台。常见于新换了一台电脑,ssh 密钥没同步过去,或者之前用的是 HTTPS 地址,后来 remote 被改成了 SSH 格式。
解决:先执行 git remote -v 看当前远程地址是什么形式。图省事就改用 HTTPS 地址,重新设置 remote;要保留 SSH 方式,就执行 ssh-keygen 生成密钥对,用 cat ~/.ssh/id_rsa.pub 把公钥内容复制到 GitHub 等平台的 SSH keys 设置里,再用 ssh -T git@github.com 验证连通性。另外检查一下 remote 地址里的用户名有没有写错,很多时候认证失败纯粹是地址配错了。
5.5 合并冲突标记被直接提交:仓库里残留 <<<<<<<
现象:分支合并完成后,代码文件里出现大段 <<<<<<< HEAD ======= >>>>>>> 标记,而且还有同事已经基于这个文件继续开发了。
原因:处理冲突时只手动改了代码内容,没有把 Git 插入的冲突标记删除干净,或者解决完冲突后没有重新 add,而是直接 commit。很多新手不知道冲突标记是需要人为清理的,以为 commit 之后 Git 会自动处理。
解决:处理冲突的标准流程是,逐个打开冲突文件,人工判断保留哪些行,删掉全部标记行,然后 git add 标记为已解决,最后 git commit 提交。提交之前,我习惯在当前项目目录下搜一遍 <<<<<<< 字符串,确认没有残留再提交。这个检查在团队协作里很好用,因为冲突标记一旦混入主干,后面每个人都得替你收拾。
6. 把本地仓库推到 GitHub:最小可用流程与 reflog 兜底习惯
6.1 创建远端仓库并完成第一次推送
本地仓库已经提交了好几个版本,现在把它推到 GitHub 上。登录 GitHub 后在页面右上角 New repository,填一个项目名(比如 2020),勾上 Readme 文件,然后点 Create repository。创建完页面会给出一段命令提示,照做就行。本地已经有的仓库,执行:
git remote add origin https://github.com/你的用户名/仓库名.git git push -u origin master第一行把本地仓库和远端仓库建立关联,origin 是默认的远程仓库别名。第二行把本地 master 分支推送到远端,-u 参数会记录本地和远端分支的对应关系,之后提交完直接 git push 就行,不用再带分支名。如果第 5 章里的 ssh 问题没解决,就用 HTTPS 地址,推送时按要求输入账号密码或 access token,这是最不容易出错的方式。日常拉取远程更新用 git pull,它会自动把远端的新提交合并下来。如果你想改提交说明,轻量做法是 git commit --amend -m "新的说明",注意这是改写上一次提交,如果已经 push 出去了,就不要再随意改,会影响团队里的其他人。
6.2 reflog 兜底习惯:reset 前先留一个备份
最后一章讲一个我吃了亏之后养成的习惯。Git 的 reset --hard 在误操作时给人的冲击力是最大的,工作区改动一旦被覆盖,任何版本控制都救不回来。一开始我觉得 git reflog 是万能的后悔药,直到有一次我 reset 完又做了好几轮操作,reflog 里那条记录被新记录挤出了窗口,想找的那个提交彻底找不回来了,只能凭记忆补代码。从那以后,我每次执行 git reset --hard 之前,都会强制做两件事:第一件,git status 检查当前有没有未提交的改动,有就先 git stash;第二件,git reflog 看一眼当前 HEAD 的位置,把当前 commit hash 写到便签上。做好这两件事之后,reset 再硬,心里也有底。如果你想更稳,还可以在 reset 前临时创建一个备份分支,命令是 git branch backup-before-reset,这样就算 reflog 被刷掉了,分支引用还在,随时可以切回去。
这套 git 使用教程虽然覆盖到分支合并和远程推送,但真正的上手速度还是靠多敲。建议你按照第 3 章的节奏在 git_test 目录里把 add、commit、reset、checkout、merge 各跑一遍,亲眼看看文件内容前后的变化,再去看别人的项目,就不会再觉得终端里那些 commit 是一团乱麻了。希望帮到你。
本文还有配套的精品资源,点击获取