做技术面试这些年有一个现象我一直觉得很有意思不管候选人的简历上写的是前端、后端、移动端还是算法岗Git 面试题几乎都是躲不掉的环节。你说 Git 难吗日常用起来无非就是 add、commit、push、pull 那几板斧但面试官偏偏能从最简单的“Git 和 SVN 有什么区别”一路追到“cherry-pick 和 rebase 的底层区别是什么”问到很多人当场卡壳。这篇文章就是我结合自己带团队、面候选人和平时折腾仓库踩坑的经验整理出的一套 Git 面试题拆解。我不会像网上很多题库那样只给你答案让你背而是带着你把每个高频考点背后的原理、使用场景和面试官真实想考察的点说透。不管你是准备面试的开发者还是用 Git 多年但感觉体系不扎实的老手这篇内容都值得你从头到尾认真过一遍——文章里覆盖的脉络基本就是面试官最爱问的 30 问的核心骨架。1. 基础关版本控制概念与 Git 核心模型1.1 面试官为什么总从“Git 和 SVN 有什么区别”开始问这道题几乎是我见过的所有 Git 面试题里的开胃菜。你以为面试官只是想听“Git 是分布式的SVN 是集中式的”这一句话吗不是的。这道题真正的考察点有两个一是你有没有接触过老一代版本控制工具二是你能不能把“分布式”三个字背后的工程意义说清楚。分布式和集中式的核心区别在于每个开发者本地都有一个完整的仓库副本。也就是说你电脑上的 .git 目录不只是工作区的索引而是包含着全部历史提交、全部分支、全部标签的“另一个仓库”。这意味着你在没有网络的情况下依然可以正常提交代码、查看历史、切换分支。等联网之后再 push 上去别人就能看到你的全部提交。而 SVN 这类集中式系统所有操作都依赖于中央服务器你离线的时候连 log 都查不了更别说提交了。到这里你可以把话题往下延伸正因如此Git 的容灾能力极强。服务器硬盘挂了只要任意一个开发者的本地仓库还在就能完整恢复所有代码和历史。我在实际工作中就遇到过公司内部的中心仓库被误格式化的情况最后就是拿某个同事的本地仓库重新推了一遍几乎零损失。这种真实场景带来的体会比背多少概念都有说服力。回答这道题的时候我建议按照“概念差异 → 工程影响 → 个人体会”的顺序来组织语言。先一句话点出分布式和集中式接着讲离线操作、容灾、分支成本最后落在一两个你自己经历过的例子上。面试官一般听完这些就知道你不是只会敲命令的工具人。1.2 三个区域与文件状态转换面试官问“Git 的三个区域是哪三个”或者“Untracked 和 Modified 有什么区别”的时候其实是在确认你对 Git 工作模型的理解程度。这个模型就是工作区Working Directory、暂存区Staging Area / Index、版本库Repository。我们平时在编辑器里改代码改的是工作区的文件内容。接着执行 git add文件变更会被写入暂存区。暂存区你可以理解成“提交前的整理台”它记录的是一份快照清单告诉你下一次 commit 会把哪些改动打包进去。执行 git commit 之后暂存区里的内容才真正变成版本库里的一个永久提交。和这三个区域对应的是文件的四种状态Untracked未跟踪、Modified已修改、Staged已暂存、Committed已提交。我把它们串成一句话Untracked 是你新建但从未被 Git 管过的文件Modified 是 Git 已经管着、但你后来又改了内容Staged 是你把改动放进了暂存区Committed 是这些改动已经落库。面试中有一个高频追问是“git status 里的 Changes not staged for commit 和 Changes to be committed 分别代表什么”。这里其实就是把你对状态模型的理解反映出来。前者说明文件在工作区被改动但还没 add后者说明你已经 add 了但还没 commit。要是你对这块不熟下面的命令容易连续出错。建议在本地随便建个项目反复用 git status、git add、git commit 走几遍把状态变化切身体会一下比看十篇文档都管用。1.3 commit 到底是什么从哈希到内容寻址高端一点的基础题面试官会问“commit 在 Git 底层是怎么存储的为什么 commit 的哈希值可以校验完整性”要回答好这个问题需要往 Git 的对象模型里钻一钻。Git 本质上是一个内容寻址的文件系统。它把所有的内容都抽象成四种对象blob文件内容、tree目录结构、commit提交快照、tag标签。当你执行一次 git commitGit 会做三件事把本次提交涉及的文件内容打包成 blob 对象把目录结构和文件名、文件对应的 blob 哈希记录成 tree 对象然后创建 commit 对象这个 commit 对象里记录了树哈希、父提交哈希、作者、提交者、提交时间和提交信息。这整套机制最经典的地方在于每个 commit 的哈希值是根据它的全部内容算出来的。只要任何一个字节发生变化哈希值就完全不一样。这就是 Git 自带完整性的原因——如果历史里某个提交被篡改从那个提交往后的所有哈希都会对不上。我常用的一个操作是 git log --prettyraw可以直观地看到 commit 对象里的字段结构。面试官如果深入问“为什么 Git 不怕别人悄悄改历史”你就可以用这套模型答复比空谈“安全”有说服力得多。2. 进阶关分支管理与合并策略2.1 分支的本质指针理解到位很多问题迎刃而解说到进阶题分支几乎是必考内容。常见的问法是“Git 分支和 SVN 分支有什么本质区别”。如果前面你只是背了“Git 分支很轻量”这句话这里就会露馅。真正到位的理解是Git 分支本质上只是一个指向某个 commit 对象的可变指针。什么叫“可变指针”你可以把 .git/refs/heads 目录打开看一眼每个分支名对应一个文件文件内容就是一个 40 位的哈希值。创建分支其实就是新建一个文件并指向当前 commit开销几乎为零。切换分支就是改变 HEAD 这个特殊指针的指向。这个模型比 SVN 那种把整个目录复制一份的“重量级分支”快太多了所以 Git 团队才敢鼓励“分支随便开、随便并”。清楚了分支的本质很多衍生问题就顺了。比如“为什么 Git 鼓励频繁创建分支”因为创建分支只是一次文件写入成本可以忽略不计“为什么合并分支比 SVN 顺畅”因为 Git 的分支只记录差异和祖先关系而不是做目录级别的拷贝。我建议面试时画一条时间线辅助说明master 分支指向 C3 提交从 C3 拉出一个 feature 分支你在这个分支上又提交了 C4 和 C5。然后切回 master 做几次提交到 C6此时 master 和 feature 分别在两个“分叉”上。这样把对象指针的指向关系说清楚面试官马上就知道你是懂底层的人。2.2 merge 和 rebase选择背后的工程哲学“merge 和 rebase 有什么区别”是 Git 面试里出现频率最高的问题之一也是实战中踩坑最多的点。很多人只是背了“merge 会保留分支历史rebase 会整理成线性历史”却没有真正理解两者各自的代价和适用场景。先讲 merge。执行 git merge feature 时Git 会做一次三方合并找到两个分支的最近公共祖先base然后结合当前分支ours和目标分支theirs的内容把差异合并到一起生成一个新的合并提交。它的特点是完整保留真实的分支拓扑你能从历史上清清楚楚看到“这里曾经拉过一条分支最后并了回来”。缺点是历史图看起来比较乱尤其是长期并存多分支的时候log 图会像个毛线球。rebase 的思路完全不同。git rebase feature 是把当前分支的提交“摘下来”以 feature 分支最新的提交为新的基底再重新放回去。这样结果是提交序列变成一条直线历史非常干净。但代价是每个被重放的提交的哈希值都会改变因为它们的父提交变了。所以 rebase 等于重写历史它不保留“你曾经从哪个点拉出来”的信息。面试官往往会追加一句“那你怎么取舍”这里最好的回答不是“哪个好哪个坏”而是给出清晰的决策原则如果分支还没共享给别人你可以自由地用 rebase 整理成漂亮的直线一旦分支已经被推到远程、别人也可能基于它做开发就不要 rebase 了应该用 merge 或者 revert 来维护公开历史的稳定。业内那句话“绝不要对公共分支执行 rebase”不是教条而是为了避免让团队其他人陷入提交丢失的混乱。我在实际维护某个长期项目时就明确要求开发者在合入主分支之前先 rebase 到最新代码既保证主干线性又不会动到别人的远程分支。2.3 解决冲突的底层逻辑冲突标记与合并操作冲突题是很多人的心理阴影但面试官恰恰爱问“你平时怎么处理冲突”。直接背命令没用得先理解冲突是怎么产生的。当两个分支修改了同一个文件的同一位置Git 没办法自动判断哪边是对的就只能停下来让你决策。冲突的本质是“三方合并无法自动完成”。在命令行里冲突发生后文件里会出现 、、 这样的标记。 到你 之间的内容来自当前分支ours 到 之间是对方分支theirs的内容。你需要人工打开文件把两边内容合理整合删掉标记保存后再 git add 这个文件最后 git commit 完成合并。面试中有一个非常经典的追问“如果我在合并过程中突然不想合并了怎么办”答案是 git merge --abort这会让你完全回到合并前的状态。还有一个常见场景是已经合并到一半改了好几个文件发现不想继续了但又不甘心全部回退。这时可以用 git merge --quit 退出合并状态但保留手动修改的内容。这些细节知道的人不多面试时主动补充这些操作会给面试官留下“实战经验丰富”的印象。我个人的经验是解决冲突的时候别慌先看清楚这个文件的冲突范围再理性判断是保留哪边还是两边融合。很多冲突其实只是隔了几个空行或者注释手动处理起来并不复杂。真正难的是大范围重构造成的冲突这时最好召集涉及双方面对面讨论各自逻辑再合并硬来容易把代码改出问题。3. 高阶关撤销、恢复与内部机制3.1 reflogGit 的后悔药恢复误删分支和丢失提交高阶题里面试官很喜欢问“你怎么恢复一个误删的本地分支”或“我误操作了代码还能找回来吗”。这题考察的就是你知不知道 reflog 的存在以及你对外部命令和内部机制的熟悉程度。reflog 是 Git 的引用日志它会记录 HEAD 和各个分支指针在过去一段时间内的每一次移动。换句话说只要你的操作是在本地仓库里发生的即使你删了分支、reset 得面目全非reflog 里依然能找到曾经的提交哈希。我曾在一次整理分支时手滑把某个写了三天的功能分支删了当时整个人都凉了。后来想起 reflog一条命令把删除前的哈希找回来再用 git branch 新分支指向它代码全部恢复一点没丢。具体操作是这样先用 git reflog 查看操作历史它会输出一行行记录里面包含操作描述和最后指向的提交哈希。比如我看到 HEAD{2}: checkout: moving from feature/payment to master然后我就能定位 feature 分支当时指向的那个提交最后执行 git branch feature/payment 哈希分支就回来了。另外要记住reflog 默认只保留 90 天gc 后会清理所以发现代码丢了之后短期内用这个命令找回的成功率极高。面试里主动提到“90 天保留期”这个细节会显得你对命令背后机制有真正研究过。3.2 reset、revert 与 cherry-pick撤销三兄弟的适配套路撤销类题目几乎是高阶必考题而且经常连环追问“reset 和 revert 有什么区别”、“怎么撤销已经 push 到远程的提交”、“怎么把某一个提交挪到当前分支”先讲 reset。git reset 的作用是移动 HEAD 指针它有三种模式--soft 只回退指针不动暂存区和工作区--mixed默认回退指针并重置暂存区但保留工作区--hard 会把暂存区和工作区全部强制回退到目标提交。很多悲剧都出在 git reset --hard 上所以我对团队的要求是非必要不用 --hard如果非用不可执行前先记下当前提交的哈希。但你就算忘了也没关系上一节说的 reflog 还能兜底。revert 的思路和 reset 完全不同。git revert 不会把历史回退而是新建一个反向提交把目标提交的改动“撤销”一遍。所以 revert 是安全的、不会改写历史的方式适合用在公共分支上。面试官特别喜欢考“你 push 上去的提交写错了怎么办”——正确答案就是 revert然后重新 push而不是 reset 之后强推。cherry-pick 则是把某个提交单独应用到当前分支上。它的典型场景是你有一条 feature 分支上做了三个提交但只希望把其中的第二个提交合到主干这时候就切到主干执行 git cherry-pick 提交哈希。这种操作在日常团队协作里也非常常见比如某个 hotfix 提交在 release 分支上master 也需要同样的修复cherry-pick 就能精准搬过来。把这三个命令放在一起对比记忆最有效reset 是“抹掉历史”revert 是“新提交抵消历史”cherry-pick 是“把历史里的某一个拎出来”。回答面试题时用这个“历史操作”的视角去解释比单纯背命令用法要清晰得多。3.3 stash 的完整用法临时保存工作区的正确姿势“工作区改到一半要切分支怎么办”这一道题考察的就是 stash。很多应届生会说“那我先 commit 再切”但对于上不了台面的半成品提交这种行为其实会让历史变得很脏。更好的方案是 git stash。git stash 能把当前工作区和暂存区的改动保存到一个“暂存栈”里然后帮你把工作区恢复到干净状态这样你就可以放心切换分支。等你需要的时候再 git stash pop 把改动弹回来。我还经常用 git stash push -m 改了一半的登录逻辑 来给暂存内容加上说明这样一个礼拜之后再弹回来也不至于忘了当时在改什么。关于这个栈有几点容易被人忽略git stash list 可以查看栈里的所有保存记录git stash apply 和 git stash pop 的区别在于前者不会自动移除栈里的记录后者会如果你同时存了多份内容可以指定 git stash pop stash{1}。如果后续改动已经不需要了直接 git stash drop 就能清理掉对应记录。面试官如果想深挖还会问“stash 能保存未跟踪的文件吗”。默认情况下 stash 不会包含 Untracked 文件你需要用 git stash -u 才会把未跟踪文件也一起保存。另外 stash 之后不影响分支指针的位置所以理论上它只涉及工作区暂存区的快照和 commit 历史完全没关系。把这两点补充上这道题基本就是高分答案。3.4 子模块与仓库瘦身进阶运维向的加分项有些面试官会在高级追问里问“git submodule 是什么用过吗”或者“仓库越来越臃肿怎么处理”。这些在实际团队里不一定人人用过但能答出来绝对是加分项。git submodule 允许你在一个仓库里嵌套引用另一个仓库的某个提交。典型的场景是项目里依赖一个内部公共库你想锁定它的版本而不是把代码直接复制进来。做法是 git submodule add 仓库地址 路径它会创建一个特殊的 gitlink 记录把子仓库固定在某个具体提交上。注意子模块更新后父项目不会自动跟踪新提交需要手动在子模块目录里 pull再回到父项目把 gitlink 的变更来提交一次。子模块的坑也确实不少。最典型的是切换分支后子模块内容和父项目期望的版本不一致导致编译失败。处理方式是 git submodule update --init --recursive 按父项目记录的哈希同步子模块。面试里你能把这些细节说出来会显得你是真在复杂项目里趟过水的人。至于仓库瘦身推荐思路是先用 git count-objects -vH 看仓库体量用 git gc 做常规的垃圾回收再找出占空间的大文件用 git filter-repo 从历史中彻底移除。filter-repo 是一个代替旧工具 filter-branch 的官方推荐方案能批量重写历史、删除路径或文件。重写历史之后所有开发者都需要重新克隆仓库否则新旧历史会互相污染。这个操作风险极高生产环境一定要提前备份这个坑我踩过一次后来每次动手前都先打全量备份。4. 团队协作与分支模型4.1 经典分支模型对比Git Flow 与 GitHub Flow 的取舍团队协作题里高频问题是“你们团队用的什么分支模型为什么这么选”。面试官想听的不是你背下来的概念而是你结合团队规模和发布节奏做出的判断。Git Flow 是一种功能非常完备的分支模型包含 master主干、develop开发集成分支、feature功能分支、release预发布分支、hotfix热修复分支。每个分支都有明确的职责新功能从 develop 拉 feature 分支开发完成合回 develop准备发版时从 develop 拉 release 分支做最后的测试和修正线上出紧急问题则从 master 拉 hotfix 分支。这个模型的好处是分工清晰、稳定性高适合有固定版本节奏、需要同时维护多版本的企业项目。缺点也很明显分支种类繁多操作成本高小团队容易在流程里迷失方向。GitHub Flow 则走极简路线它只有一个长期存在的 main 分支所有改动都从 main 拉一个短命的特性分支完成之后通过 Pull Request 做代码评审通过后合并回 main。然后立刻部署发布。这个模型对自动化程度高、发布节奏快、希望减少流程心智负担的团队非常友好。它默认你的代码是“随时可发布的”所以对测试覆盖率和代码评审质量要求更高。回答面试题时我建议少说“哪个模型更好”多说“在什么条件下哪个模型更合适”。比如我可以举一个实际例子某个团队做的是对外发布的 SDK每个版本要维护数月所以必须用 Git Flow 式的多线并行而另一个团队做的是互联网 Web 服务每天多次上线于是果断采用 GitHub Flow。这样既展示了你的方案理解力也体现了你从工程场景出发的思维方式。4.2 commit message 规范原子化提交与 Conventional Commits“你怎么写好一个 commit message”这个问题不少面试官会问但很多候选人答不上来。它考察的是你对代码历史质量的重视程度而这恰恰是团队协作中最容易被忽略但对长期维护影响巨大的事。我的经验是一个理想的提交应该是“原子化”的每次提交只做一件事只改与该事相关的文件。比如你修了一个 bug就不要顺手改了配置文件格式也不要混入一个无关的重命名。这样做的好处是后续用 git log、git bisect 排查问题时能快速定位cherry-pick 也能精准搬取不至于一个提交拖着两三个不相干的改动。在 message 格式上我比较推荐 Conventional Commits 这套轻量约定。格式是“type(scope): subject”type 用 feat新功能、fix修复、docs文档、style格式、refactor重构、test测试、chore杂务等单词开头scope 表示影响范围subject 是不超过 50 个字符的简短描述。举几个例子“fix(auth): 修复 token 失效后跳转错误”、“feat(order): 新增订单导出功能”、“refactor(payment): 抽取支付策略接口”。一看到这些 message历史就变得可读性极强。面试里你还可以加一点“反面经验”有些团队的提交信息全是“update”“fix bug”“ddd”半年之后追踪线上问题连是谁在哪个提交里改了什么都不知道。用这种对比来强调规范的价值比空谈最佳实践更能打动面试官。4.3 远程协作核心命令clone、fetch、pull 与 push远程操作题看起来简单但翻车的概率其实很高。很多候选人能说出来 git clone、git push、git pull但被追问“git pull 和 git fetch 有什么区别”时就慌了。我来拆一拆。git fetch 只负责把远程仓库的最新提交和引用下载到本地但它不会动你当前的工作区更不会自动合并到什么分支。git pull 实际上是先 fetch 再 merge或者根据配置使用 rebase所以当你执行 git pull 时工具已经瞒着你做了一次自动合并。理解这一点非常重要如果你不想让本地分支莫名其妙出现一个合并提交可以直接 git fetch然后自己决定用 merge 还是 rebase 整合。push 和 pull 不对称这一点也常被忽视。pull 默认会把本地当前分支和远程对应的跟踪分支直接搞关联但如果你的本地分支没有上游分支第一次执行 push 时会出现提示让你用 git push -u origin 分支名 来设置上游。这背后的原因是 Git 设计的“跟踪分支”机制一个本地分支可以记录它对应的远程分支这样后续的 push、pull 都不用手动指定。远程分支的管理还有很多容易出错的地方比如删除远程分支要用 git push origin --delete 分支名改名远程分支最稳妥的方式是“新建新分支名推送删除旧分支”。面试官追问“怎么同步远程已删除的分支”时正确答案是 git remote prune origin或者更彻底一点直接做一次 git fetch --prune。把这一套远程操作的逻辑理清楚团队协作题基本就稳了。5. 高频真题精析面试官到底想听什么5.1 基础十问高频必考清单一览下面我把从面试实录里整理出来的高频基础题列成一个速查表你对着自查一下哪些能脱口而出题号问题核心考点1Git 和 SVN 的区别分布式 vs 集中式离线操作、容灾2三个区域是什么工作区、暂存区、版本库3文件有哪些状态Untracked、Modified、Staged、Committed4commit 的底层结构blob、tree、commit 对象与哈希5分支的本质是什么指向 commit 的可变指针6如何查看所有分支、提交记录branch、log 相关命令7什么是 HEAD指向当前分支或提交的指针8如何放弃工作区的修改checkout / restore9如何从暂存区移除文件git reset / git rm --cached10如何删除分支git branch -d / -D这些题目不要求你有惊天动地的解法但每一道都考验基础是否扎实。我见过太多候选人卡在“HEAD 是什么”这种问题上其实只要把指针模型说清楚答案自然就出来了。建议在本地把每个命令亲手跑一遍看 .git 目录里的变化印象才深刻。5.2 进阶十问场景题与坑点一网打尽进阶类的面试题不再只问“是什么”而是给了一个具体场景考察你会怎么操作题号问题核心考点11工作区改一半要切分支怎么办git stash12写错 commit message 怎么办git commit --amend13已经 push 的提交有误怎么处理git revert避免改写公共历史14删除的本地分支还能恢复吗git reflog 找回提交15merge 和 rebase 怎么选公共分支 vs 个人分支16如何把一个提交搬到另一个分支git cherry-pick17合并冲突怎么解决冲突标记、手动修改、add 后 commit18多个提交想压成一个怎么做git rebase -i 里的 squash19如何查看某个文件的修改历史git log -- 文件20如何比较两个分支的差异git diff / git log 范围我自己在模拟面试中发现大部分候选人卡在第 18 题上。“把多个提交压成一个”这个操作本质是重写历史很多新手不敢碰还有人是 rebase -i 之后不知道如何选区。这里提供一个标准思路执行 git rebase -i HEAD~3编辑器会列出最近三个提交的命令把后两个改成 squash保存退出Git 就会把它们合并成一个提交并让你重新填写 message。这套操作能流畅讲出来面试官对你的命令熟练度就放心了。5.3 高级十问能问倒老手的隐藏考点高级题的杀伤力在于平时不怎么用的人根本答不好。我按项目里真实出现过的疑难杂症整理了下面这些题号问题核心考点21rebase 时如何跳过已合并的提交git rebase --skip22如何让 pull 默认使用 rebasepull.rebase 配置23如何清理本地冗余的远程引用git remote prune origin24子模块怎么初始化与同步submodule update --init --recursive25如何改写历史的作者信息git filter-branch / filter-repo26如何搜索遗漏在历史里的大文件git rev-list 配合对象遍历27如何彻底从历史中移除某个文件git filter-repo28大仓库卡慢怎么优化gc、clone 时加 --filter29tag 和 branch 的区别不可变指针 vs 可变指针30如何把 tag 推送到远程git push origin --tags这几道题没有标准答案模板你的应对思路本身就反映功夫。比如第 27 题我会在回答里明确警告filter-repo 会重写所有涉及到的提交哈希任何人必须重新克隆仓库。这类“安全提醒”式的补充往往是面试官加分的关键点。5.4 回答话术的底层逻辑STAR 法则在 Git 面试里的变形不少候选人明明很熟悉命令回答面试题却显得很散。我给出的建议是回答时套用“场景—操作—原因—效果”四步法类似 STAR 法则的变形。举个例子面试官问“你怎么处理冲突”。低分回答是我就打开文件改一下然后 add 提交。高分回答是先说冲突发生在哪个场景比如合并一个跨多模块的特性分支再说我当时如何定位冲突文件git status 看 Unmerged paths然后说明我如何分析冲突内容分别读两边逻辑和对应同事确认后手工合并最后讲一下处理完的效果回归测试通过提交合并成功没有把对方代码弄丢。这样一套下来面试官听到的不只是一条命令而是你的工程判断力。这套表达方式在团队协作题里尤其吃香。你可以在准备阶段就自己练习拿十道经典场景题先写要点再出声回答练到不用打草稿也能流畅表达为止。6. 常见坑与排查技巧实录6.1 误操作的后悔药清单reflog、backup 与恢复命令可以说每个用 Git 八百年以上的人都至少遇到过几次“代码不见了”的紧急情况。我把自己经历过的误操作整理成一份“后悔药”清单希望你能用上但更希望你有意识地做好预防。最典型的误操作是 git reset --hard 之后想恢复那先试 reflog 找回原哈希。如果分支被删除reflog 里会留下 checkout 的记录也能定位到那个哈希再重建分支即可。如果你在 merge 之后后悔了且还没重置过可以执行 git reset --hard ORIG_HEAD 直接回到合并前的状态。这个 ORIG_HEAD 是 Git 在执行合并、rebase 等危险操作前自动记录的先前的 HEAD 位置非常好用。另一个高频坑是git clean -fd 把你没有跟踪的文件也删了。这个命令执行后文件不进回收站属于高危操作在没有提交备份的情况下几乎无法找回。我的建议是能用 git stash -u 就别用 clean -fd如果非要用 clean先执行 git clean -nd 让工具只打印会删除哪些文件确认无误后再真正删除。安全习惯上我强烈建议团队在每次大范围重构前打一个 tag 或临时分支做备份而不是指望某个命令帮忙恢复。备份成本极低但关键时刻能保住一整天的劳动成果。所有把“后悔药”当常规手段的人早晚会在某次极端操作里栽跟头。6.2 换行符、大小写和文件权限三个悄悄搞坏仓库的小妖怪很多团队协作的问题不是出在合并逻辑上而是出在 Git 对文件本身的处理上。换行符是最常被忽视的坑。Windows 和 Linux 的换行符不一样如果团队没统一配置你可能会看到“整个文件都被标记为改动”的怪相。解决办法是在仓库根目录放一个 .gitattributes 文件显式声明文本文件的换行符策略比如 * textauto或者针对特定目录固定为 LF。个人仓库可在全局配置 core.autocrlf但团队统一用 .gitattributes 更可靠。大小写问题也是经典暗坑。Windows/macOS 默认文件系统不区分大小写但 Git 内部是严格区分大小写的。假设你有一个 Help.ps1然后改成 help.ps1在部分系统上 Git 根本检测不到变化到了 Linux 上却可能出现两个文件。解决方法是执行 git config core.ignorecase false 然后手动改名或者用 git mv 完成重命名。这类问题一旦上生产环境排查成本极高早点用 .gitattributes 和规范的命名习惯能省太多事。还有一个容易误伤的设定是文件权限。Git 会追踪文件的执行位如果你在 Windows 上不小心改了权限位提交后到 Linux 上部署就发现一堆文件权限变了。常见的处理方式是在仓库里统一约束 core.fileMode false避免权限位的噪声进入历史。这三个小妖怪都属于“不致命但极烦人”的类型面试时主动谈谈处理经验会显得你对工程细节真的敏感。6.3 仓库体积增长与性能优化实践仓库越来越慢是所有长期演进项目的宿命。面试官如果问“你怎么优化仓库性能”其实是在考察你有没有真正维护过大型仓库。第一步先诊断。可以用 git count-objects -vH 看当前的对象数量和体积用 git gc --aggressive 做一次深度垃圾回收能压缩掉不少打包空间如果你日常大量切换分支可以考虑开启 git maintenance 里的增量任务。不过 gc 不是银弹当历史里有大文件时无论怎么 gc只要文件还在对象库中体积就降不下来。第二步是定位大文件。我常用的方式是git rev-list --objects --all 配合对对象大小的统计脚本找出占据空间最大的几个 blob再追查它们来自哪条历史。找到之后如果想彻底移除就用 git filter-repo --path 大文件路径 --invert-paths。这一步务必全量备份Filter 完成之后所有人重新 clone否则旧对象会继续在新仓库里传播。日常预防比事后处理更值得做。我建议团队在 pre-commit 钩子里加上文件体积限制超过比如 5MB 的文件直接拦截并引导开发者走 git-lfs 或对象存储。Git 本身擅长文本和代码而不是二进制大礼包。能把这些预防手段和事后工具串起来讲面试官基本就能确认你是具备规模化仓库维护经验的人。我自己在各种团队里面试和带人最深的一个体会是Git 题最怕的不是你不会某条命令而是你不知道这条命令在解决什么问题。很多人把题库背得滚瓜烂熟一到“你为什么要这么做”就泄了底。所以我最后想对准备面试的朋友说一句与其刷完 30 道题不如拿一个真实的项目把 Git 的每个机制亲手折腾一遍把 reflog、reset、rebase、cherry-pick 这些命令玩明白再用自己的语言表达出来。面试官要的从来不是“会背答案的人”而是“遇到问题真的知道怎么处理”的同行。
阅读完成 · 觉得有帮助?