在Git中删除分支时会发生什么

Oeb*_*ele 7 git branch git-branch

我一直在寻找这个问题的答案,但我仍然不完全确定它的答案.我发现的关于删除分支的大多数信息只不过是手册所说的副本(例如,在SO上).我认为一个核心问题是我不确切知道Git中的一个分支是什么(即使有许多文章声称要解释这一点).我找到的唯一有用的信息是在这个SO答案和使用git安装的文档.

我的问题:

当我运行git branch -d BRANCH_NAME,

  1. 引擎盖下发生了什么?
  2. 什么是外部变化,即我与存储库的交互如何变化?
  3. 任何这些变化都可以被视为历史的变化吗?

另外还有相同的子问题git branch -D BRANCH_NAME.

我目前的理解:

首先我对分支的看法:取决于上下文,术语分支指的是指向某个提交的指针(严格称为分支头),或者指向那个提交的提交列表

我认为发生了什么(但我很不确定),因为git branch -d BRANCH_NAME:

  1. 删除了指向分支头的指针,而不是更多
  2. 我再也看不到任何列表中的分支了,我不能再切换到它或从它分支了(虽然我想我可以在该提交中创建一个新的分支,以有效地实现这些功能)
  3. 可能不是:提交仍然存在,它们只是没有标记分支的名称?

我认为发生了什么,因为git branch -D BRANCH_NAME:

  1. 删除了指向分支头的指针,并删除了不在其他分支上的任何提交
  2. 我再也看不到任何列表中的分支了,我不能再切换到它或从中分支,或以任何方式检索代码
  3. 是的:分支中的提交丢失了

Gre*_*con 5

无论你是否删除git branch -dor git branch -D,git都不会删除提交而只删除分支ref.继续阅读,看看这意味着什么.

首先,我们将设置一个简单的演示历史记录.

$ 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'
Run Code Online (Sandbox Code Playgroud)

在这一点上,两者mastermybranch都指向同一个commit,我们可以验证至少有两种方法.

$ git lola
* 2182bb2 (HEAD -> mybranch, master) Initial commit
Run Code Online (Sandbox Code Playgroud)

请注意,这git lola是一个非标准但非常有用的别名,相当于

$ git log --graph --decorate --pretty=oneline --abbrev-commit --all
* 2182bb2 (HEAD -> mybranch, master) Initial commit
Run Code Online (Sandbox Code Playgroud)

我们将在创建新提交后查看另一种方式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
Run Code Online (Sandbox Code Playgroud)

执行此操作后,我们确实在多个分支上有多个提交.

$ git lola
* 7143aa4 (HEAD -> mybranch) My branch
* 2182bb2 (master) Initial commit
Run Code Online (Sandbox Code Playgroud)

我们现在可以看看git如何在引擎盖下实现这一点.

$ ls -R .git/refs
.git/refs:
heads  tags

.git/refs/heads:
master  mybranch

.git/refs/tags:
Run Code Online (Sandbox Code Playgroud)

很奇怪有些文件与我们的分支名称相同.我们看到他们在里面看

$ cat .git/refs/heads/master .git/refs/heads/mybranch
2182bb2d5a0a7f57d0b74e95d37e208dac41f95b
2182bb2d5a0a7f57d0b74e95d37e208dac41f95b
Run Code Online (Sandbox Code Playgroud)

所以git将refs实现为某个位置的文件,这些位置的名称与分支名称匹配,并且包含某些提交的SHA1哈希值.注意git lola(2182bb2)输出中的缩写哈希是cat上面输出的前导前缀.

将git refs视为简单的指针,为存储库历史记录中的特定提交提供人类可读的名称.

现在,如果我们切换回master和zapmybranch

$ git checkout master ; git branch -D mybranch
Switched to branch 'master'
Deleted branch mybranch (was 7143aa4).
Run Code Online (Sandbox Code Playgroud)

我们看到裁判已经消失了

$ ls -R .git/refs
.git/refs:
heads  tags

.git/refs/heads:
master

.git/refs/tags:
Run Code Online (Sandbox Code Playgroud)

但提交仍在那里.

$ git show --pretty=oneline 7143aa4
7143aa477735382e7a0ed11c9e4b66c1f27583df My branch
diff --git a/mybranch b/mybranch
new file mode 100644
index 0000000..e69de29
Run Code Online (Sandbox Code Playgroud)

如果你想要mybranch回来,你只需要跑步

$ git checkout -b mybranch 7143aa4
Switched to a new branch 'mybranch'
Run Code Online (Sandbox Code Playgroud)

要么

$ git branch mybranch 7143aa4
Run Code Online (Sandbox Code Playgroud)

取决于,它们各自输出的差异表示您是否要切换到分支.在后一种情况下,你留在当前分支上,git lola看起来像

$ git lola
* 7143aa4 (mybranch) My branch
* 2182bb2 (HEAD -> master) Initial commit
Run Code Online (Sandbox Code Playgroud)

是的,即使您删除了使它们保持活动状态的指针,您的提交也会暂停一段时间.这在意外删除的情况下非常有用.另见git refloggit gc.


请注意,您的存储库中的SHA1哈希值会有所不同,因为您的姓名和电子邮件地址至少会与我使用的不同.

为了完整起见,之间的差异-d,并-D为小写版本稍微更安全.

-d
--delete

删除分支.分支必须在其上游分支中完全合并,或者HEAD如果没有上游设置为--track或者--set-upstream.

-D

快捷方式--delete --force.

-f
--force

如果存在branchname,则将branchname重置为startpoint.没有git branch拒绝更改现有分支.与(或)结合使用,允许删除分支,而不管其合并状态如何......-f-d--delete

  • 我无法给出比花一小时探索所有文件夹并打开 .git 目录中的所有文件以轻松了解其工作原理更好的建议。这真的很简单而且做得很好。要探索“objects”子目录,请使用“git cat-file -p”,后跟 sha1。它对于日常使用确实有助于理解 git 的工作原理...... (2认同)