16

I am working on a svn project with two branches, lets call them

trunk
branches/foo

My idea is to clone the whole svn repository (telling git which folder are trunk, tags and branches), do the merge in git and then copy my merge to a svn working copy and commit the changes from svn.

In this workflow, will I be able to use gits merging power or will that only work for branches created with git itself?

rwilliams
  • 21,188
  • 6
  • 49
  • 55
unkownt
  • 621
  • 2
  • 8
  • 18
  • related post: http://stackoverflow.com/questions/1129688/git-svn-workflow-feature-branches-and-merge – zellus Nov 27 '10 at 10:18

3 Answers3

23

Create alias for checkout command:

git config alias.co checkout

Make sure that you local branches are up to date:

git co master    # checkout branch that tracks subversion's trunk
git svn rebase 
git co local/foo # checkout branch that tracks subversion's branches/foo
                 # It assumes that  the branch is created with the command:
                 # `git co -b local/foo remotes/foo`
                 # And the repo was created with:
                 # `git svn clone --stdlayout SVN_REPO_URL`
git svn rebase 

Merge branches:

# create new local branch based on `master`
git co master
git co -b merging_branch_foo 
# merge, resolve conflicts, etc (pure git)
git merge local/foo  

# rebase `merging_branch_foo` to linearize history for subversion
git rebase master # or `rebase -i`

# merge `merging_branch_foo` into `master`
git co master
git merge merging_branch_foo # --squash to create single commit

# commit changes to svn
git svn dcommit

# (optionally) delete `merging_branch_foo`
git branch -D merging_branch_foo
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • Thank you for your answer, but it did not really answer my question. I know how to merge and commit with git, but I have also read that committing a merge to svn can cause problems. Thats why I am thinking of merging it in git and then copy the merge to my svn checkout and commit the merge with svn, But my first question was also if git will understand how to merge even though git didn't do the branching since the branching was made by svn before. Thanks for the time you have put down into showing how to do a normal merging – unkownt Nov 27 '10 at 16:11
  • @unkown: If the local git branches are up to date (see the first 4 commands from my answer) and you did `git rebase` (see the 5th from the bottom command from the answer) then there should not be any problems. btw, commands `git svn rebase` and `git svn dcommit` used in the answer are working directly with svn repository; you don't need separate svn checkout. – jfs Nov 27 '10 at 16:22
  • Sebastian, What do you think about Bardleys answer in the comment regarding that Git needs to know about the history and that it wont know it? The way I understand it according to him is that with the way you have suggested Git won't know about the history and hence I wont gain anything trying to use Git for the merging. Regarding your comment about dcommit I think your actually are right that it will do the same as copy it over to and working svn copy and commit. So thanks for clarifying that part. – unkownt Nov 27 '10 at 18:35
  • @unkown: As I'd noted in the answer the git repo is assumed to be created with `git svn clone -s` command that takes entire svn history (that why this command is much slower than a mere `svn checkout`). Though the clone command doesn't work for some subversion repos. – jfs Nov 28 '10 at 03:08
  • Thanks for the answer I think I was a bit confused regarding how this worked and this seems to be the right answer. – unkownt Nov 30 '10 at 15:02
  • So I tried to follow the steps you provided today and when i use git svn dcommit, git is trying to dcommit to my branch instead of my trunk. How do I tell git svn to dcommit to the trunk instead? – unkownt Dec 02 '10 at 14:53
  • @unkownt: 1. make sure you are on the correct local branch `git co master` in your case. 2. run `git svn info --url` if it doesn't print the svn trunk url then you haven't followed the steps from my answer. 3. check that `.git/config` contains something similar to https://gist.github.com/726115 4. use `git svn dcommit --dry-run` to make sure that you dcommit on correct branch. – jfs Dec 02 '10 at 21:40
  • The method is correct but the merge --squarsh step will erase the history of changes, is there any solution that can preserve them? – QZHua Apr 07 '17 at 03:24
  • @QZHua have you noticed that the option is mentioned in a comment? (it is not used in the example but you can use it if you want). – jfs Apr 07 '17 at 06:29
  • @J.F.Sebastian, sorry I did not find the comment you mean. Can you figure it out , thanks a lot! – QZHua Apr 11 '17 at 07:56
  • @QZHua: the option `--squash` is in the comment (after `#` in the command -- it is not active, it has no effect): `git merge merging_branch_foo # --squash to create single commit` – jfs Apr 11 '17 at 08:03
  • OK, I was told never to use merge with git-svn, it will cause a very bad rebase problem when the branch to be merged and the svn branch do not have the same root. A solution I have found is to use --squash with the merge, but it will packed all commits into a single one, and thus the commit histories were missing in the svn. I problem is I want to kept each individual commit available on the svn repos, do you mean `git merge merging_branch_foo` without the --squash option can achieve that? I don't think so. – QZHua Apr 11 '17 at 08:33
  • @QZHua I don't see how it is related to my answer. I followed the steps in the answer many times: it works. – jfs Apr 11 '17 at 08:39
  • 2
    Is that alias really necessary? I feel it complicates the answer. – starbeamrainbowlabs Feb 08 '18 at 13:07
  • This doesn't work for me if `git merge merging_branch_foo` is a fast forward. In that case, the following dcommit of master somehow goes to `branches/foo` rather than `trunk`. At least `git svn dcommit --dry-run` says so. This is what solved it for me: https://stackoverflow.com/questions/190431/is-git-svn-dcommit-after-merging-in-git-dangerous – tomorrow Mar 31 '18 at 23:00
  • @tomorrow it sounds wrong. The whole point of the answer is to make the branch fast-forward (to linearize history). What is the purpose of `git rebase master` in the answer in your opinion? – jfs Mar 31 '18 at 23:09
  • yes, right, it will always be fast forward. But then... it will never work for me it seems. I may be doing something wrong (although the steps are quite straight forward) but when I run `git svn dcommit --dry-run`, it suddenly wants to dcommit the master branch to foo rather than trunk. And I have no idea why. But the --no-ff option in the above mentioned post helped. – tomorrow Mar 31 '18 at 23:26
