Git:删除当前分支并丢失了reflog

use*_*343 6 git macos version-control git-reflog

我之前遇到了一个不寻常的git问题,我已经解决了,但我仍然很好奇它为什么会发生.

当我意外删除了当前正在处理的分支时,问题就出现了.通常git不允许这样做,但是由于OSX上的大小写不敏感,我让自己进入了一种情况,我认为我有两个分支,一个命名feature/ONE,另一个命名feature/one.认为这是两个独立的分支(来自一个主要是linux /区分大小写的背景),我正在使用功能/ ONE我试图删除功能/一个使用git branch -D.

我很快注意到我做了什么,试图找回我丢失的作品git reflog,这给了我错误fatal: bad default revision 'HEAD'.我试图恢复正常状态使用git checkout -f develop,这是有效的.但是,当我看到git reflog这个之后不幸的是它只有一个条目说明checkout: moving from feature/ONE to develop.日志中没有出现先前的操作.

我已经编译了一些步骤来复制这种场景(可能只有在不区分大小写的文件系统上才有可能):

mkdir test
cd test
git init
echo 'hi' > file1
git add file1
git commit -m 'test commit 1'
git checkout -b new-branch
echo 'test2' > file2
git add file2
git commit -m 'test commit 2'
git branch -D NEW-branch
git checkout -f master
git reflog
Run Code Online (Sandbox Code Playgroud)

我已经通过检查找到了丢失的提交git-fsck,但我的问题是:

为什么这一系列动作会破坏reflog?难道reflog仍然不知道HEAD ref的历史,即使分支被删除了吗?

Ric*_*sen 5

在正常情况下,HEAD要么指向 SHA1(在这种情况下称为detached),要么指向现有分支引用(在这种情况下,命名分支被视为已检出)。

当您签出new-branchHEAD指向refs/heads/new-branch)然后以某种方式设法删除new-branch分支时,Git 只会删除分支的引用文件 ( .git/refs/heads/new-branch) 和分支的引用日志文件 ( .git/logs/refs/heads/new-branch)。混帐并没有删除HEAD,也没有更新指向其它地方(如该SHA1new-branch用于点),因为不应该有必要-你不应该能够删除当前分支。所以HEAD仍然引用现在删除的分支,这意味着HEAD不再指向有效的提交。

如果你这样做了git checkout -f master,Git 会更新HEAD为指向refs/heads/master,一个新条目被添加到HEAD的 reflog 文件 ( .git/logs/HEAD),文件被检出,并且索引被更新。所有这些都是正常的——这是当你检出另一个分支时 Git 总是这样做的。

您遇到的问题源于如何git reflog更新 reflog 文件以及如何处理更新的 reflog 文件。每个 reflog 条目都包含一个“from”和“to”SHA1。当您从不存在的new-branch分支切换到 时master,Git 不知道“来自”SHA1 是什么。它没有出错,而是使用全零的 SHA1 ( 0000000000000000000000000000000000000000)。创建 ref 时也使用全零 SHA1,因此这个最新的 reflog 条目使它看起来像是HEAD刚刚创建,而实际上它从未被删除。显然,git reflog即使有更多条目,瓷器命令在遇到全零 SHA1 时也会停止遍历 reflog,这就是为什么git reflog只打印一个条目。

下图说明了这一点:

$ git init test
Initialized empty Git repository in /home/example/test/.git/
$ cd test
$ echo hi >file1
$ git add file1
$ git commit -m "test commit 1"
[master (root-commit) 3c79ff8] test commit 1
 1 file changed, 1 insertion(+)
 create mode 100644 file1
$ git checkout -b new-branch
Switched to a new branch 'new-branch'
$ echo test2 >file2
$ git add file2
$ git commit -m "test commit 2"
[new-branch f828d50] test commit 2
 1 file changed, 1 insertion(+)
 create mode 100644 file2
$ cat .git/HEAD
ref: refs/heads/new-branch
$ cat .git/refs/heads/new-branch
f828d50ce633918f2fcaaaad5a52ac1ffa1c81b1
$ git update-ref -d refs/heads/new-branch
$ cat .git/HEAD
ref: refs/heads/new-branch
$ cat .git/refs/heads/new-branch
cat: .git/refs/heads/new-branch: No such file or directory
$ cat .git/logs/HEAD
0000000000000000000000000000000000000000 3c79ff8fc5a55d7c143765b7f749db4dd8526266 Your Name <email@example.com> 1411018898 -0400        commit (initial): test commit 1
3c79ff8fc5a55d7c143765b7f749db4dd8526266 3c79ff8fc5a55d7c143765b7f749db4dd8526266 Your Name <email@example.com> 1411018898 -0400        checkout: moving from master to new-branch
3c79ff8fc5a55d7c143765b7f749db4dd8526266 f828d50ce633918f2fcaaaad5a52ac1ffa1c81b1 Your Name <email@example.com> 1411018898 -0400        commit: test commit 2
$ git checkout -f master
Switched to branch 'master'
$ cat .git/logs/HEAD
0000000000000000000000000000000000000000 3c79ff8fc5a55d7c143765b7f749db4dd8526266 Your Name <email@example.com> 1411018898 -0400        commit (initial): test commit 1
3c79ff8fc5a55d7c143765b7f749db4dd8526266 3c79ff8fc5a55d7c143765b7f749db4dd8526266 Your Name <email@example.com> 1411018898 -0400        checkout: moving from master to new-branch
3c79ff8fc5a55d7c143765b7f749db4dd8526266 f828d50ce633918f2fcaaaad5a52ac1ffa1c81b1 Your Name <email@example.com> 1411018898 -0400        commit: test commit 2
0000000000000000000000000000000000000000 3c79ff8fc5a55d7c143765b7f749db4dd8526266 Your Name <email@example.com> 1411018898 -0400        checkout: moving from new-branch to master
$ git reflog
3c79ff8 HEAD@{0}: checkout: moving from new-branch to master
Run Code Online (Sandbox Code Playgroud)

如您所见,HEAD的 reflog 仍然包含所有旧条目 - 它们只是没有由 显示git reflog。我认为这是 Git 中的一个错误。

旁注:当您删除一个引用时,相应的日志也会被删除。我认为这是一个错误,因为除非您有日志备份,否则无法完全撤消意外的 ref 删除。