let*_*tsc 0 git git-rebase git-squash
我想合并我的分支(让我们称之为my_branch)来掌握.它有一个文件在我的github.com上的pull请求中显示为合并冲突.在重新定位之前我想要压缩我的提交(11次提交).所以我做了这样的事情:
# On master
git pull
git checkout my_branch
# on my_branch
git fetch
git rebase -i origin/master
Run Code Online (Sandbox Code Playgroud)
这打开了一个vim编辑器,我的所有提交 - 我保留了第一个,pick并将其余部分更改为s (squash)
pick commit1
s commit2
s commit3
.
.
.
s commit 11
Run Code Online (Sandbox Code Playgroud)
当我保存并退出时,我收到错误 - error: could not apply e7ce468... 'commit1 message'
任何人都可以向我解释问题是什么?我知道我不能因为挤压而变废,因为每一次提交都需要解决.
你说:
在重新定位之前我想要压缩我的提交(11次提交)
(强调我的).但很快,你git rebase就会在重新定位期间或之后进行挤压,这将是一个问题.我们马上回过头来看看.
所以我做了这样的事......
它总是玄乎地说:"我做了类似 <填空>"因为当时我们不知道你真正做到了,这使得它很难猜测到底发生了什么上.:-)幸运的是,这些都很有意义:
Run Code Online (Sandbox Code Playgroud)# On master git pull
这在技术上还不是必需的,但让我们来说明它的作用.该git pull命令只是一个方便的快捷方式,git fetch后面跟着第二个Git命令.第二个Git命令默认为git merge,但您可以将其配置为git rebase.我们现在假设第二个命令只是git merge和/或它对我们没什么特别重要的,这可能是真的.
(这git fetch部分总是安全的,没有伤害任何东西.)
Run Code Online (Sandbox Code Playgroud)git checkout my_branch # on my_branch git fetch git rebase -i origin/master
除非上游正在快速变化,否则第二个git fetch- 第一个git pull- 是不必要的,但一如既往,额外的提取是无害的,并且可能是一个好习惯.问题在于git rebase -i origin/master,开始变基.然后你编辑了要执行的指令,squash但所有的南瓜都会在 rebase 期间发生,也就是说,在重新定位到新的tip提交之前你不会被挤压origin/master.
鉴于即将发生的冲突,它将在您复制的11次提交期间的某个地方发生.它似乎恰好发生在第一个:
当我保存并退出时,我收到错误 -
error: could not apply e7ce468... 'commit1 message'
关于这种早期合并冲突的好处是它比后来的合并冲突更容易解释,尽管此时你可以做的事情与其他地方一样.
该错误告诉您Git无法完成第一次提交的副本.
您可以停止正在进行的rebase,将所有内容恢复到您开始之前的状态,使用:
git rebase --abort
Run Code Online (Sandbox Code Playgroud)
继续阅读以决定是否要这样做并尝试不同的方法.
在使用Git时,你需要记住"提交图",如果只是作为一种背景,阴影,不祥的迫在眉睫的东西:-)大部分时间.其实犯图,虽然它很吓人,是指是有帮助的.它通常非常大而且"织布机".(可能把它想象成一个非常大但很友好的狗.)
提交图是我们可以绘制的,如果我们这样做,它会看起来像这样:
...--o--o--*--o--o--o--o--L <-- origin/master
|
|
\
A--B--C--D--E--F--G--H--I--J--K <-- my_branch
Run Code Online (Sandbox Code Playgroud)
这些单个字母名称中的每一个都是实际提交ID的缩写(其中一个是丑陋的40个字符的哈希7c56b20857837de401f79db236651a1bd886fbbb).圆o节点表示更多我不需要说的提交,所以它们很无聊.这*是一个我不知道的ID的提交,并且没有任何名称,但它非常有趣,所以我给了它一个明星.
(较旧的提交位于左侧,分支名称指向每个分支的提示.最后一点是Git如何工作:分支名称指向提交提交,每个提交点向后,到其早期的父提交.内部向后箭头有点令人分心和烦人,很难用ASCII绘制,所以我只是将它们画成线条.)
请注意,A通过K是11次提交,并且L是提示到哪些origin/master点(在您git fetch的Git使Git存储库更新之后origin).我只是随机猜测了有多少普通无聊的o提交,但这并不重要.
当您运行git rebase origin/master(有或没有-i)时,Git将尝试复制所有11个提交,副本将在"提交后"进行L.也就是说,它想要将图形更改为如下所示:
...--o--o--*--o--o--o--o--L <-- origin/master
| \
| A'-B'-C'-...-J'-K' <-- my_branch
\
A--B--C--D--E--F--G--H--I--J--K [abandoned]
Run Code Online (Sandbox Code Playgroud)
(当你把它变成一个交互式的rebase并使用时squash,Git只是简单地修改了复制过程,使它首先A'像往常一样,然后制作B'出来A' + B并链接到L,然后制作C'出来B' + C等等.这里的关键是Git仍在一步一步地完成所有事情.)
这里的问题是每个步骤都可能导致合并冲突.目前尚不清楚每一步是否都会 -我们知道第一步是什么,但我们对其余部分知之甚少.
如果只有一种方法来压缩所有11个提交,同时将它们附加到我标记的提交*.也就是说,不是一次一个地复制每个提交,而是将它们添加到L,如果我们可以让Git只创建一个AK表示总和的新提交,该A+B+C+...+J+K怎么办?我们可以像这样绘制这个好结果:
...--o--o--*--o--o--o--o--L <-- origin/master
|\
| AK <-- my_branch
\
A--B--C--D--E--F--G--H--I--J--K [abandoned]
Run Code Online (Sandbox Code Playgroud)
现在我们可以做一个简单的变换AK(它仍然会与之冲突L,但我们只需要解决一次问题).
嗯,事实证明这真的很容易.我们需要的是运行git rebase -i像以前一样,但告诉它:不重订到L,重订到*.也就是说,将链从另一条链上的链条复制到现在的位置.
我们已经基于*,但如果我们"改变"到现在的位置,我们就可以轻松压制所有东西:没有冲突,南瓜就会起作用.我们只需要以*某种方式命名提交.
你怎么能找到提交*?一种方法是使用git log,它显示所有提交ID.剪切并粘贴您关注的提交的ID:
$ git rebase -i <id-of-commit-*>
Run Code Online (Sandbox Code Playgroud)
和之前的壁球一样,Git会做你想做的事:在变基之前压制.(好吧,不是完全"之前",而是作为一个更小的,压扁的基础,在大变革之前.)
查找提交ID的另一种方法*是使用git merge-base:
$ git merge-base my-branch origin/master
Run Code Online (Sandbox Code Playgroud)
这将打印出ID,准备剪切和粘贴(或者您可以使用shell语法将ID直接插入命令,或设置变量等).
随意忽略这个快捷方式,但你可以:
$ git checkout my_branch
$ git reset --soft <id-of-commit-*>
$ git commit
Run Code Online (Sandbox Code Playgroud)
这样做是为了放弃A--B--...--J--K链(my_branch指向提交*),但是将文件保存在提交中的工作树和索引中K,然后使用当前索引进行新的提交.所以这使得一个提交的树的匹配K,但其父是提交*.(您必须编写一个全新的提交消息,而压缩则允许您编辑来自原始11提交的消息.)
无论如何,您最终都希望将新AK提交或原始A--B--...--J--K链重新提交到提交L.这将需要解决合并冲突.
这样做的好处AK是你只需要解决一次,而不是每次冲突提交一次.缺点是,在一次解决一个较小的冲突时可能更清楚该做什么:可能A有一个明显的冲突,并且J有一个不同且也很明显的冲突,并且K有一个类似A但仍然明显的冲突......但是当你变基合并AK一下子,冲突之间A和K,再加上分心J,使得它很难看到如何解决它.
因此,首先压缩的好处是可能冲突的提交次数减少.首先压缩的负数是可能冲突的提交次数减少.这取决于你尝试哪一个.
无论你做什么,记住Git总是通过添加新的提交来工作.旧的,即使它们"被遗弃",仍然在你的存储库中.默认情况下,它们会至少保留30天,并且它们的ID会被保存在Git的"reflogs"中.如果要返回旧提交,可以使用保存的ID简单地创建新分支或标记名称.
HEAD每个分支都有一个reflog 和一个.该my_branch引用日志是一个更容易使用的从底垫恢复.
| 归档时间: |
|
| 查看次数: |
895 次 |
| 最近记录: |