git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 1/2] Add 'git svn help [cmd]' which works outside a repo.
@ 2009-05-31  1:17 Ben Jackson
  2009-05-31  1:17 ` [PATCH 2/2] Add 'git svn reset' to unwind 'git svn fetch' Ben Jackson
  2009-06-04  2:48 ` [PATCH 1/2] Add 'git svn help [cmd]' which works outside a repo Eric Wong
  0 siblings, 2 replies; 5+ messages in thread
From: Ben Jackson @ 2009-05-31  1:17 UTC (permalink / raw)
  To: git; +Cc: gitster, normalperson, Ben Jackson

Previously there was no explicit 'help' command, but 'git svn help'
still printed the usage message (as an invalid command), provided you
got past the initialization steps that required a valid repo.

Signed-off-by: Ben Jackson <ben@ben.com>
---

This was just a minor nit I noticed while working on the 'git-svn reset'
patch.

 git-svn.perl |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index a70c7d7..20bf828 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -219,6 +219,9 @@ for (my $i = 0; $i < @ARGV; $i++) {
 		$cmd = $ARGV[$i];
 		splice @ARGV, $i, 1;
 		last;
+	} elsif ($ARGV[$i] eq 'help') {
+		$cmd = $ARGV[$i+1];
+		usage(0);
 	}
 };
 
-- 
1.6.3.GIT

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] Add 'git svn reset' to unwind 'git svn fetch'
  2009-05-31  1:17 [PATCH 1/2] Add 'git svn help [cmd]' which works outside a repo Ben Jackson
@ 2009-05-31  1:17 ` Ben Jackson
  2009-06-01 17:49   ` Ben Jackson
  2009-06-04  2:48 ` [PATCH 1/2] Add 'git svn help [cmd]' which works outside a repo Eric Wong
  1 sibling, 1 reply; 5+ messages in thread
From: Ben Jackson @ 2009-05-31  1:17 UTC (permalink / raw)
  To: git; +Cc: gitster, normalperson, Ben Jackson

Add a command to unwind the effects of fetch by moving the rev_map
and refs/remotes/git-svn back to an old SVN revision.  This allows
revisions to be re-fetched.  Ideally SVN revs would be immutable,
but permissions changes in the SVN repository or indiscriminate use
of '--ignore-paths' can create situations where fetch cannot make
progress.

Signed-off-by: Ben Jackson <ben@ben.com>
---

I ran into a situation at work where a directory in our SVN repo was
hidden from me using SVN permissions.  Many, many revisions later the
security settings were changed which exposed those files to me.  The
permissions change is NOT a revision-controlled event, so from the
perspective of git-svn there were ollld revisions which actually
changed content.  As soon as someone checked in a change to one of the
newly visible files, 'git-svn fetch' would fail with the dreaded "file
not found in commit" errors.

I solved my problem by modifying my ignore-paths config to restore the
status quo.  I did look into what would be necessary to fix it, though,
and 'git-svn reset' is the result.  The code changes are actually pretty
minor.  They're dwarfed by the docs and the tests.

 Documentation/git-svn.txt |   59 +++++++++++++++++++++++++++++++++++++++-
 git-svn.perl              |   44 ++++++++++++++++++++++++++---
 t/t9139-git-svn-reset.sh  |   66 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 163 insertions(+), 6 deletions(-)
 create mode 100755 t/t9139-git-svn-reset.sh

diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index ca3fc3d..e209145 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -215,7 +215,7 @@ config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)
 The following features from `svn log' are supported:
 +
 --
---revision=<n>[:<n>];;
+-r/--revision=<n>[:<n>];;
 	is supported, non-numeric args are not:
 	HEAD, NEXT, BASE, PREV, etc ...
 -v/--verbose;;
@@ -313,6 +313,63 @@ Any other arguments are passed directly to 'git-log'
 	Shows the Subversion externals.  Use -r/--revision to specify a
 	specific revision.
 
