{"thread":{"id":"24747","subject":"[PATCH 2/2] git-svn: fix fetch with deleted tag","startedAt":"2010-08-15T13:15:55Z","lastAt":"2010-08-15T13:15:55Z","messageCount":1,"participants":["David D. Kilzer"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"148136","messageId":"1281878155-61937-2-git-send-email-ddkilzer@kilzer.net","threadId":"24747","inReplyTo":null,"subject":"[PATCH 2/2] git-svn: fix fetch with deleted tag","fromName":"David D. Kilzer","fromEmail":"ddkilzer@kilzer.net","sentAt":"2010-08-15T13:15:55Z","receivedAt":"2010-08-15T13:15:55Z","isPatch":true,"sender":{"key":"ddkilzer@kilzer.net","avatar":"https://avatars.githubusercontent.com/u/263571?v=4"},"body":"Currently git-svn assumes that two tags created from the same\nrevision will have the same repo url, so it uses a ref to the\ntag without checking that its url matches the current url.\n\nThis causes issues when fetching an svn repo where a tag was\ncreated, deleted, and then recreated under the following\ncircumstances:\n\n- Both tags were copied from the same revision.\n- Both tags had the same name.\n- Both tags had different repository paths.\n- [Optional] Both tags have a file with the same name but\n  different content.\n\nWhen all four conditions are met, a checksum mismatch error\noccurs because the content of two files with the same path\ndiffers (see t/t9155--git-svn-fetch-deleted-tag.sh):\n\n    Checksum mismatch: ChangeLog 065854....\n    expected: ce771b....\n         got: 9563fd....\n\nWhen only the first three conditions are met, no error occurs\nbut the tag in git matches the first (deleted) tag instead of\nthe last (most recent) tag (see\nt/t9156-git-svn-fetch-deleted-tag-2.sh).\n\nThe fix is to verify that the repo url for the ref matches the\ncurrent url.  If the urls do not match, then a \"tail\" is grown\non the tag name by appending a dash and rechecking the new ref's\nrepo url until either a matching repo url is found or a new tag\nis created.\n\nSigned-off-by: David D. Kilzer <ddkilzer@kilzer.net>\n---\n git-svn.perl                           |   15 +++++++++-\n t/t9155-git-svn-fetch-deleted-tag.sh   |   42 ++++++++++++++++++++++++++++++\n t/t9156-git-svn-fetch-deleted-tag-2.sh |   44 ++++++++++++++++++++++++++++++++\n 3 files changed, 99 insertions(+), 2 deletions(-)\n create mode 100755 t/t9155-git-svn-fetch-deleted-tag.sh\n create mode 100755 t/t9156-git-svn-fetch-deleted-tag-2.sh\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 39bcb45..9b046b6 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -2963,14 +2963,25 @@ sub other_gs {\n \t\t$ref_id .= \"\\@$r\";\n \t\t# just grow a tail if we're not unique enough :x\n \t\t$ref_id .= '-' while find_ref($ref_id);\n-\t\tprint STDERR \"Initializing parent: $ref_id\\n\" unless $::_q > 1;\n \t\tmy ($u, $p, $repo_id) = ($new_url, '', $ref_id);\n \t\tif ($u =~ s#^\\Q$url\\E(/|$)##) {\n \t\t\t$p = $u;\n \t\t\t$u = $url;\n \t\t\t$repo_id = $self->{repo_id};\n \t\t}\n-\t\t$gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1);\n+\t\twhile (1) {\n+\t\t\t# It is possible to tag two different subdirectories at\n+\t\t\t# the same revision.  If the url for an existing ref\n+\t\t\t# does not match, we must either find a ref with a\n+\t\t\t# matching url or create a new ref by growing a tail.\n+\t\t\t$gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1);\n+\t\t\tmy (undef, $max_commit) = $gs->rev_map_max(1);\n+\t\t\tlast if (!$max_commit);\n+\t\t\tmy ($url) = ::cmt_metadata($max_commit);\n+\t\t\tlast if ($url eq $gs->full_url);\n+\t\t\t$ref_id .= '-';\n+\t\t}\n+\t\tprint STDERR \"Initializing parent: $ref_id\\n\" unless $::_q > 1;\n \t}\n \t$gs\n }\ndiff --git a/t/t9155-git-svn-fetch-deleted-tag.sh b/t/t9155-git-svn-fetch-deleted-tag.sh\nnew file mode 100755\nindex 0000000..ef0ac87\n--- /dev/null\n+++ b/t/t9155-git-svn-fetch-deleted-tag.sh\n@@ -0,0 +1,42 @@\n+#!/bin/sh\n+\n+test_description='git svn fetch deleted tag'\n+\n+. ./lib-git-svn.sh\n+\n+test_expect_success 'setup svn repo' '\n+\tmkdir -p import/trunk/subdir &&\n+\tmkdir -p import/branches &&\n+\tmkdir -p import/tags &&\n+\techo \"base\" >import/trunk/subdir/file &&\n+\tsvn_cmd import -m \"import for git svn\" import \"$svnrepo\" &&\n+\trm -rf import &&\n+\n+\tsvn_cmd mkdir --parents -m \"create mybranch directory\" \"$svnrepo/branches/mybranch\" &&\n+\tsvn_cmd cp -m \"create branch mybranch\" \"$svnrepo/trunk\" \"$svnrepo/branches/mybranch/trunk\" &&\n+\n+\tsvn_cmd co \"$svnrepo/trunk\" svn_project &&\n+\t(cd svn_project &&\n+\t\techo \"trunk change\" >>subdir/file &&\n+\t\tsvn_cmd ci -m \"trunk change\" subdir/file &&\n+\n+\t\tsvn_cmd switch \"$svnrepo/branches/mybranch/trunk\" &&\n+\t\techo \"branch change\" >>subdir/file &&\n+\t\tsvn_cmd ci -m \"branch change\" subdir/file\n+\t) &&\n+\n+\tsvn_cmd cp -m \"create mytag attempt 1\" -r5 \"$svnrepo/trunk/subdir\" \"$svnrepo/tags/mytag\" &&\n+\tsvn_cmd rm -m \"delete mytag attempt 1\" \"$svnrepo/tags/mytag\" &&\n+\tsvn_cmd cp -m \"create mytag attempt 2\" -r5 \"$svnrepo/branches/mybranch/trunk/subdir\" \"$svnrepo/tags/mytag\"\n+'\n+\n+test_expect_success 'fetch deleted tags from same revision with checksum error' '\n+\tgit svn init --stdlayout \"$svnrepo\" git_project &&\n+\tcd git_project &&\n+\tgit svn fetch &&\n+\n+\tgit diff --exit-code mybranch:trunk/subdir/file tags/mytag:file &&\n+\tgit diff --exit-code master:subdir/file tags/mytag^:file\n+'\n+\n+test_done\ndiff --git a/t/t9156-git-svn-fetch-deleted-tag-2.sh b/t/t9156-git-svn-fetch-deleted-tag-2.sh\nnew file mode 100755\nindex 0000000..5ce7e2f\n--- /dev/null\n+++ b/t/t9156-git-svn-fetch-deleted-tag-2.sh\n@@ -0,0 +1,44 @@\n+#!/bin/sh\n+\n+test_description='git svn fetch deleted tag 2'\n+\n+. ./lib-git-svn.sh\n+\n+test_expect_success 'setup svn repo' '\n+\tmkdir -p import/branches &&\n+\tmkdir -p import/tags &&\n+\tmkdir -p import/trunk/subdir1 &&\n+\tmkdir -p import/trunk/subdir2 &&\n+\tmkdir -p import/trunk/subdir3 &&\n+\techo \"file1\" >import/trunk/subdir1/file &&\n+\techo \"file2\" >import/trunk/subdir2/file &&\n+\techo \"file3\" >import/trunk/subdir3/file &&\n+\tsvn_cmd import -m \"import for git svn\" import \"$svnrepo\" &&\n+\trm -rf import &&\n+\n+\tsvn_cmd co \"$svnrepo/trunk\" svn_project &&\n+\t(cd svn_project &&\n+\t\techo \"change1\" >>subdir1/file &&\n+\t\techo \"change2\" >>subdir2/file &&\n+\t\techo \"change3\" >>subdir3/file &&\n+\t\tsvn_cmd ci -m \"change\" .\n+\t) &&\n+\n+\tsvn_cmd cp -m \"create mytag 1\" -r2 \"$svnrepo/trunk/subdir1\" \"$svnrepo/tags/mytag\" &&\n+\tsvn_cmd rm -m \"delete mytag 1\" \"$svnrepo/tags/mytag\" &&\n+\tsvn_cmd cp -m \"create mytag 2\" -r2 \"$svnrepo/trunk/subdir2\" \"$svnrepo/tags/mytag\" &&\n+\tsvn_cmd rm -m \"delete mytag 2\" \"$svnrepo/tags/mytag\" &&\n+\tsvn_cmd cp -m \"create mytag 3\" -r2 \"$svnrepo/trunk/subdir3\" \"$svnrepo/tags/mytag\"\n+'\n+\n+test_expect_success 'fetch deleted tags from same revision with no checksum error' '\n+\tgit svn init --stdlayout \"$svnrepo\" git_project &&\n+\tcd git_project &&\n+\tgit svn fetch &&\n+\n+\tgit diff --exit-code master:subdir3/file tags/mytag:file &&\n+\tgit diff --exit-code master:subdir2/file tags/mytag^:file &&\n+\tgit diff --exit-code master:subdir1/file tags/mytag^^:file\n+'\n+\n+test_done\n-- \n1.7.2.1.49.g98551\n"}]}