git-svn dcommit提交单个git提交

27

如果有多个未推送的 git 提交记录,是否可以只将其中一个提交记录 git-svn dcommit 到SVN仓库?

例如,我有提交记录foo、bar和baz,但现在我只想将bar提交记录上传到svn仓库。这是否可行?


提交记录 foo、bar 和 baz 是否已经在跟踪 SVN 仓库的主分支中? - Pradeep
在我的情况下,不需要。但是展示如何两种方式都可以做到是很好的。 - baudtack
4个回答

27

(以下假设您的工作在master分支上。)

首先,重新排序最后三次提交,使bar成为第一次提交。

git rebase -i HEAD~3

编辑器会弹出一个类似于这样的窗口:

pick 498e4f4 foo
pick 71547ae bar
pick abf09c6 baz

# Rebase 4d3fe72..abf09c6 onto 4d3fe72
#
# ...

在弹出的编辑器中重新排序,使得 bar 排在第一位。

pick 71547ae bar
pick 498e4f4 foo
pick abf09c6 baz

# Rebase 4d3fe72..abf09c6 onto 4d3fe72
#
# ...

Git会旋转几秒钟,然后吐出一个确认:

Successfully rebased and updated refs/heads/master.

现在你可以暂时回滚到bar提交(HEAD~2表示从HEAD往前两个提交),并进行dcommit:

git checkout HEAD~2
git svn dcommit
如果你像我一样很谨慎,可以先使用git svn dcommit -n命令来确认你只提交了想要提交的内容。
现在回到master分支:
git checkout master

最后一步是变基操作,以使得 master 与 svn 同步:

git svn rebase

我有点不太清楚为什么需要这样做,但我猜测在分离 HEAD 状态下提交可能与此有关。


我发现这个答案比其他答案更容易理解。git svn dcommit -n--dry-run是完美的使用案例。 - hdl

13

git svn dcommit无法选择性提交bar。如果您直接在主分支上提交了foo、bar和baz,则需要执行以下操作才能仅将bar提交到svn。

假设bar的提交sha类似于13abc...

而git log master显示了您的3个提交foo、bar和baz。

  • 您需要从master创建一个分支

    git branch wip

wip分支现在具有foo、bar和baz

  • 将主分支的head重置为foo、bar或baz之前的提交。您可以使用git reset(阅读手册,hard、soft和mixed选项之间的差异会影响工作树中未提交的更改)

    git reset --hard(foo、bar、baz之前的COMMIT-ID)

    (或者)

    git reset --hard HEAD~3(返回3个版本)

现在您的主分支没有foo、bar或baz。使用git log进行验证。

  • 现在,您可以从wip分支中挑选要提交到svn的提交。所以要得到bar

    git cherry-pick wip 13abc(bar提交的sha)

主分支只获取bar提交。

  • 现在,git svn dcommit应该只推送bar。

建议未来使用

因此,对于 git-svn,最好不要直接在跟踪远程 svn 的主分支上进行提交。在本地分支上完成您的工作,并在 dcommit 之前有选择性地合并到主分支。


我听到了不同的意见,关于合并应该在哪里进行。我现在的做法是分支、dcommit,然后再将主分支rebase。我将主分支保持为标准跟踪分支,而在其他分支中完成我的工作。然后我将这些更改推送到svn,并将它们拉回到主分支中。这就是在freenode的#git上建议我这样做的方式。我之前是按照你建议的方式做的,但这是额外的步骤,因为你需要将更改合并到主分支,而不仅仅是将它们推送到svn并用rebase拉回来。 - baudtack

4
我有一个简单粗暴的方法。你可以创建一个新的分支,不包含foo、bar和baz,然后将bar cherry-pick到新分支上,接着git-svn dcommit该分支,并在完成后删除它。但是这种方法并不太优雅。
假设foo、bar和baz在分支x中,而主分支没有它们。

git branch y master

git checkout y

git cherry-pick <sha1 of bar>

git svn dcommit

git checkout x

git svn rebase

git branch -d y

如果主分支已经有了这些提交,你可以像Sizzler建议的那样重置head。

我会提交主分支并将其他部分保持分离。你也可以在这里使用stash。 - Ben Stiglitz
@Ben 我不确定提交主分支会有什么帮助。我已经在git中有了foo、bar和baz的提交记录。它们只是还没有上传到svn仓库。如果我创建一个新分支并挑选我想要的提交记录,那么我只会得到这些提交记录。 - baudtack
如果您正在主分支上工作,仍然想按照此方式操作,可以使用以下命令:"git checkout trunk -b y"。如果这种方法不适用于您,请查看 git svn 文档并搜索布局选项。 - haggi

2

有时候我只想提交我的分支里的几个commit,例如:

A-----B-----C------D  
^                  ^
|                  |
svn/trunk          trunk

如果我想提交BC但不想提交D,我会创建一个新分支,执行svn dcommit,然后切换回trunk并删除该分支。
当我在trunk分支上时,我会执行以下操作:
git checkout -b temp `C`
git svn info // just to check that branch temp is properly connected to svn
git svn dcommit
git checkout trunk
git branch -D temp

编辑

正如Stefan所评论的:

通过额外的'git svn rebase'对我很有用。

这是必要的,因为提交到svn的提交将被重写。 git-svngit-svn-id添加到提交消息中,因此即使提交的内容相同,提交哈希也会更改。但由于内容相同,rebase不会导致冲突。

附注:我经常省略新分支并只是检出分离的。例如:

git checkout --detach C
git svn dcommit
git checkout trunk
git svn rebase 

1
在我这里,使用额外的 'git svn rebase' 命令很有效。 - Stefan
@Stefan 是的,那是真的。我忘记了,会更新我的答案。rebase是必要的,因为git-svn将重写提交。它会在提交消息中添加git-svn-id - René Link

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