在 Git 中,正如 larsmans 在
他的评论 中指出的那样,分支只是指向特定提交的指针/引用。像您在图表左侧所做的那样,使用分支名称标记代码行可能会令人困惑。
例如,过去可能是真的,提交 G、H 和 I 仅属于 development 分支的祖先。然而,在您的 repo 的当前状态下,它们属于所有三个分支(master、development 和 release)的祖先。
想到那三个提交(
G
,
H
和
I
)在某种程度上仍然与
development
分支更相关,而不是
master
或
release
,这已经没有任何意义了,因为您的存储库不记得过去分支引用指向的位置(尽管该信息在本地存储在称为
reflog的东西中)。您的Git存储库只知道分支引用在当前指向哪里。
因此,当您绘制图形来描述存储库的状态时,如果一个分支指向一个提交,则使用相应的分支名称标记提交本身更有意义。我在下面的所有图表中都这样做了。
原始状态
A - B - C - D - E - F - - - - - - - - - L [master]
\ /
G - H - I - J - K [release]
\
M [development]
期望状态
A - - - - - - - - - - - - - - - - - - - L' [master]
\ /
B - C - D - E - F - G - H - I - J - K [release]
\
M [development]
最终陷入这种状态,您应该执行以下三个步骤。
程序
1 - 检查您的主分支(
master
)
git checkout master
之后,
HEAD
指向
master
:
A - B - C - D - E - F - - - - - - - - - L [HEAD -> master]
\ /
G - H - I - J - K [release]
\
M [development]
2-执行
master
的硬重置以提交A。
git reset --hard <commit_ID_of_A>
因为在您的仓库中没有任何引用可以访问到
L
,所以它从历史记录图中“消失了”,然后您只剩下了。
A [HEAD -> master]
\
B - C - D - E - F - G - H - I - J - K [release]
\
M [development]
3 - 将release
分支真正合并到master
分支中
在这个阶段,如果你仅仅运行以下命令:
git merge release
因为
master
的尖端是
release
尖端的祖先,所以会进行快进合并,你最终只会得到:
A - B - C - D - E - F - G - H - I - J - K [HEAD -> master,release]
\
M [development]
这不是你想要的。因此,在此需要使用
--no-ff
选项来强制执行真正的合并:
git merge --no-ff release
在执行这个最后的命令之后,您的代码库应该处于所需状态:
A - - - - - - - - - - - - - - - - - - - L' [HEAD -> master]
\ /
B - C - D - E - F - G - H - I - J - K [release]
\
M [development]
请注意,我将新提交命名为
L'
而不是
L
,因为这两个提交具有不同的父级:
L
的父级是
F
和
K
,而新提交
L'
的父级是
A
和
K
。