如何在使用上游代码覆盖特定的本地冲突提交时git rebase

时间:2017-12-01 06:18:38

标签: git rebase

我们分叉和开源项目,并在此基础上开发了功能。这些功能特别是分支

现在我正在尝试使用新的上游分支来重新设置代码。 rebase在错误消息中失败了许多冲突。我希望覆盖所有传入提交的错误消息,但我找不到如何做到这一点。

根据我的发现,以下命令将覆盖与上游代码的所有冲突

git rebase -Xours upstream/branch

但我希望非常明确地覆盖那些不是代码而只是文档的提交

有任何方法可以达到这个目的吗?

1 个答案:

答案 0 :(得分:0)

注意:这是一个有点修改过的问题的答案(参见长评论帖)。这是修改过的问题:

  

我们在本地存储库中创建了一些分支 B ,基于上游存储库及其分支 upstream / U ,用于标识提交{{1} }。

     

上游存储库已由其所有者更新,现在1234567标识了提交upstream/U89abcde1234567之间有许多提交和许多更改。

     

我们已经选择了我们的分支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 复制到B1B1复制到B2,依此类推,我们得到了冲突。

     

解决这些冲突有时意味着&#34;采取文件的上游版本&#34;。例如,对于所有文档文件都是如此。对于仅有冲突的文件名为B2的情况,情况也是如此。

     

如果我们运行.gitreview来获取他们的文件版本,并尝试继续这样做,Git说:

git checkout --ours .gitreview
     

这是什么意思,我们应该如何进行?

现在,如问题中的插图所示,# 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 rebaseB1,..., B2,用于分支B1000上不在分支B上的每个提交。要复制提交,Git基本上运行upstream/Ugit cherry-pick的某些变体使用此功能)或git rebase后跟git format-patch

任何一个都可以将每个提交转换为diff(一个 changeset ,在版本控制系统术语中),然后可以应用于其他一些提交。使用git am时,此变更集将通过Git的三向合并机制应用,合并基础是樱桃挑选提交的父级。两个分支提示提交是当前提交,即左侧或&#34;本地&#34;或者git cherry-pick提交我称之为 L ,并且提交被选为右侧或者#34;远程&#34;或--ours提交我称之为 R

请注意,这些更改集一次应用一个,之后Git进行新的提交。 Git首先检查提交--theirs,使用Git称之为&#34;分离的HEAD&#34;模式,以便提交89abcde是索引和工作树中的内容,并且根本没有当前分支。然后Git将挑选提交89abcde。由于当前提交为B1,我们将上游代码称为89abcde本地 L 版。由于现在应用的提交是--ours,我们将从分支B1引用我们自己的代码B远程 R 版本。

假设--theirs的变更集成功应用于B1,Git使用来自commit 89abcde的日志消息进行新的提交。这个新提交现在是B1,我们分离的HEAD现在指向这个新的B1'

B1'

这个过程现在用 B1--B2--B3--...--B1000 <-- B / ...--o--1234567--o--o--...--o--89abcde <-- upstream/U \ B1' <-- HEAD (detached) 重复,并且一遍又一遍地重复提交要复制的许多提交(在本例中为1000),直到我们筋疲力尽并且彻底厌倦了Git。 : - )

使用B2时,更改集的应用略有不同,但结果通常相同。关键的区别在于Git 没有立即采用三向合并;相反,它首先尝试将diff直接应用于git am输出中指定的文件。如果diff无法应用,则然后 Git将提取diff未能应用的文件的合并基础版本。差异将正确应用于合并基础版本,从而生成文件的 R 版本。 ( L 版本只是现有工作树中的版本。)

git format-patch一样,合并基础版本是该文件的任何版本存储在我们正在复制的提交的提交中马上。因此,当退回时,Git将合并基础版本与HEAD版本区分开来。

现在让我们看看git cherry-pick会发生什么。假设我们正在复制提交.gitreview。文件B11在提交.gitreview中包含分支foo的名称,但它在我们作为B11的提交中包含不同的分支名称bar。 Git将B10'B11区分开来,将B10标识为已更改,因此它在变更集中。实际上,它是变更集中的文件:.gitreview完全由对B11的更改组成。

我们现在选择不接受我们的更改,因此我们运行: 1

.gitreview

并得到投诉。

我们收到此投诉的原因是此修改后的# git checkout --ours .gitreview # git add .gitreview # git rebase --continue 文件仅为 更改。通过使用.gitreview来提取与提交git checkout --ours .gitreview一致的.gitreview版本,而不是与B10'一起提供的版本,我们已经制作了当前索引 - and-work-tree完全匹配提交B11

Git注意到,与B10'HEAD)相比,索引和工作树中没有任何变化,并且抱怨。

此时的解决方案是运行:

B10'

告诉Git,实际上,我们不再需要提交B11:只需将其从提交列表中删除即可复制。

Git将继续提交# git rebase --skip 。这可能会更改为B12,也可能不会更改。如果它没有,我们就不会在那里看到任何问题。

如果.gitreview 的更改<{1}},我们可能会发生冲突,或者我们可能不会发生冲突,具体取决于:

  1. 我们正在进行B12.gitreview吗?
  2. 如果我们正在进行git am,该修补程序是否干净利落?
  3. 如果由于git cherry-pick我们正在进行三向合并,或者因为补丁未在(2)中干净地应用,那么是否存在合并冲突,或不?
  4. 假设git am份没有冲突,我们现在有:

    git cherry-pick

    注意如何简单地跳过B12。 Git将继续复制 B1--B2--B3--...--B1000 <-- B / ...--o--1234567--o--o--...--o--89abcde <-- upstream/U \ B1'-...--B10'-B12' <-- HEAD (detached) ,依此类推。

    请记住,在所有情况下,所有Git所做的都是差异的逐行应用。它不知道这些差异是什么意思。它只知道它们可以应用,或者不能应用;或者它们相互冲突(当通过三向合并组合两个差异时),或者不相互冲突。

    每次提交每个文件可以获得一次合并冲突。因此,如果要复制1000个提交,并且每个提交中有1000个文件,则可能最多有100万个合并冲突。但是,大多数提交最多只能更改几个文件,并且大多数更改都可以干净地应用或没有合并冲突;因此很可能每次合并最多会有几个冲突,最多只有几千个冲突可以解决。

    尽管如此,您可能希望使用除复制所有1000个(或多个)提交之外的其他策略。

    1 这些B11提示稍微让我感到担忧:他们建议您以用户B13执行所有操作。对于非root用户,通常的sh / bash提示符以#结尾。它通常是最明智的生活和#34;尽可能多的是除了root之外的其他人。