+'reset'::
+	Undoes the effects of 'fetch' back to the specified revision.
+	This allows you to re-'fetch' an SVN revision.  Normally the
+	contents of an SVN revision should never change and 'reset'
+	should not be necessary.  However, if SVN permissions change,
+	or if you alter your --ignore-paths option, a 'fetch' may fail
+	with "not found in commit" (file not previously visible) or
+	"checksum mismatch" (missed a modification).  If the problem
+	file cannot be ignored forever (with --ignore-paths) the only
+	way to repair the repo is to use 'reset'.
+
+Only the rev_map and refs/remotes/git-svn are changed.  Follow 'reset'
+with a 'fetch' and then 'git-reset' or 'git-rebase' to move local
+branches onto the new tree.
+
+-r/--revision=<n>;;
+	Specify the most recent revision to keep.  All later revisions
+	are discarded.
+-p/--parent;;
+	Discard the specified revision as well, keeping the nearest
+	parent instead.
+Example:;;
+Assume you have local changes in "master", but you need to refetch "r2".
+
+------------
+    r1---r2---r3 remotes/git-svn
+                \
+                 A---B master
+------------
+
+Fix the ignore-paths or SVN permissions problem that caused "r2" to
+be incomplete in the first place.  Then:
+
+[verse]
+git svn reset -r2 -p
+git svn fetch
+
+------------
+    r1---r2'--r3' remotes/git-svn
+      \
+       r2---r3---A---B master
+------------
+
+Then fixup "master" with 'git-rebase'.
+Do NOT use 'git-merge' or your history will not be compatible with a
+future 'dcommit'!
+
+[verse]
+git rebase --onto remotes/git-svn A^ master
+
+------------
+    r1---r2'--r3' remotes/git-svn
+                \
+                 A'--B' master
+------------
+
+
 --
 
 OPTIONS
diff --git a/git-svn.perl b/git-svn.perl
index 20bf828..2ff6bb0 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -211,6 +211,10 @@ my %cmd = (
 	'blame' => [ \&Git::SVN::Log::cmd_blame,
 	            "Show what revision and author last modified each line of a file",
 		    { 'git-format' => \$_git_format } ],
+	'reset' => [ \&cmd_reset,
+		     "Undo fetches back to the specified SVN revision",
+		     { 'revision|r=s' => \$_revision,
+		       'parent|p' => \$_fetch_parent } ],
 );
 
 my $cmd;
@@ -1024,6 +1028,19 @@ sub cmd_info {
 	print $result, "\n";
 }
 
