git svn: handle SVN merges from revisions past the tip of the branch
authorToby Allsopp <toby.allsopp@navman.co.nz>
Sat, 14 Nov 2009 21:26:47 +0000 (13:26 -0800)
committerEric Wong <normalperson@yhbt.net>
Sat, 14 Nov 2009 21:37:59 +0000 (13:37 -0800)
When recording the revisions that it has merged, SVN sets the top
revision to be the latest revision in the repository, which is not
necessarily a revision on the branch that is being merged from.  When
it is not on the branch, git-svn fails to add the extra parent to
represent the merge because it relies on finding the commit on the
branch that corresponds to the top of the SVN merge range.

In order to correctly handle this case, we look for the maximum
revision less than or equal to the top of the SVN merge range that is
actually on the branch being merged from.

[ew: This includes the following (squashed) commit to prevent
     errors during bisect:]

  Author: Toby Allsopp <toby.allsopp@navman.co.nz>
  Date:   Fri Nov 13 09:48:39 2009 +1300

    git-svn: add (failing) test for SVN 1.5+ merge with intervening commit

    This test exposes a bug in git-svn's handling of SVN 1.5+ mergeinfo
    properties.  The problematic case is when there is some commit on an
    unrelated branch after the last commit on the merged-from branch.
    When SVN records the mergeinfo property, it records the latest
    revision in the whole repository, which, in the problematic case, is
    not on the branch it is merging from.

    To trigger the git-svn bug, we modify t9151 to include two SVN merges,
    the second of which has an intervening commit.  The SVN dump was
    generated using SVN 1.6.6 (on Debian squeeze amd64).

Signed-off-by: Toby Allsopp <toby.allsopp@navman.co.nz>
Acked-by: Eric Wong <normalperson@yhbt.net>
git-svn.perl
t/t9151-svn-mergeinfo.sh
t/t9151/make-svnmerge-dump
t/t9151/svn-mergeinfo.dump

