我从其他开发人员那里挑选了一个提交来进行一些工作。
几个小时后,其中一位开发人员更新了他的补丁。
如果我挑选新补丁,那么就会有冲突。
- 两个添加的文件: - 如果新文件存在于同一文件中 补丁
- 两者都已修改: - 旧补丁和新补丁中的相同文件被修改。
有没有办法丢弃以前的补丁或者我必须手动解决冲突?
您有两个直接而明显的选择:
-
添加第二个提交以撤消第一个樱桃选择。 (现在你有一个源快照,看起来好像你从未做过第一次挑选。
-
删除第一个挑剔,即更改提交历史记录。
使用哪一个取决于很多事情,包括你是否属于说"永远不要重写任何历史"的学校(在这种情况下,你必须使用第一种方法(,或者你是否还有其他提交,除了精心挑选的提交,按图形顺序。
请记住,每个 Git 提交都由其哈希 ID 唯一标识。 如果我们使用大写字母来表示这些提交(而不是原始哈希ID(,我们可以更清楚地了解正在发生的事情。 例如,假设我们从这一系列提交开始:
... <-F <-G <-H <--yourbranch (HEAD)
I <-J <--origin/theirbranch
然后你决定出于任何原因,你喜欢他们的提交J
,所以你运行git cherry-pick <hash-of-J>
或git cherry-pick theirbranch
。 这将复制提交J
的效果,进行新的提交。 我们可以将此提交称为K
但让我们使用J'
来指示它是J
的副本:
...--F--G--H--J' <-- yourbranch (HEAD)
I--J <-- origin/theirbranch
在将来的某个时候,他们(无论他们是谁(已经放弃了他们的提交J
,转而使用新的和改进的提交K
,因此在你运行git fetch
之后,你有:
...--F--G--H--J' <-- yourbranch (HEAD)
I--K <-- origin/theirbranch
(提交J
已完全消失:新提交K
直接指向I
。 这就是人们谈论的"历史改写"。
此时,您可以使用git reset --hard
重写自己的历史记录。 当然,这会抛弃您正在做的任何工作,但假设您没有做任何新工作,因此可以:
J' [abandoned]
/
...--F--G--H <-- yourbranch (HEAD)
I--K <-- origin/theirbranch
您现在可以更轻松地挑选他们的提交K
,因为它不会与您原始J
的副本J'
冲突。 这会导致您拥有:
J' [abandoned]
/
...--F--G--H--K' <-- yourbranch (HEAD)
I--K <-- origin/theirbranch
但是,另一方面,假设您确实有工作取决于您J'
他们的J
副本。 例如,假设自从您挑选了他们的J
来制作您的J'
以来,您已经进行了六次提交? 然后你现在有这个:
...--F--G--H--J'-L--M--N--O--P--Q <-- yourbranch (HEAD)
I--K <-- origin/theirbranch
现在你更难摆脱你的J'
:它嵌入在你的历史中,从Q
一直延伸到F
。
您可以使用交互式变基(git rebase -i
(尝试通过将提交L-M-N-O-P-Q
复制到与原始提交非常相似的新提交L'-M'-N'-O'-P'-Q'
来尝试从历史记录中提取J'
,但请跳过J'
:
J'-L--M--N--O--P--Q [abandoned]
/
...--F--G--H--L'-M'-N'-O'-P'-Q' <-- yourbranch (HEAD)
I--K <-- origin/theirbranch
(请注意,这看起来很像重复采摘樱桃。 那是因为这就是git rebase
,这是反复采摘樱桃! 但是,如果这太痛苦,或者由于其他原因而令人反感,您现在可以创建一个新的提交R
,以撤消其原始J
的副本J'
的效果,并将其添加到您的分支中:
...--F--G--H--J'-L--M--N--O--P--Q--R <-- yourbranch (HEAD)
I--K <-- origin/theirbranch
通过运行以下命令,可能很容易(也可能不容易(进行新的提交R
:
git revert <hash-of-J>
git revert
命令告诉 Git:找出给定提交中更改的内容,并进行具有撤消这些更改效果的新提交。 对于我添加到某个文件的每一行,请从该文件中删除该行。 对于我从某个文件中删除的每一行,请将该行放回原处。 对于我批量删除的每个文件,请恢复该文件;对于我从头开始创建的每个文件,请完全删除该文件。
此过程完成后,提交R
中将有一个快照,看起来好像从未发生过提交J'
。 (如果提交的更改L
通过Q
与这次回退J'
尝试冲突,则在还原过程中通常会看到合并冲突。 请注意,如果是这种情况,如果在将L
-through-Q
复制到新提交时使用交互式变基来放弃提交J'
,您通常会看到相同的冲突。