Git squash-没有合并冲突

时间:2018-02-20 15:11:03

标签: git

我们有一个功能分支,人们从他们的个人分支合并。我们喜欢我们的特征分支是基于develop的单个提交,所以我们偶尔会压缩特征分支然后重新开发。

我们使用git rebase -i HEAD~<# of commits>进行挤压。问题是git force在执行此操作时会合并冲突解决方案。但是,当我们真正关心的是回购在最近提交时所处的状态时,这是浪费时间(并且容易出错)来尝试解决这些冲突。

有没有办法压缩整个分支(大约20次提交,并且沿途有各种合并)并且只保留HEAD与创建分支的develop的更改,而不必浪费时间导航大量的合并冲突?

3 个答案:

答案 0 :(得分:2)

  

有没有办法压缩整个分支(大约20个提交,并且沿途有各种合并)并且只保留HEAD与创建分支的开发的更改,而不必浪费时间导航大量的合并冲突?

是。但要理解这一点,以及它的所有含义,你应该开始 - 因为你应该经常从Git中开始很多事情 - 通过绘制(某些部分)提交图。

让我们从设置开始:

  

我们有一个功能分支,人们从他们的个人分支机构合并。

这意味着(至少对我来说)我们开始,例如:

...--o--o--o--o  <-- master
     |\
     | o--o  <-- alice
     |     \
     |      *------------*   <-- feature
     |\    /            /
     | o--o  <-- bob   /
     |                /
     .............---o   <-- carol

此处的* - ed提交是合并提交 - 第一个可能由Alice或Bob制作,第二个可能由Carol制作,尽管实际的作者和提交者并不相关。

  

我们喜欢我们的功能分支是基于开发的单个提交,因此我们偶尔会压缩功能分支然后重新开发。

     

我们使用git rebase -i HEAD~<# of commits>进行挤压。问题是git force在执行此操作时会合并冲突解决方案。但是,当我们真正关心的是最新提交时repo所处的状态时,这是浪费时间(并且容易出错)来尝试解决这些冲突。

如果你通过git checkout feature; git rebase -i ...执行此操作,那肯定是错误的:-)因为git rebase无法保留合并。相反,rebase命令必须枚举它将复制的所有提交,不包括合并,然后一次一个地复制这些提交,就像git cherry-pick一样(实际上git rebase -i字面上运行{{1 }})。结果是一个完整的提交序列,省略了合并点:爱丽丝,然后鲍勃,然后是卡罗尔,或其他顺序,但让我们假设我们保留爱丽丝& #39; s原始提交:

git cherry-pick

(注意:Bob和Carol的原始提交以及指向它们的分支机构名称可能仍然可用,也可能不会提供,我们只是选择不在此处绘制它们避免弄乱图纸。)

如果将所有...--o--o--o--o <-- master \ o--o <-- alice \ B1-B2-C1-C2 <-- feature 命令更改为pick命令,则rebase命令执行的操作是将所有这些副本一起折叠成一个大副本:

squash

(再次,爱丽丝,鲍勃和卡罗尔的原件可能仍然在这里,分支标签指向他们;但名称...--o--o--o--o <-- master \ A1A2B1B2C1C2 <-- feature 现在指向所有这些组合的单一提交。)

据推测,你想要的是这个大合并提交 - 但你希望它的源代码树匹配feature之前的提交。也就是说,当我们画画时:

feature

...--o--o--o--o <-- master |\ | o--o <-- alice | \ | *------------* <-- feature |\ / / | o--o <-- bob / | / .............---o <-- carol 点有你想要的的提交;您只想将此复制到新提交中,feature这样的新名称可以指向该提交:

new-feature

此处,提交 X <-- new-feature / ...--o--o--o--o <-- master |\ | o--o <-- alice | \ | *------------* <-- feature |\ / / | o--o <-- bob / | / .............---o <-- carol 和提交X(图中最右边的feature)具有不同的哈希ID并且是不同的提交,但它们共享相同的源树< / em>:*根本不会显示任何内容。

这个git diff new-feature feature提交非常容易,你不能使用标准的Git命令来完成它。进行此提交的命令是new-feature:您告诉它要提交哪个源树,以及您想要的提交 - 您必须查找以某种方式提交 - 它使提交git commit-tree。它生成该提交的哈希ID作为其标准输出:

X

tree=$(git rev-parse feature^{tree}) # find the tree to keep parent=... # somehow, find the place to put this commit echo 'combined commit for replacement feature branch' > /tmp/msg-file hash=$(git commit-tree -F /tmp/msg-file -p $parent $tree) 部分留待您了解。它可能像...一样简单(但要注意多个合并基础以及那些不是您期望的提交的情况)。它可能更简单,如果你永远不允许新的提交在git merge-base master feature上增长,那么它只是master指向&#34;的提交。

完成新的提交master后,您需要为其指定一些分支名称:

X

现在你有了我们上面绘制的图表,新的分支名称git branch new-feature $hash 指向了新的功能分支。

您现在可以删除名为new-feature的分支,它将忘记/丢失/放弃所有可从分支名称到达的提交。或者,您可以强制更新旧分支名称以指向新提交,以便旧提交位于分支名称的reflog中,而不是删除旧分支并创建新分支,因此保留通常的30天(之后Git将忘记/丢失/放弃所有提交,除非其他一些名称使其中的一些或全部存活)。

或者,您可以重命名旧功能分支,例如feature,或将其设为标记(制作标记并删除旧功能分支);然后您可以将新的重命名为feature-<date>。通过这种方式,您可以永久保留 - 或直到您删除旧的feature名称 - 它记住的所有提交,但是使用该名称而不是名称feature-<date>

请注意,拥有副本克隆的任何人都将拥有feature。如果他们正在使用它,并且您重新将名称origin/feature指向新提交feature,那么拥有该克隆的人将获取新名称和新提交X他们运行X。他们的git fetch将停止指向旧的纠结图片段,并开始指向新的提交origin/feature

答案 1 :(得分:1)

您可以使用merge --squash

git checkout <your_branch>
git merge --squash develop

git commit

但是,请注意,无论名称如何,此方法实际上都不会导致合并。它只是将所有更改带入您的工作索引,您可以相应地提交它们,就好像您已经在目标分支中完成它们一样。

答案 2 :(得分:0)

git rebase -i <hash of the commit used to create the feature branch in the first place>

您将不会发生任何冲突,因为您的功能分支与用于创建分支的初始提交有关。

交互式 rebase期间使用&#39; f &#39;对于所有提交的修复(第一个提交除外),它会压缩所有提交并丢弃它们的提交日志消息,它在命令行中将如下所示

pick f0454e5 [RFG] window parameter generic
f 4eca527 [FIX] adding missing column
f 13f5202 [FIX] table name