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".
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.
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.
Since git 1.6.6, this should happen automatically.
" * "git svn" learned to read SVN 1.5+ and SVK merge tickets."
in:
http://www.kernel.org/pub/software/scm/git/docs/RelNotes/1.6.6.txt
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With