我们使用git pull --rebase
代替git pull
。我们在检索服务器上不再显示的fork信息时遇到问题。
假设一个人“推拉”的单个“主”分支。 此外,假设人们修改了不同的文件,并且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都工作。即使没有冲突,如果有两个冗余代码块,也可能发生这种情况,第一个人删除了一个块,而另一个人删除了另一个块。 / p>
通常,要检查的修改是提交A',B',C,F,G中的修改,因为fork发生在E.但是因为我们使用git pull --rebase
我们无法知道何时fork发生了,所以我们无法识别集合A',B',C,F,G。
1)知道问题现在只出现在C',有没有办法识别E,因此有一套A',B',C,F,G?
2)如果1)的答案是“否”,那么应该检查什么提交?
答案 0 :(得分:2)
E
和reflog信息找到提交git merge-base
。你的绘图是正确的,因为rebase的作用是 copy 提交(对于新的,略有不同的提交)。
原始提交在存储库中保留了一段时间(默认情况下一般为30天):它们只是放在视图之外。可以(使用reflogs和/或ORIG_HEAD
查找原始C
,并从那里找到合并库提交E
。
如果经常发生这种事情,我建议不要直接使用git pull
。实际上,我建议永远不要使用git pull
启动,即使需要更多的工作和更多的输入,使用两个单独的基础步骤。这里的想法是明确Git正在做什么,因此更容易插入有用的自动化。 (之后,根据您自己的自动化,如果您发现运行一个命令而不是两个命令更方便,则可以返回使用git pull
,有或没有--rebase
。)
git pull
执行的操作是git fetch
,然后是git merge
或git rebase
。虽然pull
有一些额外的花里胡哨,但这确实是它行动的核心。分别执行这两项操作的好处是,它们允许您在fetch
之后和merge
- 或 - rebase
之前检查状态。
(对于merge
来说,这远远不那么必要了,因为“合并之前”状态显而易见:只是剥离合并提交并且你有合并前状态。它对rebase
更有用因为“合并前”状态允许你分别查看分叉开发的两面,如果你愿意,在允许Git做疯狂和疯狂的事情之前,制作提交的副本。)
让我们在这里重现你的“之前”状态,然后展示什么是rebase真正做到的。以下是“之前”状态,在运行git fetch
之后,但在运行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 log
,gitk --all
等)会跳过ORIG_HEAD
,CHERRY_PICK_HEAD
等特殊引用。他们还忽略了reflogs(branch@{1}
)的内容。使用git reflog
或git log -g
或在命令行中添加ORIG_HEAD
等名称,您可以指示这些查看者向您显示原件。
如果将这两个步骤分开,则可以轻松保存有关任何特定提交的信息或添加标记(例如临时git tag
)。例如,在git fetch
之后,您可以标记提交E
:找到branch
和origin/branch
的 1 合并基础,并将其标记为:< / p>
$ git tag temp-marker $(git merge-base branch origin/branch)
(假设为sh或bash或类似内容;请注意,为了概括这一点,您可以使用HEAD
和@{u}
代替branch
和origin/branch
)。
如果您不想混淆用户(“为什么我们所有的存储库中都有一个名为temp-marker
的标记?”,请务必删除temp-marker
标记(或至少避免推送它)? “),一旦你完成它。
即使你使用git pull --rebase
来保持它们的组合,你也可以使用reflog和/或ORIG_HEAD
来做同样的事情。 (这里的主要问题是reflog中的数字 - branch@{1}
以及ORIG_HEAD
本身都会更新。如果你再做一次rebase,ORIG_HEAD
现在跟踪那个 rebase而不是你仍然关注的那个。同时如果你对branch
进行任何更新,则数字(@{1}
)递增:现在你需要branch@{2}
,然后{{1 (还可以使用branch@{3}
,它会检查记录到branch@{yesterday}
的每个更改的日期戳,并使用最新的“昨天”。请参阅{{ 3}}及其链接返回the git reflog
documentation,还有git log
,以获取详细信息。)
换句话说,一旦你进入这个特定的泡菜,检查branch
是否是正确的参考(或branch@{1}
仍然是好的)。如果没有,请使用ORIG_HEAD
或类似内容找到正确的参考。无论如何,一旦找到它:
git reflog
将找到提交git merge-base branch@{1} origin/branch
。
1 这假设只有一个合并基础提交。对于我们在这里考虑的所有情况,这应该是真的。只有存在“纵横交错合并”(必须手工制作)才能获得多个合并基础:
E
此处,...--o--*---o--o <-- branch1
\ /
X
/ \
...--o--*---o--o <-- branch2
和branch1
之间没有单一的合并基础:两个branch2
提交都是合适的合并基础。在具有单个上游分支的正常工作流中不会发生这种情况(因为您无法检出*
并对其进行提交)。你将不得不做一些你自己疯狂和疯狂的事情(使用一个临时分支,两个显式合并,至少一次推动)来实现它。