index 6a3b501d24ebaa50e297511ccf0b18e3bbd2bb16..27fbe3063bfab8be3c67a7879f63ba977556ad1b 100755 (executable)
@@ -2950,8 +2950,11 @@ sub find_extra_svn_parents {
                        my $bottom_commit =
                                $gs->rev_map_get($bottom, $self->ra_uuid) ||
                                $gs->rev_map_get($bottom+1, $self->ra_uuid);
-                       my $top_commit =
-                               $gs->rev_map_get($top, $self->ra_uuid);
+                       my $top_commit;
+                       for (; !$top_commit && $top >= $bottom; --$top) {
+                               $top_commit =
+                                       $gs->rev_map_get($top, $self->ra_uuid);
+                       }
 
                        unless ($top_commit and $bottom_commit) {
                                warn "W:unknown path/rev in svn:mergeinfo "
index 9bee516358bd98d1b5c701f6aa0c4f3e4d95bd45..f57daf401ac7c36c1d9f2380200e0efad2400f70 100755 (executable)
@@ -15,7 +15,11 @@ test_expect_success 'load svn dump' "
        git svn fetch --all
        "
 
-test_expect_success 'svn merges were represented coming in' "
+test_expect_success 'represent svn merges without intervening commits' "
+       [ `git cat-file commit HEAD^1 | grep parent | wc -l` -eq 2 ]
+       "
+
+test_expect_success 'represent svn merges with intervening commits' "
        [ `git cat-file commit HEAD | grep parent | wc -l` -eq 2 ]
        "
 
index e35d64d5859076ac09ec719e3ff9cd6700936533..7e3da75f8602621f0f202fc812fad2feefccda28 100644 (file)
@@ -28,6 +28,10 @@ svn cp trunk branches/left
 
 echo "Committing BRANCH POINT"
 svn commit -m "make left branch"
+svn cp trunk branches/right
+
+echo "Committing other BRANCH POINT"
+svn commit -m "make right branch"
 cd branches/left/
 
 #$sm init
@@ -64,7 +68,33 @@ git cat-file blob b51ad431:Makefile > Makefile
 
 svn resolved Makefile
 
-svn commit -m "Merge trunk"
+svn commit -m "Merge trunk 1"
+
+# create commits on both branches
+
+cd ../branches/left
+git cat-file blob ff5ebe39:Makefile > Makefile
+echo "Committing BRANCH UPDATE 4"
+svn commit -m "left update 4"
+
+cd ../right
+git cat-file blob b5039db6:Makefile > Makefile
+echo "Committing other BRANCH UPDATE 1"
+svn commit -m "right update 1"
+
+# merge to trun again
+
+cd ../..
+svn update
+cd trunk
+
+svn merge ../branches/left --accept postpone
+
+git cat-file blob b51ad431:Makefile > Makefile
+
+svn resolved Makefile
+
+svn commit -m "Merge trunk 2"
 
 cd ../..
 
index 2153187c9b11f7f17cb2b397086b43d675fe290e..11a883fda96ec81f3ed9ba3a9cfc424cc41d8103 100644 (file)
@@ -1,6 +1,6 @@
 SVN-fs-dump-format-version: 2
 
-UUID: 1ce241d1-ba54-4eb9-bded-03057fe48a33
+UUID: 1530d5a2-a1dc-4438-8ad5-d95e96db8945
 
 Revision-number: 0
 Prop-content-length: 56
@@ -9,12 +9,12 @@ Content-length: 56
 K 8
 svn:date
 V 27
-2009-10-20T01:33:37.692723Z
+2009-11-12T20:29:38.812226Z
 PROPS-END
 
 Revision-number: 1
-Prop-content-length: 123
-Content-length: 123
+Prop-content-length: 127
+Content-length: 127
 
 K 7
 svn:log
@@ -22,12 +22,12 @@ V 24
 Setup trunk and branches
 K 10
 svn:author
-V 4
-samv
+V 8
+tallsopp
 K 8
 svn:date
 V 27
-2009-10-20T01:33:38.159933Z
+2009-11-12T20:29:39.045856Z
 PROPS-END
 
 Node-path: branches
@@ -49,8 +49,8 @@ PROPS-END
 
 
 Revision-number: 2
-Prop-content-length: 106
-Content-length: 106
+Prop-content-length: 110
+Content-length: 110
 
 K 7
 svn:log
@@ -58,12 +58,12 @@ V 8
 ancestor
 K 10
 svn:author
-V 4
-samv
+V 8
+tallsopp
 K 8
 svn:date
 V 27
-2009-10-20T01:33:39.160059Z
+2009-11-12T20:29:40.079587Z
 PROPS-END
 
 Node-path: trunk/Makefile
@@ -72,6 +72,7 @@ Node-action: add
 Prop-content-length: 10
 Text-content-length: 2401
 Text-content-md5: bfd8ff778d1492dc6758567373176a89
+Text-content-sha1: 103205ce331f7d64086dba497574734f78439590
 Content-length: 2411
 
 PROPS-END
@@ -155,8 +156,8 @@ backup: clean
 
 
 Revision-number: 3
-Prop-content-length: 115
-Content-length: 115
+Prop-content-length: 119
+Content-length: 119
 
 K 7
 svn:log
@@ -164,12 +165,12 @@ V 16
 make left branch
 K 10
 svn:author
-V 4
-samv
+V 8
+tallsopp
 K 8
 svn:date
 V 27
-2009-10-20T01:33:41.148192Z
+2009-11-12T20:29:42.084439Z
 PROPS-END
 
 Node-path: branches/left
@@ -177,27 +178,54 @@ Node-kind: dir
 Node-action: add
 Node-copyfrom-rev: 1
 Node-copyfrom-path: trunk
-Prop-content-length: 34
-Content-length: 34
 
-K 13
-svn:mergeinfo
-V 0
 
+Node-path: branches/left/Makefile
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/Makefile
+Text-copy-source-md5: bfd8ff778d1492dc6758567373176a89
+Text-copy-source-sha1: 103205ce331f7d64086dba497574734f78439590
+
+
+Revision-number: 4
+Prop-content-length: 120
+Content-length: 120
+
+K 7
+svn:log
+V 17
+make right branch
+K 10
+svn:author
+V 8
+tallsopp
+K 8
+svn:date
+V 27
+2009-11-12T20:29:44.065452Z
 PROPS-END
 
+Node-path: branches/right
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk
+
 
-Node-path: branches/left/Makefile
+Node-path: branches/right/Makefile
 Node-kind: file
 Node-action: add
 Node-copyfrom-rev: 2
 Node-copyfrom-path: trunk/Makefile
 Text-copy-source-md5: bfd8ff778d1492dc6758567373176a89
+Text-copy-source-sha1: 103205ce331f7d64086dba497574734f78439590
 
 
-Revision-number: 4
-Prop-content-length: 112
-Content-length: 112
+Revision-number: 5
+Prop-content-length: 116
+Content-length: 116
 
 K 7
 svn:log
@@ -205,12 +233,12 @@ V 13
 left update 1
 K 10
 svn:author
-V 4
-samv
+V 8
+tallsopp
 K 8
 svn:date
 V 27
-2009-10-20T01:33:42.148773Z
+2009-11-12T20:29:45.066262Z
 PROPS-END
 
 Node-path: branches/left/Makefile
@@ -218,6 +246,7 @@ Node-kind: file
 Node-action: change
 Text-content-length: 2465
 Text-content-md5: 16e38d9753b061731650561ce01b1195
+Text-content-sha1: 36da4b84ea9b64218ab48171dfc5c48ae025f38b
 Content-length: 2465
 
 # -DCOLLISION_CHECK if you believe that SHA1's
@@ -299,9 +328,9 @@ backup: clean
        cd .. ; tar czvf dircache.tar.gz dir-cache
 
 
-Revision-number: 5
-Prop-content-length: 111
-Content-length: 111
+Revision-number: 6
+Prop-content-length: 115
+Content-length: 115
 
 K 7
 svn:log
@@ -309,12 +338,12 @@ V 12
 trunk update
 K 10
 svn:author
-V 4
-samv
+V 8
+tallsopp
 K 8
 svn:date
 V 27
-2009-10-20T01:33:43.159959Z
+2009-11-12T20:29:46.278498Z
 PROPS-END
 
 Node-path: trunk/Makefile
@@ -322,6 +351,7 @@ Node-kind: file
 Node-action: change
 Text-content-length: 2521
 Text-content-md5: 0668418a621333f4aa8b6632cd63e2a0
+Text-content-sha1: 4f29afd038e52f45acb5ef8c41acfc70062a741a
 Content-length: 2521
 
 # -DCOLLISION_CHECK if you believe that SHA1's
@@ -406,9 +436,9 @@ backup: clean
        cd .. ; tar czvf dircache.tar.gz dir-cache
 
 
-Revision-number: 6
-Prop-content-length: 112
-Content-length: 112
+Revision-number: 7
+Prop-content-length: 116
+Content-length: 116
 
 K 7
 svn:log
@@ -416,12 +446,12 @@ V 13
 left update 2
 K 10
 svn:author
-V 4
-samv
+V 8
+tallsopp
 K 8
 svn:date
 V 27
-2009-10-20T01:33:44.164175Z
+2009-11-12T20:29:47.069090Z
 PROPS-END
 
 Node-path: branches/left/Makefile
@@ -429,6 +459,7 @@ Node-kind: file
 Node-action: change
 Text-content-length: 2529
 Text-content-md5: f6b197cc3f2e89a83e545d4bb003de73
+Text-content-sha1: 2f656677cfec0bceec85e53036ffb63e25126f8e
 Content-length: 2529
 
 # -DCOLLISION_CHECK if you believe that SHA1's
@@ -510,9 +541,9 @@ backup: clean
        cd .. ; tar czvf dircache.tar.gz dir-cache
 
 
-Revision-number: 7
-Prop-content-length: 112
-Content-length: 112
+Revision-number: 8
+Prop-content-length: 116
+Content-length: 116
 
 K 7
 svn:log
@@ -520,12 +551,12 @@ V 13
 left update 3
 K 10
 svn:author
-V 4
-samv
+V 8
+tallsopp
 K 8
 svn:date
 V 27
-2009-10-20T01:33:45.144214Z
+2009-11-12T20:29:48.053835Z
 PROPS-END
 
 Node-path: branches/left/Makefile
@@ -533,6 +564,7 @@ Node-kind: file
 Node-action: change
 Text-content-length: 2593
 Text-content-md5: 5ccff689fb290e00b85fe18ee50c54ba
+Text-content-sha1: a13de8e23f1483efca3e57b2b64b0ae6f740ce10
 Content-length: 2593
 
 # -DCOLLISION_CHECK if you believe that SHA1's
@@ -614,22 +646,22 @@ backup: clean
        cd .. ; tar czvf dircache.tar.gz dir-cache
 
 
-Revision-number: 8
-Prop-content-length: 110
-Content-length: 110
+Revision-number: 9
+Prop-content-length: 116
+Content-length: 116
 
 K 7
 svn:log
-V 11
-Merge trunk
+V 13
+Merge trunk 1
 K 10
 svn:author
-V 4
-samv
+V 8
+tallsopp
 K 8
 svn:date
 V 27
-2009-10-20T01:33:48.176135Z
+2009-11-12T20:29:51.098306Z
 PROPS-END
 
 Node-path: trunk
@@ -641,7 +673,7 @@ Content-length: 53
 K 13
 svn:mergeinfo
 V 18
-/branches/left:2-7
+/branches/left:2-8
 PROPS-END
 
 
@@ -650,6 +682,7 @@ Node-kind: file
 Node-action: change
 Text-content-length: 2713
 Text-content-md5: 0afbe34f244cd662b1f97d708c687f90
+Text-content-sha1: 46d9377d783e67a9b581da110352e799517c8a14
 Content-length: 2713
 
 # -DCOLLISION_CHECK if you believe that SHA1's
@@ -734,3 +767,244 @@ backup: clean
        cd .. ; tar czvf dircache.tar.gz dir-cache
 
 
+Revision-number: 10
+Prop-content-length: 116
+Content-length: 116
+
+K 7
+svn:log
+V 13
+left update 4
+K 10
+svn:author
+V 8
+tallsopp
+K 8
+svn:date
+V 27
+2009-11-12T20:29:52.081644Z
+PROPS-END
+
+Node-path: branches/left/Makefile
+Node-kind: file
+Node-action: change
+Text-content-length: 2529
+Text-content-md5: f6b197cc3f2e89a83e545d4bb003de73
+Text-content-sha1: 2f656677cfec0bceec85e53036ffb63e25126f8e
+Content-length: 2529
+
+# -DCOLLISION_CHECK if you believe that SHA1's
+# 1461501637330902918203684832716283019655932542976 hashes do not give you
+# enough guarantees about no collisions between objects ever hapenning.
+#
+# -DNSEC if you want git to care about sub-second file mtimes and ctimes.
+# Note that you need some new glibc (at least >2.2.4) for this, and it will
+# BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely randomly
+# break unless your underlying filesystem supports those sub-second times
+# (my ext3 doesn't).
+CFLAGS=-g -O3 -Wall
+
+CC=gcc
+
+
+PROG=   update-cache show-diff init-db write-tree read-tree commit-tree \
+       cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
+       check-files ls-tree merge-base
+
+all: $(PROG)
+
+install: $(PROG)
+       install $(PROG) $(HOME)/bin/
+
+LIBS= -lssl -lz
+
+init-db: init-db.o
+
+update-cache: update-cache.o read-cache.o
+       $(CC) $(CFLAGS) -o update-cache update-cache.o read-cache.o $(LIBS)
+
+show-diff: show-diff.o read-cache.o
+       $(CC) $(CFLAGS) -o show-diff show-diff.o read-cache.o $(LIBS)
+
+write-tree: write-tree.o read-cache.o
+       $(CC) $(CFLAGS) -o write-tree write-tree.o read-cache.o $(LIBS)
+
+read-tree: read-tree.o read-cache.o
+       $(CC) $(CFLAGS) -o read-tree read-tree.o read-cache.o $(LIBS)
+
+commit-tree: commit-tree.o read-cache.o
+       $(CC) $(CFLAGS) -o commit-tree commit-tree.o read-cache.o $(LIBS)
+
+cat-file: cat-file.o read-cache.o
+       $(CC) $(CFLAGS) -o cat-file cat-file.o read-cache.o $(LIBS)
+
+fsck-cache: fsck-cache.o read-cache.o object.o commit.o tree.o blob.o
+       $(CC) $(CFLAGS) -o fsck-cache fsck-cache.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
+
+checkout-cache: checkout-cache.o read-cache.o
+       $(CC) $(CFLAGS) -o checkout-cache checkout-cache.o read-cache.o $(LIBS)
+
+diff-tree: diff-tree.o read-cache.o
+       $(CC) $(CFLAGS) -o diff-tree diff-tree.o read-cache.o $(LIBS)
+
+rev-tree: rev-tree.o read-cache.o object.o commit.o tree.o blob.o
+       $(CC) $(CFLAGS) -o rev-tree rev-tree.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
+
+show-files: show-files.o read-cache.o
+       $(CC) $(CFLAGS) -o show-files show-files.o read-cache.o $(LIBS)
+
+check-files: check-files.o read-cache.o
+       $(CC) $(CFLAGS) -o check-files check-files.o read-cache.o $(LIBS)
+
+ls-tree: ls-tree.o read-cache.o
+       $(CC) $(CFLAGS) -o ls-tree ls-tree.o read-cache.o $(LIBS)
+
+merge-base: merge-base.o read-cache.o
+       $(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o $(LIBS)
+
+read-cache.o: cache.h
+show-diff.o: cache.h
+
+clean:
+       rm -f *.o $(PROG)
+
+backup: clean
+       cd .. ; tar czvf dircache.tar.gz dir-cache
+
+
+Revision-number: 11
+Prop-content-length: 117
+Content-length: 117
+
+K 7
+svn:log
+V 14
+right update 1
+K 10
+svn:author
+V 8
+tallsopp
+K 8
+svn:date
+V 27
+2009-11-12T20:29:53.059636Z
+PROPS-END
+
+Node-path: branches/right/Makefile
+Node-kind: file
+Node-action: change
+Text-content-length: 2593
+Text-content-md5: 5ccff689fb290e00b85fe18ee50c54ba
+Text-content-sha1: a13de8e23f1483efca3e57b2b64b0ae6f740ce10
+Content-length: 2593
+
+# -DCOLLISION_CHECK if you believe that SHA1's
+# 1461501637330902918203684832716283019655932542976 hashes do not give you
+# enough guarantees about no collisions between objects ever hapenning.
+#
+# -DNSEC if you want git to care about sub-second file mtimes and ctimes.
+# Note that you need some new glibc (at least >2.2.4) for this, and it will
+# BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely randomly
+# break unless your underlying filesystem supports those sub-second times
+# (my ext3 doesn't).
+CFLAGS=-g -O3 -Wall
+
+CC=gcc
+
+
+PROG=   update-cache show-diff init-db write-tree read-tree commit-tree \
+       cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
+       check-files ls-tree merge-base
+
+all: $(PROG)
+
+install: $(PROG)
+       install $(PROG) $(HOME)/bin/
+
+LIBS= -lssl -lz
+
+init-db: init-db.o
+
+update-cache: update-cache.o read-cache.o
+       $(CC) $(CFLAGS) -o update-cache update-cache.o read-cache.o $(LIBS)
+
+show-diff: show-diff.o read-cache.o
+       $(CC) $(CFLAGS) -o show-diff show-diff.o read-cache.o $(LIBS)
+
+write-tree: write-tree.o read-cache.o
+       $(CC) $(CFLAGS) -o write-tree write-tree.o read-cache.o $(LIBS)
+
+read-tree: read-tree.o read-cache.o
+       $(CC) $(CFLAGS) -o read-tree read-tree.o read-cache.o $(LIBS)
+
+commit-tree: commit-tree.o read-cache.o
+       $(CC) $(CFLAGS) -o commit-tree commit-tree.o read-cache.o $(LIBS)
+
+cat-file: cat-file.o read-cache.o
+       $(CC) $(CFLAGS) -o cat-file cat-file.o read-cache.o $(LIBS)
+
+fsck-cache: fsck-cache.o read-cache.o object.o commit.o tree.o blob.o
+       $(CC) $(CFLAGS) -o fsck-cache fsck-cache.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
+
+checkout-cache: checkout-cache.o read-cache.o
+       $(CC) $(CFLAGS) -o checkout-cache checkout-cache.o read-cache.o $(LIBS)
+
+diff-tree: diff-tree.o read-cache.o
+       $(CC) $(CFLAGS) -o diff-tree diff-tree.o read-cache.o $(LIBS)
+
+rev-tree: rev-tree.o read-cache.o object.o commit.o tree.o blob.o
+       $(CC) $(CFLAGS) -o rev-tree rev-tree.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
+
+show-files: show-files.o read-cache.o
+       $(CC) $(CFLAGS) -o show-files show-files.o read-cache.o $(LIBS)
+
+check-files: check-files.o read-cache.o
+       $(CC) $(CFLAGS) -o check-files check-files.o read-cache.o $(LIBS)
+
+ls-tree: ls-tree.o read-cache.o
+       $(CC) $(CFLAGS) -o ls-tree ls-tree.o read-cache.o $(LIBS)
+
+merge-base: merge-base.o read-cache.o object.o commit.o tree.o blob.o
+       $(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
+
+read-cache.o: cache.h
+show-diff.o: cache.h
+
+clean:
+       rm -f *.o $(PROG)
+
+backup: clean
+       cd .. ; tar czvf dircache.tar.gz dir-cache
+
+
+Revision-number: 12
+Prop-content-length: 116
+Content-length: 116
+
+K 7
+svn:log
+V 13
+Merge trunk 2
+K 10
+svn:author
+V 8
+tallsopp
+K 8
+svn:date
+V 27
+2009-11-12T20:29:56.083003Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 54
+Content-length: 54
+
+K 13
+svn:mergeinfo
+V 19
+/branches/left:2-11
+PROPS-END
+
+