+sub cmd_reset {
+	my $target = shift || $_revision or die "SVN revision required\n";
+	$target = $1 if $target =~ /^r(\d+)/;
+	my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
+	unless ($gs) {
+		die "Unable to determine upstream SVN information from ".
+		    "history\n";
+	}
+	my ($r, $c) = $gs->find_rev_before($target, not $_fetch_parent);
+	$gs->rev_map_set($r, $c, 'reset', $uuid);
+	print "r$r = $c ($gs->{ref_id})\n";
+}
+
 ########################### utility functions #########################
 
 sub rebase_cmd {
@@ -2982,6 +2999,14 @@ sub _rev_map_set {
 	  croak "write: $!";
 }
 
+sub _rev_map_reset {
+	my ($fh, $rev, $commit) = @_;
+	my $c = _rev_map_get($fh, $rev);
+	$c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n";
+	my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!";
+	truncate $fh, $offset or croak "truncate: $!";
+}
+
 sub mkfile {
 	my ($path) = @_;
 	unless (-e $path) {
@@ -2998,6 +3023,7 @@ sub rev_map_set {
 	my $db = $self->map_path($uuid);
 	my $db_lock = "$db.lock";
 	my $sig;
+	$update_ref ||= 0;
 	if ($update_ref) {
 		$SIG{INT} = $SIG{HUP} = $SIG{TERM} = $SIG{ALRM} = $SIG{PIPE} =
 		            $SIG{USR1} = $SIG{USR2} = sub { $sig = $_[0] };
@@ -3021,7 +3047,8 @@ sub rev_map_set {
 
 	sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)
 	     or croak "Couldn't open $db_lock: $!\n";
-	_rev_map_set($fh, $rev, $commit);
+	$update_ref eq 'reset' ? _rev_map_reset($fh, $rev, $commit) :
+				 _rev_map_set($fh, $rev, $commit);
 	if ($sync) {
 		$fh->flush or die "Couldn't flush $db_lock: $!\n";
 		$fh->sync or die "Couldn't sync $db_lock: $!\n";
@@ -3029,7 +3056,9 @@ sub rev_map_set {
 	close $fh or croak $!;
 	if ($update_ref) {
 		$_head = $self;
-		command_noisy('update-ref', '-m', "r$rev",
+		my $note = "";
+		$note = " ($update_ref)" if ($update_ref !~ /^\d*$/);
+		command_noisy('update-ref', '-m', "r$rev$note",
 		              $self->refname, $commit);
 	}
 	rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ",
@@ -3091,12 +3120,19 @@ sub rev_map_get {
 	return undef unless -e $map_path;
 
 	sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
+	my $c = _rev_map_get($fh, $rev);
+	close($fh) or croak "close: $!";
+	$c
+}
+
+sub _rev_map_get {
+	my ($fh, $rev) = @_;
+
 	binmode $fh or croak "binmode: $!";
 	my $size = (stat($fh))[7];
 	($size % 24) == 0 or croak "inconsistent size: $size";
 
 	if ($size == 0) {
-		close $fh or croak "close: $fh";
 		return undef;
 	}
 
@@ -3114,11 +3150,9 @@ sub rev_map_get {
 		} elsif ($r > $rev) {
 			$u = $i - 24;
 		} else { # $r == $rev
-			close($fh) or croak "close: $!";
 			return $c eq ('0' x 40) ? undef : $c;
 		}
 	}
-	close($fh) or croak "close: $!";
 	undef;
 }
 
diff --git a/t/t9139-git-svn-reset.sh b/t/t9139-git-svn-reset.sh
new file mode 100755
index 0000000..0735526
--- /dev/null
+++ b/t/t9139-git-svn-reset.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Ben Jackson
+#
+
+test_description='git svn reset'
+. ./lib-git-svn.sh
+
+test_expect_success 'setup test repository' '
+	svn_cmd co "$svnrepo" s &&
+	(
+		cd s &&
+		mkdir vis &&
+		echo always visible > vis/vis.txt &&
+		svn_cmd add vis &&
+		svn_cmd commit -m "create visible files" &&
+		mkdir hid &&
+		echo initially hidden > hid/hid.txt &&
+		svn_cmd add hid &&
+		svn_cmd commit -m "create initially hidden files" &&
+		svn_cmd up &&
+		echo mod >> vis/vis.txt &&
+		svn_cmd commit -m "modify vis" &&
+		svn_cmd up
+	)
+'
+
+test_expect_success 'clone SVN repository with hidden directory' '
+	git svn init "$svnrepo" g &&
+	( cd g && git svn fetch --ignore-paths="^hid" )
+'
+
+test_expect_success 'modify hidden file in SVN repo' '
+	( cd s &&
+	  echo mod hidden >> hid/hid.txt &&
+	  svn_cmd commit -m "modify hid" &&
+	  svn_cmd up
+	)
+'
+
+test_expect_success 'fetch fails on modified hidden file' '
+	( cd g &&
+	  git svn find-rev refs/remotes/git-svn > ../expect &&
+	  ! git svn fetch 2> ../errors &&
+	  git svn find-rev refs/remotes/git-svn > ../expect2 ) &&
+	fgrep "not found in commit" errors &&
+	test_cmp expect expect2
+'
+
+test_expect_success 'reset unwinds back to r1' '
+	( cd g &&
+	  git svn reset -r1 &&
+	  git svn find-rev refs/remotes/git-svn > ../expect2 ) &&
+	echo 1 >expect &&
+	test_cmp expect expect2
+'
+
+test_expect_success 'refetch succeeds not ignoring any files' '
+	( cd g &&
+	  git svn fetch &&
+	  git svn rebase &&
+	  fgrep "mod hidden" hid/hid.txt
+	)
+'
+
+test_done
-- 
1.6.3.GIT

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] Add 'git svn reset' to unwind 'git svn fetch'
  2009-05-31  1:17 ` [PATCH 2/2] Add 'git svn reset' to unwind 'git svn fetch' Ben Jackson
@ 2009-06-01 17:49   ` Ben Jackson
  2009-06-04  0:24     ` Eric Wong
  0 siblings, 1 reply; 5+ messages in thread
From: Ben Jackson @ 2009-06-01 17:49 UTC (permalink / raw)
  To: git; +Cc: gitster, normalperson, ben

On Sat, May 30, 2009 at 06:17:07PM -0700, Ben Jackson wrote:
> Add a command to unwind the effects of fetch by moving the rev_map
> and refs/remotes/git-svn back to an old SVN revision.

I just realized this morning that I didn't do any special handling for
bad revision input.  I will submit a revised patch.  In the mean time
I would still like feedback on the concept and the docs.

Known issues:

1.  Garbage revision input is accepted and prints several internal errors
before bombing out.  The repo is not harmed, though.

2.  Huge revision numbers cause git-svn to spin for quite a while because
I used the pre-existing find_rev_before which is a linear search.

3.  Without --parent it should probably fail for a nonexistent rev rather
than automatically find_rev_before..

-- 
Ben Jackson AD7GD
<ben@ben.com>
http://www.ben.com/

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] Add 'git svn reset' to unwind 'git svn fetch'
  2009-06-01 17:49   ` Ben Jackson
@ 2009-06-04  0:24     ` Eric Wong
  0 siblings, 0 replies; 5+ messages in thread
From: Eric Wong @ 2009-06-04  0:24 UTC (permalink / raw)
  To: Ben Jackson; +Cc: git, gitster

Ben Jackson <ben@ben.com> wrote:
> On Sat, May 30, 2009 at 06:17:07PM -0700, Ben Jackson wrote:
> > Add a command to unwind the effects of fetch by moving the rev_map
> > and refs/remotes/git-svn back to an old SVN revision.
> 
> I just realized this morning that I didn't do any special handling for
> bad revision input.  I will submit a revised patch.  In the mean time
> I would still like feedback on the concept and the docs.

Hi Ben,

Sorry for the late response, I've been distracted with other projects.
I like the overall idea of it, it would actually be useful for
developing/debugging git-svn as well :)

> Known issues:
> 
> 1.  Garbage revision input is accepted and prints several internal errors
> before bombing out.  The repo is not harmed, though.
> 
> 2.  Huge revision numbers cause git-svn to spin for quite a while because
> I used the pre-existing find_rev_before which is a linear search.

find_rev_before can certainly be improved.  I haven't noticed
performance issues with it myself, but you should be able to improve it.

> 3.  Without --parent it should probably fail for a nonexistent rev rather
> than automatically find_rev_before..

Probably best to ignore the --parent flag and just pass 1 as the second
argument to find_rev_before.  That's how SVN operations work when a
non-exact revision is specified..

-- 
Eric Wong

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] Add 'git svn help [cmd]' which works outside a repo.
  2009-05-31  1:17 [PATCH 1/2] Add 'git svn help [cmd]' which works outside a repo Ben Jackson
  2009-05-31  1:17 ` [PATCH 2/2] Add 'git svn reset' to unwind 'git svn fetch' Ben Jackson
@ 2009-06-04  2:48 ` Eric Wong
  1 sibling, 0 replies; 5+ messages in thread
From: Eric Wong @ 2009-06-04  2:48 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Ben Jackson

Ben Jackson <ben@ben.com> wrote:
> Previously there was no explicit 'help' command, but 'git svn help'
> still printed the usage message (as an invalid command), provided you
> got past the initialization steps that required a valid repo.
> 
> Signed-off-by: Ben Jackson <ben@ben.com>
> ---
> 
> This was just a minor nit I noticed while working on the 'git-svn reset'
> patch.

Thanks Ben,

Acked and pushed out to git://git.bogomips.org/git-svn

-- 
Eric Wong

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2009-06-04  2:48 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-05-31  1:17 [PATCH 1/2] Add 'git svn help [cmd]' which works outside a repo Ben Jackson
2009-05-31  1:17 ` [PATCH 2/2] Add 'git svn reset' to unwind 'git svn fetch' Ben Jackson
2009-06-01 17:49   ` Ben Jackson
2009-06-04  0:24     ` Eric Wong
2009-06-04  2:48 ` [PATCH 1/2] Add 'git svn help [cmd]' which works outside a repo Eric Wong

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).