{"thread":{"id":"19656","subject":"[PATCHv2 1/2] Limit start revision of find_rev_before to max existing revision","startedAt":"2009-06-04T03:45:51Z","lastAt":"2009-06-04T22:38:42Z","messageCount":3,"participants":["Ben Jackson","Eric Wong"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"115409","messageId":"1244087152-17002-1-git-send-email-ben@ben.com","threadId":"19656","inReplyTo":null,"subject":"[PATCHv2 1/2] Limit start revision of find_rev_before to max existing revision","fromName":"Ben Jackson","fromEmail":"ben@ben.com","sentAt":"2009-06-04T03:45:51Z","receivedAt":"2009-06-04T03:45:51Z","isPatch":false,"sender":{"key":"ben@ben.com","avatar":"https://gravatar.com/avatar/df49904dd23b03a5f57d9d53c0bf9fb6f69a14fac075c98f54f26cf1ce960794?d=mp&s=160"},"body":"Signed-off-by: Ben Jackson <ben@ben.com>\n---\n\nOn Wed, Jun 03, 2009 at 05:24:06PM -0700, Eric Wong wrote:\n>\n> find_rev_before can certainly be improved.  I haven't noticed\n> performance issues with it myself, but you should be able to improve it.\n\nThis avoids a long wait if you do 'git svn reset -r 9999999'.  The\nlinear search within the contiguous revisions doesn't seem to be a\nproblem.\n\n git-svn.perl |    2 ++\n 1 files changed, 2 insertions(+), 0 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 20bf828..b77710c 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -3130,6 +3130,8 @@ sub find_rev_before {\n \tmy ($self, $rev, $eq_ok, $min_rev) = @_;\n \t--$rev unless $eq_ok;\n \t$min_rev ||= 1;\n+\tmy $max_rev = $self->rev_map_max;\n+\t$rev = $max_rev if ($rev > $max_rev);\n \twhile ($rev >= $min_rev) {\n \t\tif (my $c = $self->rev_map_get($rev)) {\n \t\t\treturn ($rev, $c);\n-- \n1.6.3.GIT\n"},{"id":"115410","messageId":"1244087152-17002-2-git-send-email-ben@ben.com","threadId":"19656","inReplyTo":"1244087152-17002-1-git-send-email-ben@ben.com","subject":"[PATCHv2 2/2] Add 'git svn reset' to unwind 'git svn fetch'","fromName":"Ben Jackson","fromEmail":"ben@ben.com","sentAt":"2009-06-04T03:45:52Z","receivedAt":"2009-06-04T03:45:52Z","isPatch":false,"sender":{"key":"ben@ben.com","avatar":"https://gravatar.com/avatar/df49904dd23b03a5f57d9d53c0bf9fb6f69a14fac075c98f54f26cf1ce960794?d=mp&s=160"},"body":"Add a command to unwind the effects of fetch by moving the rev_map\nand refs/remotes/git-svn back to an old SVN revision.  This allows\nrevisions to be re-fetched.  Ideally SVN revs would be immutable,\nbut permissions changes in the SVN repository or indiscriminate use\nof '--ignore-paths' can create situations where fetch cannot make\nprogress.\n\nSigned-off-by: Ben Jackson <ben@ben.com>\n---\n\nUpdate ensures revision input is numeric.\n\nOn Wed, Jun 03, 2009 at 05:24:06PM -0700, Eric Wong wrote:\n> Ben Jackson <ben@ben.com> wrote:\n> > 3.  Without --parent it should probably fail for a nonexistent rev rather\n> > than automatically find_rev_before..\n>\n> Probably best to ignore the --parent flag and just pass 1 as the second\n> argument to find_rev_before.  That's how SVN operations work when a\n> non-exact revision is specified..\n\nThat is how '-r' works.  Passing '1' to find_rev_before *skips* the\ninput rev.  The theory is that you may know that r1000 is \"bad\" and\nso you use 'git svn reset -r1000 --parent' to discard r1000 (while\n'reset -r1000' *keeps* r1000, analagous to 'git reset SHA').  You could\nget the same effect with 'git svn reset -r999' (and internally that's\nidentical).  I looked for a SVN syntax to copy, eg '-r1000^' if it were\nlike GIT, but I didn't see one.  I know I am overloading --parent which\nmeans something else for other git-svn commands, so I'm happy to remove\nthat if you don't like it.\n\n\n Documentation/git-svn.txt |   59 +++++++++++++++++++++++++++++++++++++++-\n git-svn.perl              |   45 +++++++++++++++++++++++++++---\n t/t9139-git-svn-reset.sh  |   66 +++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 164 insertions(+), 6 deletions(-)\n create mode 100755 t/t9139-git-svn-reset.sh\n\ndiff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt\nindex ca3fc3d..e209145 100644\n--- a/Documentation/git-svn.txt\n+++ b/Documentation/git-svn.txt\n@@ -215,7 +215,7 @@ config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)\n The following features from `svn log' are supported:\n +\n --\n---revision=<n>[:<n>];;\n+-r/--revision=<n>[:<n>];;\n \tis supported, non-numeric args are not:\n \tHEAD, NEXT, BASE, PREV, etc ...\n -v/--verbose;;\n@@ -313,6 +313,63 @@ Any other arguments are passed directly to 'git-log'\n \tShows the Subversion externals.  Use -r/--revision to specify a\n \tspecific revision.\n \n+'reset'::\n+\tUndoes the effects of 'fetch' back to the specified revision.\n+\tThis allows you to re-'fetch' an SVN revision.  Normally the\n+\tcontents of an SVN revision should never change and 'reset'\n+\tshould not be necessary.  However, if SVN permissions change,\n+\tor if you alter your --ignore-paths option, a 'fetch' may fail\n+\twith \"not found in commit\" (file not previously visible) or\n+\t\"checksum mismatch\" (missed a modification).  If the problem\n+\tfile cannot be ignored forever (with --ignore-paths) the only\n+\tway to repair the repo is to use 'reset'.\n+\n+Only the rev_map and refs/remotes/git-svn are changed.  Follow 'reset'\n+with a 'fetch' and then 'git-reset' or 'git-rebase' to move local\n+branches onto the new tree.\n+\n+-r/--revision=<n>;;\n+\tSpecify the most recent revision to keep.  All later revisions\n+\tare discarded.\n+-p/--parent;;\n+\tDiscard the specified revision as well, keeping the nearest\n+\tparent instead.\n+Example:;;\n+Assume you have local changes in \"master\", but you need to refetch \"r2\".\n+\n+------------\n+    r1---r2---r3 remotes/git-svn\n+                \\\n+                 A---B master\n+------------\n+\n+Fix the ignore-paths or SVN permissions problem that caused \"r2\" to\n+be incomplete in the first place.  Then:\n+\n+[verse]\n+git svn reset -r2 -p\n+git svn fetch\n+\n+------------\n+    r1---r2'--r3' remotes/git-svn\n+      \\\n+       r2---r3---A---B master\n+------------\n+\n+Then fixup \"master\" with 'git-rebase'.\n+Do NOT use 'git-merge' or your history will not be compatible with a\n+future 'dcommit'!\n+\n+[verse]\n+git rebase --onto remotes/git-svn A^ master\n+\n+------------\n+    r1---r2'--r3' remotes/git-svn\n+                \\\n+                 A'--B' master\n+------------\n+\n+\n --\n \n OPTIONS\ndiff --git a/git-svn.perl b/git-svn.perl\nindex b77710c..dcbf397 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -211,6 +211,10 @@ my %cmd = (\n \t'blame' => [ \\&Git::SVN::Log::cmd_blame,\n \t            \"Show what revision and author last modified each line of a file\",\n \t\t    { 'git-format' => \\$_git_format } ],\n+\t'reset' => [ \\&cmd_reset,\n+\t\t     \"Undo fetches back to the specified SVN revision\",\n+\t\t     { 'revision|r=s' => \\$_revision,\n+\t\t       'parent|p' => \\$_fetch_parent } ],\n );\n \n my $cmd;\n@@ -1024,6 +1028,20 @@ sub cmd_info {\n \tprint $result, \"\\n\";\n }\n \n+sub cmd_reset {\n+\tmy $target = shift || $_revision or die \"SVN revision required\\n\";\n+\t$target = $1 if $target =~ /^r(\\d+)$/;\n+\t$target =~ /^\\d+$/ or die \"Numeric SVN revision expected\\n\";\n+\tmy ($url, $rev, $uuid, $gs) = working_head_info('HEAD');\n+\tunless ($gs) {\n+\t\tdie \"Unable to determine upstream SVN information from \".\n+\t\t    \"history\\n\";\n+\t}\n+\tmy ($r, $c) = $gs->find_rev_before($target, not $_fetch_parent);\n+\t$gs->rev_map_set($r, $c, 'reset', $uuid);\n+\tprint \"r$r = $c ($gs->{ref_id})\\n\";\n+}\n+\n ########################### utility functions #########################\n \n sub rebase_cmd {\n@@ -2982,6 +3000,14 @@ sub _rev_map_set {\n \t  croak \"write: $!\";\n }\n \n+sub _rev_map_reset {\n+\tmy ($fh, $rev, $commit) = @_;\n+\tmy $c = _rev_map_get($fh, $rev);\n+\t$c eq $commit or die \"_rev_map_reset(@_) commit $c does not match!\\n\";\n+\tmy $offset = sysseek($fh, 0, SEEK_CUR) or croak \"seek: $!\";\n+\ttruncate $fh, $offset or croak \"truncate: $!\";\n+}\n+\n sub mkfile {\n \tmy ($path) = @_;\n \tunless (-e $path) {\n@@ -2998,6 +3024,7 @@ sub rev_map_set {\n \tmy $db = $self->map_path($uuid);\n \tmy $db_lock = \"$db.lock\";\n \tmy $sig;\n+\t$update_ref ||= 0;\n \tif ($update_ref) {\n \t\t$SIG{INT} = $SIG{HUP} = $SIG{TERM} = $SIG{ALRM} = $SIG{PIPE} =\n \t\t            $SIG{USR1} = $SIG{USR2} = sub { $sig = $_[0] };\n@@ -3021,7 +3048,8 @@ sub rev_map_set {\n \n \tsysopen(my $fh, $db_lock, O_RDWR | O_CREAT)\n \t     or croak \"Couldn't open $db_lock: $!\\n\";\n-\t_rev_map_set($fh, $rev, $commit);\n+\t$update_ref eq 'reset' ? _rev_map_reset($fh, $rev, $commit) :\n+\t\t\t\t _rev_map_set($fh, $rev, $commit);\n \tif ($sync) {\n \t\t$fh->flush or die \"Couldn't flush $db_lock: $!\\n\";\n \t\t$fh->sync or die \"Couldn't sync $db_lock: $!\\n\";\n@@ -3029,7 +3057,9 @@ sub rev_map_set {\n \tclose $fh or croak $!;\n \tif ($update_ref) {\n \t\t$_head = $self;\n-\t\tcommand_noisy('update-ref', '-m', \"r$rev\",\n+\t\tmy $note = \"\";\n+\t\t$note = \" ($update_ref)\" if ($update_ref !~ /^\\d*$/);\n+\t\tcommand_noisy('update-ref', '-m', \"r$rev$note\",\n \t\t              $self->refname, $commit);\n \t}\n \trename $db_lock, $db or die \"rev_map_set(@_): \", \"Failed to rename: \",\n@@ -3091,12 +3121,19 @@ sub rev_map_get {\n \treturn undef unless -e $map_path;\n \n \tsysopen(my $fh, $map_path, O_RDONLY) or croak \"open: $!\";\n+\tmy $c = _rev_map_get($fh, $rev);\n+\tclose($fh) or croak \"close: $!\";\n+\t$c\n+}\n+\n+sub _rev_map_get {\n+\tmy ($fh, $rev) = @_;\n+\n \tbinmode $fh or croak \"binmode: $!\";\n \tmy $size = (stat($fh))[7];\n \t($size % 24) == 0 or croak \"inconsistent size: $size\";\n \n \tif ($size == 0) {\n-\t\tclose $fh or croak \"close: $fh\";\n \t\treturn undef;\n \t}\n \n@@ -3114,11 +3151,9 @@ sub rev_map_get {\n \t\t} elsif ($r > $rev) {\n \t\t\t$u = $i - 24;\n \t\t} else { # $r == $rev\n-\t\t\tclose($fh) or croak \"close: $!\";\n \t\t\treturn $c eq ('0' x 40) ? undef : $c;\n \t\t}\n \t}\n-\tclose($fh) or croak \"close: $!\";\n \tundef;\n }\n \ndiff --git a/t/t9139-git-svn-reset.sh b/t/t9139-git-svn-reset.sh\nnew file mode 100755\nindex 0000000..0735526\n--- /dev/null\n+++ b/t/t9139-git-svn-reset.sh\n@@ -0,0 +1,66 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2009 Ben Jackson\n+#\n+\n+test_description='git svn reset'\n+. ./lib-git-svn.sh\n+\n+test_expect_success 'setup test repository' '\n+\tsvn_cmd co \"$svnrepo\" s &&\n+\t(\n+\t\tcd s &&\n+\t\tmkdir vis &&\n+\t\techo always visible > vis/vis.txt &&\n+\t\tsvn_cmd add vis &&\n+\t\tsvn_cmd commit -m \"create visible files\" &&\n+\t\tmkdir hid &&\n+\t\techo initially hidden > hid/hid.txt &&\n+\t\tsvn_cmd add hid &&\n+\t\tsvn_cmd commit -m \"create initially hidden files\" &&\n+\t\tsvn_cmd up &&\n+\t\techo mod >> vis/vis.txt &&\n+\t\tsvn_cmd commit -m \"modify vis\" &&\n+\t\tsvn_cmd up\n+\t)\n+'\n+\n+test_expect_success 'clone SVN repository with hidden directory' '\n+\tgit svn init \"$svnrepo\" g &&\n+\t( cd g && git svn fetch --ignore-paths=\"^hid\" )\n+'\n+\n+test_expect_success 'modify hidden file in SVN repo' '\n+\t( cd s &&\n+\t  echo mod hidden >> hid/hid.txt &&\n+\t  svn_cmd commit -m \"modify hid\" &&\n+\t  svn_cmd up\n+\t)\n+'\n+\n+test_expect_success 'fetch fails on modified hidden file' '\n+\t( cd g &&\n+\t  git svn find-rev refs/remotes/git-svn > ../expect &&\n+\t  ! git svn fetch 2> ../errors &&\n+\t  git svn find-rev refs/remotes/git-svn > ../expect2 ) &&\n+\tfgrep \"not found in commit\" errors &&\n+\ttest_cmp expect expect2\n+'\n+\n+test_expect_success 'reset unwinds back to r1' '\n+\t( cd g &&\n+\t  git svn reset -r1 &&\n+\t  git svn find-rev refs/remotes/git-svn > ../expect2 ) &&\n+\techo 1 >expect &&\n+\ttest_cmp expect expect2\n+'\n+\n+test_expect_success 'refetch succeeds not ignoring any files' '\n+\t( cd g &&\n+\t  git svn fetch &&\n+\t  git svn rebase &&\n+\t  fgrep \"mod hidden\" hid/hid.txt\n+\t)\n+'\n+\n+test_done\n-- \n1.6.3.GIT\n"},{"id":"115457","messageId":"20090604223842.GA32010@dcvr.yhbt.net","threadId":"19656","inReplyTo":"1244087152-17002-2-git-send-email-ben@ben.com","subject":"Re: [PATCHv2 2/2] Add 'git svn reset' to unwind 'git svn fetch'","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2009-06-04T22:38:42Z","receivedAt":"2009-06-04T22:38:42Z","isPatch":false,"sender":{"key":"e@80x24.org","avatar":null},"body":"Ben Jackson <ben@ben.com> wrote:\n> Add a command to unwind the effects of fetch by moving the rev_map\n> and refs/remotes/git-svn back to an old SVN revision.  This allows\n> revisions to be re-fetched.  Ideally SVN revs would be immutable,\n> but permissions changes in the SVN repository or indiscriminate use\n> of '--ignore-paths' can create situations where fetch cannot make\n> progress.\n> \n> Signed-off-by: Ben Jackson <ben@ben.com>\n> ---\n> \n> Update ensures revision input is numeric.\n> \n> On Wed, Jun 03, 2009 at 05:24:06PM -0700, Eric Wong wrote:\n> > Ben Jackson <ben@ben.com> wrote:\n> > > 3.  Without --parent it should probably fail for a nonexistent rev rather\n> > > than automatically find_rev_before..\n> >\n> > Probably best to ignore the --parent flag and just pass 1 as the second\n> > argument to find_rev_before.  That's how SVN operations work when a\n> > non-exact revision is specified..\n> \n> That is how '-r' works.  Passing '1' to find_rev_before *skips* the\n> input rev.  The theory is that you may know that r1000 is \"bad\" and\n> so you use 'git svn reset -r1000 --parent' to discard r1000 (while\n> 'reset -r1000' *keeps* r1000, analagous to 'git reset SHA').  You could\n> get the same effect with 'git svn reset -r999' (and internally that's\n> identical).  I looked for a SVN syntax to copy, eg '-r1000^' if it were\n> like GIT, but I didn't see one.  I know I am overloading --parent which\n> means something else for other git-svn commands, so I'm happy to remove\n> that if you don't like it.\n\nAh, I always subconciously just decremented the revision number\nby 1 myself.  Maybe adding \"^\"/\"~\" handling to git-svn to handle\nSVN revisions would work, too, but --parent is fine, I guess.\n\nThis series acked and pushed out to git://git.bogomips.org/git-svn\n\n-- \nEric Wong\n"}]}