在执行git svn dcommit之前是否需要进行git svn rebase操作?

16
我正在阅读有关在此处使用git作为svn客户端的信息:http://learn.github.com/p/git-svn.html
该页面建议您在git svn dcommit之前执行git svn rebase,这非常合理;这就像在svn提交之前执行svn更新一样。然后,我开始查看git svn dcommit的文档(我想知道'd'是什么意思):http://git-scm.com/docs/git-svn
您必须向下滚动一点才能看到有关dcommit的文档,其中说:
从指定的head直接提交每个差异到SVN存储库,然后重新基于或重置(取决于是否存在SVN和head之间的差异)。
这让我感到困惑,因为如果按照第一页所说的那样,当dcommit的第一部分完成后,就不会有任何要拉取的svn更改。
我也困惑于谈到重置的部分;不是用于从暂存区删除更改的git reset吗?
为什么在dcommit的第一部分之后需要重新基于或重置呢?
1个回答

20

声明:通常我在执行git svn dcommit之前都会运行git svn rebase。我通常将我的更改保存在另一个git分支中,以便rebase没有任何失败的机会。我在我的主题分支中使用git rebase master将其更新。然后我切换到master分支,并使用git merge将主题分支的更改合并到master(由于rebase的原因,这是一个快进)。

下面的解释说明了为什么这不是机械上必要的,但我同意这是个好主意。你的更改可能不会造成差异和合并方面的冲突,但如果你在没有获取最新的svn更改并审查其影响的情况下dcommit你的代码,那么你可能会向svn提交不正确的代码。


在运行git svn dcommit之前,你不一定需要运行git svn rebase。如果你要dcommit的修改是在svn自从你上次获取更改后没有变化的文件中,那么git-svn就不会显示冲突。这样,你可以使用一个没有所有来自svn的最新更改的git存储库向svn存储库提交更改。

假设我启动了一个包含两个文件foo.txtbar.txt的svn存储库。它们到目前为止只有一个修订版。我执行git svn clone以开始使用git跟踪svn存储库。

$ git log --oneline --decorate
7e72290 (git-svn, master) 初始提交。

你对foo.txt进行更改并将其在本地的master分支中git commit,因此它超前于git-svn

$ git log --oneline --decorate
aa70eca (master) 添加了一行到foo。
7e72290(git-svn)初始提交。

你没有意识到,你的朋友已经在svn版本号为2时对bar.txt进行了更改。

现在当你从master运行git svn dcommit时,git会查找从当前位置到git-svn结束之间的更改集。在这种情况下,只有一个:aa70eca。git试图将该差异发送到svn存储库。

$ git svn dcommit
正在提交至 [svn存储库地址] ...
        M       foo.txt
提交 r3
        M       bar.txt
r2 = 12b95b96e11f782f31b07a78756660cb82437ca2 (refs/remotes/git-svn)
        M       foo.txt
r3 = d4a7b84e0383f3af5fb0db439169c9f1b8af1152 (refs/remotes/git-svn)
W: aa70ecae4121854ac3754fb882a483b67d706a4a 与 refs/remotes/git-svn 不同,使用变基操作:
:100644 100644 5771152459bfaa7cc62caa3b6b4d24e52ab8e447 dbfaecb10330d0509e092f1891a4a7e673802413 M      bar.txt
首先,倒回头来重播您的工作...
无事可做。

$ git log --oneline --decorate
d4a7b84(git-svn,master)向foo添加了一行。
12b95b9 添加到bar。
7e72290 初始提交。

你可以在svn修订版本3中看到提交成功了。当git-svn将本地svn历史与svn仓库同步时,它获取了所有新的提交,包括你刚刚提交到svn的更改。你会注意到这个更改(d4a7b84)与你在git中使用的不同 (aa70eca)。这是由于多种原因造成的:不同的提交时间戳、可能不同的作者名称、在从svn获取的提交日志中的git-svn-id,以及不同的祖先 - 获取的svn r3 有r2作为其父级,但你的git提交是从r1继承下来的。

在这种情况下,在获取后当前的git头(master)和SVN之间发现了差异,因为r2中的内容更改了foo.txt。因此,git-svn将进行rebase操作。

如果我进行了更改并且同时没有进行其他svn提交(或者我一直运行 git svn rebase 以保持最新状态),那么git-svn 将不会在头部和SVN之间找到差异,因此它只需重置:

$ git svn dcommit
正在提交至 [svn repo address] ...
        M       foo.txt
已提交 r4
        M       foo.txt
r4 = 533f7337999778628cf39fcd9155d085eb1c2b89 (refs/remotes/git-svn)
当前HEAD和refs/remotes/git-svn之间没有变化
重置到最新的refs/remotes/git-svn

我已经重写了大部分答案,包括一些示例,这些示例应该说明在dcommit之后进行fetch+rebase的重要性。我希望它能解决第1点和第2点。 - Mike Seplowitz
2
回复 #3:git reset 的作用取决于你使用的形式。git reset HEAD foo.txt 会将对 foo 的更改从索引中撤销。git reset [--soft|--mixed|--hard|...] <commit> 根据你给出的开关移动你的分支并更改索引/工作区。 - Mike Seplowitz
2
回复 #4:我认为这种情况并不经常发生,所以我并没有意味着这样。你可以给 git svn dcommit 传递一个参数(“可以指定一个可选的修订版本或分支参数,使得 git svn 在该修订版本/分支上执行所有操作而不是 HEAD。”),但我自己从未使用过这个功能。 - Mike Seplowitz
2
谢谢你的澄清,Mike。我现在明白了。在dcommit之后进行rebase(或reset)的原因是因为dcommit在将提交添加到(远程)svn仓库后拉取新的修订版本(包括刚刚在dcommit过程中创建的修订版本)。您希望这些提交位于主分支上,这就是rebase或reset所做的。只要远程svn仓库没有超过您(例如,在git svn dcommit之前始终执行git svn rebase),那么它将始终在dcommit之后执行reset;否则,可能需要执行rebase。 - allyourcode
你的更改可能不会在差异和合并方面引起冲突,但如果你在没有从svn获取最新更改并审查其影响的情况下提交代码,那么你可能会向svn提交代码,而这些代码实际上并不能做正确的事情。 <-- 这真的为我解释清楚了重点。感谢您详尽的解释! - skrebbel
显示剩余4条评论

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