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

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

问题描述

我有一个带有 mainline(相当于 master)和一些本地功能分支的 git 存储库.例如:

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

$ git branch
* mainline
  feature1
  feature2
  feature3

当我执行以下操作时,我能够将特性分支中的所有编辑合并到一个对 mainline 的提交中:

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

我的问题是,此时,当我尝试删除 feature1 分支时,它告诉我它没有完全合并:

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'.

是什么导致了这个错误?我以为 git merge --squash feature1feature1 合并到 mainline 中.

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

推荐答案

发生这种情况是因为 Git 不知道壁球合并等效于"各种特定于分支的提交.必须强行删除分支,用git branch -D代替git branch -d.

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.)

让我们绘制(部分)提交图(这一步适用于 Git 中的很多事情......).事实上,让我们再退一步,这样我们在你的 git rebase 之前开始,像这样:

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

分支名称,如mainlinefeature1,只指向一个特定的提交.该提交向后(向左)指向前一个提交,依此类推,正是这些向后的指针形成了实际的分支.

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.

最上面一行的提交,这里都只称为 o,有点无聊,所以我们没有给它们字母名称.提交的底行 A-B-C 位于分支 feature1 上.C 是最新的此类提交;它返回到 B,返回到 A,返回到无聊的 o 提交之一.(顺便说一句:最左边的 o 提交,以及 ... 部分中所有较早的提交,都在 both 分支上.)

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.)

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

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]

新的A'-B'-C' 提交与原来的三个提交基本相同,但它们在图中移动.(请注意,所有三个无聊的 o 提交现在都在两个分支上.)放弃原来的三个意味着 Git 通常没有将副本与原始文件进行比较.(如果原始文件可以通过其他名称访问——例如,一个附加到旧 feature1 的分支——Git 至少在大多数情况下可以解决这个问题.Git 如何计算的精确细节在这里并不特别重要.)

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.)

无论如何,现在你继续运行 git checkout 主线;git merge --squash feature1.这会生成一个新提交,它是 feature1 上的三个(或多个)提交的压缩副本".我将停止绘制旧的废弃的,并为 Squash 调用新的壁球提交 S:

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

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

当您要求 Git 删除 feature1 时,它会执行安全检查:feature1 是否合并到 mainline 中?"这种合并到"测试完全基于图连通性.名称mainline指向提交S;commit S 指向第一个无聊的 o 提交,这导致返回更无聊的 o 提交.提交 C'feature1 的提示,notS 可达:我们不允许移动向右,只向左.

"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.

将其与进行正常"合并 M 对比:

Contrast this with making a "normal" merge M:

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

使用相同的测试——feature1 的tip commit 是否可以从mainline 的tip commit 到达?"——现在的答案是yes,因为提交 M 有一个向下和向左提交 C' 的链接.(Commit C' 在 Git 内部用语来说是合并提交 M第二个父级.)

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.)

因为壁球合并实际上不是合并,所以没有从 S 返回到 C' 的连接.

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

再说一次,Git 甚至不会尝试看看 S 是否与 A'B'相同"C'.但是,如果是这样,它会说不一样",因为 S 仅与所有三个提交的 sum 相同.让 S 与压缩的提交匹配的唯一方法是只有一个这样的提交(在这种情况下,首先不需要压缩).

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:为什么我不能在壁球合并后删除我的分支?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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