Git-SVN:重置主分支的跟踪

28

我正在使用 git-svn 与 SVN 存储库一起工作。我的工作副本是使用 git svn clone -s http://foo.bar/myproject 创建的,以便我的工作副本遵循 SVN 的默认目录结构 (trunk、tags、branches)。

最近我正在一个分支上工作,该分支是使用 git-svn branch myremotebranch 创建的,并使用 git checkout --track -b mybranch myremotebranch 进行了检出。由于需要从多个位置工作,因此我在分支上经常使用 git-svn dcommit 将文件提交到 SVN 存储库。

完成更改后,我切换回主分支并执行了合并,提交了合并,并尝试将成功合并的内容提交到远程主干。

似乎在合并后,主分支的远程跟踪已经切换到我正在工作的分支上:

# git checkout master
# git merge mybranch
... (successful)
# git add .
# git commit -m '...'
# git svn dcommit
Committing to http://foo.bar/myproject/branches/myremotebranch ...
#

有没有一种方法可以使主分支更新后像合并前一样跟踪 remotes/trunk?

我正在使用 git 1.7.0.5,如果这有帮助的话。

如果您能解释一下为什么会发生这种情况,那就太好了,这样我就可以避免再次出现这个问题。谢谢!

编辑:

这是我的当前 .git/config 文件:

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    autocrlf = false
[svn-remote "svn"]
    url = http://foo.bar/myproject
    fetch = trunk:refs/remotes/trunk
    branches = branches/*:refs/remotes/*
    tags = tags/*:refs/remotes/tags/*
[branch "mybranch"]
    remote = .
    merge = refs/remotes/myremotebranch

看起来主干指向了正确的位置。然而,切换到分支后再回到主干没有帮助; 在主干上使用 git svn dcommit 仍然试图推送到 myremotebranch

6个回答

22

如果主干没有更改,Git会执行快进合并,并将本地的“master”分支设置为分支上的提交。但是,Git-svn不知道如何将快进合并提交回主干,实际上它认为“master”现在指向svn分支。

为了解决这个问题,在合并时使用git merge --no-ff。这将强制Git创建一个合并提交,然后可以将其提交到svn。


澄清一下,如果我理解正确的话,git使用“master”指针所在的提交来决定要提交到哪个SVN分支。这就是为什么SVN dcommit步骤会失败的原因,因为在完成合并后,“mybranch”和“master”都指向同一个提交。该提交最初是从“myremotebranch” SVN分支创建的。 - cmcginty
2
我认为创建一个新的合并提交并不能帮助澄清问题,因为当它传播到svn存储库时,合并信息将会丢失。 - Walter Mundt
1
@Walter:是的,合并信息不会被提交(尽管您可以将其保留在git存储库中)。但是如果没有新的合并提交,就没有任何可以提交到SVN的内容 - dcommit最终什么也不会做(这是OP的问题所在)。 - Daniel

13
如果你在切换回主分支后使用git svn rebase并使用--squash,就可以避免这种情况。
# git checkout master
# git svn rebase   //(<--the missing step)
# git merge --squash mybranch // (<-- doesn't commit, more like an svn merge would do)
... (successful)
# git add . 
# git commit -m '...' 
# git svn dcommit
Committing to http://foo.bar/myproject/trunk...
#

解决当前状态(即您的主分支指向一个 SVN 分支)的方法:

您可以“切换”到另一个分支,删除主分支,再次“切换”回来,然后再合并即可:

# git checkout mybranch
# git branch -D master
# git checkout -b master trunk
... continue with merge...
# git merge --squash mybranch

现在你的分支已经合并到主干(master)上,可以进行commit操作,然后将代码dcommittrunk分支。


1
非常感谢您的解释,包括“解决当前状态”的部分。我也遇到了同样的问题,这个方法非常有效地解决了它。 - sockmonk
2
我认为 git checkout -b master trunk 不正确。应该是 git checkout -b master remotes/git-svn - janos
如果你想要在一个名为“git-svn”的SVN分支上工作(即合并到该分支),那么这个说法是正确的。但是,如果你想要合并到主干(trunk),而且你的SVN仓库是“标准”的(例如,在同一目录下有/branches /tags /trunk),那么git checkout -b master trunk绝对是正确的。 - dyodji

5
如果您在主分支上没有进行任何提交,那么这意味着git merge mybranch是一个快进合并: master HEAD 直接移动到 mybranch HEAD。这可能解释了为什么 git svn dcommit 将您的更改推送到了 SVN mybranch。它会:首先将相应的 SVN 分支更新为尚未 dcommit 的最后一个 Git mybranch 提交,然后在 SVN 端记录合并到主干,最后在 Git 端将主分支变基(无需操作,已经在那里)。
我不认为主分支没有改变其引用,但如果您有疑问(且您的工作目录干净),则可以(如果当前已检出主分支):
git reset --hard remotes/trunk

似乎重置、更改主分支上的某些内容、执行 dcommit,然后重新合并以产生冲突,解决该冲突,最后再次执行 dcommit 可以解决这个问题。但这并不是一种愉快的体验。 - Phillip B Oldham
@digitala:你的意思是仅仅重置不够吗?重置后的第一个dcommit没有出现在SVN主干上? - VonC

4
总的来说,你不应该使用git merge和git svn,因为即使是在分支的情况下,svn也不支持git的合并跟踪。当需要合并分支时,我最成功的方法(至少在最近的svn中)是进行简单的svn checkout/merge过程,然后使用git svn rebase更新我的git-svn存储库。这保留了svn本机的合并跟踪元数据,而git-svn完全不知道这些信息。
我不太确定你的svn存储库处于什么状态——请确保merge dcommit在主干上做了您想要的事情。即使它完成了,我敢打赌,如果您查看存储库中refs/heads/master和refs/remotes/trunk文件的内容,您会发现它们目前是不同的。如果是这种情况,我将(无需本地更改)执行git-svn fetch,然后执行git branch -f master remotes/trunk; git reset --hard master,以将git分支与git-svn跟踪分支重新同步。如果您有本地更改,您必须提交并执行类似于git rebase master^4 --onto remotes/trunk的操作,其中4是您需要保留的提交数量。或者,如果它们都未提交,请先使用git stash隐藏它们。
如果以上方法都失败了,您可以始终将所有内容放入svn中,然后清除存储库并获取新的检出。

我同意那个分析。+1 - VonC

3
我们在git-svn功能分支开发中成功地使用了git merge --squash。 git-svn的问题是,当您的本地git-svn克隆可以存储合并信息时,一旦您提交到svn存储库,信息就会丢失。
因此,对于其他(git-)svn用户,合并提交看起来就像普通提交一样。 squash适用于与git merge --no-ff 相同的事情(例如,在主分支上生成合并提交),但它还包括所合并的分支中实际提交的列表,否则这些信息将在提交时丢失。

0

我曾经遇到过同样的问题,后来我将远程分支(remotes/trunk)合并回主分支(master),然后 git svn info 就指向了 trunk。

当时我没有时间实际执行 dcommit,因为我离开了这个项目,我的 git-svn 仓库也随着我的工作站一起消失了。不过我尝试了 dcommit --dry-run,它说它会提交到 trunk。

等我有时间了,我会重新建立环境并进行测试。

谢谢。


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