4

There is a way to perform merging with git but committing (upstream) with Subversion that is complicated to set up, but is powerful (and much easier than merging with Subversion!) in practice. First, read Derick Bailey's git+svn overview, because you will need to set up the git and SVN ignore files as he instructs.

Note that this doesn't use the standard git-svn package, but replicates a lot of what that does, manually. If you're already using git-svn, don't use this method. Also, it's only worth using this method if you'll be repeatedly merging from the branch to the trunk (and especially if cherry-picking from the trunk to the branch) because that takes advantage of git's history when performing additional merges.

Then, the basic steps are as follows:

  1. SVN Checkout /trunk/ to a working copy folder; I'll assume it's C:\trunk.
  2. git init a git repository in that folder; set up .gitignore; git add -A; git commit (see git+svn above).
  3. Create a git clone of the repository (in a different folder): git clone C:\trunk foo. I'll assume this clone is in C:\foo.
  4. Delete everything in C:\foo except the .git subfolder, then SVN Checkout /branches/foo in C:\foo.
  5. In C:\foo, run git add -A; git commit to save the changes on the branch to the git repository. This creates the initial git history that diverges from the history in C:\trunk.

We now have two folders that are both git repositories and Subversion working copies; additionally, git thinks the folders are clones of the same repository.

Perform work in the C:\trunk and C:\foo folders (or just svn update to get others' work). Periodically, run git add -A; git commit to save changes to your git repositories.

Now you want to merge the foo branch back into trunk. In C:\trunk, run git pull C:\foo. This pulls in and merges all the changes from the C:\foo folder, which is your git repository tracking the /branches/foo Subversion branch. If necessary, resolve any conflicts and finish the git commit.

You can now commit the changes in C:\trunk to Subversion without having to use Subversion to perform the merge.

Bradley Grainger
  • 27,458
  • 4
  • 91
  • 108
  • Thank you, This seems like what I am looking for. Would this be different from using git for merging the remote svn trunk and foo and then just copy them over to my svn working copy and commit it trough svn? – unkownt Nov 27 '10 at 16:26
  • @unkown: The difference in this approach is that by creating a git branch that contains the `branches/foo` code, you can use git's knowledge of history to perform multiple merges (from the branch to the trunk) and avoid conflicts typically generated by Subversion's merging in that scenario. Also, git has to know about a common ancestor--you can't just tell it to merge two folders. – Bradley Grainger Nov 27 '10 at 17:48
  • Bradley, I up voted your answer and will probably make it the right answer soon. I will just wait a bit longer to see if other people have some suggestions too. What do you think about Sebastians answer regarding the merging not the dcommit? Won't git have any knowledge of the history in that case? I think you already said that it won't but I do just want to be 100% sure of that. Thanks for the answer once again. – unkownt Nov 27 '10 at 18:32
  • I'm not very familiar with git-svn (one of the reasons I used the "git+svn" approach is that (just like Derick Bailey) I couldn't get git-svn to import my upstream Subversion repository without crashing) so I can't say if his answer solves your problem or not. His answer does assume that you're using git-svn; if you are, you'll probably want to do what he says; if you're not, my approach may work better for you. – Bradley Grainger Nov 27 '10 at 19:05
-1

I would recommend you to use SmartGit for your SVN project. It has very good support for both cherry-picking merges and full merges, properly modifying svn:mergeinfo.

Dmitry Pavlenko
  • 8,530
  • 3
  • 30
  • 38