删除 Git 中的分支时究竟发生了什么
What precisely happens when deleting a branch in Git
我一直在寻找这个问题的答案,但我仍然不完全确定它的答案。
我发现的大多数关于删除分支的信息只不过是手册内容的副本(例如 )。
我认为一个核心问题是我不知道 Git 中的分支到底是什么(尽管有很多文章声称可以对此进行解释)。
我发现的唯一有用的信息是 this SO answer 和随 git.
安装的文档
我的问题:
当我运行git branch -d BRANCH_NAME
,
- 引擎盖下发生了什么?
- 外部发生了什么变化,即我与存储库的交互如何变化?
- 这些变化中的任何一个都可以被认为是历史上的变化吗?
以及 git branch -D BRANCH_NAME
的相同子问题。
我目前的理解:
首先我对一个分支的认知:
根据上下文,术语分支指的是指向某个提交(严格称为分支头)的指针,或者指向该提交的提交列表
我认为 git branch -d BRANCH_NAME
:
会发生什么(但我很不确定)
- 指向分支头的指针被移除,不再存在
- 我在任何列表中都看不到分支了,我不能再切换到它或从它分支(尽管我想我可以在那个提交时创建一个新分支,以有效地实现这些事情)
- 可能不是:提交仍然存在,只是不再标记分支名称?
我认为发生了什么,git branch -D BRANCH_NAME
:
- 指向分支头的指针被删除,所有不在其他分支上的提交也被删除
- 我无法再在任何列表中看到该分支,我无法再切换到它或从它分支,也无法以任何方式检索代码
- 是:分支中的提交丢失
删除分支后提交仍然存在,直到下一次垃圾收集。 git branch -d
(和-D
)打印缩写的提交哈希,你可以将它用作git log
或git checkout
或git branch
的参数,这给了你可能性恢复删除的分支。
-d
和 -D
之间的唯一区别是 git branch -d
不会让您删除未合并的分支(即可能丢失提交)。
无论您是使用 git branch -d
还是 git branch -D
删除,git 都不会删除提交,只会删除分支引用。继续阅读以了解这意味着什么。
首先,我们将设置一个简单的演示历史记录。
$ touch initial ; git add initial ; git commit -m 'Initial commit'
[master (root-commit) 2182bb2] Initial commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 initial
$ git checkout -b mybranch
Switched to a new branch 'mybranch'
此时,master
和mybranch
都指向同一个
提交,我们至少可以通过两种方式验证。
$ git lola
* 2182bb2 (HEAD -> mybranch, master) Initial commit
请注意 git lola
是一个 non-standard 但非常有用的别名,
相当于
$ git log --graph --decorate --pretty=oneline --abbrev-commit --all
* 2182bb2 (HEAD -> mybranch, master) Initial commit
我们将在 mybranch
上创建新提交后查看另一种方式。
$ touch mybranch ; git add mybranch ; git commit -m 'My branch'
[mybranch 7143aa4] My branch
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 mybranch
这样做之后,我们确实在多个分支上进行了多次提交。
$ git lola
* 7143aa4 (HEAD -> mybranch) My branch
* 2182bb2 (master) Initial commit
我们现在可以一窥 git 如何在幕后实现这一点。
$ ls -R .git/refs
.git/refs:
heads tags
.git/refs/heads:
master mybranch
.git/refs/tags:
很好奇有些文件与我们的分支同名。
往里面看,我们看到
$ cat .git/refs/heads/master .git/refs/heads/mybranch
2182bb2d5a0a7f57d0b74e95d37e208dac41f95b
7143aa477735382e7a0ed11c9e4b66c1f27583df
因此 git 将 refs 实现为名称匹配的特定位置的文件
包含 SHA1 的分支名称
某些提交的哈希值。观察 git lola
(2182bb2
) 输出中的缩写散列是上面 cat
输出的前导前缀。
将 git refs 视为简单的指针,为存储库历史记录中的特定提交提供人类可读的名称。
现在,如果我们切换回 master
并 zap mybranch
$ git checkout master ; git branch -D mybranch
Switched to branch 'master'
Deleted branch mybranch (was 7143aa4).
我们看到裁判不见了
$ ls -R .git/refs
.git/refs:
heads tags
.git/refs/heads:
master
.git/refs/tags:
但提交仍然存在。
$ git show --pretty=oneline 7143aa4
7143aa477735382e7a0ed11c9e4b66c1f27583df My branch
diff --git a/mybranch b/mybranch
new file mode 100644
index 0000000..e69de29
如果你想mybranch
回来,你只需要运行
$ git checkout -b mybranch 7143aa4
Switched to a new branch 'mybranch'
或
$ git branch mybranch 7143aa4
取决于,正如它们各自输出的差异所表明的,
是否要切换到分支。在后一种情况下,
你在当前分店停留的位置,git lola
看起来像
$ git lola
* 7143aa4 (mybranch) My branch
* 2182bb2 (HEAD -> master) Initial commit
是的,您的提交会在 短时间内挂起 即使在您删除了使它们保持活动状态的指针之后也是如此。这在意外删除的情况下非常有用。另见 git reflog
and git gc
.
请注意,您存储库中的 SHA1 哈希会有所不同
因为您的姓名和电子邮件地址至少会有所不同
从我使用的。
为了完整起见,-d
和 -D
之间的区别是小写版本稍微安全一些。
-d
--delete
Delete a branch. The branch must be fully merged in its upstream branch, or in HEAD
if no upstream was set with --track
or --set-upstream
.
-D
Shortcut for --delete --force
.
-f
--force
Reset branchname to startpoint if branchname exists already. Without -f
git branch refuses to change an existing branch. In combination with -d
(or --delete
), allow deleting the branch irrespective of its merged status …
我一直在寻找这个问题的答案,但我仍然不完全确定它的答案。
我发现的大多数关于删除分支的信息只不过是手册内容的副本(例如
我的问题:
当我运行git branch -d BRANCH_NAME
,
- 引擎盖下发生了什么?
- 外部发生了什么变化,即我与存储库的交互如何变化?
- 这些变化中的任何一个都可以被认为是历史上的变化吗?
以及 git branch -D BRANCH_NAME
的相同子问题。
我目前的理解:
首先我对一个分支的认知: 根据上下文,术语分支指的是指向某个提交(严格称为分支头)的指针,或者指向该提交的提交列表
我认为 git branch -d BRANCH_NAME
:
- 指向分支头的指针被移除,不再存在
- 我在任何列表中都看不到分支了,我不能再切换到它或从它分支(尽管我想我可以在那个提交时创建一个新分支,以有效地实现这些事情)
- 可能不是:提交仍然存在,只是不再标记分支名称?
我认为发生了什么,git branch -D BRANCH_NAME
:
- 指向分支头的指针被删除,所有不在其他分支上的提交也被删除
- 我无法再在任何列表中看到该分支,我无法再切换到它或从它分支,也无法以任何方式检索代码
- 是:分支中的提交丢失
删除分支后提交仍然存在,直到下一次垃圾收集。 git branch -d
(和-D
)打印缩写的提交哈希,你可以将它用作git log
或git checkout
或git branch
的参数,这给了你可能性恢复删除的分支。
-d
和 -D
之间的唯一区别是 git branch -d
不会让您删除未合并的分支(即可能丢失提交)。
无论您是使用 git branch -d
还是 git branch -D
删除,git 都不会删除提交,只会删除分支引用。继续阅读以了解这意味着什么。
首先,我们将设置一个简单的演示历史记录。
$ touch initial ; git add initial ; git commit -m 'Initial commit'
[master (root-commit) 2182bb2] Initial commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 initial
$ git checkout -b mybranch
Switched to a new branch 'mybranch'
此时,master
和mybranch
都指向同一个
提交,我们至少可以通过两种方式验证。
$ git lola
* 2182bb2 (HEAD -> mybranch, master) Initial commit
请注意 git lola
是一个 non-standard 但非常有用的别名,
相当于
$ git log --graph --decorate --pretty=oneline --abbrev-commit --all
* 2182bb2 (HEAD -> mybranch, master) Initial commit
我们将在 mybranch
上创建新提交后查看另一种方式。
$ touch mybranch ; git add mybranch ; git commit -m 'My branch'
[mybranch 7143aa4] My branch
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 mybranch
这样做之后,我们确实在多个分支上进行了多次提交。
$ git lola
* 7143aa4 (HEAD -> mybranch) My branch
* 2182bb2 (master) Initial commit
我们现在可以一窥 git 如何在幕后实现这一点。
$ ls -R .git/refs
.git/refs:
heads tags
.git/refs/heads:
master mybranch
.git/refs/tags:
很好奇有些文件与我们的分支同名。 往里面看,我们看到
$ cat .git/refs/heads/master .git/refs/heads/mybranch
2182bb2d5a0a7f57d0b74e95d37e208dac41f95b
7143aa477735382e7a0ed11c9e4b66c1f27583df
因此 git 将 refs 实现为名称匹配的特定位置的文件
包含 SHA1 的分支名称
某些提交的哈希值。观察 git lola
(2182bb2
) 输出中的缩写散列是上面 cat
输出的前导前缀。
将 git refs 视为简单的指针,为存储库历史记录中的特定提交提供人类可读的名称。
现在,如果我们切换回 master
并 zap mybranch
$ git checkout master ; git branch -D mybranch
Switched to branch 'master'
Deleted branch mybranch (was 7143aa4).
我们看到裁判不见了
$ ls -R .git/refs
.git/refs:
heads tags
.git/refs/heads:
master
.git/refs/tags:
但提交仍然存在。
$ git show --pretty=oneline 7143aa4
7143aa477735382e7a0ed11c9e4b66c1f27583df My branch
diff --git a/mybranch b/mybranch
new file mode 100644
index 0000000..e69de29
如果你想mybranch
回来,你只需要运行
$ git checkout -b mybranch 7143aa4
Switched to a new branch 'mybranch'
或
$ git branch mybranch 7143aa4
取决于,正如它们各自输出的差异所表明的,
是否要切换到分支。在后一种情况下,
你在当前分店停留的位置,git lola
看起来像
$ git lola
* 7143aa4 (mybranch) My branch
* 2182bb2 (HEAD -> master) Initial commit
是的,您的提交会在 短时间内挂起 即使在您删除了使它们保持活动状态的指针之后也是如此。这在意外删除的情况下非常有用。另见 git reflog
and git gc
.
请注意,您存储库中的 SHA1 哈希会有所不同 因为您的姓名和电子邮件地址至少会有所不同 从我使用的。
为了完整起见,-d
和 -D
之间的区别是小写版本稍微安全一些。
-d
--delete
Delete a branch. The branch must be fully merged in its upstream branch, or in
HEAD
if no upstream was set with--track
or--set-upstream
.
-D
Shortcut for
--delete --force
.
-f
--force
Reset branchname to startpoint if branchname exists already. Without
-f
git branch refuses to change an existing branch. In combination with-d
(or--delete
), allow deleting the branch irrespective of its merged status …