Git入门指南:暂存区、提交、撤销与分支操作实战 📅 发布时间:2026/9/9 17:41:18 👁 浏览次数: 先别急着敲命令打开终端之前我建议你先花五分钟想清楚一件事Git 到底是怎么“记住”你的文件的。这篇《Git入门指南二基本操作》接在上一篇安装与配置后面默认你已经装好了 Git、设置好了 user.name 和 user.email。这一篇我会带你走一遍日常开发最高频的“增删改查”操作git init、git add、git commit、git status、git log、git diff再顺手处理掉那些“不小心改错了想撤回”“提交完了才发现少了个文件”的尴尬局面。适合刚装完 Git 还不知道第一步干什么的新手也适合那些会点命令但完全没搞懂“暂存区”到底是什么的朋友——搞清楚这套流转逻辑后面所有进阶操作都会顺很多。1. 基本操作的整体思路先给仓库建三个“格子”1.1 核心概念工作区、暂存区、版本库很多新手学 Git 死在同一个地方背了一堆命令却不知道这些命令到底在操作什么。其实 Git 管文件的方式非常朴素它就给了你三个“格子”。工作区Working Directory就是你电脑上肉眼能看到的那些文件。你新建一个index.html它在工作区里你改了一行代码改动的也是工作区里的文件。暂存区Staging Area / Index这是一个中间缓冲区英文文档里也叫 Index。你可以把它理解成“准备提交的候车区”。你把文件用git add丢进去文件就被登记到了暂存区但还没有真正成为一次版本记录。版本库Repository / .git这是 Git 真正存“快照”的地方对应你项目根目录下的.git隐藏目录。每一次git commit都会把暂存区里的内容固化成一个版本存进版本库里。用做饭来类比工作区是你案板上刚洗好切好的菜暂存区是装好盘的小料版本库则是你按菜单一道道做出来、端上桌的成品。你随时可以往案板上加菜改文件也可以决定哪些菜先下锅add 哪些文件做得不满意了还可以倒掉重来撤销操作。这套“分步走”的设计是 Git 和 SVN 这类老牌版本控制系统最大的区别。对应到文件状态上Git 把文件分成四种状态未跟踪Untracked、已修改Modified、已暂存Staged、已提交Committed。新手最容易迷路的点就在“已修改”和“已暂存”之间——改完文件是 Modifiedgit add之后变成 Stagedgit commit之后变回干净状态。整个流程跑顺了你就能准确预判每一步执行完文件在哪个格子里。1.2 为什么这套设计是合理的第一次接触暂存区的人大概率都会问一句“我改完文件直接保存提交不行吗为什么非要先 add 一下”这个设计初看啰嗦实际用起来是救命的。最直接的好处是可以把一次命令拆成两件独立的事。比如你改了两个文件一个修了登录页的 bug另一个是随手改的样式调整但你只想把 bug 修复作为一次独立提交样式改动留到下一次——没有暂存区的话你得先备份、改回、再提交非常狼狈。有了git add你可以只把登录页那个文件加进暂存区提交然后再把样式文件加进来提交。提交历史的粒度变细了以后出问题回滚的时候你能精准定位到每一次变动。暂存区还给你留了一个**“反悔缓冲”**。提交是写进版本库的改起来相对麻烦但暂存区里的东西想调整很容易git reset一下就能把文件从暂存区退回到工作区什么都不丢。换句话说暂存区是你和版本历史之间的一堵软墙它给了你一个“提交之前最后看一眼”的机会。2. 第一次提交把仓库“跑起来”2.1 git init 与仓库建置磨刀不误砍柴工。先把仓库建出来。我习惯每个项目单独建一个目录然后在目录里执行mkdir git-demo cd git-demo git init执行完git initGit 会输出一句Initialized empty Git repository in ...同时在这个目录下生成一个.git文件夹。这个文件夹就是版本库本体里面装的是 Git 的全部内部数据——你手动删了它项目的文件还在但版本历史就全没了。所以.git文件夹要像命根子一样护着正常情况下不要进去乱动更别把它提交到 Git 里。看一下.git目录里这几个关键部分config文件保存仓库级配置比如你给这个仓库单独指定的用户名HEAD文件指示当前处于哪个分支objects目录存放所有版本快照的压缩数据refs目录存放分支和标签的引用地址。新手不需要深入理解这些内部结构但知道它们的存在以后遇到“为什么不显示提交”“分支怎么不见了”这类问题排查方向会清晰很多。顺便说一句如果你在已有文件的项目里执行git init也没问题Git 会把当前所有文件标记为未跟踪untracked不会自动帮你提交它们也不会改动文件内容。也就是说在任何已有项目里初始化 Git 都是安全的。2.2 add、status、commit提交三步曲仓库建好了往里面放一个文件试试echo hello git hello.txt git statusgit status会告诉你当前仓库的状态。这时候hello.txt会出现在 “Untracked files” 区域后面还有一行提示告诉你git add可以把文件跟踪起来。这个提示本身就是新手最好的老师刚开始不记命令都行只要养成“每次都看一下提示再动手”的习惯。接下来进入核心三步git add hello.txt git commit -m add hello.txtgit add把文件挪进暂存区git commit -m把暂存区里的内容固化成一次版本记录。提交之后 Git 会输出类似这样的信息[master (root-commit) 5d1f3a0] add hello.txt 1 file changed, 1 insertion()这表示提交成功了5d1f3a0是这次提交的短哈希值相当于这次版本的身份证号。此时再执行git status会看到 “nothing to commit, working tree clean”工作区干净了所有文件都已经归档进了版本库。三个命令里git add的变体最值得多花点时间熟悉git add .把当前目录下所有新增和修改的文件加进暂存区是最常用的写法。注意它默认不包含被删除的文件某些版本行为略有差异新手不用太纠结。git add -A把所有改动包括删除全部加进暂存区比add .更彻底。git add -p进入交互模式让你逐个 hunk 代码块选择是否暂存。这个属于进阶技巧但非常实用适合“想把一个文件里的一部分改动提交、另一部分留下”的场景。git commit也有一堆讲究。第一个建议是尽量每个提交只做一件事。提交信息用动词开头、祈使句比如fix login bug、add user profile page不要写update这种什么信息也没提供的词。我见过太多“update”满天飞的仓库半年后回看历史完全想不起来那个提交是干嘛的。2.3 提交之前先看变化git diff 的两个视角新手最容易犯的错是“改了一堆、提交完才发现改错了”。git diff就是给你在这个环节把最后一次关的。git diff本身有两种最常见的用法git diff查看工作区与暂存区之间的差异也就是“我改了但还没 add 的内容”。git diff --staged等价于git diff --cached查看暂存区与最近一次提交HEAD之间的差异也就是“我已经 add 了、准备提交的内容”。我个人的操作节奏是改完代码先git diff看一遍工作区的改动确认没问题后git add再用git diff --staged检查一次准备提交的内容确认无误才git commit。两步检查看似多花几秒钟实际能拦下大量的低级错误比如不小心把调试用的console.log也提交上去了。拿刚才的例子串一遍echo second line hello.txt git diff git add hello.txt git diff --staged git commit -m append second line你会看到第一次git diff显示的是工作区里那行新增内容git diff --staged显示的则是暂存区里等待提交的内容。数据源不同展示的内容阶段也不同把这两个命令练成肌肉记忆基本就不会再出现“提交了不是预期内容”的事故。3. 版本的回溯与撤销把做错的事“反悔”回来3.1 git log先看历史再动手术要撤销什么首先得知道历史长什么样。git log就是版本历史的说明书。最基本的用法git log会带出完整的提交记录、作者、提交时间和提交信息。不过这个输出在提交多了以后有点冗长我日常最常用的是这两个变体git log --oneline git log --graph --oneline --all--oneline把每个提交压缩成一行短哈希 提交信息扫一眼就知道历史脉络。--graph会画出分支和合并的路线图配合--all可以看到所有分支的提交情况排查问题时的信息量非常足。在开始任何撤销操作之前养成先跑一遍git log的习惯。你得先确认要回的版本是哪个哈希值别凭着记忆猜。哈希值也可以不用复制完整的那一串Git 支持前缀匹配复制前 6-7 位就足够唯一了。3.2 git reset回到过去的三种模式git reset是撤销操作的“重武器”它的核心作用是把当前分支的 HEAD 指针挪到历史某个位置顺便决定暂存区和工作区跟不跟着变。理解它之前先记住一个口诀reset 的三种模式管的东西不一样多。git reset --soft commit只移动 HEAD 指针暂存区和工作区都不动。也就是说你 reset 之后之前 add 的内容还在暂存区文件内容也没变只是版本历史回退了。适合“提交完了发现忘了 add 某些文件想重新提交”的场景。git reset --mixed commit默认模式移动 HEAD并且把暂存区重置成和这个 commit 一致但工作区文件不变。这是最常用的模式适合“提交完发现内容不对想撤销提交但保留文件修改”。git reset --hard commit移动 HEAD暂存区和工作区全部重置成目标 commit 的状态。这是最危险的操作用它等于把目标 commit 之后的所有文件改动全部抹掉没有后悔药。举一个实际场景我提交了一个文件但马上发现提交信息写错了或者漏掉了一个文件。这时候我通常用--soft回退一步git reset --soft HEAD~1HEAD~1表示“上一个提交”。执行完之后提交历史往前退了一条但暂存区里还保留着你上一次提交的全部内容文件也原封不动。这时候你可以重新git add漏掉的文件再次git commit -m 正确的提交信息一次干净利落的“后悔药”。如果你做了一次提交但想保留文件改动、把提交历史彻底抹掉用默认的--mixedgit reset HEAD~1文件改动会回到工作区所有暂存状态被清空提交历史少了一条。你可以在工作区继续修改想好之后重新 add、提交。关于--hard的警告不要轻易用用之前至少确认三遍。如果你连续提交了三五次发现方向全错了想全部推倒重来可以用--hard回退到最初的提交点但前提是你确定中间这些改动全都是废的。如果只是某个文件的改动是废的你更需要的可能是git checkout -- file或者git restore file这种单文件恢复命令。哦对想完全抹掉提交的时候还可以配合git push --force但那是协同场景等以后讲冲突处理的时候再展开。3.3 git revert用一次新提交来“抵消”错误提交git reset有个致命短板它会改写历史。如果你已经把这个提交推送push到了远程仓库别人也已经拉取pull了你 reset 之后再 push必然引发冲突和混乱。这种多人协作场景下正确做法是用git revert。git revert的逻辑不是“把头移回去”而是“做一次反向操作”。比如你提交了一个文件里面加了一行console.log你执行git revert HEADGit 会生成一次新的提交这次提交的内容刚好抵消掉上一次提交的改动——相当于把多出来的那行删掉。版本历史是一条往前延伸的线没有发生过“历史重写”远程协作的同伴 pull 下来也不会出问题。配套git log一起用你还能精准找到某个历史提交并把它 revertgit log --oneline git revert 5d1f3a0执行时 Git 可能会打开编辑器让你填提交信息默认信息是Revert 原来的提交信息直接保存退出就好。新手看到这里大概率会纠结“那我到底该用 reset 还是 revert”我给你一个傻瓜判断标准如果这个提交只在你本地用 reset如果已经推送到了远程用 revert。前者是你自己的事怎么都好说后者涉及别人的本地历史绝对不能重写。3.4 文件的删除与改名让 Git 知道“少了一个文件”你可能会说删文件不就是rm一下嘛有什么好讲的这里坑点相当隐蔽。假设你仓库里有个hello.txt你直接在文件管理器里把它删了再去git statusGit 会提示你有一个 “deleted” 状态的文件。如果这时候直接git commit -m delete hello.txtGit 会拒绝因为删除操作还没有被记录到暂存区。正确做法是git rm hello.txt git commit -m delete hello.txtgit rm会同时完成“删除工作区文件”和“把删除动作暂存”两件事之后提交就顺理成章了。如果你是用系统命令删的也可以用git add -A把删除动作补进暂存区效果一样。改名同理。直接在文件管理器里把hello.txt改名成greeting.txtGit 会把它理解为“删除 hello.txt 新增 greeting.txt”提交后历史里会有两条记录。更优雅的做法是git mv hello.txt greeting.txt git commit -m rename hello.txt to greeting.txtGit 内部的“重命名检测”其实不看命令而是看文件内容相似度git mv只是帮你省去“先 rm 再 add”的步骤。但养成用git mv的习惯好处是别人看你的操作记录时一眼就能看出这是一个改名动作而不是“删了一个又加了一个”可读性完全不同。4. 分支操作把开发线“岔开”再“合拢”4.1 为什么分支操作是 Git 的“大招”如果只学一个 Git 功能我会毫不犹豫选分支。Claude、GitHub Copilot 这些工具再强也替代不了分支给你带来的并行能力。给一个最容易理解的类比你在同一台电脑上维护着两个版本的简历一份是“面向外企的英文版”一份是“面向国企的中文版”。如果只有一份文件每次改版本前都得先复制一份特别容易把两版搞混。分支就是 Git 帮你实现“同一份文件多个修改方向并存”的机制——你在一个分支上改英文版另一个分支上改中文版互不干扰什么时候想合并了再合。分支在 Git 内部其实只是一个指向提交的指针创建和切换的成本极低这正是它比传统版本控制系统的“拷贝目录”方案高明的地方。哪怕你的仓库有几百个分支也不会多占多少磁盘空间。所以放开了建分支建错了删掉也不心疼。4.2 分支的新建、切换与合并继续用我们的git-demo演示。先看看现在在哪个分支上git branch默认情况下你会在master某些新版 Git 默认是main分支上。新建一个分支并切过去git branch feature-login git checkout feature-login这两条命令可以合并成一条git checkout -b feature-login。我平时几乎都这么写。如果你用的是 Git 2.23 以上版本更推荐用新命令git switch -c feature-login——checkout同时肩负着“切分支”和“恢复文件”两个职责职责不单一新手容易混淆switch就是专门负责切分支的。切到feature-login分支后改点东西echo login page login.html git add login.html git commit -m add login page然后切回主分支git checkout master注意你切回主分支后login.html这个文件就“消失”了——别慌它只是在feature-login分支里存在主分支的历史里没有这个文件所以工作区里看不到它。这正是分支隔离性的体现在不同分支上工作工作区的内容完全不同。接下来把功能分支合并回主分支git merge feature-loginGit 会把feature-login上多出来的提交合进来如果两个分支修改的文件互不冲突合并是自动完成的。这时候再看一眼git log --oneline --graph你会看到一条从主分支分出又合回的轨迹成就感直接拉满。4.3 第一次遇到冲突怎么办不冲突是幸运冲突才是常态。当两个分支改了同一个文件的同一行Git 就没法替你决定保留哪个版本了它会告诉你CONFLICT (content): Merge conflict in login.html Automatic merge failed; fix conflicts and then commit the result.这时候打开冲突文件你会看到类似这样的内容 HEAD div当前分支的内容/div divfeature-login 分支的内容/div feature-login HEAD到之间是当前分支的内容到 feature-login之间是对方的改动。你要做的是手动编辑这个文件决定最终保留成什么样然后删掉标记符号最后git add login.html git commit -m resolve merge conflict记住一个关键点冲突解决完成后提交一次就可以了不需要再手动跑git merge。这一节只讲最基础的处理流程像 git rebase 那种更高级的“改写历史式合并”等后面讲“进阶操作”时再展开入门阶段掌握merge 手动解决冲突已经足够覆盖绝大多数日常需求。4.4 远程仓库与克隆把代码搬到另一台电脑上“基本操作”讲到这里理论上你已经可以在本地愉快地玩耍了。但版本控制最大的价值在于协作和备份这就要用到远程仓库了。这一节只讲两个最基础动作克隆和推送。从远程拉一个项目到本地git clone https://github.com/username/repo.git执行完当前目录下会出现一个repo文件夹里面既包含全部代码也包含完整的版本历史。这一步做完你就拥有了这个项目的完整本地副本之后的git log、git branch、git add、git commit全部照常使用。把一个本地仓库推到远程需要先关联远程地址git remote add origin https://github.com/username/repo.git git push -u origin master第一次推送时-u参数会把本地分支和远程分支建立关联之后就可以简写为git push。别人改完了代码你拉取最新内容git pull这里稍微提一句git pull实际是git fetchgit merge的简写先抓取远程的新提交再合并到你当前分支。入门阶段你可以把pull当成“从远程把最新代码拿下来”的一站式命令但心里要清楚它是两个动作的组合以后遇到 “pull 之后冲突了” 的情况才能知道是在哪一步出的问题。5. 常见问题与排查技巧实录5.1 新手高频问题速查下面这些问题是我在带新人时几乎每周都会遇到一次的经典坑。整理成一张速查表踩坑的时候直接对着找。现象原因解决办法git commit后敲了git log发现提交人有误全局 user.name/user.email 没配好git config --global重新配置后再提交输入git status后中文文件名显示成\xxx\xxx的转义码Git 默认对非 ASCII 文件名做了转义执行git config --global core.quotepath falsegit add .后提交最后发现少了一个文件.gitignore把那个文件忽略了检查.gitignore用git add -f file强制添加执行git reset --hard之后想找回被删的改动没有备份git 本身也无法直接找回日常多用git stash或git branch备份commit 前先git diff确认在 Windows 下复制粘贴命令时卡住键盘输入不进去终端把 CtrlC 等快捷键拦截了处于“等待输入”状态按 Enter 结束输入或者 CtrlC 先退出当前命令重新跑分支太多不想看到一大串分支列表太长影响判断git branch -v看带最新提交的分支或者用git branch --merged看已合并分支这里面有两个点想单独强调一下。第一误操作git reset --hard后的“后悔药”不是完全没有。如果你在 reset 之前一刻做过git stash或者创建过分支改动还能从那里恢复。但如果你什么都没做那真的是神仙难救。所以我的习惯是大改动之前先git checkout -b backup-temp开个临时分支或者git stash一下给自己留条后路。第二“提交了不该提交的文件”是个超级常见问题。比如把node_modules这种依赖目录、.env这种包含密钥的环境变量文件提交进了仓库。前者会让仓库变得巨大后者是安全事故。解决办法优先写.gitignore在仓库初始化时就把它写好如果已经提交了用git rm --cached file把文件从 Git 跟踪中移除保留本地文件然后提交一次再做一次 push。5.2 两个值得养成的配置小习惯操作层面之外有两个配置项能显著提高日常使用体验。第一个是配置默认编辑器。如果你git commit不带-mGit 会打开一个文本编辑器让你填提交信息。很多新手在 Vim 里卡住不知道怎么退出其实只要配置成自己熟悉的编辑器体验立刻起飞。Windows 下配置成 VSCodegit config --global core.editor code --wait之后不带-m提交时VSCode 会自动打开一个临时文件写完保存、关掉标签页提交就完成了全程可视化再也不怕卡在 Vim 里。第二个是配置命令别名。如果你觉得git status和git log --graph --oneline敲着太长可以设置别名git config --global alias.st status git config --global alias.lg log --graph --oneline --all之后git st和git lg就能直接用了。别小看这个习惯命令敲得越顺手你越愿意频繁提交、频繁查看状态版本管理的效果也就越好。写到这里回头看Git 基本操作其实就两件事先把文件流转的“三个格子”装进脑子里然后把“增删改查 后悔药 分支”这几个动作练熟。命令本身几个小时就能记住真正区分熟手和新手的是操作习惯——提交前先看 diff、reset 前先留后路、提交信息写谁都看得懂的话、该开分支时毫不犹豫地开。这些习惯比记住任何一条命令都金贵。至于 rebase、stash、cherry-pick、远程分支协作那些进阶玩法等你把这一篇的命令都练到不用过脑子的程度自然就会觉得水到渠成到时候再看下一篇就轻松多了。