git:为什么我在squash合并后不能删除我的分支? [英] git: why can't I delete my branch after a squash merge?

查看:251
本文介绍了git:为什么我在squash合并后不能删除我的分支?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含 mainline (相当于 master )和一些本地特性分支的git仓库。例如:

  $ git分支
*主线
特征1
特征2
feature3

当我执行以下操作时,我可以将所有编辑合并到一个功能分支中进入一个提交到 mainline

  $ git checkout mainline 
$ git pull
$ git checkout feature1
$ git rebase mainline
$ git checkout mainline
$ git merge --squash feature1
$ git commit
$ g $ push

我的问题是,在这一点上,当我尝试删除 feature1 分支,它告诉我它没有完全合并:

  $ git branch -d feature1 
错误:分支'feature1'未完全合并。
如果您确定要删除它,请运行'git branch -D feature1'。

导致此错误的原因是什么?我认为 git merge --squash feature1 合并 feature1 mainline

解决方案

发生这种情况是因为Git不知道压扁合并是等同于各种特定分支的提交。你必须用 git branch -D 而不是 git branch -d 来强制删除分支。



(其余部分仅仅是为什么是这种情况。)



绘制提交graph



让我们绘制(部分)提交图(这一步适合Git中的很多事情......)。事实上,让我们再退一步,让我们在 git rebase 之前开始,如下所示:

  ...  -  o  -  o  -  o < -  mainline 
\
A - B - C < - feature1

分支名称,如 mainline code>或 feature1 ,仅指向一个特定的提交。该提交指向前一个提交(向左),等等,它们是形成实际分支的这些反向指针。



第一行提交,全部只是在这里称为 o 有点无聊,所以我们没有给他们写信。最后一行提交 A-B-C 仅在 feature1 中的 C 是最新的这样的提交;它会回到 B ,这会导致回到 A ,这会导致无聊的 o 提交。 (顺便说一句:最左边的 o 提交以及所有之前在 ... 部分提交的提交都处于打开状态)



运行 git rebase 时,三个 ABC 提交被复制到 附加到 mainline ,给我们:

  ...-- o  -  o  -  o<  -  mainline 
\\ \\\
\ A'-B'-C'< - feature1
\
A - B - C [旧功能1,现已放弃]

新的 A'-B'-C'提交是大部分与原来的三个一样,但是它们在图表中移动了。 (请注意,所有三个无聊 o 提交现在都在两个分支上。)放弃原始三个意味着Git通常不会 来比较复制到原件。 (如果原始文件可以通过其他名称到达 - 旧的 feature1 附加的分支,例如Git can 可以解决这个问题,至少在大多数情况下,Git的具体细节在这里并不特别重要。)

无论如何,现在你继续运行 git结帐主线; git merge --squash feature1 。这会产生一个新的提交,它是 feature1 上的三个或多个提交的压缩副本。我将停止绘制旧的被遗弃者,并为Squash调用新的squash-commit S

  ...  -  o  -  o  -  o  -  S < - 主线
\
A'-B'-C'< - 特征1



删除安全性完全由提交历史决定



当你要求Git删除 feature1 时,它会执行一个安全检查:is feature1 合并到主线?这个被合并到测试完全基于图连通性。名称主线指向提交 S ;提交 S 指向第一个无聊 o 提交,这会导致更多枯燥的 o 提交。提交 C' feature1 的提示 c> S :我们不允许向右移动,只能向左移动。



将这与做一个正常合并 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ - M-主线
\ /
A'-B'-C'< - 特征1

使用相同的测试 - 是 feature1 从<$ c的提示提交可到达的提示提交$ c> mainline ? - 答案现在是 yes ,因为commit M 有一个向左和向左的链接提交 C'。 (提交 C',在Git内部说法中,合并提交 M >。)



因为压缩合并实际上并不是 merges ,所以 S 返回到 C'



