编辑:现在问题已经更清晰了,大部分回答都与此无关。简短的答案是“不行,至少目前还不行:当你删除分支时,引用日志也会被删除。”有一些建议改变这种情况,如果能够解决一些问题的话,在未来的版本中可以实现。(我认为这样做很好,因为你可以通过
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
分支变基到名称为
devel
和
origin/devel
的分支的末尾,但同时保留原始分支
branch-X
的副本并使用其他名称存储。
这个操作很简单。先复制分支名称,然后进行变基操作:
$ git checkout branch-X
$ git branch branch-X-v1
$ git rebase -i devel
假设在变基过程中,您将所有三个阶段合并并更改消息。这将为您提供:
* 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 branch
和
git tag
)会自动查找它们。分支更为特殊,因为
git checkout
将“连接”到一个分支上,然后git知道当新的提交在那里进行时自动推进分支引用,并移动
rebase
的标签等等。但是,对于标记一系列提交的尖端,例如三个
some work
,任何名称都可以。你需要的是替代名称。
幸运的是,git内置了一些持续“一段时间”的名称,但不会显示在
git log --all
输出中。这些是git的“reflogs”,您可以使用
git reflog
和
git reflog branch
查看。您将看到类似于
branch-X@{1}
这样的名称,它跟踪
rebase
前
branch-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-v1
到X-v5
或其他版本。
1“远程分支”位于refs/remotes/
中。笔记(在git中有点新的东西)位于refs/notes/
中。 filter-branch
命令使用refs/original/
。我认为这是一个完整的列表,至少在今天是这样,但很难确定。
2它们默认情况下会在30天后过期。有时它们会默认持续90天,但对于这种特殊情况并不是这样,因为先前的rebase分支端点无法从后续的rebase分支端点访问。
git reflog
不够吗? - Gominogit branch -d foobar
命令还会删除存储在.git/logs
中的引用日志。 - Alexander Bird.git/logs/refs/heads/<分支名>
中。在删除该分支之前,您可以将其存储在其他地方,但不能直接从git中使用。尽管如此,它是可读的。 - Gary Fixler