在拉取请求合并父分支后删除父分支是否安全?

Is it safe to delete a parent branch after a pull request merges that parent?

我在 GitHub 上使用共享存储库模型。我创建了一个功能分支 A,将一些更改推送到远程源,然后创建了一个拉取请求。我想在 A 的基础上做更多的更改,所以从 A 创建了一个新分支 B。在推送更多编辑之后,我为 B 创建了另一个 pull request。

A 的拉取请求已被接受。所以 'git pull origin master' 然后让我的本地 master 包含 A。

如果分支 A 有一个子分支 B,我该怎么办?

我看到了

$ git checkout B
$ git diff origin/master --

不再像预期的那样包含 A 差异。

• 那么我可以在不影响B的情况下删除分支A吗?接受 pull request 后,我​​在 master 中看到了 A 提交历史。

• 那么B会不会重新学习master?

• 对 B 的现有 GitHub 拉取请求有什么影响(如果有)?

tldr; dvcs 像病毒一样工作

Git 中的 "branch" 只是一个 DAG of changesets,其中通过分支名称访问 HEAD 提交(在该分支上)。如果已为另一个存储库提供(即 'pushed' 或 'pulled')已提交的变更集,那么它们现在也存在于该存储库中。 删除本地提交不会影响已应用于其他存储库的提交。

要使来自上游的拉取生效,变更集 "branch" DAG 的根必须已经存在于上游目标上。因此,拉取的数据实际上是 root_from_upstream->commit(s)->head_at_pull 变更集:来自上游存储库的拉取导致它将变更集应用于自身,一直到分支的头部(这是一个特定的修订),在拉取请求。

删除(或者,也许更好,'closing')本地分支不会删除任何变更集;它只是让它们无法通过 that 分支名称访问。

即使提交是来自本地 Git 存储库的 'purged'(或者用 Mercurial 的说法是 'stripped'),提交变更集仍然存在于其他存储库中以他们被推到(或拉到).

如果完成从源的拉取,将根据需要获取变更集以完成 DAG。然而,"branch" 本身并没有重新创建,因为这样的名称是一个本地工件,后来被丢弃了。


So can I delete branch A without affecting B? After the accepted pull request, I see the A commit history in master.

是的。如果本地分支不再有用,则可以将其删除。提交已经传播到另一个存储库 - 即使没有传播,变更集仍将是分支 'B'.

形成的 DAG 的一部分

Will B then reparent to master?

没有。分支名称仅标识变更集图的特定提交。删除分支 'A' 不会影响 changesets/DAG,也不会影响 'B'。 绝对没有隐含的重新设置。

What will the effect be, if any, on the existing GitHub pull request for B?

没有。


这就是为什么像电子邮件一样,在推送(或拉取)之前整理和组织提交很重要。一旦发布到野外,就没有简单的方法来捕获变更集。


Mercurial 的工作方式略有不同,但任何特定 Hg 分支的 'tip' 与 Git 分支的工作方式类似:它标识变更集 DAG 中代表当前分支 HEAD 的特定提交。

让我们假设事件的顺序是这样的:

git checkout -b A
git commit
git commit
git commit
git checkout -b B
git commit
git commit
git checkout master
git commit
git merge A

这会给你一张看起来像这样的图片:

在这种情况下,删除 A 是绝对安全的,因为您基于 B 的工作包含在 master 中。

不过,

B 不会自动拥有一个新的 parent;你应该考虑 rebasing your branch 对抗 master。这将使历史看起来总是在 master 中的提交之后,并将减少您以后工作的噪音和混乱。

将其视为 Dictator and Lieutenants 工作流程。上游应始终代表真实的规范来源,您的工作应始终基于它进行重新设计。

所以我发现我可以使用脚本轻松演示 user2864740 和 Makoto 对第二个问题的回答,如下所示。

答案如下:

+ git log --graph --oneline --branches
* a392a9d branch_B change_b2 commit
* 7c29ca6 initial branch_B change_b1 commit
| *   30591f8 merge branch_A into master
| |\
| |/
|/|
* | 34a1162 branch_A change_a2 commit
* | 2ad533b initial branch_A change_a1 commit
| * 67941a1 mergable change in master
|/
* 36d7364 initial master commit
+ git branch -d branch_A
Deleted branch branch_A (was 34a1162).
+ git log --graph --oneline --branches
* a392a9d branch_B change_b2 commit
* 7c29ca6 initial branch_B change_b1 commit
| *   30591f8 merge branch_A into master
| |\
| |/
|/|
* | 34a1162 branch_A change_a2 commit
* | 2ad533b initial branch_A change_a1 commit
| * 67941a1 mergable change in master
|/
* 36d7364 initial master commit

这表明,确实删除A对树没有影响。

这是脚本,其他人可能会发现它对测试 git 序列很有用:

#!/bin/bash

d=_test_`date +"%y%m%d%H%M"`
mkdir $d
cd $d
echo Testing in `pwd`

set -x  #echo on

# init and make master
git init
touch f
echo master1 >> f
git add .
git commit -a -m'initial master commit'

# make branch A
git checkout -b branch_A
echo change_a1 >> f
git commit -a -m'initial branch_A change_a1 commit'
echo change_a2 >> f
git commit -a -m'branch_A change_a2 commit'
cat f

# commit on master so we can see the branching structure
git checkout master
echo change_a1 >> f
echo change_a2 >> f
git commit -a -m'mergable change in master'

# make branch B
git checkout branch_A
git checkout -b branch_B
echo change_b1 >> f
git commit -a -m'initial branch_B change_b1 commit'
echo change_b2 >> f
git commit -a -m'branch_B change_b2 commit'

# commit on branch_A so we can see the branching structure
#git checkout branch_A
#echo change_a3 >> f
#git commit -a -m'another commit on a'

# Where's B on the tree?
git log --graph --oneline --branches

# merge branch A into master
git checkout master
git merge branch_A -m'merge branch_A into master'
cat f

# Where's B on the tree?
git log --graph --oneline --branches

# delete branch A
git branch -d branch_A

# Where's B on the tree?
git log --graph --oneline --branches