【发布时间】:2018-08-28 13:29:21
【问题描述】:
我已经从其他开发人员那里挑选了一个提交来完成一些工作。
几个小时后,一位开发人员更新了他的补丁。
如果我选择新补丁,那么就会有冲突。
- 添加了两个文件: - 如果新文件存在于同一个文件中 补丁
- 已修改: - 旧补丁和新补丁中的相同文件已修改。
有什么方法可以丢弃之前的补丁或者我必须手动解决冲突?
【问题讨论】:
标签: git cherry-pick git-merge-conflict
我已经从其他开发人员那里挑选了一个提交来完成一些工作。
几个小时后,一位开发人员更新了他的补丁。
如果我选择新补丁,那么就会有冲突。
有什么方法可以丢弃之前的补丁或者我必须手动解决冲突?
【问题讨论】:
标签: git cherry-pick git-merge-conflict
您有两个直接而明显的选择:
添加第二个提交,以撤消第一个樱桃选择。 (现在您的源快照看起来好像您从未进行过第一次挑选。)
删除第一个选择,即更改您的提交历史记录。
使用哪一个取决于很多事情,包括您是否属于说“永远不要重写任何历史”的学校(在这种情况下,您必须使用第一种方法),或者您是否有额外的提交- 选择一个,按图表顺序。
请记住,每个 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。
您可以使用交互式 rebase (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' 冲突,您通常会在还原过程中看到合并冲突。请注意,if 就是这种情况,如果您在将 L-through-Q 复制到新提交时使用交互式变基丢弃提交 J',通常会看到 same 冲突。)
【讨论】:
git commit --amend 可能是其他开发人员如何创建 K-instead-of-J。 --amend 真正所做的只是使 new 提交点回到 当前提交的父级,有效地将当前提交推到行尾。您实际上无法更改提交,git commit --amend 不会尝试这样做:它只是使 不同 提交成为分支上的最后一个。