What's the right way to work with (different) SVN remote repositories via GIT
The environnement:
- A nearby SVN Repository called svn+ssh://yourserver/svn/prj
- An external SVN Repository called svn+ssh://theirserver/svn/prj
- A local git repository that called "myrep" which is a git-svn clone of the nearby one
- made with:
git svn clone -R nearbysvn -s svn+ssh://yourserver/svn/prj
so there is a trunk and some branches (both forked / copied from trunk r3.
- made with:
$ git branch -a * master remotes/b1 remotes/b2 remotes/trunk
Here we come.
Simple changes made in my master (which is a branch from the remotes/trunk) are added, then committed, then "pushed" to the SVN via git svn dcommit
.
So good, so far. The tree now looks like this:
$ git log --graph --oneline --all * 1e6277f change 3 in b2 * 7623755 two new branches | * 7901fad change3 in b1 | * e83f135 two new branches |/ | * 6fac7ad change 3 | * 5858495 new file test3 | * 4cdf2ed change2 | * 511ed7a change1 |/ * d5c68ab init
Conclusion 1:
git svn dcommit
sends all changes made in my local master branch to the remotes/trunk SVN, then rebase it
The output and tree looks like this:
$ git add test $ git ci [master 8a03901] modified test via git for SVN trunk 1 files changed, 1 insertions(+), 1 deletions(-) $ git svn dcommit Committing to svn+ssh://yourserver/svn/prj/trunk ... M test Committed r9 M test r9 = 542eb78f841fc1a4d12f4a72f68e40e3069f3309 (refs/remotes/trunk) No changes between current HEAD and refs/remotes/trunk Resetting to the latest refs/remotes/trunk $ git log --graph --oneline --all * 542eb78 modified test via git for SVN trunk * 6fac7ad change 3 * 5858495 new file test3 * 4cdf2ed change2 * 511ed7a change1 | * 1e6277f change 3 in b2 | * 开发者_如何学C7623755 two new branches |/ | * 7901fad change3 in b1 | * e83f135 two new branches |/ * d5c68ab init
Question 1:
- why is init the parent for b1 and b2?
- why is my master the same as the "init" tree, shouldn't it be a "branch" from the remote one? The merge status is still "unmerged" cause only a rebase was done
Question 2:
what is the correct / best way to patch some changes to the remote/b1
my way: create a local branch myb1 with git checkout -b myb1 remotes/b1
then $ git diff master^..master | patch -p1
then add, ci, dcommit
Question 3:
how can I get informations about my branches to which remote paths they belong to / are forked from? config doesn't tell me anything about it:
$ git config --get-regexp svn-remote svn-remote.nearbysvn.url svn+ssh://yourserver/svn/prj svn-remote.nearbysvn.fetch trunk:refs/remotes/trunk svn-remote.nearbysvn.branches branches/:refs/remotes/ svn-remote.nearbysvn.tags tags/:refs/remotes/tags/
Question 4:
This is some more tricky: The second (external) SVN is now a "duplicate" of the first one, with one exception: external might be used by others too. Currently all changes made in "nearby" has to be done again in the external one (patching files in a second working copy, and so on...
If this remove SVN is now a second remote SVN repository, what is best practice to "optimize" this with merges via git?
Yes, there are some great guy'S who will use BeyondCompare, etc (see How to compare source in Git repository between source in SVN repository). But this is NOT my favorite way to "merge"
I propose I need:
* local branches like myb1, master, master2
* forks / branches of this for my work like master-taskX (git checkout -b master-taskX
)
* then I might use merge to get my changes back to master and then dcommit them??
I'll be glad to hear from some git-svn experts soon ;)
With kind regards, ~Marcel
Appendix:
FYI: here is the inital SVN history for "nearby":
------------------------------------------------------------------------ r8 | konqi | 2011-01-19 17:48:51 +0100 (Mi, 19 Jan 2011) | 2 lines Changed paths: M /branches/b2/test3 change 3 in b2 ------------------------------------------------------------------------ r7 | konqi | 2011-01-19 17:48:42 +0100 (Mi, 19 Jan 2011) | 2 lines Changed paths: M /branches/b1/test3 change3 in b1 ------------------------------------------------------------------------ r6 | konqi | 2011-01-19 17:46:07 +0100 (Mi, 19 Jan 2011) | 2 lines Changed paths: M /trunk/test3 change 3 ------------------------------------------------------------------------ r5 | konqi | 2011-01-19 17:36:13 +0100 (Mi, 19 Jan 2011) | 3 lines Changed paths: A /branches/b1 (from /trunk:1) R /branches/b1/test (from /trunk/test:2) R /branches/b1/test2 (from /trunk/test2:3) A /branches/b1/test3 (from /trunk/test3:4) A /branches/b2 (from /trunk:1) R /branches/b2/test (from /trunk/test:2) R /branches/b2/test2 (from /trunk/test2:3) A /branches/b2/test3 (from /trunk/test3:4) two new branches ------------------------------------------------------------------------ r4 | konqi | 2011-01-19 17:30:05 +0100 (Mi, 19 Jan 2011) | 2 lines Changed paths: A /trunk/test3 new file test3 ------------------------------------------------------------------------ r3 | konqi | 2011-01-19 17:28:46 +0100 (Mi, 19 Jan 2011) | 2 lines Changed paths: M /trunk/test2 change2 ------------------------------------------------------------------------ r2 | konqi | 2011-01-19 17:28:34 +0100 (Mi, 19 Jan 2011) | 2 lines Changed paths: M /trunk/test change1 ------------------------------------------------------------------------ r1 | konqi | 2011-01-19 17:28:10 +0100 (Mi, 19 Jan 2011) | 2 lines Changed paths: A /branches A /tags A /trunk A /trunk/test A /trunk/test2 init ------------------------------------------------------------------------
- why is init the parent for b1 and b2?
- Because in svn's history, init creates the 'branches' folder, and git-svn regards it as the parent of all branch commits. In the end it's just a convention and not particularly important to any functionality.
- why is my master the same as the "init" tree, shouldn't it be a "branch" from the remote one?
- It is a branch from the remote, but git commits aren't part of branches, that's not how git thinks. To git, a "branch" is a pointer to a commit, that includes by implication all parent commits. The commits themselves don't know or care what branch(es) they are part of.
- The merge status is still "unmerged" cause only a rebase was done
- (no idea what you're talking about here)
Question 2:
- what is the correct / best way to patch some changes to the remote/b1
- If you aren't doing a full merge, try git cherry-pick (see git help cherry-pick); it's more or less an easier and more reliable way of doing what you are doing already
Question 3:
- how can I get informations about my branches to which remote paths they belong to / are forked from?
- You could check them out and run git svn info, or use git log and grep for the svn line at the bottom of the commit message that lists the path and rev of the source. The latter is git-svn's authoritative source for where svn commits come from.
Question 4:
This is some more tricky: The second (external) SVN is now a "duplicate" of the first one, with one exception: external might be used by others too. Currently all changes made in "nearby" has to be done again in the external one (patching files in a second working copy, and so on...
If this remove SVN is now a second remote SVN repository, what is best practice to "optimize" this with merges via git?
Yes, there are some great guy'S who will use BeyondCompare, etc (see How to compare source in Git repository between source in SVN repository). But this is NOT my favorite way to "merge"
I propose I need: * local branches like myb1, master, master2 * forks / branches of this for my work like master-taskX (git checkout -b master-taskX) * then I might use merge to get my changes back to master and then dcommit them??
- I'd have two git repositories on the same machine, one (let's call them A and B) set to track each svn repo. Do your dev on A, set to track the nearby repo. Have B register the A as a regular git "remote" (git remote add /path/to/repo/A) after you git svn clone. Once you have got your commits ready to dcommit on A, use git fetch -f in B to bring them there. Then git svn dcommit in A; in B use something like
git checkout -b temp A/master; git rebase --onto trunk HEAD^; git svn dcommit; git checkout master; git branch -D temp
to commit the changes to repo B. To dcommit multiple revs you will neat to adjust the number of carats in the rebase command.
- I'd have two git repositories on the same machine, one (let's call them A and B) set to track each svn repo. Do your dev on A, set to track the nearby repo. Have B register the A as a regular git "remote" (git remote add /path/to/repo/A) after you git svn clone. Once you have got your commits ready to dcommit on A, use git fetch -f in B to bring them there. Then git svn dcommit in A; in B use something like
Note generally that in my experience git merge doesn't play well with git-svn, so you probably want to stick to techniques like the above which do not create two-parent commits in the git history.
I would make 2 separate git repos for the 2 svn repos. Then, coordinate changes via rebasing, etc. in one of the Git repositories.
精彩评论