我想在推送之前压缩我的提交。 这适用于“git rebase -i head~#”,#是提交次数。
然后我想将我的分支更新到远程仓库的最新状态。 所以我做“git pull remoterepo branch”并解决任何冲突。
但这是我的问题: 这会创建一个新的提交,我也想用我之前提交的提交压缩。 但是当我再次执行“git rebase -i head~2”时(用我的最后一个来压缩这个新提交),编辑器会分发一个单独的提交列表,这些提交是用pull-command拉出来的。
我现在该怎么办,我该怎么办? 不仅我必须在这里为每个提交编辑数百个选项(将“选择”改为“s(quash)”),而且 - 之后我的历史会变得干净吗?这是我的拼贴想要的吗?
答案 0 :(得分:1)
简短版本:你可能想要重新提交他们的提交。在这一点上,最简单的方法可能是:
git fetch origin
git rebase origin/master
如果您通常希望在将代码与上游代码组合时进行重新定义,则可以配置git pull
为您执行此操作,或运行git pull --rebase
(但请参阅文档中的警告,并了解rebase确实如此;见下文)。
这里发生了什么。
在一段时间内你做了很多提交。它们可能都是很好的和线性的,并且链接了你从遥控器获得的一些较旧的提交:
...-o-o-o <-- origin/master
\
u-u-u-u-u-u <-- HEAD=master
你选择&#34;壁球&#34;所有提交都归结为一个U
提交,其内容与最后一个小的u
提交相同,并且其消息是您提出的任何内容:
...-o-o-o <-- origin/master
\
U <-- HEAD=master
唉,在您进行u
提交并将其转换为一个大U
提交所花费的时间内,他们(无论他们是谁)生成了数百个 new 提交。
让我们绘制他们的回购,以及他们拥有的提交。我会将o
用于原始版本,将n
用于新版本,但我不会因为太难而使用数百个:
...-o-o-o-n-n-n-n-n-n <-- master
他们当然没有你的提交 - 既不是原始的u
提交,也不是你做出的一个大的U
提交,作为压缩小{{{}的最后一步。 1}}提交。
现在,u
基本上只是git pull
,后跟git fetch
。 1 无论如何,git merge
是第一个基本操作,首先要看的那个。
git fetch
做的是要求你的git在网络电话 2 上调用他们的git,看看发生了什么&#34;在那里&#34;自从上次这两个人互相交谈以来。你的git问他们的git发生了什么,他们告诉你所有新的fetch
提交。你的git有他们的git发送它们,并且它们被集成到你的存储库中。你的git更新你的远程跟踪分支&#34;,n
,与他们的git告诉他们他们的git-repository现在看起来是同步的。所以现在我们可以在您的回购中绘制您的内容:
origin/master
你有一个大的提交,你在最后一次...-o-o-o-n-n-n-n-n-n <-- origin/master
\
U <-- HEAD=master
提交之前做了。他们有数百个新的o
提交,他们也在最后一次n
提交之前做出了提交。
您现在遇到了问题。您必须将存储在提交o
下的版本与其版本集成,然后添加到最后一个U
。
你的两个选择是 merge ,这会产生一个新的&#34;合并提交&#34; n
:
M
或 rebase ,它需要一系列提交(一个...-o-o-o-n-n-n-n-n-n <-- origin/master
\ \
U-----------M <-- HEAD=master
提交只是一个非常短的系列)和&#34;重放&#34;那些提交在其他提交之上:
U
&#34;合并&#34; 和&#34;重播&#34;使用git的合并机制,无论你使用哪种方法,结果都非常相似。最后有两个真正的差异。
定期合并以更明显的方式使用合并系统, 3 查看&#34;你做了什么&#34; (最后...-o-o-o-n-n-n-n-n-n <-- origin/master
| \
| U' <-- HEAD=master
\
U [abandoned]
提交和o
提交之间的差异)和#34;他们做了什么&#34; (最后U
提交和最后o
提交之间的差异),并将它们组合在一起。如果你们都认为git认为是&#34;同样的&#34;改变,它保留了一个变化的副本。对于其他更改,git尝试将它们组合在一起,如果它认为它成功了,它会收费;如果它需要你的帮助,它会停止并让你自己解决合并冲突。
(即使git认为合并有效,你应该自己看看结果,因为有时git认为它做的一切都很正确,但结果不是你想要的。)
rebase(重放)更巧妙地使用合并系统。为了重放你的一个提交,git将提交中的工作树与之前提交中的工作树进行比较(即,从最后一个 - n
- 提交到o
提交的差异在这种情况下)。但是,它还仍然抓取合并式差异:相同的&#34;最后U
vs后o
&#34;它得到合并。如果您要重播整个提交链 - 例如,您的一系列小n
次提交,它会将第一个u
与最后一个u
进行比较,第二个o
反对第一个u
,依此类推;并获得一个大的合并风格差异。然后,rebase将应用您的每个提交,但是合并会做同样的事情:如果您的一个更改已经存在于上一个u
提交中,它只保留更改的一个副本。 (由于你只有一个n
提交重播,这种区别无论如何都没有区别。)
无论是合并还是rebase,生成的工作树实际上都是相同的。那究竟是什么区别呢?正如我所说,最终有两个真正的区别:
如果进行合并,则会获得合并提交:额外提交,上面标有U
的提交。此合并记录了这样一个事实:在这种情况下,只要您进行了提交,就会完成原始工作提交M
。如果你保持整个小U
提交链,那么这就完全跟踪你做了什么以及你做了什么:你工作的真实历史。由于你做了一个大的u
提交,这跟踪了一个小谎言,声称你在最后一次U
提交之前做了一次大提交。
合并还会记录您为了获取o
工作树而需要进行的任何更改 - 我们可能希望这些代码版本经过充分测试并正常运行 - 并将其与最后U
提交。因此,它允许将来检查n
下的版本并测试该版本,以防U
下的版本出现问题。如果上一个M
版本有效且您的n
版本有效,则必须通过组合这两个版本来引入任何错误。
如果你做了一个rebase,你将放弃你的版本U
,只有一个版本U
,其版本与你在版本中的版本相同U'
。这使得您似乎等到现在为止,查看了所有M
次提交,并根据这些提交编写了n
版本。
这段历史比较简单:你几个小时前醒来,冲掉大量代码,让它全部工作,测试了好几天等等,然后提交U'
(全部在几分钟的跨度!太棒了!:-))。但这并不是真正的历史。另一方面,其他人真的会关心吗?他们真的需要合并提交U'
来保留半真实历史吗?这实际上会帮助某人追踪未来的错误吗?或者它只是混乱,使开发历史更难以阅读和遵循?
实际上不可能先验地知道哪一个更好。大多数人似乎更喜欢这种有针对性的版本 - 特别是如果你已经&#34;搞乱历史&#34;隐藏所有小的M
提交。我发现&#34;正确答案&#34;不同,我自己:变化很小,很容易重新定位,应该重新定位。大合并问题发生了重大变化......好吧,如果它们可以很容易地重新定位并减少合并问题,那么就这样做;如果没有,请保留更多历史记录,保留更多合并等等。
1 或者,u
后跟git fetch
。如果你有一个足够新的git,那么它也是git rebase
模式,或者你可以在pull配置中设置--rebase=preserve
,以便在重新定位时保留任何本地合并。
2 或其他通讯渠道,但&#34;通过网络&#34;是最常见的更新。
3 实际上,有时不是那么明显。
答案 1 :(得分:0)
您是否在--ff-only
命令上尝试了git pull
标志?以下是documentation:
--ff-only
Refuse to merge and exit with a non-zero status unless the current HEAD is already up-to-date or the merge can be resolved as a fast-forward.
我想你的额外提交是合并提交。这可能是您的配置强制要求,也可能是解决某些冲突所必需的。 Git可以避免在某些条件下(例如没有冲突)生成它(快进)。 --ff-only
允许取消执行,除非不需要额外的提交。