分支操作中git diff与git show结果不符,求排查问题原因
我当前处于一个与master分支差异较大的feature分支,该分支上修改了5个文件。其中file5本不应被修改,我希望将其恢复到该分支从master分支分出时的状态,但无法直接从master分支复制该文件,因为master分支上的该文件也新增了其他修改。
我认为恢复该文件的正确方式是执行:
git show 123abc:file5 > file5
其中123abc是当前分支从master分支分出时的提交哈希,该操作似乎有效。
但我想再次验证,因此先执行:
git show 123abc:file5 > file5.old
然后通过:
diff file5.old file5
确认获取到了正确的旧版本file5,以及该基础版本与当前分支版本的差异。
为进一步验证,我尝试用git diff,认为执行:
git diff master...
应该能得到当前分支与从master分支分出时的共同祖先之间的差异,且file5的差异应与diff file5.old file5的结果完全一致。
但实际结果完全不符!(另外,我并不确定预期的差异是什么,因为有其他人的工作参与,这也是我决定排除该分支对file5的修改再合并回master的原因。核心问题是我不确定哪组差异是正确的。)
因此我怀疑:
git show 123abc:file5并未获取到我预期的基础版本,或git diff master...并未像我认为的那样对比共同祖先版本。
请问我哪里出错了?
核心行为澄清
git show 123abc:file5是正确的
这个命令确实会提取提交123abc中file5的完整内容——只要123abc确实是feature分支从master分出时的共同祖先提交,那这就是你要的“分支创建时file5的状态”,这部分逻辑没有问题。git diff master...的实际行为和你的理解有偏差
你以为这个命令是对比当前分支与共同祖先的差异,但实际上git diff A...B(省略B时默认当前分支)的作用是:展示当前分支相对于共同祖先的变更中,排除掉master分支之后新增的变更的部分,也就是“当前分支独有的修改”。举个具体例子:
- 共同祖先
123abc的file5是版本V0 - feature分支把file5改成了V1
- master分支把file5改成了V2
此时git diff master...会计算(V1-V0)减去(V2-V0),最终只显示V1和V2之间的差异里属于feature独有的部分,这和直接对比V0与V1的diff file5.old file5结果自然完全不同。
- 共同祖先
正确的验证方式
如果想用git命令验证当前feature分支的file5与共同祖先版本的差异,直接指定共同祖先提交即可:
# 仅对比file5的差异 git diff 123abc:file5 file5 # 对比当前分支与共同祖先的所有差异 git diff 123abc HEAD
这两种方式得到的file5差异会和diff file5.old file5的结果完全一致。
更稳妥的恢复方式
除了手动导出覆盖,你可以用git内置命令直接恢复文件,更符合git工作流:
git checkout 123abc -- file5
这个命令会直接将提交123abc中的file5内容覆盖到工作区和暂存区,效果和你之前的操作一致,但避免了手动处理文件的潜在风险。
内容的提问来源于stack exchange,提问作者Steve Summit

