我能删除Git分支,但不删除分支reflogs吗?

3
有时我想通过删除所有本地创建的分支来清理我的个人git仓库。然而,在推送更改之前,我喜欢先进行变基。通过单独进行变基:
  1. 在向其他人推送之前,我可以清除提交历史记录
  2. 我仍然可以通过git reflog访问该分支的上一个提示
但是,如果我删除该分支,则也会删除reflog(从而失去对这些提交对象的访问)。有没有一种方法可以删除分支,但保留reflog?
目前,我通过在我的机器上创建名为backup的辅助仓库来解决问题,并在进行变基和任何其他“破坏性”的操作之前将其推送到那里。这样备份的reflog会保留所有活动记录。但如果可能的话,我宁愿将reflog保留在我的主要仓库中。

git reflog 不够吗? - Gomino
我重新措辞了问题,以符合我的最初意图。问题在于 git branch -d foobar 命令还会删除存储在 .git/logs 中的引用日志。 - Alexander Bird
3
提醒一下,分支的日志存储在.git/logs/refs/heads/<分支名>中。在删除该分支之前,您可以将其存储在其他地方,但不能直接从git中使用。尽管如此,它是可读的。 - Gary Fixler
1个回答

4
编辑:现在问题已经更清晰了,大部分回答都与此无关。简短的答案是“不行,至少目前还不行:当你删除分支时,引用日志也会被删除。”有一些建议改变这种情况,如果能够解决一些问题的话,在未来的版本中可以实现。(我认为这样做很好,因为你可以通过git branch --undelete foo或类似的方式把所有东西都恢复回来,从保存的引用日志中恢复。最大的问题纯粹是一个实现细节:如果你有一个分支x,然后删除它,再创建一个分支x/sub,那么被删除的分支的引用日志将占据名称x,必须成为一个目录。还有一个问题是创建分支x、删除分支x和再次创建分支x,而不使用某种--undelete拼写的含义是什么:这对旧的x引用日志有什么影响?)
起初我以为你指的是“删除分支但保留其引用日志”(对于这种情况,当前的答案是“不行”,当你删除分支时,引用日志也会被删除,尽管有一些建议可以改变这种情况,如果能够解决一些问题)。但现在我认为你的意思是,你有像这样的东西(从git log --oneline --graph --decorate输出):
* 9390606 (devel, origin/devel) latest tip
| * a45b0c4 (branch-X) some work, finished
| * a37b5ec some work, phase two
| * eef283e some work, phase one
|/  
* 1f0507b starting point

你需要将本地的 branch-X 分支变基到名称为 develorigin/devel 的分支的末尾,但同时保留原始分支 branch-X 的副本并使用其他名称存储。
这个操作很简单。先复制分支名称,然后进行变基操作:
$ git checkout branch-X
$ git branch branch-X-v1
$ git rebase -i devel     # with or without -i, really

假设在变基过程中,您将所有三个阶段合并并更改消息。这将为您提供:

* 3afbcac (branch-X) add feature X
* 9390606 (devel, origin/devel) latest tip
| * a45b0c4 (branch-X-v1) some work, finished
| * a37b5ec some work, phase two
| * eef283e some work, phase one
|/  
* 1f0507b starting point

另一件你可能想做的事情是“隐藏”标签branch-X-v1, 以便在正常视图中不会看到这些提交。有一种更容易的方法可以实现:不要复制标签,只需进行变基。
让我们暂停一下,描述一下git的标签机制。标签是人类可读的字符串,它们通过其大而丑陋的SHA-1(完整的SHA-1,而不仅仅是上面显示的7个字符的缩写)标识提交(或其他git对象)。
Git中的所有标记工作方式都相当相似:它们只是名称,主要位于类似目录的顶级名称refs/下。分支和标签分别位于refs/heads/refs/tags/中。1 分支和标签名字还有一些“特殊”的地方:具体来说,各种git命令(如git branchgit tag)会自动查找它们。分支更为特殊,因为git checkout将“连接”到一个分支上,然后git知道当新的提交在那里进行时自动推进分支引用,并移动rebase的标签等等。但是,对于标记一系列提交的尖端,例如三个some work,任何名称都可以。你需要的是替代名称。
幸运的是,git内置了一些持续“一段时间”的名称,但不会显示在git log --all输出中。这些是git的“reflogs”,您可以使用git refloggit reflog branch查看。您将看到类似于branch-X@{1}这样的名称,它跟踪rebasebranch-X指向的位置。
这里的缺点是这些名称是临时的2和相对的(branch-X@{1}变成branch-X@{2}{2}变成{3}等等,每次分支尖端移动时)。您还可以使用像@{yesterday}之类的形式,这可能有所帮助,但我更喜欢我的名称具有更加持久和稳定的特性。
您可以使用非分支名称。显而易见的是标签。不要将分支标签复制到另一个分支中,如branch-X-v1,而是将其复制到标签中:
git tag tag-X-v1

但是你可能会发现它们在视图中很混乱。

如果您想要,可以将其复制到标准名称空间之外的名称,但即使这些名称也会显示在--all输出中,该输出查看所有引用,而不仅仅是分支和标记。如果您的查看器——无论是您运行的git log还是gitk或其他GUI——使用--branches --tags --remotes而不是--all,那么这些“外部名称”将被隐藏,以及它们标记的提交。但是,您将不得不明确拼写它们,每次都使用refs/mine/或您放置它们的任何空间,并且您将不得不使用git update-ref来创建和删除它们。(当然,您可以将此放入脚本中:实际上,git update-ref用于脚本中。)

我个人偏好只使用额外的分支名称。随着我修订提交系列,我最终会得到X-v1X-v5或其他版本。


1“远程分支”位于refs/remotes/中。笔记(在git中有点新的东西)位于refs/notes/中。 filter-branch命令使用refs/original/。我认为这是一个完整的列表,至少在今天是这样,但很难确定。

2它们默认情况下会在30天后过期。有时它们会默认持续90天,但对于这种特殊情况并不是这样,因为先前的rebase分支端点无法从后续的rebase分支端点访问。


哇,非常感谢您的回答。我觉得我应该给自己的问题投反对票,因为我意识到我提出的问题非常不正确 :( (我现在已经编辑了问题)。我的问题实际上是如何在完全删除分支的同时保留reflog。然而,您确实回答了那个问题(无法完成),并且回答了我提出的问题。谢谢! - Alexander Bird
你是否了解有关邮件列表讨论添加在分支删除期间保留reflog功能的参考资料?如果不知道也没关系。 - Alexander Bird
它们可以在Gmane列表的某个地方找到。不确定确切的位置。 - torek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接