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

标签 macos git version-control git-reflog

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

问题发生在我不小心删除了我当前正在处理的分支时。通常 git 不允许这样做,但是由于 OSX 不区分大小写,我陷入了一种情况,我认为我有两个分支,一个名为 feature/ONE 另一个名为 feature/一个。认为这是两个独立的分支(主要来自 linux/case-sensitive 背景)并且我正在处理功能/ONE 我试图使用 git branch -D 删除功能/one。

我很快注意到我做了什么,试图从 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 引用的历史,即使分支已被删除?

最佳答案

在正常情况下,HEAD 要么指向 SHA1(在这种情况下它被称为分离的),要么指向一个现有的分支引用(在这种情况下命名分支被视为已 checkout )。

当您 checkout new-branch(HEAD 指向 refs/heads/new-branch)然后设法删除new-branch 分支,Git 只是删除分支的ref 文件(.git/refs/heads/new-branch)和分支的reflog 文件(.git/日志/refs/heads/new-branch)。 Git 不会删除HEAD,也不会更新它以指向其他地方(例如 new-branch 曾经指向的 SHA1) , 因为应该没有必要——你不应该能够删除当前分支。所以 HEAD 仍然引用现在删除的分支,这意味着 HEAD 不再指向有效的提交。

如果您随后执行 git checkout -f master,Git 会更新 HEAD 以指向 refs/heads/master,一个新条目是添加到 HEAD 的 reflog 文件 (.git/logs/HEAD),文件被 check out ,索引被更新。所有这一切都是正常的——这就是 Git 在您 check out 另一个分支时总是做的事情。

您遇到的问题源于 reflog 文件的更新方式以及 git 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

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

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

关于macos - Git:删除当前分支并丢失 reflog,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25898078/

相关文章:

svn - 分配代码(提交)主版本号

ios - 即使 macOS 应用程序已使用开发者 ID 签名,Safari 也会要求允许未签名的扩展

git - 使用 Git 特性分支工作流,什么时候更新 master 分支?

postgresql - Docker 错误 - 5432 : bind: address already in use

git - `git diff HEAD^` 的反义词是什么?

linux - 从 BitBucket pull 到服务器使文件组权限为 0 0

xcode - 你将如何避免 "Xcode, Subversion Error: 155007 (Path is not a working copy directory)"?

git - ISO 一个版本控制工具,可以管理不在标记为由 VC 工具管理的目录树下的文件

objective-c - 如何在 Objective C 中隐藏 Mac OS X 菜单栏

python - 找不到满足 hdf5 要求的版本(来自版本 : ) No matching distribution found for hdf5