Git: 让分支 a 忽略分支 B 删除文件的操作

在 git 的使用中,有时会遇到一种情况——在一个长期分支 a 中含有某个文件,而在另一个长期分支 b 中却没有。在之后只有 a 会从 b 合并修改。最好的方法当然是从 b 中新建一些 a 该有的文件,但如果一开始只有 a ,而不得不通过删除操作产生 b 呢?考虑下面一种情况:

a 分支有 foo.md, no_in_b.md 两个文件,而在 b 分支中不想要 no_in_b.md。我们不得不在 b 分支中删除 no_in_b.md 并提交。这时执行 git log 会有删除 not_in_b.md 的记录。

PS D:\Documents\merge-ours-demo> git log --pretty=oneline
c6e8aa93da45da5129aafe78bd99772af39df8e4 (HEAD -> b) delete not_in_b.md
4162012db692750ec018679c7a3bd868e8a311f5 (a) add foo.md and not_in_b.md

这时我想要在 b 中修改 foo.md。

PS D:\Documents\merge-ours-demo> git log --pretty=oneline
e5c57fbbd8625cf120af1612a9de5c8482c9a6af (HEAD -> b) do some change
c6e8aa93da45da5129aafe78bd99772af39df8e4 delete not_in_b.md
4162012db692750ec018679c7a3bd868e8a311f5 (a) add foo.md and not_in_b.md

然后合并至 a 中。

PS D:\Documents\merge-ours-demo> git checkout a
Switched to branch 'a'
PS D:\Documents\merge-ours-demo> git merge b
Updating 4162012..e5c57fb
Fast-forward
 foo.md      | 3 ++-
 not_in_b.md | 1 -
 2 files changed, 2 insertions(+), 2 deletions(-)
 delete mode 100644 not_in_b.md

not_in_b.md 被不出意外地删除了,但我并不想这样。先回退至 merge 之前吧。

PS D:\Documents\merge-ours-demo> git reset --hard HEAD^^
HEAD is now at 4162012 add foo.md and not_in_b.md

找找 b 删除 not_in_b.md 的一次 commit。

PS D:\Documents\merge-ours-demo> git checkout b
Switched to branch 'b'
PS D:\Documents\merge-ours-demo> git log --pretty=oneline
e5c57fbbd8625cf120af1612a9de5c8482c9a6af (HEAD -> b) do some change
c6e8aa93da45da5129aafe78bd99772af39df8e4 delete not_in_b.md
4162012db692750ec018679c7a3bd868e8a311f5 (a) add foo.md and not_in_b.md

可以看到我们就是在 c6e8aa93 的提交中删除了 not_in_b.md。让我们回到 a 分支中先假装合并这次 commit。

PS D:\Documents\merge-ours-demo> git checkout a
Switched to branch 'a'
PS D:\Documents\merge-ours-demo> git merge -s ours c6e8aa93
Merge made by the 'ours' strategy.

好了现在我们已经假装合并了删除 not_in_b.md 的commit。让我们检查一下 not_in_b.md 还在不在。

PS D:\Documents\merge-ours-demo> dir

    目录: D:\Documents\merge-ours-demo

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         2022/4/13     21:08             12 foo.md
-a----         2022/4/13     21:07             40 not_in_b.md

可以看到我们的 not_in_b.md 还在这里。有意思哦~ 再 log 一下我们的记录。

PS D:\Documents\merge-ours-demo> git log --pretty=oneline
9da6a2f428ac42ccf54d7fc513e93c0112dbbcb2 (HEAD -> a) Merge commit 'c6e8aa93' into a
c6e8aa93da45da5129aafe78bd99772af39df8e4 delete not_in_b.md
4162012db692750ec018679c7a3bd868e8a311f5 (a) add foo.md and not_in_b.md

发现在 delete not_in_b.md 之上多了个 merge 的记录。

然后再合并我们真正想要的 b 中作出的修改。

PS D:\Documents\merge-ours-demo> git merge b
Merge made by the 'recursive' strategy.
 foo.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

成功合并了。再检查一下 not_in_b.md 还在吗?

PS D:\Documents\merge-ours-demo> dir

    目录: D:\Documents\merge-ours-demo

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         2022/4/13     21:17             29 foo.md
-a----         2022/4/13     21:07             40 not_in_b.md

还在!这发生了什么?让我们 log 一下看看。

PS D:\Documents\merge-ours-demo> git log --pretty=oneline
b2fc4fc90f7e19bbf8dc1c155bd944068311df00 (HEAD -> a) Merge branch 'b' into a
9da6a2f428ac42ccf54d7fc513e93c0112dbbcb2 Merge commit 'c6e8aa93' into a
e5c57fbbd8625cf120af1612a9de5c8482c9a6af (b) do some change
c6e8aa93da45da5129aafe78bd99772af39df8e4 delete not_in_b.md
4162012db692750ec018679c7a3bd868e8a311f5 (a) add foo.md and not_in_b.md

跟合并前对比发现在 delete not_in_b.md 后追加了我们想要的 do some change。最顶上多了个 merge 的记录。

其实奥秘就在这条语句中 git merge -s ours c6e8aa93。这条语句会做一次假的合并,它会记录提交,而并不在意合入的分支,只会将当前分支的内容当作合并结果。

更详细的介绍可以参考git book 的这篇教程


Git: 让分支 a 忽略分支 B 删除文件的操作
https://worranhin.github.io/2022/04/13/merge-stuff/
作者
Hin
发布于
2022年4月13日
许可协议