git pull --rebase 分叉信息

git pull --rebase fork infomation

我们使用 git pull --rebase 而不是 git pull。我们在检索服务器上不再显示的分叉信息时遇到问题。

假设只有一个 "master" 分支,人们可以从中推拉。 此外,假设人们修改了不同的文件并且 git.

没有引发冲突

这是拉取前我的本地分支及其上游的图像

      A---B---C local
     /
D---E---F---G server

如果我们使用 git pull(标准的)会发生这种情况

      A---B---C 
     /         \
D---E---F---G---M---

但是因为我们使用的是 git pull --rebase 如果我没记错的话会发生这种情况:

D---E---F---G---A'--B'--C' 

现在我们知道其中一个测试在 C' 中不再有效。我们确信它在 C 和 G 中都能正常工作。即使没有冲突,如果有两个冗余代码块,并且第一个人删除了一个块,而另一个人删除了另一个块,这也可能发生。

通常要检查的修改是提交 A',B',C,F,G 中的修改,因为分叉发生在 E。但是由于我们使用 git pull --rebase 我们无法知道当分叉发生时,我们无法识别集合 A'、B'、C、F、G。

1) 知道问题现在只出现在 C' 是否有办法识别 E 并因此识别集合 A',B',C,F,G?

2) 如果 1) 的答案是 "no" 那么应该检查哪些提交?

TL;DR:您可以使用 git merge-base 和 reflog 信息找到提交 E


你的绘图是正确的,因为 rebase 所做的是 copy 提交(到新的,略有不同的)。

原始提交会在存储库中保留一段时间(一般情况下,默认为 30 天):它们只是被放置在视图之外。有可能(使用 reflogs and/or ORIG_HEAD 找到原始的 C 并从那里,合并基础提交 E.

如果这种事情经常发生,我建议不要直接使用 git pull。事实上,我建议永远不要 开始 git pull,即使使用这两个独立的基础步骤需要更多的工作和更多的输入。这里的想法是让 Git 正在做什么变得显而易见,从而更容易插入有用的自动化。 (之后,根据您自己的自动化程度,如果您发现 运行 一个命令比两个命令更方便,您可以返回使用 git pull,有或没有 --rebase。)

git pull 所做的是 运行 git fetch,然后是 git mergegit rebase。虽然 pull 有一些额外的花里胡哨,但这确实是其行动的核心。分别执行这两个操作的好处是,它们让您可以检查 fetch 之后和 merge-or-rebase.

之前的状态

(这对于 merge 来说是不必要的,因为 "before merge" 状态很明显:只需剥离合并提交,你就会拥有合并前的状态。它对 [= 更有用31=] 因为 "before merge" 状态允许你在允许 Git 做它疯狂和疯狂的事情之前分别查看分叉开发的两侧,制作提交的副本。)

让我们在这里重现您的 "before" 状态,然后展示 rebase 真正做了什么。这是 "before" 状态,在 运行ning git fetch 之后,但在 运行ning git rebase:

之前
      A---B---C   <-- HEAD -> branch
     /
D---E---F---G     <-- origin/branch

我添加了指向您当前分支的名称 HEAD,并将分支重新命名为更典型。

git rebase 步骤之后,我们有:

      A---B---C            <-- ORIG_HEAD, branch@{1}
     /
D---E---F---G              <-- origin/branch
             \
              A'--B'--C'   <-- HEAD -> branch

通常,观看者(git loggitk --all 等)会跳过 ORIG_HEADCHERRY_PICK_HEAD 等特殊引用。他们还忽略了 reflogs 的内容 (branch@{1})。使用 git refloggit log -g,或在命令行中添加名称 ORIG_HEAD,您可以指示这些观众向您展示原件。

如果将这两个步骤分开,可以很容易地保存关于任何特定提交的信息或向其添加标记(例如临时 git tags)。比如在git fetch之后,可以标记commitE:找到branchorigin/branch1合并基,然后标记它:

$ git tag temp-marker $(git merge-base branch origin/branch)

(假设 sh 或 bash 或类似的;请注意,要概括这一点,您可以只使用 HEAD@{u} 代替 branchorigin/branch).

如果你不想让人们感到困惑 ("why is there a tag named temp-marker in all our repositories?!"),请确保在完成后删除 temp-marker 标签(或至少避免推送它)。

即使您使用 git pull --rebase 将它们组合在一起,之后您也可以使用 reflog and/or ORIG_HEAD 来做同样的事情。 (这里的主要问题是 reflog 中的数字——上面的 branch@{1}——和 ORIG_HEAD 本身都会更新。如果你再做一次变基,ORIG_HEAD 现在会跟踪 rebase 而不是你仍然关心的那个。同时,如果你对 branch 进行任何更新,数字 (@{1}) 递增:现在你需要 branch@{2},然后branch@{3},等等。(您也可以使用 branch@{yesterday},它检查记录到 branch 的每个更改的日期戳,并使用来自 "yesterday"。有关详细信息,请参阅 the git reflog documentation and its link back to git log, and also gitrevisions。)

换句话说,一旦你进入了这个特定的泡菜,检查 branch@{1} 是否是正确的参考(或者 ORIG_HEAD 仍然是好的)。如果不是,请使用 git reflog 或类似的方法找到正确的参考。无论如何,一旦找到它:

git merge-base branch@{1} origin/branch

将找到提交 E.


1这假设只有一个合并基础提交。对于我们在这里考虑的所有情况,这应该是正确的。只有在存在 "criss-cross merges" 的情况下才能获得多个合并基础(必须手工制作):

...--o--*---o--o   <-- branch1
         \ /
          X
         / \
...--o--*---o--o   <-- branch2

在这里,branch1branch2 之间没有单一的合并基础:两个 * 提交都是合适的合并基础。这不会发生在具有单个上游分支的正常工作流中(因为您无法签出 origin/branch 并对其进行提交)。你将不得不做一些你自己的狂野和疯狂的事情(使用一个临时分支、两个显式合并和至少一个推送)来实现它。