som*_*ser 5 git squash git-squash
我确实尝试过浏览类似的主题,但我似乎无法掌握这个概念。
我分叉了一个仓库,做了一些更改。加班的时候,我也用过git fetch upstreamandgit merge upstream/<branch>几次。有时,我会解决并重新测试一些冲突。
现在,当涉及到将更改推送到上游时,我想进行一次提交。我得到的指示是使用git fetch upstream和git rebase -i upstream/<branch>。
我不明白的是,我再次陷入解决冲突的困境。我不明白为什么当我的叉子与它的起源相同时我需要解决冲突。我可以备份所有修改过的文件,核对我的分叉,再次分叉,恢复备份,这样我就没有冲突需要解决并准备提交。这个过程似乎很机械,我不明白为什么我必须走这条艰难的路(再次解决冲突)。
有人可以帮我理解吗?
“为什么你需要重新解决所有问题”的最佳答案是“你不需要”。但这意味着放弃给你的指示(我不清楚是谁给你这些指示的)。
\n\n正如ElpieKay 评论的那样,您可以使用它git rerere来自动重用以前记录的解决方案。通过这种方式,你重新解决了所有问题,但是让 Git 来做,而不是必须手动做。
但是,如果您的意图是在当前上游提示之上进行一个新的“挤压合并”提交(即,不是合并,只是普通提交)以从中发出拉取请求,则无需执行通过这一切。您可以只执行以下命令序列(请注意下面的假设):
\n\ngit fetch upstream\ngit checkout -b for-pull-request upstream/branch\ngit merge --squash branch\ngit commit\ngit push origin -u for-pull-request\nRun Code Online (Sandbox Code Playgroud)\n\n然后使用 Web 服务上的可点击 Web 按钮发出拉取请求origin。
最终,他们接受您的拉取请求,此时您将删除 branch,放弃所有这些工作,转而采用他们接受的新的单一提交。(请参阅末尾以了解如何重命名/重置。)或者,他们不接受它,此时您可以删除for-pull-request,并可以继续处理branch并最终重复该过程。
这假设:
\n\nupstream\'s) 分叉位于同一个网络服务提供商上。upstream来引用上游存储库(它们的分支),并使用短名称origin来引用存储在 Web 服务提供商上的您自己的分支。Web 提供商提供了发出拉取请求的点击按钮。理解这一切有几个关键点,其中大部分都与 Git提交图的工作方式相关。其余部分与 Git 分发存储库的(单个)魔术有关,以及各种命令\xe2\x80\x94 git merge、git rebase和git merge --squash\xe2\x80\x94 实际执行的操作以及 和git fetch的git push实际操作。
我真的不想再写一篇关于这个的巨篇文章(……太晚了:-)),所以让我们通过注意这些要点来总结一下。它们的顺序不是很好,但我不确定是否有很好的顺序:有很多交叉引用的项目。
\n\nHEADxe2\x80\x94 指向新提交,而新提交又指向该HEAD提交。git rebase通过将现有提交复制到新提交,然后放弃原始提交来工作。它使用“分离的 HEAD”进行复制,其中HEAD直接指向提交,而不是使用分支名称。(“添加新提交”仍然照常工作,只是它只是HEAD直接更新,而不是名称不再存储的分支HEAD。)复制的提交不包括任何合并提交。在某种程度上,这意味着您随后所做的任何冲突解决都将很大程度上丢失(除非您已git rerere启用)。(实际上由于不同的原因丢失了,我还没想好如何解释。)git cherry-pick,有时甚至是通过运行而制作的git cherry-pick。每个cherry-pick都可能导致合并冲突,因为cherry-picking提交会运行合并机制,merge作为动词合并作为我喜欢称之为的
\n\n此操作的合并基础是精心挑选的提交的父级,即使这不是一个非常明智的合并基础。一如既往,提交是当前提交或提交,而另一个提交\xe2\x80\x94提交--ours\ xe2\x80\x94 是正在复制/挑选的提交。在成功的选择结束后,新的提交将作为普通的非合并提交进行。HEAD--theirs
相比之下, Running 则git merge不太复杂,只是存在各种单独的情况。
有时Git发现根本不需要合并,可以进行快进操作:更改当前分支指向的提交,使分支指向目标提交。
\n\n有时需要合并,或者(使用--no-ff)你告诉 Git 不要进行快进,即使可以。在这种情况下,Git 使用合并机制来进行合并。此合并的合并基础是两个提示提交的实际合并基础。与所有合并一样,这里可能存在合并冲突。最后进行的最终提交是合并提交:合并为形容词或名词。
提交图中存在合并提交意味着将来的合并将找到一个新的、更好的合并基础。这将避免重新解决冲突。
跑步git merge --squash是另一个特殊情况。就像实际的合并一样,它使用正常的合并机制来计算真实的合并所涉及的两个分支提示的
当然,要合并的两个提交是一如既往的HEAD( --ours) 和您在命令行中命名的提交。由于合并基础是真正的合并基础,它使用现有的合并作为名词合并(合并提交)来最小化新的合并冲突,因此可以获得相对无冲突的合并结果。
然而,最终提交又回到了樱桃选择的想法:最终提交不是合并提交。这只是一个普通的提交。该树是通过 merge-as-a-verb 计算的,但提交是常规提交,而不是 merge-as-a-noun。(没有特别好的理由,该--squash标志也会打开该--no-commit标志,迫使您git commit自己运行。可能有一个原因曾经\xe2\x80\x94可能对于编写初始代码的人来说是最方便的--squash提早退出可能是最方便的\xe2 \x80\x94但今天没有理由这样做。)
我们添加以下事实:
\n\n您的分叉最初是其他存储库的克隆。所以它从相同的提交(相同的历史)开始upstream。从那时起,你和他们有了一些分歧,但同时你更新了你的分叉git push从您自己的本地存储库中提交来更新您的分叉。
当您这样做时,您可以从他们的git fetch upstream分支中获取他们的提交,并将它们放入您自己的本地存储库中。这些的跟踪名称等等。upstream/master
当您git fetch origin(如果需要)时,您可以从分支中获取提交,并将它们放入您自己的本地存储库中。这些的跟踪名称origin/master等等。
您的存储库有自己的分支(当然)。
\n\n这意味着您的本地存储库\xe2\x80\x94(您自己的计算机上的存储库\xe2\x80\x94)具有“他们的分叉”、“您的分叉”和“您的提交”的完整联合。您可以随时将自己的提交推回自己的分支。
您可以使用您的分叉轻松发出“拉取请求”,因为您的提供商(例如 GitHub)会为您记住“您的分叉”和“他们的分叉”之间的链接。
因此,让我们绘制存储库中的\xe2\x80\x94 或\xe2\x80\x94 提交图的简化版本,结果如下:
\n\n\n\n\n我分叉了一个仓库,做了一些更改。加班的时候,我也用过
\ngit fetch upstreamandgit merge upstream/<branch>几次。有时,我会解决并重新测试一些冲突。
你有:
\n\n...--o--*--o...o...o--T <-- upstream/branch\n \\ \\\n A--B---M---C <-- branch (HEAD), origin/branch\nRun Code Online (Sandbox Code Playgroud)\n\n在这里,提交*是您开始的公共基础提交upstream。您在自己的分支上进行了一些提交,例如A通过。C您还至少进行了一次合并提交M。我假设您git push origin branch在不同的点运行,以便origin/branch在您自己的存储库中将您的分支的分支名称记录branch为指向您的提示提交C。(它是否存在并不重要,因为我们下面不使用它。)
如果您现在运行 ,git rebase -i upstream/branch这将列出提交A、B和C,但不会列出 commit M,因为提交是复制(“pick”)。副本的目标将是 commit T,这是 的提示,您的 Git 从上的upstream/branch分支中记住它branchupstream分支中记住的提示。
如果您忍受重做所有合并冲突,并将三个提交复制到三个新提交,您将得到:
\n\n A\'-B\'-C\' <-- branch (HEAD)\n /\n...--o--*--o...o...o--T <-- upstream/branch\n \\ \\\n A--B---M---C <-- origin/branch\nRun Code Online (Sandbox Code Playgroud)\n\n然后,您可以将其推送(或强制推送)到origin,或者您现在可以(这次没有合并冲突)将序列折叠A\'-B\'-C\'为单个“压缩”提交S:
S <-- branch (HEAD)\n /\n...--o--o--o...o...o--T <-- upstream/branch\n \\ \\\n A--B---M---C <-- origin/branch\nRun Code Online (Sandbox Code Playgroud)\n\norigin并再次将其作为分支名称推送或强制推送到您的分支branch。
(请注意,*一旦基本提交不再是有趣的基本提交,我就停止对其进行标记。当我们考虑运行 时,它特别有趣,因为它是和永久重新加入的git rebase -i upstream/branch点。这决定了必须被标记的提交集复制以进行操作。)branchupstream/branchgit rebase
但是,如果我们创建一个名为 的新分支for-pull-request,指向 commitT并检查它:
...--o--o--o...*...o--T <-- for-pull-request (HEAD), upstream/branch\n \\ \\\n A--B---M---C <-- branch, origin/branch\nRun Code Online (Sandbox Code Playgroud)\n\n现在我们跑git merge --squash branch。这会调用合并机制,使用当前提交TasHEAD和另一个提交 being C。我们将找到合并基础,它现在是我标记的提交*:它是第一个(或“最低”)共同祖先,而不是Arebase 使用的最后一个不相交祖先。也就是说,从提交C和提交开始T并向后工作,Git 会找到“最接近”两个分支提示的提交,即您上次合并的提交。
这意味着您将看到的唯一冲突是您在C(上次合并之后M)所做的任何事情与他们此后所做的任何事情发生冲突*。
当git merge --squash branch完成使用合并机制来合并提交T并将C其*用作合并基础时,它会停止并让您git commit手动运行。当你这样做时,你会得到一个新的普通提交,我们可以将其称为SSquash:
S <-- for-pull-request (HEAD)\n /\n...--o--o--o...o...o--T <-- upstream/branch\n \\ \\\n A--B---M---C <-- branch, origin/branch\nRun Code Online (Sandbox Code Playgroud)\n\n现在,除了它被命名为 之外for-pull-request,如果我们按照您所给出的说明进行操作,我们将得到与我们得到的图表相同的图表。git rebase -i upstream/branch此外,如果我们正确解决任何合并冲突,提交的来源与我们以其他方式获得的来源S相同\xe2\x80\x94,但我们首先要解决的合并冲突(如果有的话)会少得多。
您现在可以将此名称(并提交S)推送到提供商(GitHub?)上的分支,并执行合并请求。如果他们接受它,您可以删除您的分支branch,然后创建一个branch指向S(或将其合并到)的新分支upstream,或者如果他们压缩合并,则它们的S\'分支基本上相同S,但具有不同的哈希ID和不同的提交者:无论如何你都必须git fetch upstream再次获得他们的提交)。
branch您可以简单地强制分支名称指向最新的提交,而不是删除并重新创建。假设他们将你的挤压合并到他们的分叉中,这样他们就有了新的提交,S\'这是 的副本S,而你git fetch:
S <-- for-pull-request (HEAD), origin/for-pull-request\n /\n...--o--o--o...o...o--T--S\' <-- upstream/branch\n \\ \\\n A--B---M---C <-- branch, origin/branch\nRun Code Online (Sandbox Code Playgroud)\n\n您现在可以运行git branch -f branch upstream/branch,或者git checkout branch && git reset --hard upstream/branch,让您的 Git 具有以下功能:
S <-- for-pull-request, origin/for-pull-request\n /\n...--o--o--o...o...o--T--S\' <-- branch, upstream/branch\n \\ \\\n A--B---M---C <-- origin/branch\nRun Code Online (Sandbox Code Playgroud)\n\n(这些分支中的哪一个是HEAD取决于您使用的命令序列)。
一旦您git push --force origin branch将更新发送branch到提供商的分叉并删除for-pull-request(在您的存储库和分叉中),您将有效地放弃一系列origin/branch提交,从而:
S [abandoned]\n /\n...--o--o--o...o...o--T--S\' <-- branch, origin/branch, upstream/branch\n \\ \\\n A--B---M---C [abandoned]\nRun Code Online (Sandbox Code Playgroud)\n\n如果我们停止绘制所有废弃的提交,一切看起来都干净整洁,这可能就是这一切的重点。:-)
\n| 归档时间: |
|
| 查看次数: |
4655 次 |
| 最近记录: |