Is git svn rebase required before git svn dcommit?
I'm reading about using git as an svn client here:
http://learn.github.com/p/git-svn.html
That page suggests that you do git svn rebase before git svn dcommit, which makes perfect sense; it's like doing svn update before doing svn commit. Then, I started looking at the documentation for git svn dcommit (I 开发者_JAVA百科was wondering what the 'd' is about):
http://git-scm.com/docs/git-svn
You have to scroll down a bit to see the documentation on dcommit, which says this:
Commit each diff from a specified head directly to the SVN repository, and then rebase or reset (depending on whether or not there is a diff between SVN and head).
This confuses me, because if you do as the first page says, there will be no changes to pull down from svn once the first part of dcommit finishes.
I'm also confused by the part that talks about reset; isn't git reset for removing changes from the staging area?
Why would rebase or reset follow (the first part of) a dcommit?
Disclaimer: I generally do tend to run git svn rebase
before doing a git svn dcommit
. I usually keep my changes in another git branch, so that the rebase doesn't have any chance of failing. I use git rebase master
in my topic branch to bring it up to date. Then I switch to the master
branch and use git merge
to incorporate the changes from my topic branch into master
(this is a fast-forward due to the rebase).
My explanation below explains why this isn't mechanically necessary, but I do agree that it's a good idea to do. Your changes might not cause conflicts in terms of diffs and merging, but if you dcommit
your code without getting the latest changes from svn and reviewing their effects, you could be committing code to svn that doesn't really do the right thing.
You don't have to git svn rebase
before running git svn dcommit
. If the modifications you want to dcommit are in files that haven't changed in svn since you last fetched changes, then git-svn won't show a conflict. In this way, you could be committing changes to an svn repository using a git repository that doesn't have all the latest changes from svn.
Let's say I start an svn repository that contains two files, foo.txt
and bar.txt
. They only have a single revision so far. I do a git svn clone
to start tracking the svn repository using git.
$ git log --oneline --decorate 7e72290 (git-svn, master) Initial commit.
You make changes to foo.txt
and git commit
them to your local master
branch, so it moves ahead of git-svn
.
$ git log --oneline --decorate aa70eca (master) Added a line to foo. 7e72290 (git-svn) Initial commit.
What you didn't realize is that your friend already committed changes to bar.txt
as svn revision 2.
Now when you run git svn dcommit
from master
, git will look for changesets between where you are and where git-svn
left off. In this case, you only have one: aa70eca
. git tries to send that diff to your svn repository.
$ git svn dcommit Committing to [svn repo address] ... M foo.txt Committed r3 M bar.txt r2 = 12b95b96e11f782f31b07a78756660cb82437ca2 (refs/remotes/git-svn) M foo.txt r3 = d4a7b84e0383f3af5fb0db439169c9f1b8af1152 (refs/remotes/git-svn) W: aa70ecae4121854ac3754fb882a483b67d706a4a and refs/remotes/git-svn differ, using rebase: :100644 100644 5771152459bfaa7cc62caa3b6b4d24e52ab8e447 dbfaecb10330d0509e092f1891a4a7e673802413 M bar.txt First, rewinding head to replay your work on top of it... Nothing to do. $ git log --oneline --decorate d4a7b84 (git-svn, master) Added a line to foo. 12b95b9 Added to bar. 7e72290 Initial commit.
You can see that the commit succeeded as svn revision 3. When git-svn then sync'd your local svn history with the svn repository, it fetched all the new commits including the change you just submitted to svn. You'll notice that this change (d4a7b84
) has a different SHA hash from the one you used to have in git (aa70eca
). This is due to a variety of things: different commit timestamps, potentially different author names, the git-svn-id
in the log of the commit fetched from svn, and different ancestry— the fetched svn r3 has r2 as its parent, but your git commit was descended from r1.
In this scenario, there was a diff found after fetching between the current git head (master
) and SVN, since the content in r2 changed foo.txt
. As a result, git-svn
will rebase.
If I make a change and no other svn commits occurred in the meantime (or I had been running git svn rebase
to keep up to date), then git-svn
won't find a diff between the head and SVN, so it can just reset:
$ git svn dcommit Committing to [svn repo address] ... M foo.txt Committed r4 M foo.txt r4 = 533f7337999778628cf39fcd9155d085eb1c2b89 (refs/remotes/git-svn) No changes between current HEAD and refs/remotes/git-svn Resetting to the latest refs/remotes/git-svn
精彩评论