我对某事感到困惑,这是一个总结。
我们的仓库有一个主分支和一个d2l_phase_4分支。自从创建了d2l_phase_4分支以来,已经为master添加了几个新的提交。
今天有人错误地将拉取请求合并到了应该定位到d2l_phase_4分支的提交的主人。
因此我这样做了:
此时我们已经安全地撤消了对我们主分支的提交效果。
然后我这样做了:
此时d2l_phase_4分支与原始提交有所需的更改,到目前为止一直很好。
最后,我想让d2l_phase_4分支与master上的所有其他东西保持同步,因为d2l_phase_4分支已经创建。所以再次在d2l_phase_4分支上我从master合并并创建了一个新的合并提交。
然后我将这个更新的d2l_phase_4分支推送到我的fork / d2l_phase_4,最后创建一个针对主repo / d2l_phase_4的拉取请求,然后合并该PR。
但是 - 我突然意识到Id现在已经在早期版本中从主分支合并,因此必须使我之前提到的提交无效!
然而,当检查d2l_phase_4上的文件状态时,没有从master中合并的恢复的痕迹 - 这正是我想要的 - 但我不明白。
为什么我的樱桃选择了对d2l_phase_4的提交没有被从master合并的revert无效?我预计我需要在d2l_phase_4分支上恢复我的恢复,但是当我尝试这个git似乎告诉我没有什么可以恢复...
如果我查看所涉及的文件之一,在d2l_phase_4分支上,那么我看不到恢复或任何事情的痕迹,我只能看到樱桃选择了我做的提交。
答案 0 :(得分:1)
这有点复杂,并且 - 通常 - 要理解发生了什么,我们必须绘制(部分)提交图。
这是您在错误合并之前显然(基于您的文字)的内容。我可能有错误的提交数量,但整体图表必须合理地接近:
...--A--B--C--D--E <-- master
\
F--G--H <-- dl2_phase_4
对于下一部分,我们必须猜测,因为只有你(以及有权访问你的回购的其他人)拥有正确的信息:
今天有人错误地将拉取请求合并到了应该定位到d2l_phase_4分支的提交的主人。
&#34;定位&#34;不重要;重要的是提交图。拉取请求只是意味着有人发布了一个与您拥有相同提交的存储库,以及至少一次提交。关键问题是,其中提交在他们的图中,我不知道答案。但是,我们只是说它出现在D
之后,所以它看起来像这样:
__I <-- their-commit
/
...--A--B--C--D--E <-- master
\
F--G--H <-- dl2_phase_4
(如果它出现在E
之后,我们可以有一个快进而不是合并,但最终这没有区别。如果它出现在F
之后,图表会变得混乱,尽管它最终没有区别。)
然后,就像你说的那样,将其合并到master
,提供一个新的合并提交(我称之为M
,但我们会进行更多的合并,所以让我们继续使用单个字母并将其称为J
):
__I
/ \
...--A--B--C--D--E--J <-- master
\
F--G--H <-- dl2_phase_4
(我们不再需要标记I
,因为它只是J
的第二个父级 - 第一个父级是E
;第一个是I
vs第二个父母的区别往往会在这些图纸中迷失。)
然后,根据您的三个步骤,使用一个冗长的复杂过程(推送到fork,从fork中撤回)恢复合并,这只会提供与简单地撤消提交K
相同的效果master
上的新提交 __I
/ \
...--A--B--C--D--E--J--K <-- master
\
F--G--H <-- dl2_phase_4
:
K
关于提交E
的重要注意事项是它的树 - 存储的快照 - 与提交的树完全相同J
。提交E
只是I
和K
的合并(因此J = E + I) 1 和{ {1}}&#34;否定我&#34;添加,因此K = E + I - I = E。
1 这不保证!如果I
重复E
中的更改,则J
实际上不是E加我,它是E加我减去重复的部分。但如果是这种情况,我们会在稍后看到效果,因此I
不得在E
中复制某些内容,或者在I
之后复制E
。这就是为什么实际拥有图表,有时候存储库本身很重要的原因。
然后,您经历了另一个长期错综复杂的过程,实际上只相当于一个简单的git cherry-pick
:
- Cherry选择了master的原始提交[into dl2_phase_4]。
醇>
目前尚不清楚哪一个是&#34;原作&#34; (I
或J
,但如果I
实际上是快进的,则没有J
),但这也没关系:我们只是得到一份副本,我就是将致电I'
:
__I
/ \
...--A--B--C--D--E--J--K <-- master
\
F--G--H--I' <-- dl2_phase_4
虽然I'
的树与I
的树不同,但两个相对更改 - 如果我们运行git diff <id-of-D> <id-of-I>
和git diff <id-of-H> <id-of-I'>
,我们会得到什么。这是git cherry-pick
的作用:它对其父项进行了一些提交,然后将生成的diff应用于当前提交并进行新的提交。
最后,我想让d2l_phase_4分支与master上的所有其他东西保持同步,因为d2l_phase_4分支已经创建。所以再次在d2l_phase_4分支上我从master合并并创建了一个新的合并提交。
所以,让我们画 ,现在:
__I
/ \
...--A--B--C--D--E--J--K <-- master
\ \
F--G--H--I'----L <-- dl2_phase_4
然而 - 我突然意识到我现在已经在早期的主分支恢复中合并了...... [但是]检查d2l_phase_4上的文件状态那里没有恢复的痕迹从主人那里合并 - 这正是我想要的 - 但我不明白。
这将进入第一个关键项目:
为什么我的樱桃选择了对d2l_phase_4的提交没有被从master合并的revert无效? [剪断]
正如您从图表中看到的那样,我们正在合并提交K
,同时&#34; on&#34;提交I'
。 合并基础 - 图表行重新加入的提交提交 - 提交B
。
合并进程,merge-as-a-verb,实质上是在执行(然后组合)两个git diff
s:一个从合并库到当前提交,一个从合并基地到另一个提交。因此:
git diff <id-of-B> <id-of-I'>
git diff <id-of-B> <id-of-K>
我们已经注意到,就 tree (git diff
所看到的)而言,提交K
与提交E
相同。因此,第一个diff会忽略不正确的提交及其返回。比较B
与I'
的第二个差异,将樱桃挑选的提交看作是一种变化,因此它包含了这种变化。组合第一个和第二个差异可以为您提供一个更改副本。
git log
命令有点(或有时很多)如果我查看其中一个文件的历史记录,在d2l_phase_4分支上,那么我看不到恢复或任何内容的痕迹,我只能看到樱桃选择了我做的提交。
现在我们已经进行了最后一次合并L
,git log
应该向我们展示提交L
的内容,L
的第一和第二内容父母,他们的父母的内容,等等。
提交L
是一个合并提交,因此它有两个父项K
和I'
。 I'
是您挑选的提交,因此当git log
到达那一点时您会看到它。
K
是一个简单的提交,其中包含一个父项J
;但是J
是一个包含两个父项E
和I
的合并提交。您可能希望在此处看到提交I
,并且 - 此部分变得棘手 - 有时您会。
当你运行git log -- <pathspecs>
时,你给Git一个隐含的论据,即(我认为)不能明确拼写,尽管--dense
和--sparse
可能足够接近解释性目的。这些开启历史简化,历史简化抛出了一个&#34; side&#34;如果合并的话。在任何情况下,您还指示Git忽略在<pathspecs>
参数中命名的所有 文件。
当Git查看commit L
时,它是一个包含两个父项的合并提交,因此历史简化规则的这部分适用:
如果对任何父母不是TREESAME,则包括提交(但是 这可以更改,请参阅下面的
--sparse
。如果提交是一个 合并,对一位父母来说是TREESAME,只关注那位父母。 ...否则,跟随所有父母。
这&#34; TREESAME&#34;被定义为:抛弃除指定路径之外的所有路径之后,被修剪的提交树与其父项之一相同[&#39;树?因此,对于L
,我们会在删除除您要询问的文件之外的所有文件后将其与K
和I'
进行比较。如果L
中的文件版本与I'
中的文件版本相匹配 - 可能就是这样 - 那么此时git log
会删除K
,并且将不会再看到K
1}},也不是J
,也不是J
的父母,也不是E
,D
也不是C
。但是,它会跟随I'
返回H
,然后转到G
和F
以及B
,依此类推,然后返回历史记录。
如果L
中的文件版本与K
中的版本匹配,则git log
会删除I'
;但由于I'
肯定触及了该文件,因此Git仅在此处跟I'
。
要让Git向您展示完整的历史记录,您需要--full-history
,而不是简化图表中找到的侧枝。 Git仍会将历史记录限制为触及文件的提交,但这次它会查看L
的父母。
the git log
documentation中有所有这些例子,但它绝对是眼睛上釉的材料。
另一件需要注意的事情是,git log
经常没有提及合并提交本身,除非你指示它分裂&#34;他们(使用-m
)或强制合并差异(-c
或--cc
)。也就是说,它可以打印日志消息,但不显示任何更改,即使git show
会显示某些内容(--cc
样式合并差异)。