cherry-picking with git-svn
I'm facing the problem of merging a subset of revisions from one topic-branch to another. Since I am using git-svn, I was curious to see if it is possible to use cherry-picking for this. Using Subversion, I would do:
svn merge -c A
svn merge -c B
svn merge -c C
...
svn commit ...
what will happen if I try to do this?
git checkout branch1
git cherry-pick A
git cherry-pick B
git cherry-pick C
git svn dcommit
If I read the git svn man-page, the answers is "don't do that", but I get the impression when googling around that git svn does a much better job now with these kinds of iss开发者_开发问答ues.
git-svn had a serious problem related to cherry-picked commits:
Suppose you have commit a1b2c3f9 which is already dcommitted into svn repository:
$ git show a1b2c3f9
commit a1b2c3f9...
Author: Happy Dev <happyd@43fe5c0-...>
Date: Mon Nov 14 13:01:38 2011 +0000
Commit message
git-svn-id: https://host/svn/branches/some-branch@1000 43fe5c0-...
See this git-svn-id line? This is how git-svn understands where your commit lies in Subversion repository.
Now you want to cherry-pick this commit to master branch you're currently on:
$ git cherry-pick a1b2c3f9
If there were no merge conflicts, git creates a new commit, say, 9f3c2b1a and here what we have:
$ git show 9f3c2b1a
commit 9f3c2b1a...
Author: Happy Dev <happyd@43fe5c0-...>
Date: Mon Nov 14 13:01:39 2011 +0000
Commit message
git-svn-id: https://host/svn/branches/some-branch@1000 43fe5c0-...
So, Git created a commit with exactly the same message. This caused serious problems. Former versions of git-svn sent such commit into wrong branch — ^/branches/some-branch instead of ^/trunk/.
This problem is already fixed in the latest versions of Git. But there is another one which is still present:
git-svn doesn't honor merge-tracking mechanism of Subversion.
Subversion tracks merge information on performed cherry-picks, so the command
$ svn merge -c 1000 ^/branches/some-branch trunk-working-copy
adjusts the svn:mergeinfo property of trunk-working-copy as follows:
+ /branches/some-branch: 1000
This way Subversion understands that this particular revision was already merged into ^/trunk/ branch thus it skips this change in further merges.
When you run git cherry-pick
and then git svn dcommit
Subversion repository doesn't get svn:mergeinfo modification.
Here goes the disclaimer:
Currently I don't work on SmartGit but I work in a close contact with SmartGit developers.
Syntevo company developed SmartGit — a great replacement of git-svn. This Git client resolves all the issues I've described above:
So, you cherry-pick a1b2c3f9 commit:
$ git cherry-pick a1b2c3f9
as result you get 9f3c2b1a commit, and then you push it into Subversion repository. SmartGit does everything to keep merge-tracking information, so ^/trunk/ branch gets necessary modification of its svn:mergeinfo property:
+ /branches/some-branch: 1000
You can perform Git cherry-pick either from SmartGit itself or using Git command line interface. In the second case commit message should have git-svn-id line of the cherry-pick source.
SmartGit is proprietary software but it's free for non-commercial usage. It has a lot of great features, for more information please refer to SmartGit documentation.
There is another interesting project which solves certain problems with git-svn — SubGit. Basically it is the server-side solution for synchronizing changes between Subversion and Git repositories. It's much more superior than git-svn and doesn't have its problems.
As svn-via-git user, I believe, you might be interested in that too.
When you do git svn dcommit
, it will sequentially run an svn commit
for each git commit between your svn tracking branch and whatever HEAD
is in git. In your example, that's three commits – one each for A, B, and C – since git cherry-pick
commits the changes right away. Granted, you could use git rebase -i
to squash those commits together into a single revision before you run git svn dcommit
to push them to svn.
Running git-svn
completely ignores all svn:mergeinfo
properties. From the git-svn
man page:
We ignore all SVN properties except svn:executable. Any unhandled properties are logged to
$GIT_DIR/svn/<refname>/unhandled.log
There should be no problem with this at all; I've done this many times at work before. Additionally, when TortoiseSVN has had trouble merging entire branches in the past, I have resorted to rebasing topic branches on top of trunk and squashing all the commits into one commit, which is similar in nature to a cherry-pick. It's worked great.
精彩评论