Git rebase 检查父提交

Git rebase checks out parent commit

Git 在特定情况下表现异常,我能够重现该问题。我有两个分支,比如 master 和 feature,指向同一个提交。当我将 master 重置为父提交并尝试在 master 之上重新设置功能时,功能分支也指向父提交,尽管我希望 rebase 什么都不做。我不确定为什么会这样。

重现步骤:

运行 以下命令重现初始状态:

deepakgupta @ git init
Initialized empty Git repository in /tmp/hello/.git/

deepakgupta (master)@ touch hello

deepakgupta (master)@ git add hello

deepakgupta (master)@ git commit -m "First commit"
[master (root-commit) 1750f9c] First commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 hello

deepakgupta (master)@ touch world

deepakgupta (master)@ git add world

deepakgupta (master)@ git commit -m "Second commit"
[master 7411ad0] Second commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 world

deepakgupta (master)@ git branch feature

此时,git log 看起来是这样的:

commit 7411ad0984841b28dca630d54c3b079ebd01c7e9 (HEAD -> master, feature)
Author: Deepak Gupta <deepakguptacse@gmail.com>
Date:   Tue Apr 7 13:58:09 2020 +0530

    Second commit

commit 1750f9c5ba95f53742005657e9cee41390165dc7
Author: Deepak Gupta <deepakguptacse@gmail.com>
Date:   Tue Apr 7 13:57:54 2020 +0530

    First commit

现在试试:

git reset --hard HEAD^
git checkout feature
git branch --set-upstream-to master

现在是 git 日志现在看起来:

commit 7411ad0984841b28dca630d54c3b079ebd01c7e9 (HEAD -> feature)
Author: Deepak Gupta <deepakguptacse@gmail.com>
Date:   Tue Apr 7 13:58:09 2020 +0530

    Second commit

commit 1750f9c5ba95f53742005657e9cee41390165dc7 (master)
Author: Deepak Gupta <deepakguptacse@gmail.com>
Date:   Tue Apr 7 13:57:54 2020 +0530

    First commit

当我尝试 git rebase 时会发生什么?我觉得状态应该保持不变。 但它变为:

commit 1750f9c5ba95f53742005657e9cee41390165dc7 (HEAD -> feature, master)
Author: Deepak Gupta <deepak.gupta@rubrik.com>
Date:   Tue Apr 7 13:57:54 2020 +0530

    First commit
(END)

有人可以解释这种行为吗?

这个问题——或者说 特征,因为 Git 人喜欢提到它——是由于 Git 的 叉点模式The git rebase documentation 描述如下:

If upstream is not specified, the upstream configured in branch.<em>name</em>.remote and branch.<em>name</em>.merge options will be used (see git-config[1] for details) and the --fork-point option is assumed. If you are currently not on any branch or if the current branch does not have a configured upstream, the rebase will abort.

(格式,尤其是粗体部分,是我的)。下一段提供了这个神秘的摘要:

All changes made by commits in the current branch but that are not in upstream are saved to a temporary area. This is the same set of commits that would be shown by git log <upstream>..HEAD; or by git log 'fork_point'..HEAD, if --fork-point is active (see the description on --fork-point below); or by git log HEAD, if the --root option is specified.

(此描述省略了一些重要的项目:特别是,默认情况下也丢弃了等效于补丁 ID 的合并和提交。但这些都不会影响您的特定情况。)

分叉点描述在页面的中途。它提到:

fork_point is the result of git merge-base --fork-point <upstream> <branch> command (see git-merge-base[1]). If fork_point ends up being empty, the upstream will be used as a fallback.

upstreammasterbranch是当前分支,feature。在我的存储库中,我现在 运行:

$ git merge-base --fork-point master feature
af07c3c48ff0d499400ac539aa9c665a8dddcd6f

(使用我在复制您的示例时创建的存储库中的哈希 ID)。让我们在我的存储库上使用 git log 来查看两个提交:

$ git log --decorate --oneline
af07c3c (HEAD -> feature) Second commit
dbf1741 (master) First commit

因此,鉴于 git merge-base --fork-point 的输出,rebase 承诺它将复制的提交是 git log af07c3c48ff0d499400ac539aa9c665a8dddcd6f..HEAD:

显示的提交
$ git log af07c3c48ff0d499400ac539aa9c665a8dddcd6f..HEAD
$

未列出任何提交,因此未复制任何提交。

如何解决问题

禁用分叉点模式,运行:

git rebase --no-fork-point

或:

git rebase master

即使当前分支 feature 的上游是 master,一个 explicit git rebase master disables 默认叉点模式。在使用明确的分支名称时强制 Git 使用分叉点模式——如果你想这样做的话;在这种情况下,您可能想要它——您也可以运行:

git rebase --fork-point master

完全没有任何参数,你会得到 git rebase --fork-point master 的效果。