Paul Hammant's Blog: Subversion Merge Limitations That Are Not In Git
A couple of days ago I published an article on how Subversion merging still has upper limits that some users may encounter. I just ported the code to Git, to show how it is not limied. At least not limited in the same way. This shouldn’t be a surprise to anyone of course - Git is really good at merging and merge tracking.
Here’s Subversion blowing up in a merge scenario after a series of cherry-picks, when it shouldn’t have done, from that previous blog entry:
Attempt redundant merge of branch two into branch one (individual commits are merged already, and files at HEAD revision are idential):
--- Merging r2 through r13 into 'one':
C one/testfile.txt
--- Recording mergeinfo for merge of r2 through r13 into 'one':
U one
Summary of conflicts:
Text conflicts: 1
Conflict discovered in file 'one/testfile.txt'.
Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
(mc) my side of conflict, (tc) their side of conflict,
(s) show all options:
So here are the same bash scripts, but issuing Git commands rather than subversion ones (link to Github repo/branch).
And the diff between the two might prove interesting to some. (as github presents that).
The same two tests again…
Test one - merging one way - all good
./reset.sh
./test_of_out_order_merges_from_one_branch_to_another.sh
Merging changes out of order from branch ‘one’ to ‘two’ worked fine. Git Script:
test_of_out_order_merges_from_one_branch_to_another.sh
$ ./test_of_out_order_merges_from_one_branch_to_another.sh
Initialized empty Git repository in /scm/oss/subversion_testing/data/.git/
[master (root-commit) 246d112] branch_one_creation
1 file changed, 10 insertions(+)
create mode 100644 testfile.txt
Switched to branch 'two'
Switched to branch 'one'
[one 111692d] line a changed
1 file changed, 1 insertion(+), 1 deletion(-)
[one fde599f] line b changed
1 file changed, 1 insertion(+), 1 deletion(-)
[one 9fbd9af] line c changed
1 file changed, 1 insertion(+), 1 deletion(-)
[one a4e062b] line d changed
1 file changed, 1 insertion(+), 1 deletion(-)
[one 8cdd684] line e changed
1 file changed, 1 insertion(+), 1 deletion(-)
Switched to branch 'two'
[two e628150] line a merged into two
1 file changed, 1 insertion(+), 1 deletion(-)
[two 1c85f1a] line e merged into two
1 file changed, 1 insertion(+), 1 deletion(-)
[two acbce02] line c merged into two
1 file changed, 1 insertion(+), 1 deletion(-)
[two eaacd6e] line d merged into two
1 file changed, 1 insertion(+), 1 deletion(-)
[two f25a08b] line b merged into two
1 file changed, 1 insertion(+), 1 deletion(-)
Automatic merge went well; stopped before committing as requested
[two 920e4f4] remainder (whatever that means) merged into two
Like Subversion, after a series of seemingly complete (if out of order) cherry-picks, Git wants to do one more ghost merge that doesn’t have any details in the “git show”.
Test two - merging back - all good too
./reset.sh
./test_of_out_order_merges_back_the_original_branch.sh
For subversion, this one had a bug in it - or rather highlighted a bug in Subversion. Script:
test_of_out_order_merges_back_the_original_branch.sh
This was merging another series of changes, as cherry-picks, back to ‘one’ from branch ‘two’. It worked without barfing, unlike the Subversion one (see previous blog entry). Git will also do a “one more” merge from ‘two’ to ‘one’ even if all of the cherry picks have been done already. Again with no diffs in the “git show” for the last commit. Git doesn’t use visible annotations/properties for merge point tracking, so the bash script is slightly shorter. The result:
$ ./test_of_out_order_merges_back_the_original_branch.sh
Switched to branch 'two'
Switched to branch 'one'
Switched to branch 'two'
Automatic merge went well; stopped before committing as requested
Already on 'two'
[two 1bce6ce] line a changed again
1 file changed, 1 insertion(+), 1 deletion(-)
[two 94b0f94] line b changed again
1 file changed, 1 insertion(+), 1 deletion(-)
[two f2a6b82] line c changed again
1 file changed, 1 insertion(+), 1 deletion(-)
[two 2918889] line d changed again
1 file changed, 1 insertion(+), 1 deletion(-)
[two 7edce88] line e changed again
1 file changed, 1 insertion(+), 1 deletion(-)
Switched to branch 'one'
[one 1ae9916] line a merged into one
1 file changed, 1 insertion(+), 1 deletion(-)
[one fffe2b6] line e merged into one
1 file changed, 1 insertion(+), 1 deletion(-)
[one 6893fab] line c merged into one
1 file changed, 1 insertion(+), 1 deletion(-)
[one 29a35c4] line d merged into one
1 file changed, 1 insertion(+), 1 deletion(-)
[one 913dbee] line b merged into one
1 file changed, 1 insertion(+), 1 deletion(-)
Contents of testfile.txt on branch 'one':
a !! aa
b !! bbb
c !! cccc
d !! ddddd
e !! eeeeee
Switched to branch 'two'
Contents of testfile.txt on branch 'two' (they are the same, as a result of merges):
a !! aa
b !! bbb
c !! cccc
d !! ddddd
e !! eeeeee
Switched to branch 'one'
Attempt redundant merge of branch two into branch one (individual commits are merged already, and files at HEAD revision are idential):
Automatic merge went well; stopped before committing as requested
[one 44e962c] remainder (whatever that means) merged into one
While that is good news, this was all towards a config-sysem usage of source-control:
And sadly Git can’t model quite the fidelity and directionality of branches that this needs, even if it is better at merge tracking.
Other features I need are branch and directory permissions (Subversion had that). Some of the portals around Git have added the former, others have not (yet). Another nice to have would be history separation where there were permissions policy differences. That’s much harder in Git given the nature of the reflog.