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

时间:2014-09-17 18:44:32

标签: macos git version-control git-reflog

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

当我意外删除了当前正在处理的分支时出现了问题。通常git不允许这样做,但是由于OSX上的大小写不敏感,我让自己陷入了一种情况,我认为我有两个分支,一个名为feature/ONE,另一个名为feature/one。认为这些是两个独立的分支(来自一个主要是linux /区分大小写的背景),我正在使用feature / 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

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

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

2 个答案:

答案 0 :(得分:4)

在正常情况下,HEAD或者指向SHA1(在这种情况下,它被称为分离)或者它指向现有的分支引用(在这种情况下,命名为分支被认为是签出的。)

当您查看new-branchHEAD指向refs/heads/new-branch)然后以某种方式设法删除new-branch分支时,Git只会删除分支的参考号文件(.git/refs/heads/new-branch)和分支的reflog文件(.git/logs/refs/heads/new-branch)。 Git会删除HEAD,也不会将其更新为指向其他位置(例如new-branch过去指向的SHA1),因为不应该这样做是一个需要 - 你不应该能够删除当前分支。因此HEAD仍然引用现在已删除的分支,这意味着HEAD不再指向有效的提交。

如果您执行git checkout -f master,Git将HEAD更新为指向refs/heads/master,则会在HEAD的reflog文件中添加一个新条目({{ 1}}),检出文件,并更新索引。所有这一切都很正常 - 这就是Git在您查看另一个分支时总是会做的事情。

您遇到的问题源于reflog文件的更新方式以及.git/logs/HEAD如何处理更新的reflog文件。每个reflog条目都包含一个" from"和"到" SHA1。当您从不存在的git reflog分支切换到new-branch时,Git不知道"来自"来自" SHA1是。它使用全零SHA1(master)而不是错误输出。创建ref时也会使用全零SHA1,因此这个最新的reflog条目使其看起来像0000000000000000000000000000000000000000刚创建,实际上它从未被删除过。显然,即使有更多条目,HEAD瓷器命令在遇到全零SHA1时停止遍历reflog,这就是为什么git 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 的reflog仍然包含所有旧条目 - 它们只是HEAD未显示。我认为这是Git中的一个错误。

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

答案 1 :(得分:1)

  

删除当前分支并丢失了reflog

两年后,这个问题应该在Git 2.13(2017年第二季度)中得到缓解。

commit 39ee4c6commit 893dbf5commit de92266commit 755b49aKyle Meyer (kyleam)(2017年2月21日){。}}。
Junio C Hamano -- gitster --于2017年2月27日commit c13c783合并)

  

branch:在HEAD的日志中记录创建重命名的分支

     

重命名当前分支会将事件添加到当前分支的日志中   和HEAD的日志。
  但是,记录的条目不同   分支的日志中的条目表示整个重命名操作(旧的和新的哈希是相同的),而HEAD的日志中的条目表示   仅删除(新sha1为空)。

     

扩展replace_each_worktree_head_symref(),其唯一来电者是   branch_rename(),以获取reflog消息参数   这允许创建新的引用记录在HEAD的日志中   因此,重命名事件由HEAD&#39>的日志中的两个条目(删除和创建条目)表示。

     

有点不幸的是,分支机构的日志和HEAD的日志现在以不同的方式表示重命名事件。
  鉴于重命名操作不是原子操作,两个表单形式更多   准确地表示操作,如果在删除和创建事件之间发生故障,则对于调试目的更有用

     

将分支的日志移动到双条目形式是有意义的,但这将涉及更改重命名的执行方式以及更新标志和reflog如何处理删除,因此可能不值得努力。