tags:

views:

331

answers:

3

We have an SVN setup with stable trunk and unstable development branch. Dev work is (mostly) done on the branch and then merged to trunk before deployment.

I use git-svn as my SVN client. My merge process from unstable to trunk is as follows:

git svn fetch
git co -b trunk svn/trunk 
git merge --no-ff svn/unstable
git svn dcommit

svn/* are the remote SVN branches.

This of course requires that no one commits anything to the trunk before I am done, but this is not a problem in practice.

The benefits of this process is that git now records the parents of the merge commit in my local repository. This does not benefit my coworkers, but it does allow git to compute the common ancestor when I do the merge. This is very desirable.

And here is the rub. When someone else makes a merge, git doesn't know about it. Here is an example:

  o-...-A---o---C--- unstable
 /
X--...--B---o---o--- stable

The unstable branch was created at point X. At point A we decide to merge changes from the unstable branch into the stable branch at point B. The common ancestor is correctly X.

Because the merge is not recorded in the git history, the following merge at C again assumes X is the common ancestor. I would like it be A, as in the following graph:

  o-...-A---o---C--- unstable
 /       \
X---...---B---o---o--- stable

It is not absolutely necessary to get a graph that looks exacly like the one pictured. Any graph, which would recognize A as the common ancestor is fine by me.

I have some options in mind, such as a proper use of git-filter-branch or a "fake" commit which is never dcommited to SVN. However none of my attempts have worked sufficiently so far.

I am grateful for any ideas you can present. The procedure does not have to be automatic. The merges are pretty rare and I can live with the pain of doing it "by hand".

+2  A: 

Your problem is a bit like SVN populating svnmergeinfo from git merges in reverse:
You do not want SVN to record merges from Git, but Git to record merges from SVN ;)

Since git-svn does not care about svnmergeinfo attribute when importing from SVN, that leave a "manual operation" option.

I would not recommend a git-filter-branch solution or anything which rewrites history on the Git side.
If you are aware of a "A->B" merge on SVN, you should do that merge on Git **in a "merge" branch, and then merge it right back into the stable branch (trivial merge at this point), thus adding a new commit to your current stable history.

    o-.....-A---o---C--- unstable
   /         \
  /           o-------\__ merge recorder branch
 /           /         \
X---.....---B---o---o---o__ stable

Then a merge from C to stable should have A as common ancestor.

VonC
Right! So the key is to make _two_ intermediary commits, one of which does end up in SVN as well. This seems to work at least on paper. Thanks for the information! I wonder if it is possible to squeeze this into a git alias...
Antti Rasinen
You forgot to end your "**" (bold) in "... Git **in a "merge" branch ..."
Lucas Jones
+2  A: 

An additional alternative would be to use the Grafts file, which allows you to override the parents of a commit without actually manipulating history.

This means that after you see a merge in the SVN repository, you just need to add a line to .git/info/grafts with the SHA-1s of the merge commit (M) and its parents (A,B).

      o-...-A---o---D--- unstable
     /       
    X-----B---M---o---o--- stable

A = 31423cd8a838f984547a908777308d846043cbda
B = d99cfccb1f859a8f1dbfac95eec75227fe518b23
M = 13319a54d3e3d61b501e7cc6474c46f37784aaa3

In order to create the link from A-M, you would specify M's parents as B and A. The format of the grafts file is fairly straightforward:

commit newparent1 ... newparentN

This means you add the following (rather long) line to your grafts file:

13319a54d3e3d61b501e7cc6474c46f37784aaa3 d99cfccb1f859a8f1dbfac95eec75227fe518b23 31423cd8a838f984547a908777308d846043cbda

Git will now pretend that this merge actually occurred. As a downside, this doesn't get propagated via git push/fetch/clone, but this shouldn't be a major issue for personal development.

NTmatter
Thanks! This is the first time I've heard of grafts. Always good to learn more.
Antti Rasinen
A: 

Watch out with grafts file thou.

  1. Do them wrong and a git gc will (after a while) drop parts of the history
  2. If you push to another host, it will not know of the grafts and may end up with broken history.