再次,Git甚至不尝试 em>来查看 S 是否与 A'相同, B' C'。如果它确实如此,它会说不一样,因为 S 仅与所有三个提交的 sum 相同。获得 S 来匹配被压扁的提交的唯一方法是只有一个这样的提交(在这种情况下,不需要首先挤压)。 p>

I have a git repo with mainline (equivalent to master) and some local feature branches. For example:

$ git branch
* mainline
  feature1
  feature2
  feature3

When I do the following, I am able to squash merge all of my edits in a feature branch into one commit to mainline:

$ git checkout mainline
$ git pull
$ git checkout feature1
$ git rebase mainline
$ git checkout mainline
$ git merge --squash feature1
$ git commit
$ git push

My question is, at this point, when I try to delete the feature1 branch, it tells me it is not fully merged:

$ git branch -d feature1
error: The branch 'feature1' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature1'.

What causes this error? I thought git merge --squash feature1 merged feature1 into mainline.

解决方案

This happens because Git doesn't know that the squash merge is "equivalent to" the various branch-specific commits. You must forcibly delete the branch, with git branch -D instead of git branch -d.

(The rest of this is merely about why this is the case.)

Draw the commit graph

Let's draw (part of) the commit graph (this step is appropriate for so many things in Git...). In fact, let's step back one more step, so that we start before your git rebase, with something like this:

...--o--o--o     <-- mainline
      \
       A--B--C   <-- feature1

A branch name, like mainline or feature1, points only to one specific commit. That commit points back (leftward) to a previous commit, and so on, and it's these backward pointers that form the actual branches.

The top row of commits, all just called o here, are kind of boring, so we didn't give them letter-names. The bottom row of commits, A-B-C, are only on branch feature1. C is the newest such commit; it leads back to B, which leads back to A, which leads back to one of the boring o commits. (As an aside: the leftmost o commit, along with all earlier commits in the ... section, is on both branches.)

When you ran git rebase, the three A-B-C commits were copied to new commits appended to the tip of mainline, giving us:

...--o--o--o            <-- mainline
      \     \
       \     A'-B'-C'   <-- feature1
        \
         A--B--C       [old feature1, now abandoned]

The new A'-B'-C' commits are mostly the same as the original three, but they are moved in the graph. (Note that all three boring o commits are on both branches now.) Abandoning the original three means that Git usually doesn't have to compare the copies to the originals. (If the originals had been reachable by some other name—a branch that appended to the old feature1, for instance—Git can figure this out, at least in most cases. The precise details of how Git figures this out are not particularly important here.)

Anyway, now you go on to run git checkout mainline; git merge --squash feature1. This makes one new commit that is a "squash copy" of the three—or however many—commits that are on feature1. I will stop drawing the old abandoned ones, and call the new squash-commit S for Squash:

...--o--o--o--S         <-- mainline
            \
             A'-B'-C'   <-- feature1

"Delete safety" is determined entirely by commit history

When you ask Git to delete feature1, it performs a safety check: "is feature1 merged into mainline?" This "is merged into" test is based purely on the graph connectivity. The name mainline points to commit S; commit S points back to the first boring o commit, which leads back to more boring o commits. Commit C', the tip of feature1, is not reachable from S: we're not allowed to move rightward, only leftward.

Contrast this with making a "normal" merge M:

...--o--o--o---------M   <-- mainline
            \       /
             A'-B'-C'    <-- feature1

Using the same test—"is the tip commit of feature1 reachable from the tip commit of mainline?"—the answer is now yes, because commit M has a down-and-left link to commit C'. (Commit C' is, in Git internal parlance, the second parent of merge commit M.)

Since squash merges are not actually merges, though, there is no connection from S back to C'.

Again, Git doesn't even try to see if S is "the same as" A', B', or C'. If it did, though, it would say "not the same", because S is only the same as the sum of all three commits. The only way to get S to match the squashed commits is to have only one such commit (and in this case, there's no need to squash in the first place).

这篇关于git:为什么我在squash合并后不能删除我的分支?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