我可以删除git branch,但不能删除分支reflogs吗?

时间:2014-02-18 15:49:19

标签: git branch git-branch git-log

有时我想通过删除所有本地制作的分支来清理我的个人git仓库。但是,我喜欢在推动变革之前进行重组。凭借自身的变化:

  1. 我在推送给其他人之前清理了提交历史记录
  2. 我仍然可以通过git reflog
  3. 访问分支的上一个提示

    但是如果我删除了分支,我也会删除reflog(因此无法访问这些提交对象)。有没有办法删除分支,但保留reflog?

    目前,我通过在我的机器上创建一个名为backup的辅助仓库解决了这个问题,然后在重新定位和任何其他“破坏性”操作之前将其推送到那里。这样备份的reflog保留所有活动。但是如果可能的话,我宁愿将reflog保存在我的主仓库中。

1 个答案:

答案 0 :(得分:2)

编辑:既然编辑了这个问题以澄清它,那么大部分答案都是无关紧要的。短版本是“不,至少还没有:删除分支时删除reflogs”。如果某些问题可以解决,有一些建议可以在未来的git版本中对此进行更改。 (我认为这样会很好,因为你可以做git branch --undelete foo,或者他们决定拼写它,然后把所有东西都归还,全部从保存的reflog中恢复。最大的问题纯粹是一个实现细节:if你有一个分支x并删除它然后创建一个分支x/sub,删除分支的reflog将占用必须成为目录的名称x。还有一个问题是什么它意味着创建分支x,删除分支x,并再次创建分支x而不使用某种--undelete拼写:这对旧{{1}做了什么reflog?)


起初我认为你的意思是“删除一个分支但保留其reflog”(答案当前为“no”,删除分支时reflogs会被删除,尽管有一些建议要改变这个,如果有些问题可以解决。但现在我认为你的意思是,你有这样的东西(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-Xdevel,同时还保留原始分支origin/devel,其他一些名字。

这很容易做到。复制分支标签,然后重新定义:

branch-X

让我们说在rebase中你将所有三个阶段结合起来并改变信息。这给你:

$ 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 ,而不是在普通视图中看到这些提交。有一种方法可以做到这一点,甚至更容易:复制标签,只需进行rebase。

让我们暂停一下,然后描述一下git的标签机制。标签是人类可读的字符串,通过其丑陋的SHA-1(完整的SHA-1,而不仅仅是上面显示的7个字符的缩写)来标识提交(或其他git对象)。

git中的所有标签都非常相似:它们只是名称,主要位于类似顶级目录的名称branch-X-v1下。分支和标签分别位于refs/refs/heads/ 1 关于分支和标记名称还有一些其他“特殊”的东西:具体来说,各种git命令(如{{ 1}}和refs/tags/)自动查找它们。分支更加特殊,因为git branch将“on”一个,然后git知道在那里进行新的提交时自动推进分支引用,并在git tag上移动标签,等等上。但是为了标记一系列提交的提示,例如三个git checkout提交,任何名称都可以。你需要的是另一个名字。

幸运的是,有一些内置于git的名称可以持续“一段时间”,但不会显示在rebase输出中。这些是git的“reflogs”,您可以使用some workgit log --all查看这些内容。您会看到git reflog等名称,用于跟踪git reflog branch之前branch-X@{1}所指向的位置。

这里的缺点是这些名称是临时的 2 且相对(branch-X变为rebasebranch-X@{1}变为branch-X@{2},依此类推,每次分支尖端移动)。您也可以使用像{2}这样的表格,这可以提供帮助,但我希望自己的名字更加永久和稳定。

您可以使用非分支名称。显而易见的是标签。而不是将分支标签复制到另一个分支,如{3},而是将其复制到标记:

@{yesterday}

但你也可能会发现这些问题也很混乱。

如果您愿意,可以将其复制到标准名称空间之外的名称,但即使是那些也会显示在branch-X-v1输出中,它会查看所有引用,而不仅仅是分支和标签。如果您的观看者 - 无论是您正在运行git tag tag-X-v1 ,还是--all或其他GUI使用git log而不是gitk,那么这些“外部名称”将被隐藏,以及他们标记的提交。但是你必须每次使用--branches --tags --remotes或你放入它们的任何空间明确拼写它们;并且您必须使用--all来创建和删除它们。 (你当然可以将它放在一个脚本中:事实上,refs/mine/适用于脚本。)

我个人的偏好就是使用额外的分支名称。当我修改提交系列时,我结束了git update-refgit update-ref或其他什么。


1 “远程分支”位于X-v1。 Notes,有点像git的新东西,住在X-v5refs/remotes/命令使用refs/notes/。我认为这是一个完整的清单,至少在今天,但很难确定。

2 默认情况下,它们会在30天后过期。有时它们默认持续90天,但不适用于这种特殊情况,因为无法从rebase后的分支尖端访问pre-rebase branch-tip。