我们分叉和开源项目,并在此基础上开发了功能。这些特征特别是分支
现在我试图用新的上游分支重新设置我们的代码。 rebase在错误消息中失败了许多冲突。我希望覆盖传入提交的所有错误消息,但我找不到如何做到这一点。
根据我的发现,以下命令将覆盖与上游代码的所有冲突
git rebase -Xours upstream/branch
但我希望非常明确地覆盖那些不是代码而只是文档的提交
有没有办法实现这个目标?
注意:这是一个有点修改的问题的答案(参见长评论帖)。这是修改后的问题:
我们在本地存储库中创建了一些分支B,它基于上游存储库及其上游/ U分支,用于识别提交
1234567
。上游存储库已由其所有者更新,现在
upstream/U
识别提交89abcde
。1234567
和89abcde
之间有许多承诺和许多变化。我们已经选择改变我们的分支
B
,它有很长的提交列表,所以我们所有的提交都将在89abcde
之后应用。也就是说,我们现在有:...--o--1234567--o--o--...--o--89abcde <-- upstream/U \ B1--B2--B3--...--B1000 <-- B
但最终会有:
B1--B2--B3--...--B1000 [abandoned] / ...--o--1234567--o--o--...--o--89abcde <-- upstream/U \ B1'-B2'-B3'-...--B1000' <-- B
因此,我们通过以下方式开始此操作:
git checkout B git rebase upstream/U
然而,在此过程中,我们遇到了很多情况,在将
B1
提交到B1
,B2
到B2
等等的同时,我们发生了冲突。解决这些冲突有时意味着“获取文件的上游版本”。例如,对于所有文档文件都是如此。对于一些唯一冲突的文件名为
.gitreview
的情况也是如此。如果我们运行
git checkout --ours .gitreview
来获取他们的文件版本,并尝试继续这样,Git说:# git checkout --ours `.gitreview` # git add .gitreview # git rebase --continue Applying: Update .gitreview for stable/mitaka No changes - did you forget to use 'git add'? #
这是什么意思,我们应该如何进行?
现在,如问题中的插图所示,git rebase
正在做的是复制每个提交,B1
,B2
,...,B1000
,用于分支B
上不在分支upstream/U
上的每个提交。为了复制一个提交,Git基本上运行git cherry-pick
(git rebase
的一些变体使用它)或git format-patch
然后git am
。
任何一个都将每个提交转换为差异(在版本控制系统术语中的变更集),然后可以将其应用于其他一些提交。当使用git cherry-pick
时,这个变更集将通过Git的三向合并机制应用,合并基础是樱桃挑选提交的父级。两个分支提示提交是当前提交,它是左侧或“本地”或--ours
提交,我称之为L,并且提交被挑选为右侧或“远程”或--theirs
提交,我称之为R.
请注意,这些更改集一次应用一个,之后Git进行新的提交。 Git首先检查提交89abcde
,使用Git称之为“分离的HEAD”模式,以便提交89abcde
是索引和工作树中的内容,并且根本没有当前分支。然后Git将挑选承诺B1
。由于当前提交是89abcde
,我们将上游代码称为--ours
或本地或L版本。由于现在应用的提交是B1
,我们将从B
分支引用我们自己的代码作为--theirs
或远程或R版本。
假设B1
的变更集成功应用于89abcde
,Git使用commit B1
中的日志消息进行新的提交。这个新的提交现在是B1'
,我们的超级HEAD现在指向这个新的B1'
:
B1--B2--B3--...--B1000 <-- B
/
...--o--1234567--o--o--...--o--89abcde <-- upstream/U
\
B1' <-- HEAD (detached)
这个过程现在用B2
重复,并且一遍又一遍地重复进行许多提交,因为要复制(在这个例子中为1000),直到我们筋疲力尽并且彻底厌恶Git。 :-)
使用git am
时,更改集的应用略有不同,但通常结果相同。关键的区别在于Git没有立即采用三方合并;相反,它首先尝试将diff直接应用于git format-patch
输出中指定的文件。如果diff无法应用,那么Git将提取diff无法应用的文件的合并基础版本。 diff将正确应用于merge-base版本,从而生成文件的R版本。 (L版本只是现有工作树中的版本。)
与git cherry-pick
一样,合并基础版本是该文件的任何版本存储在我们正在复制的提交的父提交中。因此,当退回时,Git将合并基础版本与HEAD版本区分开来。
现在让我们来看看.gitreview
会发生什么。假设我们正在复制提交B11
。文件.gitreview
在提交foo
中包含分支B11
的名称,但它在我们作为bar
的提交中包含不同的分支名称B10'
。 Git在B11
与B10
的分歧中确定.gitreview
已经改变了,所以它在变化集中。实际上,它是变更集中唯一的文件:B11
完全由.gitreview
的变化组成。
我们现在选择不接受我们的更改,因此我们运行:1
# git checkout --ours .gitreview
# git add .gitreview
# git rebase --continue
并得到投诉。
我们得到这个投诉的原因是这个修改过的.gitreview
文件是唯一的变化。通过使用git checkout --ours .gitreview
提取与提交.gitreview
相关的B10'
版本,而不是与B11
一起使用的版本,我们已经使当前的索引和工作树匹配提交B10'
。
Git注意到,与HEAD
(B10'
)相比,索引和工作树没有任何变化,并抱怨。
此时的解决方案是运行:
# git rebase --skip
告诉Git,实际上,我们不再需要提交B11:只需将其从提交列表中删除即可复制。
Git将继续承诺B12
。这可能会改变.gitreview
,或者可能没有。如果没有,我们不会在那里看到任何问题。
如果B12
确实改变了.gitreview
,我们可能会发生冲突,或者我们可能不会,这取决于:
git am
或git cherry-pick
吗?git am
,补丁应该干净利落吗?git cherry-pick
我们正在进行三向合并,或者因为补丁在(2)中没有干净地应用,是否存在合并冲突?假设B12
副本没有冲突,我们现在将:
B1--B2--B3--...--B1000 <-- B
/
...--o--1234567--o--o--...--o--89abcde <-- upstream/U
\
B1'-...--B10'-B12' <-- HEAD (detached)
请注意如何简单地跳过B11
。 Git将继续复制B13
,依此类推。
请记住,在所有情况下,所有Git正在做的是差异的逐行应用。它不知道这些差异意味着什么。它只知道它们可以应用,或者不能应用;或者它们相互冲突(当通过三向合并组合两个差异时),或者不相互冲突。
每次提交,每个文件可以获得一次合并冲突。因此,如果要复制1000个提交,每个提交中有1000个文件,则最多可能有100万个合并冲突。但是,大多数提交最多只能更改几个文件,并且大多数更改都可以干净地应用或没有合并冲突;所以很可能每次合并最多会有几个冲突,最多只有几千个冲突要解决。
尽管如此,除了复制所有1000个(或多个)提交之外,您可能还想使用某些策略。
1这些#
提示我稍微关注一下:他们建议你用root
用户做这一切。对于非root用户,通常的sh / bash提示符是或以$
结尾。通常最明智的做法是尽可能地“生活”为非root用户。