git-svn 克隆 | 伪分支

27

我使用了以下命令将 svn 仓库克隆到 git 中,执行完后发现一些无关的分支。

git svn clone [SVN 仓库 URL] --no-metadata -A authors-transform.txt --stdlayout ~/temp

git branch -a

*(no branch)
  master
  remotes/abc-1.3.x
  remotes/abc-1.3.x@113346
  remotes/abc-1.3.x@541512
  remotes/branch_test_script
  remotes/tags/modules-1.2
  remotes/tags/modules-1.2@113346
  remotes/tags/modules-1.2@516265
  remotes/tags/release-1.1
  remotes/tags/release-1.1@113346
  remotes/tags/release-1.1@468862
  remotes/trunk

实际在svn中创建的分支是abc,branch_test_script,modules和release。 有人能帮助理解'abc-1.3.x@113346','abc-1.3.x@541512' ... 'release-1.1@468862'等是什么吗?

如何摆脱这些虚假分支/它们表示什么?
谢谢, Gayathri


我很难找到这个命名的来源,但看起来这些分支是从 SVN 提交中创建的,这些提交被发现不再被它们最初所在的 svn 分支(或标签)引用。就像 Git 中未引用的提交一样,只不过可以恢复提交的分支名称。 - fork0
@fork0:感谢回复。但我不太明白未引用的提交如何存在于svn中。引用怎么会丢失?你能分享一下你的想法吗? - crankparty
我不知道。也许 SVN 存储库的维护者从未清理它们(或者 SVN 根本没有这个能力?)。我并不是说引用丢失了,而是有人从历史记录中较早的某个点开始提交。 - fork0
也许 SVN 中的提交列表总是生成所有提交的完整列表,无论它们是否被标签或分支引用。 - fork0
显示剩余2条评论
2个回答

22

tl;dr:

git svn创建这些 "@"-分支,如果为子目录(或由 git-svn 未跟踪的另一个目录)创建了分支(或标记)。还将始终存在具有相同名称但没有 "@" 后缀的“常规”分支。 "@"-分支仅作为常规分支的分支点存在。


注意:我已经为此提交了一个补丁; 这个解释的编辑版本现在是官方git svn手册的一部分,作为新的“SVN分支处理”部分(自Git 1.8.1起)。


在Subversion中,分支和标记只是目录树的副本,因此可以(虽然通常不建议)从不是分支(或主干)的目录创建分支。例如,通过将 /trunk/foo 复制到 /branches/bar,而不是复制 /trunk(所谓的“子目录分支”),或者复制位于 trunk/tags/branches 结构之外的目录(在 SVN 中可能会出现)。

但是,在 git 中,分支总是针对整个存储库,子目录分支不存在。因此,git svn使用一种解决方法。如果它检测到从未被 git-svn 跟踪为分支的目录复制的分支,它将创建一个新的历史记录。例如,对于 /trunk/foo 复制到 /branches/bar(在 r1234 中)的子目录分支,它会创建:

  • 每个 SVN 修订版本从 r1233 开始向后的新 git 提交(请注意,这个数字是创建分支之前的最后一个修订版本)。这些提交的树只包含被分支的子目录。因此,从 r1233 开始的每个修订版本通常都有两个 git 提交,一个使用整个树(当 git-svn 处理trunk的历史记录时创建),而另一个使用新的提交。
  • 名为 "bar@1233" 的虚拟分支(分支名称@修订版本),指向上面从 r1233 创建的提交。
  • 一个来自r1234的提交,创建了这个分支。这个提交将会作为该分支的(唯一)祖先。
  • 名为"bar"的分支,指向第二个提交。

这样,在子目录分支bar中,你将得到git中的两个分支:

  • bar@1233,代表创建该分支时仓库的状态
  • bar,代表该分支

我不太确定为什么要创建这个虚拟分支。我认为这是为了表示该分支从哪个版本开始分支,并且为该分支拥有完整的历史记录。


注意,通过使用标志--no-follow-parent可以关闭整个机制。在这种情况下,每个SVN分支都将产生一个只包含SVN分支目录中提交的git分支。每个分支都将与历史记录的其余部分无关,并且将具有自己的根提交,对应于分支中的第一个提交。


6
当我将我的SVN仓库克隆到Git仓库时,我也有这样奇怪命名的分支。
检查了预期的分支(在您的情况下是modules-1.2abc-1.3.xbranch_test_scriptrelease-1.1)后,我注意到@revisionnumber分支只是其前缀分支中的提交。
如果您想手动操作,请在abc-1.3.x分支上打开gitk,并验证 abc-1.3.x@113346abc-1.3.x@541512 是否出现在该分支的历史记录中。如果是,您可以删除相应的分支。
如果您有许多分支或许多提交要浏览,则可能会有点麻烦。
自动方式:请让git代劳:
git branch -r --contains abc-1.3.x@113346

将输出(至少应该)
abc-1.3.x
abc-1.3.x@113346
abc-1.3.x@541512

这意味着您可以安全地删除abc-1.3.x@113346,因为它包含在abc-1.3.x中。
git branch -r -d abc-1.3.x@113346

因为SVN具有线性历史记录,因此当然也包含(较新的)提交“541512”。
顺便提一下:
您可能已经注意到,您的SVN标签实际上没有被转换为Git标签和本地Git分支。可以使用svn2git将SVN存储库克隆到Git存储库中以实现该目的。

如何删除这些分支?是否有任何参数可以传递给 Git,以忽略此类提交并不创建分支? - crankparty
正如我所写的那样:可以使用 git branch -r -d <branchname> 删除分支。我认为没有一个标志可以实现不创建这些分支。 - eckes
1
git-svn 可能会不必要地创建这些 "@" 分支,但如果该分支在 subversion 中被删除,然后通过从另一个点复制重新创建,则会出现 abc@113346 不是 abc 祖先的重要情况。同样,abc@113346abc 的祖先并不意味着这没有发生过,它可能意味着 abc 被合入了主干,被删除(在高于 113346 的某个修订版本中)并且从主干上的新位置创建了一个新的替代品。 - Jan Hudec
换句话说,这个答案是错误的。"应该"并不正确。这取决于分支是否在删除之前合并。 - Jan Hudec

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