我们有一个功能分支,人们从他们的个人分支合并。我们喜欢我们的特征分支是基于develop
的单个提交,所以我们偶尔会压缩特征分支然后重新开发。
我们使用git rebase -i HEAD~<# of commits>
进行挤压。问题是git force在执行此操作时会合并冲突解决方案。但是,当我们真正关心的是回购在最近提交时所处的状态时,这是浪费时间(并且容易出错)来尝试解决这些冲突。
有没有办法压缩整个分支(大约20次提交,并且沿途有各种合并)并且只保留HEAD与创建分支的develop
的更改,而不必浪费时间导航大量的合并冲突?
答案 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