Git development
 help / color / mirror / Atom feed
* Re: Prepend the history of one git tree to another
From: Thomas Glanzmann @ 2006-02-20 12:20 UTC (permalink / raw)
  To: Ryan Anderson; +Cc: GIT
In-Reply-To: <43F9A0B3.6020304@michonline.com>

Hello,

> I wrote a program called "graft-ripple", that takes a commit, and
> rewrites the current branch's history to reflect as if it started at
> that commit. It doesn't ever actually work with diffs or anything, it
> just reads commits and trees and recreates them.

> http://www.gelato.unsw.edu.au/archives/git/0511/12965.html

that is *exactly* what I was looking for. Thanks.

> Hope this helps!

Well it does!

Thanks,
        Thomas

^ permalink raw reply

* Re: Prepend the history of one git tree to another
From: Johannes Schindelin @ 2006-02-20 12:51 UTC (permalink / raw)
  To: Thomas Glanzmann; +Cc: Andreas Ericsson, GIT
In-Reply-To: <20060220104345.GG26454@cip.informatik.uni-erlangen.de>

Hi,

On Mon, 20 Feb 2006, Thomas Glanzmann wrote:

> Hello Andreas,
> 
> > Something like this might do the trick, depending on how linear your 
> > ancestry graph is:
> 
> > $ cd blastwave
> > $ first=$(git rev-list HEAD | tail -n 1)
> > $ git format-patch -k --stdout $first..HEAD > ../blw.mbox
> > $ cd ../blastwave.old
> > $ git am -k -3 ../blw.mbox
> 
> My graph is very linear. However. I have binaries checked into my tree.
> I am not sure if format-patch can handle this.

Do you need the history at all times? If not, you could just make a graft 
file. If you need it always, you could even check in a version of the 
graft file (but remember to copy it to .git/info/grafts, too).

Hth,
Dscho

^ permalink raw reply

* Re: RFC: Subprojects
From: Uwe Zeisberger @ 2006-02-20 13:16 UTC (permalink / raw)
  To: git
In-Reply-To: <7vacdzkww3.fsf@assigned-by-dhcp.cox.net>

Hello,

Junio C Hamano wrote:
> The "containing" project would have a handful "gitlink" objects
> among other things.  The toplevel tree object from a commit in
> such a project might look like this (mode bits 0160000 is
> S_IFDIR|S_IFLNK, which is what this thing is):
> 
>       $ git ls-tree HEAD
>         0100644 blob 012345... Makefile
>         0100644 blob 123456... README
>         0160000 link 234567... gcc-4.0
>         0160000 link 345678... linux-2.6
>         0040000 tree 456789... src
>       $ git cat-file -t 345678
>         link
>       $ git cat-file link 345678
>         commit 87530db5ec7d519c7ba334e414307c5130ae2da8
>         url git://...torvalds/linux-2.6.git/
> 
>         The upstream Linux 2.6 repository.
>       $ cd linux-2.6 && git-rev-parse --verify HEAD
>         87530db5ec7d519c7ba334e414307c5130ae2da8
> 
> URL will be used as a suggestion for people who cloned this tree
> to set up their repository.
I'd prefer to have the objects needed to get the linux-2.6 tree in the
object db of the containing project.  Then "url" is not needed, and you
could directly use the commit as value for the link.  i.e.

       $ git ls-tree HEAD
         0100644 blob 012345... Makefile
         0100644 blob 123456... README
         0160000 link 435363... gcc-4.0
         0160000 link 87530d... linux-2.6
         0040000 tree 456789... src

(You could now rename "link" to "commit", but it would break the
layout.)

Moreover I prefer the the link approach over the bind method.  The
reason is, that binds use information from the commit object to build
the wc other than the tree.  Moreover the condition that the
"containing" tree must not have an entry named linux-2.6 is handled
implicitly with links.

Please correct me if I'm wrong somewhere.  It's some time ago I read the
patches and this thread.  This mail is the result of some thoughts in my
vacation.

Best regards
Uwe


-- 
Uwe Zeisberger

http://www.google.com/search?q=1+year+divided+by+3+in+seconds

^ permalink raw reply

* Re: git faq : draft and rfc
From: Bertrand Jacquin @ 2006-02-20 13:30 UTC (permalink / raw)
  To: Thomas Riboulet; +Cc: git
In-Reply-To: <22e91bb0602161552k3f88b98fu4ef2a4c97c840ad7@mail.gmail.com>

Maybe another question :

How could I merge a branch 'to-merge' with structure a/b/c into branch
'master' with structure g/h/i and include files from branch 'to-merge'
in g/h/i ?

I don't know if it's very clear

--
Beber
#e.fr@freenode

^ permalink raw reply

* Re: git faq : draft and rfc
From: Bertrand Jacquin @ 2006-02-20 13:41 UTC (permalink / raw)
  To: Thomas Riboulet; +Cc: git
In-Reply-To: <4fb292fa0602200530s3e2a2cdag39eec0282187edf3@mail.gmail.com>

On 2/20/06, Bertrand Jacquin <beber.mailing@gmail.com> wrote:
> Maybe another question :
>
> How could I merge a branch 'to-merge' with structure a/b/c into branch
> 'master' with structure g/h/i and include files from branch 'to-merge'
> in g/h/i ?

Like as Junio with branch man and html.

>
> I don't know if it's very clear
>
> --
> Beber
> #e.fr@freenode
>


--
Beber
#e.fr@freenode

^ permalink raw reply

* Re: [PATCH 2/2] Add 'stg uncommit' command
From: Catalin Marinas @ 2006-02-20 17:20 UTC (permalink / raw)
  To: Karl Hasselström; +Cc: git
In-Reply-To: <20060219144752.GA5541@diana.vm.bytemark.co.uk>

On 19/02/06, Karl Hasselström <kha@treskal.com> wrote:
> By the way, it seems like my name got munged when you edited the
> commit.

I fixed the escaping in the name_email* functions (I'll push it
tonight). It was adding a \ for every character it didn't know. It now
only escapes the quotes and back-slashes. This is needed when passing
the strings via the GIT_AUTHOR_* variables.

--
Catalin

^ permalink raw reply

* Re: [PATCH 2/2] Add 'stg uncommit' command
From: Karl Hasselström @ 2006-02-20 17:30 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git
In-Reply-To: <b0943d9e0602200920v10ef8788o@mail.gmail.com>

On 2006-02-20 17:20:47 +0000, Catalin Marinas wrote:

> On 19/02/06, Karl Hasselström <kha@treskal.com> wrote:
>
> > By the way, it seems like my name got munged when you edited the
> > commit.
>
> I fixed the escaping in the name_email* functions (I'll push it
> tonight). It was adding a \ for every character it didn't know. It
> now only escapes the quotes and back-slashes. This is needed when
> passing the strings via the GIT_AUTHOR_* variables.

It put curly braces around the name as well.

-- 
Karl Hasselström, kha@treskal.com
      www.treskal.com/kalle

^ permalink raw reply

* Should we support Perl 5.6?
From: Johannes Schindelin @ 2006-02-20 18:37 UTC (permalink / raw)
  To: git

Hi,

I just had a failure when pulling, because since a few days (to be exact, 
since commit 1cb30387, git-fmt-merge-msg uses a syntax which is not 
understood by Perl 5.6.

It is this:

	open $fh, '-|', 'git-symbolic-ref', 'HEAD' or die "$!";

I know that there was already some discussion on this list, but I don't 
remember if we decided on leaving 5.6 behind or not.

Somebody remembers?

Ciao,
Dscho

^ permalink raw reply

* [PATCH 1/9] git-svn: fix a typo in defining the --no-stop-on-copy option
From: Eric Wong @ 2006-02-20 18:57 UTC (permalink / raw)
  To: git; +Cc: junkio, Eric Wong
In-Reply-To: <11404618453236-git-send-email-normalperson@yhbt.net>

Just a typo, I doubt anybody would use (and I highly recommend not
using) this option anyways.  But you never know...

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

7292b0320d5aab4f335b7c1198b77231bf78d44a
diff --git a/contrib/git-svn/git-svn b/contrib/git-svn/git-svn
index 71a8b3b..1a8f40e 100755
--- a/contrib/git-svn/git-svn
+++ b/contrib/git-svn/git-svn
@@ -38,7 +38,7 @@ GetOptions(	'revision|r=s' => \$_revisio
 		'edit|e' => \$_edit,
 		'rmdir' => \$_rmdir,
 		'help|H|h' => \$_help,
-		'no-stop-copy' => \$_no_stop_copy );
+		'no-stop-on-copy' => \$_no_stop_copy );
 my %cmd = (
 	fetch => [ \&fetch, "Download new revisions from SVN" ],
 	init => [ \&init, "Initialize and fetch (import)"],
-- 
1.2.0.gdee6

^ permalink raw reply related

* [PATCH 2/9] git-svn: allow --find-copies-harder and -l<num> to be passed on commit
From: Eric Wong @ 2006-02-20 18:57 UTC (permalink / raw)
  To: git; +Cc: junkio, Eric Wong
In-Reply-To: <11404618452729-git-send-email-normalperson@yhbt.net>

Both of these options are passed directly to git-diff-tree when
committing to a SVN repository.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn     |   10 ++++++++--
 contrib/git-svn/git-svn.txt |    7 +++++++
 2 files changed, 15 insertions(+), 2 deletions(-)

f00770e6f3151e5fdc94208efab22b3068dbb882
diff --git a/contrib/git-svn/git-svn b/contrib/git-svn/git-svn
index 1a8f40e..477ec16 100755
--- a/contrib/git-svn/git-svn
+++ b/contrib/git-svn/git-svn
@@ -30,7 +30,8 @@ use Getopt::Long qw/:config gnu_getopt n
 use File::Spec qw//;
 my $sha1 = qr/[a-f\d]{40}/;
 my $sha1_short = qr/[a-f\d]{6,40}/;
-my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit);
+my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
+	$_find_copies_harder, $_l);
 
 GetOptions(	'revision|r=s' => \$_revision,
 		'no-ignore-externals' => \$_no_ignore_ext,
@@ -38,6 +39,8 @@ GetOptions(	'revision|r=s' => \$_revisio
 		'edit|e' => \$_edit,
 		'rmdir' => \$_rmdir,
 		'help|H|h' => \$_help,
+		'find-copies-harder' => \$_find_copies_harder,
+		'l=i' => \$_l,
 		'no-stop-on-copy' => \$_no_stop_copy );
 my %cmd = (
 	fetch => [ \&fetch, "Download new revisions from SVN" ],
@@ -348,7 +351,10 @@ sub svn_checkout_tree {
 	my $pid = open my $diff_fh, '-|';
 	defined $pid or croak $!;
 	if ($pid == 0) {
-		exec(qw(git-diff-tree -z -r -C), $from, $commit) or croak $!;
+		my @diff_tree = qw(git-diff-tree -z -r -C);
+		push @diff_tree, '--find-copies-harder' if $_find_copies_harder;
+		push @diff_tree, "-l$_l" if defined $_l;
+		exec(@diff_tree, $from, $commit) or croak $!;
 	}
 	my $mods = parse_diff_tree($diff_fh);
 	unless (@$mods) {
diff --git a/contrib/git-svn/git-svn.txt b/contrib/git-svn/git-svn.txt
index 4b79fb0..9912f5a 100644
--- a/contrib/git-svn/git-svn.txt
+++ b/contrib/git-svn/git-svn.txt
@@ -99,6 +99,13 @@ OPTIONS
 	default for objects that are commits, and forced on when committing
 	tree objects.
 
+-l<num>::
+--find-copies-harder::
+	Both of these are only used with the 'commit' command.
+
+	They are both passed directly to git-diff-tree see
+	git-diff-tree(1) for more information.
+
 COMPATIBILITY OPTIONS
 ---------------------
 --no-ignore-externals::
-- 
1.2.0.gdee6

^ permalink raw reply related

* git-svn: nearing 1.0.0
From: Eric Wong @ 2006-02-20 18:57 UTC (permalink / raw)
  To: git; +Cc: junkio

      
This should hopefully be the last set of bugfixes I have for git-svn.  I'm
pretty satisfied with it, as I haven't needed to directly invoke svn and wait
for it in any of my day-to-day operations for doing work on svn repositories.

Most of the major changes are in 'commit' functionality where several
corner-case bugs have been found and fixed.

      git-svn: fix a typo in defining the --no-stop-on-copy option
      git-svn: allow --find-copies-harder and -l<num> to be passed on commit
      git-svn: Allow for more argument types for commit (from..to)
      git-svn: remove any need for the XML::Simple dependency
      git-svn: change ; to && in addremove()
      contrib/git-svn.txt: add a note about renamed/copied directory support
      git-svn: fix several corner-case and rare bugs with 'commit'
      contrib/git-svn: add Makefile, test, and associated ignores
      git-svn: 0.9.1: add --version and copyright/license (GPL v2+) information

 .gitignore                 |    4 
 Makefile                   |   32 +++
 git-svn.perl               |  382 +++++++++++++++++++++++++++++++--------------
 git-svn.txt                |   16 +
 t/t0000-contrib-git-svn.sh |  216 +++++++++++++++++++++++++
 5 files changed, 532 insertions(+), 118 deletions(-)

-- 
Eric Wong

^ permalink raw reply

* [PATCH 5/9] git-svn: change ; to && in addremove()
From: Eric Wong @ 2006-02-20 18:57 UTC (permalink / raw)
  To: git; +Cc: junkio, Eric Wong
In-Reply-To: <11404618483821-git-send-email-normalperson@yhbt.net>

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

ff01f98a865018be26baf1008c669009e95a93bf
diff --git a/contrib/git-svn/git-svn b/contrib/git-svn/git-svn
index 4391bc3..25c248d 100755
--- a/contrib/git-svn/git-svn
+++ b/contrib/git-svn/git-svn
@@ -580,10 +580,10 @@ sub sys { system(@_) == 0 or croak $? }
 
 sub git_addremove {
 	system( "git-diff-files --name-only -z ".
-				" | git-update-index --remove -z --stdin; ".
+				" | git-update-index --remove -z --stdin && ".
 		"git-ls-files -z --others ".
 			"'--exclude-from=$GIT_DIR/$GIT_SVN/info/exclude'".
-				" | git-update-index --add -z --stdin; "
+				" | git-update-index --add -z --stdin"
 		) == 0 or croak $?
 }
 
-- 
1.2.0.gdee6

^ permalink raw reply related

* [PATCH 3/9] git-svn: Allow for more argument types for commit (from..to)
From: Eric Wong @ 2006-02-20 18:57 UTC (permalink / raw)
  To: git; +Cc: junkio, Eric Wong
In-Reply-To: <11404618464102-git-send-email-normalperson@yhbt.net>

Allow 'from..to' notation from the command line.

More liberal sha1 parsing when reading from stdin no longer requires the
sha1 to be the first character, so a leading 'commit ' string is OK.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn     |   13 ++++++++++---
 contrib/git-svn/git-svn.txt |    2 +-
 2 files changed, 11 insertions(+), 4 deletions(-)

4d8326c4868461e8a48a4e25ef11ece6e9f92843
diff --git a/contrib/git-svn/git-svn b/contrib/git-svn/git-svn
index 477ec16..5f23d6b 100755
--- a/contrib/git-svn/git-svn
+++ b/contrib/git-svn/git-svn
@@ -216,14 +216,21 @@ sub commit {
 		print "Reading from stdin...\n";
 		@commits = ();
 		while (<STDIN>) {
-			if (/^([a-f\d]{6,40})\b/) {
+			if (/\b([a-f\d]{6,40})\b/) {
 				unshift @commits, $1;
 			}
 		}
 	}
 	my @revs;
-	foreach (@commits) {
-		push @revs, (safe_qx('git-rev-parse',$_));
+	foreach my $c (@commits) {
+		chomp(my @tmp = safe_qx('git-rev-parse',$c));
+		if (scalar @tmp == 1) {
+			push @revs, $tmp[0];
+		} elsif (scalar @tmp > 1) {
+			push @revs, reverse (safe_qx('git-rev-list',@tmp));
+		} else {
+			die "Failed to rev-parse $c\n";
+		}
 	}
 	chomp @revs;
 
diff --git a/contrib/git-svn/git-svn.txt b/contrib/git-svn/git-svn.txt
index 9912f5a..07a236f 100644
--- a/contrib/git-svn/git-svn.txt
+++ b/contrib/git-svn/git-svn.txt
@@ -149,7 +149,7 @@ Tracking and contributing to an Subversi
 # Commit only the git commits you want to SVN::
 	git-svn commit <tree-ish> [<tree-ish_2> ...]
 # Commit all the git commits from my-branch that don't exist in SVN::
-	git rev-list --pretty=oneline git-svn-HEAD..my-branch | git-svn commit
+	git commit git-svn-HEAD..my-branch
 # Something is committed to SVN, pull the latest into your branch::
 	git-svn fetch && git pull . git-svn-HEAD
 
-- 
1.2.0.gdee6

^ permalink raw reply related

* [PATCH 6/9] contrib/git-svn.txt: add a note about renamed/copied directory support
From: Eric Wong @ 2006-02-20 18:57 UTC (permalink / raw)
  To: git; +Cc: junkio, Eric Wong
In-Reply-To: <11404618481876-git-send-email-normalperson@yhbt.net>

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn.txt |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

72331d46b99b182406e06070e905123f76abbac8
diff --git a/contrib/git-svn/git-svn.txt b/contrib/git-svn/git-svn.txt
index 07a236f..cf098d7 100644
--- a/contrib/git-svn/git-svn.txt
+++ b/contrib/git-svn/git-svn.txt
@@ -206,6 +206,13 @@ working trees with metadata files.
 svn:keywords can't be ignored in Subversion (at least I don't know of
 a way to ignore them).
 
+Renamed and copied directories are not detected by git and hence not
+tracked when committing to SVN.  I do not plan on adding support for
+this as it's quite difficult and time-consuming to get working for all
+the possible corner cases (git doesn't do it, either).  Renamed and
+copied files are fully supported if they're similar enough for git to
+detect them.
+
 Author
 ------
 Written by Eric Wong <normalperson@yhbt.net>.
-- 
1.2.0.gdee6

^ permalink raw reply related

* [PATCH 4/9] git-svn: remove any need for the XML::Simple dependency
From: Eric Wong @ 2006-02-20 18:57 UTC (permalink / raw)
  To: git; +Cc: junkio, Eric Wong
In-Reply-To: <1140461846433-git-send-email-normalperson@yhbt.net>

XML::Simple was originally required back when I made svn-arch-mirror
because I needed to explictly track renames with Arch.  Then I carried
it over to git-svn because I was afraid somebody could commit an svn
log message that could throw off a non-XML log parser.  Then I noticed
the <n> lines column in the header.  So, no more XML :)

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn |   84 ++++++++++++++++++++---------------------------
 1 files changed, 35 insertions(+), 49 deletions(-)

9b380ed2f8f1b18f95d12b86cb760f95e6e0cefe
diff --git a/contrib/git-svn/git-svn b/contrib/git-svn/git-svn
index 5f23d6b..4391bc3 100755
--- a/contrib/git-svn/git-svn
+++ b/contrib/git-svn/git-svn
@@ -21,7 +21,7 @@ $ENV{LC_ALL} = 'C';
 
 # If SVN:: library support is added, please make the dependencies
 # optional and preserve the capability to use the command-line client.
-# See what I do with XML::Simple to make the dependency optional.
+# use eval { require SVN::... } to make it lazy load
 use Carp qw/croak/;
 use IO::File qw//;
 use File::Basename qw/dirname basename/;
@@ -177,8 +177,7 @@ sub fetch {
 	push @log_args, "-r$_revision";
 	push @log_args, '--stop-on-copy' unless $_no_stop_copy;
 
-	eval { require XML::Simple or croak $! };
-	my $svn_log = $@ ? svn_log_raw(@log_args) : svn_log_xml(@log_args);
+	my $svn_log = svn_log_raw(@log_args);
 	@$svn_log = sort { $a->{revision} <=> $b->{revision} } @$svn_log;
 
 	my $base = shift @$svn_log or croak "No base revision!\n";
@@ -476,49 +475,6 @@ sub svn_commit_tree {
 	return fetch("$rev_committed=$commit")->{revision};
 }
 
-sub svn_log_xml {
-	my (@log_args) = @_;
-	my $log_fh = IO::File->new_tmpfile or croak $!;
-
-	my $pid = fork;
-	defined $pid or croak $!;
-
-	if ($pid == 0) {
-		open STDOUT, '>&', $log_fh or croak $!;
-		exec (qw(svn log --xml), @log_args) or croak $!
-	}
-
-	waitpid $pid, 0;
-	croak $? if $?;
-
-	seek $log_fh, 0, 0;
-	my @svn_log;
-	my $log = XML::Simple::XMLin( $log_fh,
-				ForceArray => ['path','revision','logentry'],
-				KeepRoot => 0,
-				KeyAttr => {	logentry => '+revision',
-						paths => '+path' },
-			)->{logentry};
-	foreach my $r (sort {$a <=> $b} keys %$log) {
-		my $log_msg = $log->{$r};
-		my ($Y,$m,$d,$H,$M,$S) = ($log_msg->{date} =~
-					/(\d{4})\-(\d\d)\-(\d\d)T
-					 (\d\d)\:(\d\d)\:(\d\d)\.\d+Z$/x)
-					 or croak "Failed to parse date: ",
-						 $log->{$r}->{date};
-		$log_msg->{date} = "+0000 $Y-$m-$d $H:$M:$S";
-
-		# XML::Simple can't handle <msg></msg> as a string:
-		if (ref $log_msg->{msg} eq 'HASH') {
-			$log_msg->{msg} = "\n";
-		} else {
-			$log_msg->{msg} .= "\n";
-		}
-		push @svn_log, $log->{$r};
-	}
-	return \@svn_log;
-}
-
 sub svn_log_raw {
 	my (@log_args) = @_;
 	my $pid = open my $log_fh,'-|';
@@ -529,21 +485,42 @@ sub svn_log_raw {
 	}
 
 	my @svn_log;
-	my $state;
+	my $state = 'sep';
 	while (<$log_fh>) {
 		chomp;
 		if (/^\-{72}$/) {
+			if ($state eq 'msg') {
+				if ($svn_log[$#svn_log]->{lines}) {
+					$svn_log[$#svn_log]->{msg} .= $_."\n";
+					unless(--$svn_log[$#svn_log]->{lines}) {
+						$state = 'sep';
+					}
+				} else {
+					croak "Log parse error at: $_\n",
+						$svn_log[$#svn_log]->{revision},
+						"\n";
+				}
+				next;
+			}
+			if ($state ne 'sep') {
+				croak "Log parse error at: $_\n",
+					"state: $state\n",
+					$svn_log[$#svn_log]->{revision},
+					"\n";
+			}
 			$state = 'rev';
 
 			# if we have an empty log message, put something there:
 			if (@svn_log) {
 				$svn_log[$#svn_log]->{msg} ||= "\n";
+				delete $svn_log[$#svn_log]->{lines};
 			}
 			next;
 		}
 		if ($state eq 'rev' && s/^r(\d+)\s*\|\s*//) {
 			my $rev = $1;
-			my ($author, $date) = split(/\s*\|\s*/, $_, 2);
+			my ($author, $date, $lines) = split(/\s*\|\s*/, $_, 3);
+			($lines) = ($lines =~ /(\d+)/);
 			my ($Y,$m,$d,$H,$M,$S,$tz) = ($date =~
 					/(\d{4})\-(\d\d)\-(\d\d)\s
 					 (\d\d)\:(\d\d)\:(\d\d)\s([\-\+]\d+)/x)
@@ -551,6 +528,7 @@ sub svn_log_raw {
 			my %log_msg = (	revision => $rev,
 					date => "$tz $Y-$m-$d $H:$M:$S",
 					author => $author,
+					lines => $lines,
 					msg => '' );
 			push @svn_log, \%log_msg;
 			$state = 'msg_start';
@@ -560,7 +538,15 @@ sub svn_log_raw {
 		if ($state eq 'msg_start' && /^$/) {
 			$state = 'msg';
 		} elsif ($state eq 'msg') {
-			$svn_log[$#svn_log]->{msg} .= $_."\n";
+			if ($svn_log[$#svn_log]->{lines}) {
+				$svn_log[$#svn_log]->{msg} .= $_."\n";
+				unless (--$svn_log[$#svn_log]->{lines}) {
+					$state = 'sep';
+				}
+			} else {
+				croak "Log parse error at: $_\n",
+					$svn_log[$#svn_log]->{revision},"\n";
+			}
 		}
 	}
 	close $log_fh or croak $?;
-- 
1.2.0.gdee6

^ permalink raw reply related

* [PATCH 7/9] git-svn: fix several corner-case and rare bugs with 'commit'
From: Eric Wong @ 2006-02-20 18:57 UTC (permalink / raw)
  To: git; +Cc: junkio, Eric Wong
In-Reply-To: <11404618483094-git-send-email-normalperson@yhbt.net>

None of these were really show-stoppers (or even triggered)
on most of the trees I've tracked.

* Node change prevention for identically named nodes.  This is
  a limitation of SVN, but we find the error and exit before
  it's passed to SVN so we don't dirty our working tree when our
  commit fails.  git-svn will exit with an error code 1 if any
  of the following conditions are found:

  1.  a directory is removed and a file of the same name of the
      removed directory is created
  1a. a file has its parent directory removed and the file is
      takes the name of the removed parent directory::
          baz/zzz    =>  baz
  2.  a file is removed and a directory of the same name of the
      removed file is created.
  2a. a file is moved into a deeper directory that shares the
      previous name of the file::
          dir/$file  =>  dir/file/$file

  Since SVN cannot handle these cases, the user will have to
  manually split the commit into several parts.

* --rmdir now handles nested/deep removals. If dir/a/b/c/d/e/file
  is removed, and everything else is in the dir/ hierarchy is
  otherwise empty, then dir/ will be deleted when file is deleted
  from svn and --rmdir specified.

* Always assert that we have written the tree we want to write
  on commits.  This helped me find several bugs in the symlink
  handling code (which as been fixed).

* Several symlink handling fixes.  We now refuse to set
  permissions on symlinks.  We also always unlink a file
  if we're going to overwrite it.

* Apply changes in a pre-determined order, so we always have
  rename from locations handy before we delete them.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn |  260 ++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 200 insertions(+), 60 deletions(-)

cc9e5f27fee073de35fd6f50ec15ea59dda8b71b
diff --git a/contrib/git-svn/git-svn b/contrib/git-svn/git-svn
index 25c248d..3a59454 100755
--- a/contrib/git-svn/git-svn
+++ b/contrib/git-svn/git-svn
@@ -238,7 +238,11 @@ sub commit {
 	my $svn_current_rev =  svn_info('.')->{'Last Changed Rev'};
 	foreach my $c (@revs) {
 		print "Committing $c\n";
-		svn_checkout_tree($svn_current_rev, $c);
+		my $mods = svn_checkout_tree($svn_current_rev, $c);
+		if (scalar @$mods == 0) {
+			print "Skipping, no changes detected\n";
+			next;
+		}
 		$svn_current_rev = svn_commit_tree($svn_current_rev, $c);
 	}
 	print "Done committing ",scalar @revs," revisions to SVN\n";
@@ -267,9 +271,9 @@ sub setup_git_svn {
 }
 
 sub assert_svn_wc_clean {
-	my ($svn_rev, $commit) = @_;
+	my ($svn_rev, $treeish) = @_;
 	croak "$svn_rev is not an integer!\n" unless ($svn_rev =~ /^\d+$/);
-	croak "$commit is not a sha1!\n" unless ($commit =~ /^$sha1$/o);
+	croak "$treeish is not a sha1!\n" unless ($treeish =~ /^$sha1$/o);
 	my $svn_info = svn_info('.');
 	if ($svn_rev != $svn_info->{'Last Changed Rev'}) {
 		croak "Expected r$svn_rev, got r",
@@ -282,12 +286,42 @@ sub assert_svn_wc_clean {
 		print STDERR $_ foreach @status;
 		croak;
 	}
-	my ($tree_a) = grep(/^tree $sha1$/o,`git-cat-file commit $commit`);
-	$tree_a =~ s/^tree //;
-	chomp $tree_a;
-	chomp(my $tree_b = `GIT_INDEX_FILE=$GIT_SVN_INDEX git-write-tree`);
-	if ($tree_a ne $tree_b) {
-		croak "$svn_rev != $commit, $tree_a != $tree_b\n";
+	assert_tree($treeish);
+}
+
+sub assert_tree {
+	my ($treeish) = @_;
+	croak "Not a sha1: $treeish\n" unless $treeish =~ /^$sha1$/o;
+	chomp(my $type = `git-cat-file -t $treeish`);
+	my $expected;
+	while ($type eq 'tag') {
+		chomp(($treeish, $type) = `git-cat-file tag $treeish`);
+	}
+	if ($type eq 'commit') {
+		$expected = (grep /^tree /,`git-cat-file commit $treeish`)[0];
+		($expected) = ($expected =~ /^tree ($sha1)$/);
+		die "Unable to get tree from $treeish\n" unless $expected;
+	} elsif ($type eq 'tree') {
+		$expected = $treeish;
+	} else {
+		die "$treeish is a $type, expected tree, tag or commit\n";
+	}
+
+	my $old_index = $ENV{GIT_INDEX_FILE};
+	my $tmpindex = $GIT_SVN_INDEX.'.assert-tmp';
+	if (-e $tmpindex) {
+		unlink $tmpindex or croak $!;
+	}
+	$ENV{GIT_INDEX_FILE} = $tmpindex;
+	git_addremove();
+	chomp(my $tree = `git-write-tree`);
+	if ($old_index) {
+		$ENV{GIT_INDEX_FILE} = $old_index;
+	} else {
+		delete $ENV{GIT_INDEX_FILE};
+	}
+	if ($tree ne $expected) {
+		croak "Tree mismatch, Got: $tree, Expected: $expected\n";
 	}
 }
 
@@ -298,7 +332,6 @@ sub parse_diff_tree {
 	my @mods;
 	while (<$diff_fh>) {
 		chomp $_; # this gets rid of the trailing "\0"
-		print $_,"\n";
 		if ($state eq 'meta' && /^:(\d{6})\s(\d{6})\s
 					$sha1\s($sha1)\s([MTCRAD])\d*$/xo) {
 			push @mods, {	mode_a => $1, mode_b => $2,
@@ -309,36 +342,44 @@ sub parse_diff_tree {
 				$state = 'file_b';
 			}
 		} elsif ($state eq 'file_a') {
-			my $x = $mods[$#mods] or croak __LINE__,": Empty array\n";
+			my $x = $mods[$#mods] or croak "Empty array\n";
 			if ($x->{chg} !~ /^(?:C|R)$/) {
-				croak __LINE__,": Error parsing $_, $x->{chg}\n";
+				croak "Error parsing $_, $x->{chg}\n";
 			}
 			$x->{file_a} = $_;
 			$state = 'file_b';
 		} elsif ($state eq 'file_b') {
-			my $x = $mods[$#mods] or croak __LINE__,": Empty array\n";
+			my $x = $mods[$#mods] or croak "Empty array\n";
 			if (exists $x->{file_a} && $x->{chg} !~ /^(?:C|R)$/) {
-				croak __LINE__,": Error parsing $_, $x->{chg}\n";
+				croak "Error parsing $_, $x->{chg}\n";
 			}
 			if (!exists $x->{file_a} && $x->{chg} =~ /^(?:C|R)$/) {
-				croak __LINE__,": Error parsing $_, $x->{chg}\n";
+				croak "Error parsing $_, $x->{chg}\n";
 			}
 			$x->{file_b} = $_;
 			$state = 'meta';
 		} else {
-			croak __LINE__,": Error parsing $_\n";
+			croak "Error parsing $_\n";
 		}
 	}
 	close $diff_fh or croak $!;
+
 	return \@mods;
 }
 
 sub svn_check_prop_executable {
 	my $m = shift;
-	if ($m->{mode_b} =~ /755$/ && $m->{mode_a} !~ /755$/) {
-		sys(qw(svn propset svn:executable 1), $m->{file_b});
+	return if -l $m->{file_b};
+	if ($m->{mode_b} =~ /755$/) {
+		chmod((0755 &~ umask),$m->{file_b}) or croak $!;
+		if ($m->{mode_a} !~ /755$/) {
+			sys(qw(svn propset svn:executable 1), $m->{file_b});
+		}
+		-x $m->{file_b} or croak "$m->{file_b} is not executable!\n";
 	} elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) {
 		sys(qw(svn propdel svn:executable), $m->{file_b});
+		chmod((0644 &~ umask),$m->{file_b}) or croak $!;
+		-x $m->{file_b} and croak "$m->{file_b} is executable!\n";
 	}
 }
 
@@ -349,84 +390,166 @@ sub svn_ensure_parent_path {
 	sys(qw(svn add -N), $dir_b) unless (-d "$dir_b/.svn");
 }
 
+sub precommit_check {
+	my $mods = shift;
+	my (%rm_file, %rmdir_check, %added_check);
+
+	my %o = ( D => 0, R => 1, C => 2, A => 3, M => 3, T => 3 );
+	foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) {
+		if ($m->{chg} eq 'R') {
+			if (-d $m->{file_b}) {
+				err_dir_to_file("$m->{file_a} => $m->{file_b}");
+			}
+			# dir/$file => dir/file/$file
+			my $dirname = dirname($m->{file_b});
+			while ($dirname ne File::Spec->curdir) {
+				if ($dirname ne $m->{file_a}) {
+					$dirname = dirname($dirname);
+					next;
+				}
+				err_file_to_dir("$m->{file_a} => $m->{file_b}");
+			}
+			# baz/zzz => baz (baz is a file)
+			$dirname = dirname($m->{file_a});
+			while ($dirname ne File::Spec->curdir) {
+				if ($dirname ne $m->{file_b}) {
+					$dirname = dirname($dirname);
+					next;
+				}
+				err_dir_to_file("$m->{file_a} => $m->{file_b}");
+			}
+		}
+		if ($m->{chg} =~ /^(D|R)$/) {
+			my $t = $1 eq 'D' ? 'file_b' : 'file_a';
+			$rm_file{ $m->{$t} } = 1;
+			my $dirname = dirname( $m->{$t} );
+			my $basename = basename( $m->{$t} );
+			$rmdir_check{$dirname}->{$basename} = 1;
+		} elsif ($m->{chg} =~ /^(?:A|C)$/) {
+			if (-d $m->{file_b}) {
+				err_dir_to_file($m->{file_b});
+			}
+			my $dirname = dirname( $m->{file_b} );
+			my $basename = basename( $m->{file_b} );
+			$added_check{$dirname}->{$basename} = 1;
+			while ($dirname ne File::Spec->curdir) {
+				if ($rm_file{$dirname}) {
+					err_file_to_dir($m->{file_b});
+				}
+				$dirname = dirname $dirname;
+			}
+		}
+	}
+	return (\%rmdir_check, \%added_check);
+
+	sub err_dir_to_file {
+		my $file = shift;
+		print STDERR "Node change from directory to file ",
+				"is not supported by Subversion: ",$file,"\n";
+		exit 1;
+	}
+	sub err_file_to_dir {
+		my $file = shift;
+		print STDERR "Node change from file to directory ",
+				"is not supported by Subversion: ",$file,"\n";
+		exit 1;
+	}
+}
+
 sub svn_checkout_tree {
-	my ($svn_rev, $commit) = @_;
+	my ($svn_rev, $treeish) = @_;
 	my $from = file_to_s("$REV_DIR/$svn_rev");
 	assert_svn_wc_clean($svn_rev,$from);
-	print "diff-tree '$from' '$commit'\n";
+	print "diff-tree '$from' '$treeish'\n";
 	my $pid = open my $diff_fh, '-|';
 	defined $pid or croak $!;
 	if ($pid == 0) {
 		my @diff_tree = qw(git-diff-tree -z -r -C);
 		push @diff_tree, '--find-copies-harder' if $_find_copies_harder;
 		push @diff_tree, "-l$_l" if defined $_l;
-		exec(@diff_tree, $from, $commit) or croak $!;
+		exec(@diff_tree, $from, $treeish) or croak $!;
 	}
 	my $mods = parse_diff_tree($diff_fh);
 	unless (@$mods) {
 		# git can do empty commits, SVN doesn't allow it...
-		return $svn_rev;
+		return $mods;
 	}
-	my %rm;
-	foreach my $m (@$mods) {
+	my ($rm, $add) = precommit_check($mods);
+
+	my %o = ( D => 1, R => 0, C => -1, A => 3, M => 3, T => 3 );
+	foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) {
 		if ($m->{chg} eq 'C') {
 			svn_ensure_parent_path( $m->{file_b} );
 			sys(qw(svn cp),		$m->{file_a}, $m->{file_b});
-			blob_to_file(		$m->{sha1_b}, $m->{file_b});
+			apply_mod_line_blob($m);
 			svn_check_prop_executable($m);
 		} elsif ($m->{chg} eq 'D') {
-			$rm{dirname $m->{file_b}}->{basename $m->{file_b}} = 1;
 			sys(qw(svn rm --force), $m->{file_b});
 		} elsif ($m->{chg} eq 'R') {
 			svn_ensure_parent_path( $m->{file_b} );
 			sys(qw(svn mv --force), $m->{file_a}, $m->{file_b});
-			blob_to_file(		$m->{sha1_b}, $m->{file_b});
+			apply_mod_line_blob($m);
 			svn_check_prop_executable($m);
-			$rm{dirname $m->{file_a}}->{basename $m->{file_a}} = 1;
 		} elsif ($m->{chg} eq 'M') {
-			if ($m->{mode_b} =~ /^120/ && $m->{mode_a} =~ /^120/) {
-				unlink $m->{file_b} or croak $!;
-				blob_to_symlink($m->{sha1_b}, $m->{file_b});
-			} else {
-				blob_to_file($m->{sha1_b}, $m->{file_b});
-			}
+			apply_mod_line_blob($m);
 			svn_check_prop_executable($m);
 		} elsif ($m->{chg} eq 'T') {
 			sys(qw(svn rm --force),$m->{file_b});
-			if ($m->{mode_b} =~ /^120/ && $m->{mode_a} =~ /^100/) {
-				blob_to_symlink($m->{sha1_b}, $m->{file_b});
-			} else {
-				blob_to_file($m->{sha1_b}, $m->{file_b});
-			}
-			svn_check_prop_executable($m);
+			apply_mod_line_blob($m);
 			sys(qw(svn add --force), $m->{file_b});
+			svn_check_prop_executable($m);
 		} elsif ($m->{chg} eq 'A') {
 			svn_ensure_parent_path( $m->{file_b} );
-			blob_to_file(		$m->{sha1_b}, $m->{file_b});
-			if ($m->{mode_b} =~ /755$/) {
-				chmod 0755, $m->{file_b};
-			}
+			apply_mod_line_blob($m);
 			sys(qw(svn add --force), $m->{file_b});
+			svn_check_prop_executable($m);
 		} else {
 			croak "Invalid chg: $m->{chg}\n";
 		}
 	}
-	if ($_rmdir) {
-		my $old_index = $ENV{GIT_INDEX_FILE};
-		$ENV{GIT_INDEX_FILE} = $GIT_SVN_INDEX;
-		foreach my $dir (keys %rm) {
-			my $files = $rm{$dir};
-			my @files;
-			foreach (safe_qx('svn','ls',$dir)) {
-				chomp;
-				push @files, $_ unless $files->{$_};
-			}
-			sys(qw(svn rm),$dir) unless @files;
-		}
-		if ($old_index) {
-			$ENV{GIT_INDEX_FILE} = $old_index;
-		} else {
-			delete $ENV{GIT_INDEX_FILE};
+
+	assert_tree($treeish);
+	if ($_rmdir) { # remove empty directories
+		handle_rmdir($rm, $add);
+	}
+	assert_tree($treeish);
+	return $mods;
+}
+
+# svn ls doesn't work with respect to the current working tree, but what's
+# in the repository.  There's not even an option for it... *sigh*
+# (added files don't show up and removed files remain in the ls listing)
+sub svn_ls_current {
+	my ($dir, $rm, $add) = @_;
+	chomp(my @ls = safe_qx('svn','ls',$dir));
+	my @ret = ();
+	foreach (@ls) {
+		s#/$##; # trailing slashes are evil
+		push @ret, $_ unless $rm->{$dir}->{$_};
+	}
+	if (exists $add->{$dir}) {
+		push @ret, keys %{$add->{$dir}};
+	}
+	return \@ret;
+}
+
+sub handle_rmdir {
+	my ($rm, $add) = @_;
+
+	foreach my $dir (sort {length $b <=> length $a} keys %$rm) {
+		my $ls = svn_ls_current($dir, $rm, $add);
+		next if (scalar @$ls);
+		sys(qw(svn rm --force),$dir);
+
+		my $dn = dirname $dir;
+		$rm->{ $dn }->{ basename $dir } = 1;
+		$ls = svn_ls_current($dn, $rm, $add);
+		while (scalar @$ls == 0 && $dn ne File::Spec->curdir) {
+			sys(qw(svn rm --force),$dn);
+			$dir = basename $dn;
+			$dn = dirname $dn;
+			$rm->{ $dn }->{ $dir } = 1;
+			$ls = svn_ls_current($dn, $rm, $add);
 		}
 	}
 }
@@ -692,10 +815,23 @@ sub git_commit {
 	return $commit;
 }
 
+sub apply_mod_line_blob {
+	my $m = shift;
+	if ($m->{mode_b} =~ /^120/) {
+		blob_to_symlink($m->{sha1_b}, $m->{file_b});
+	} else {
+		blob_to_file($m->{sha1_b}, $m->{file_b});
+	}
+}
+
 sub blob_to_symlink {
 	my ($blob, $link) = @_;
 	defined $link or croak "\$link not defined!\n";
 	croak "Not a sha1: $blob\n" unless $blob =~ /^$sha1$/o;
+	if (-l $link || -f _) {
+		unlink $link or croak $!;
+	}
+
 	my $dest = `git-cat-file blob $blob`; # no newline, so no chomp
 	symlink $dest, $link or croak $!;
 }
@@ -704,6 +840,10 @@ sub blob_to_file {
 	my ($blob, $file) = @_;
 	defined $file or croak "\$file not defined!\n";
 	croak "Not a sha1: $blob\n" unless $blob =~ /^$sha1$/o;
+	if (-l $file || -f _) {
+		unlink $file or croak $!;
+	}
+
 	open my $blob_fh, '>', $file or croak "$!: $file\n";
 	my $pid = fork;
 	defined $pid or croak $!;
-- 
1.2.0.gdee6

^ permalink raw reply related

* [PATCH 9/9] git-svn: 0.9.1: add --version and copyright/license (GPL v2+) information
From: Eric Wong @ 2006-02-20 18:57 UTC (permalink / raw)
  To: git; +Cc: junkio, Eric Wong
In-Reply-To: <11404618491275-git-send-email-normalperson@yhbt.net>

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/git-svn.perl |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

372473c658e9f48323430af003f8a1a887989edf
diff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl
index 3a59454..a32ce15 100755
--- a/contrib/git-svn/git-svn.perl
+++ b/contrib/git-svn/git-svn.perl
@@ -1,4 +1,6 @@
 #!/usr/bin/env perl
+# Copyright (C) 2006, Eric Wong <normalperson@yhbt.net>
+# License: GPL v2 or later
 use warnings;
 use strict;
 use vars qw/	$AUTHOR $VERSION
@@ -6,7 +8,7 @@ use vars qw/	$AUTHOR $VERSION
 		$GIT_SVN_INDEX $GIT_SVN
 		$GIT_DIR $REV_DIR/;
 $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
-$VERSION = '0.9.0';
+$VERSION = '0.9.1';
 $GIT_DIR = $ENV{GIT_DIR} || "$ENV{PWD}/.git";
 $GIT_SVN = $ENV{GIT_SVN_ID} || 'git-svn';
 $GIT_SVN_INDEX = "$GIT_DIR/$GIT_SVN/index";
@@ -31,7 +33,7 @@ use File::Spec qw//;
 my $sha1 = qr/[a-f\d]{40}/;
 my $sha1_short = qr/[a-f\d]{6,40}/;
 my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
-	$_find_copies_harder, $_l);
+	$_find_copies_harder, $_l, $_version);
 
 GetOptions(	'revision|r=s' => \$_revision,
 		'no-ignore-externals' => \$_no_ignore_ext,
@@ -41,6 +43,7 @@ GetOptions(	'revision|r=s' => \$_revisio
 		'help|H|h' => \$_help,
 		'find-copies-harder' => \$_find_copies_harder,
 		'l=i' => \$_l,
+		'version|V' => \$_version,
 		'no-stop-on-copy' => \$_no_stop_copy );
 my %cmd = (
 	fetch => [ \&fetch, "Download new revisions from SVN" ],
@@ -66,6 +69,7 @@ foreach (keys %cmd) {
 	}
 }
 usage(0) if $_help;
+version() if $_version;
 usage(1) unless (defined $cmd);
 svn_check_ignore_externals();
 $cmd{$cmd}->[0]->(@ARGV);
@@ -91,6 +95,11 @@ and want to keep them separate.
 	exit $exit;
 }
 
+sub version {
+	print "git-svn version $VERSION\n";
+	exit 0;
+}
+
 sub rebuild {
 	$SVN_URL = shift or undef;
 	my $repo_uuid;
-- 
1.2.0.gdee6

^ permalink raw reply related

* [PATCH 8/9] contrib/git-svn: add Makefile, test, and associated ignores
From: Eric Wong @ 2006-02-20 18:57 UTC (permalink / raw)
  To: git; +Cc: junkio, Eric Wong
In-Reply-To: <11404618483587-git-send-email-normalperson@yhbt.net>

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 contrib/git-svn/.gitignore                 |    4 +
 contrib/git-svn/Makefile                   |   32 ++++
 contrib/git-svn/git-svn.perl               |    0 
 contrib/git-svn/t/t0000-contrib-git-svn.sh |  216 ++++++++++++++++++++++++++++
 4 files changed, 252 insertions(+), 0 deletions(-)
 create mode 100644 contrib/git-svn/.gitignore
 create mode 100644 contrib/git-svn/Makefile
 rename contrib/git-svn/{git-svn => git-svn.perl} (100%)
 create mode 100644 contrib/git-svn/t/t0000-contrib-git-svn.sh

1f5de0dcbe26fedb3236c437808d2cb20ab282c1
diff --git a/contrib/git-svn/.gitignore b/contrib/git-svn/.gitignore
new file mode 100644
index 0000000..d8d87e3
--- /dev/null
+++ b/contrib/git-svn/.gitignore
@@ -0,0 +1,4 @@
+git-svn
+git-svn.xml
+git-svn.html
+git-svn.1
diff --git a/contrib/git-svn/Makefile b/contrib/git-svn/Makefile
new file mode 100644
index 0000000..a330c61
--- /dev/null
+++ b/contrib/git-svn/Makefile
@@ -0,0 +1,32 @@
+all: git-svn
+
+prefix?=$(HOME)
+bindir=$(prefix)/bin
+mandir=$(prefix)/man
+man1=$(mandir)/man1
+INSTALL?=install
+doc_conf=../../Documentation/asciidoc.conf
+-include ../../config.mak
+
+git-svn: git-svn.perl
+	cp $< $@
+	chmod +x $@
+
+install: all
+	$(INSTALL) -d -m755 $(DESTDIR)$(bindir)
+	$(INSTALL) git-svn $(DESTDIR)$(bindir)
+
+install-doc: doc
+	$(INSTALL) git-svn.1 $(DESTDIR)$(man1)
+
+doc: git-svn.1
+git-svn.1 : git-svn.xml
+	xmlto man git-svn.xml
+git-svn.xml : git-svn.txt
+	asciidoc -b docbook -d manpage \
+		-f ../../Documentation/asciidoc.conf $<
+test:
+	cd t && $(SHELL) ./t0000-contrib-git-svn.sh
+
+clean:
+	rm -f git-svn *.xml *.html *.1
diff --git a/contrib/git-svn/git-svn b/contrib/git-svn/git-svn.perl
similarity index 100%
rename from contrib/git-svn/git-svn
rename to contrib/git-svn/git-svn.perl
diff --git a/contrib/git-svn/t/t0000-contrib-git-svn.sh b/contrib/git-svn/t/t0000-contrib-git-svn.sh
new file mode 100644
index 0000000..181dfe0
--- /dev/null
+++ b/contrib/git-svn/t/t0000-contrib-git-svn.sh
@@ -0,0 +1,216 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Eric Wong
+#
+
+
+PATH=$PWD/../:$PATH
+test_description='git-svn tests'
+if test -d ../../../t
+then
+    cd ../../../t
+else
+    echo "Must be run in contrib/git-svn/t" >&2
+    exit 1
+fi
+
+. ./test-lib.sh
+
+GIT_DIR=$PWD/.git
+GIT_SVN_DIR=$GIT_DIR/git-svn
+SVN_TREE=$GIT_SVN_DIR/tree
+
+svnadmin >/dev/null 2>&1
+if test $? != 1
+then
+    test_expect_success 'skipping contrib/git-svn test' :
+    test_done
+    exit
+fi
+
+svn >/dev/null 2>&1
+if test $? != 1
+then
+    test_expect_success 'skipping contrib/git-svn test' :
+    test_done
+    exit
+fi
+
+svnrepo=$PWD/svnrepo
+
+set -e
+
+svnadmin create $svnrepo
+svnrepo="file://$svnrepo/test-git-svn"
+
+mkdir import
+
+cd import
+
+echo foo > foo
+ln -s foo foo.link
+mkdir -p dir/a/b/c/d/e
+echo 'deep dir' > dir/a/b/c/d/e/file
+mkdir -p bar
+echo 'zzz' > bar/zzz
+echo '#!/bin/sh' > exec.sh
+chmod +x exec.sh
+svn import -m 'import for git-svn' . $svnrepo >/dev/null
+
+cd ..
+
+rm -rf import
+
+test_expect_success \
+    'initialize git-svn' \
+    "git-svn init $svnrepo"
+
+test_expect_success \
+    'import an SVN revision into git' \
+    'git-svn fetch'
+
+
+name='try a deep --rmdir with a commit'
+git checkout -b mybranch git-svn-HEAD
+mv dir/a/b/c/d/e/file dir/file
+cp dir/file file
+git update-index --add --remove dir/a/b/c/d/e/file dir/file file
+git commit -m "$name"
+
+test_expect_success "$name" \
+    "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch &&
+     test -d $SVN_TREE/dir && test ! -d $SVN_TREE/dir/a"
+
+
+name='detect node change from file to directory #1'
+mkdir dir/new_file
+mv dir/file dir/new_file/file
+mv dir/new_file dir/file
+git update-index --remove dir/file
+git update-index --add dir/file/file
+git commit -m "$name"
+
+test_expect_code 1 "$name" \
+    'git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch' \
+    || true
+
+
+name='detect node change from directory to file #1'
+rm -rf dir $GIT_DIR/index
+git checkout -b mybranch2 git-svn-HEAD
+mv bar/zzz zzz
+rm -rf bar
+mv zzz bar
+git update-index --remove -- bar/zzz
+git update-index --add -- bar
+git commit -m "$name"
+
+test_expect_code 1 "$name" \
+    'git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch2' \
+    || true
+
+
+name='detect node change from file to directory #2'
+rm -f $GIT_DIR/index
+git checkout -b mybranch3 git-svn-HEAD
+rm bar/zzz
+git-update-index --remove bar/zzz
+mkdir bar/zzz
+echo yyy > bar/zzz/yyy
+git-update-index --add bar/zzz/yyy
+git commit -m "$name"
+
+test_expect_code 1 "$name" \
+    'git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch3' \
+    || true
+
+
+name='detect node change from directory to file #2'
+rm -f $GIT_DIR/index
+git checkout -b mybranch4 git-svn-HEAD
+rm -rf dir
+git update-index --remove -- dir/file
+touch dir
+echo asdf > dir
+git update-index --add -- dir
+git commit -m "$name"
+
+test_expect_code 1 "$name" \
+    'git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch4' \
+    || true
+
+
+name='remove executable bit from a file'
+rm -f $GIT_DIR/index
+git checkout -b mybranch5 git-svn-HEAD
+chmod -x exec.sh
+git update-index exec.sh
+git commit -m "$name"
+
+test_expect_success "$name" \
+    "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch5 &&
+     test ! -x $SVN_TREE/exec.sh"
+
+
+name='add executable bit back file'
+chmod +x exec.sh
+git update-index exec.sh
+git commit -m "$name"
+
+test_expect_success "$name" \
+    "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch5 &&
+     test -x $SVN_TREE/exec.sh"
+
+
+
+name='executable file becomes a symlink to bar/zzz (file)'
+rm exec.sh
+ln -s bar/zzz exec.sh
+git update-index exec.sh
+git commit -m "$name"
+
+test_expect_success "$name" \
+    "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch5 &&
+     test -L $SVN_TREE/exec.sh"
+
+
+
+name='new symlink is added to a file that was also just made executable'
+chmod +x bar/zzz
+ln -s bar/zzz exec-2.sh
+git update-index --add bar/zzz exec-2.sh
+git commit -m "$name"
+
+test_expect_success "$name" \
+    "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch5 &&
+     test -x $SVN_TREE/bar/zzz &&
+     test -L $SVN_TREE/exec-2.sh"
+
+
+
+name='modify a symlink to become a file'
+git help > help || true
+rm exec-2.sh
+cp help exec-2.sh
+git update-index exec-2.sh
+git commit -m "$name"
+
+test_expect_success "$name" \
+    "git-svn commit --find-copies-harder --rmdir git-svn-HEAD..mybranch5 &&
+     test -f $SVN_TREE/exec-2.sh &&
+     test ! -L $SVN_TREE/exec-2.sh &&
+     diff -u help $SVN_TREE/exec-2.sh"
+
+
+
+name='test fetch functionality (svn => git) with alternate GIT_SVN_ID'
+GIT_SVN_ID=alt
+export GIT_SVN_ID
+test_expect_success "$name" \
+    "git-svn init $svnrepo && git-svn fetch -v &&
+     git-rev-list --pretty=raw git-svn-HEAD | grep ^tree | uniq > a &&
+     git-rev-list --pretty=raw alt-HEAD | grep ^tree | uniq > b &&
+     diff -u a b"
+
+test_done
+
-- 
1.2.0.gdee6

^ permalink raw reply related

* Re: Should we support Perl 5.6?
From: Eric Wong @ 2006-02-20 19:10 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0602201934270.28957@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> Hi,
> 
> I just had a failure when pulling, because since a few days (to be exact, 
> since commit 1cb30387, git-fmt-merge-msg uses a syntax which is not 
> understood by Perl 5.6.
> 
> It is this:
> 
> 	open $fh, '-|', 'git-symbolic-ref', 'HEAD' or die "$!";

This is just 5.8 shorthand for the following (which is 5.6-compatible,
and probably for earlier versions, too):

	my $pid = open my $fh, '-|';
	defined $pid or die "Unable to fork: $!\n";
	if ($pid == 0) {
		exec 'git-symbolic-ref', 'HEAD' or die "$!";
	}
	<continue with original code here>

All of the Perl code I've written uses this method.

> I know that there was already some discussion on this list, but I don't 
> remember if we decided on leaving 5.6 behind or not.
> 
> Somebody remembers?

IIRC, there was no clear decision.

I still have some Debian Woody machines/chroots with 5.6 around in some
places.  I don't use git on them, but I may someday, but upgrading to
Sarge is more likely on those.

-- 
Eric Wong

^ permalink raw reply

* Re: git-svnimport -- http/dav authentication notes
From: Eric Wong @ 2006-02-20 19:22 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: Git Mailing List
In-Reply-To: <46a038f90602192324v7193f154od4ff6952a68c799d@mail.gmail.com>

Martin Langhoff <martin.langhoff@gmail.com> wrote:
> After a lot of trial and error against a server I don't control (so I
> can't log things on) I've managed to use svn-import on it and it
> mostly seems to work. Kind of. It's slowly grinding through the
> commits.
> 
> To make it short, I seem to be doing well with:
> 
>    git-svnimport -t tags -T trunk -b branches -o svntrunk -v
>          'http://martin%40catalyst.net.nz:password@nameless.server.org/svn/someproject'
> 
> The repo has LDAP authentication, and the username is my email
> address, so I guessed that url-encoding would work, and it did.

Logging in with the svn command-line client (svn ls <url>) be enough to
cache auth information for the SVN library (and therefore svnimport)?
Unless you've disabled it in your config, of course...

> svnimport is a bit of a mistery actually. I often know if it's really
> doing the import or the files are going to be there but empty. SVN is
> so flexible in its "everything is a directory" way of thinking that if
> I mess up -t or -b I get the commits alright... but no files.
> 
> Strange world, svn ;-)

Hear, hear.  I always had to reread the manpage or look here for
examples on how to use it.  And then echo !! > .git/info/svnimport-cmd
after I was done using it so I wouldn't have to remember which command
switches I used.

Then I decided to write git-svn :>

-- 
Eric Wong

^ permalink raw reply

* Re: Should we support Perl 5.6?
From: Andreas Ericsson @ 2006-02-20 21:01 UTC (permalink / raw)
  To: Eric Wong; +Cc: Johannes Schindelin, git
In-Reply-To: <20060220191011.GA18085@hand.yhbt.net>

Eric Wong wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> 
>>Hi,
>>
>>I just had a failure when pulling, because since a few days (to be exact, 
>>since commit 1cb30387, git-fmt-merge-msg uses a syntax which is not 
>>understood by Perl 5.6.
>>
>>It is this:
>>
>>	open $fh, '-|', 'git-symbolic-ref', 'HEAD' or die "$!";
> 
> 
> This is just 5.8 shorthand for the following (which is 5.6-compatible,
> and probably for earlier versions, too):
> 
> 	my $pid = open my $fh, '-|';
> 	defined $pid or die "Unable to fork: $!\n";
> 	if ($pid == 0) {
> 		exec 'git-symbolic-ref', 'HEAD' or die "$!";
> 	}
> 	<continue with original code here>
> 
> All of the Perl code I've written uses this method.
> 
> 
>>I know that there was already some discussion on this list, but I don't 
>>remember if we decided on leaving 5.6 behind or not.
>>
>>Somebody remembers?
> 
> 
> IIRC, there was no clear decision.
> 

I think we agreed not to bother at all with Perl 5.4 and earlier, and 
not to bend over backwards to support 5.6. This seems like a simple fix 
though, so I'm sure Junio will accept a patch.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply

* Re: Should we support Perl 5.6?
From: Junio C Hamano @ 2006-02-20 21:15 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: Johannes Schindelin, git
In-Reply-To: <43FA2E46.2000503@op5.se>

Andreas Ericsson <ae@op5.se> writes:

> I think we agreed not to bother at all with Perl 5.4 and earlier, and
> not to bend over backwards to support 5.6. This seems like a simple
> fix though, so I'm sure Junio will accept a patch.

Correct.  I wasn't being careful enough.

^ permalink raw reply

* [PATCH] fmt-merge-msg: avoid open "-|" list form for Perl 5.6
From: Junio C Hamano @ 2006-02-20 22:05 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Eric Wong, git
In-Reply-To: <20060220191011.GA18085@hand.yhbt.net>


Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 * Eric, thanks for the hint.  I have this four-patch series.
   Could people with perl 5.6 please check them?

 git-fmt-merge-msg.perl |   24 ++++++++++++++++--------
 1 files changed, 16 insertions(+), 8 deletions(-)

615782c9609bf23be55b403e994d88c1047be996
diff --git a/git-fmt-merge-msg.perl b/git-fmt-merge-msg.perl
index c34ddc5..a77e94e 100755
--- a/git-fmt-merge-msg.perl
+++ b/git-fmt-merge-msg.perl
@@ -28,11 +28,12 @@ sub andjoin {
 }
 
 sub repoconfig {
-	my $fh;
 	my $val;
 	eval {
-		open $fh, '-|', 'git-repo-config', '--get', 'merge.summary'
-		    or die "$!";
+		my $pid = open(my $fh, '-|');
+		if (!$pid) {
+			exec('git-repo-config', '--get', 'merge.summary');
+		}
 		($val) = <$fh>;
 		close $fh;
 	};
@@ -41,25 +42,32 @@ sub repoconfig {
 
 sub current_branch {
 	my $fh;
-	open $fh, '-|', 'git-symbolic-ref', 'HEAD' or die "$!";
+	my $pid = open($fh, '-|');
+	die "$!" unless defined $pid;
+	if (!$pid) {
+	    exec('git-symbolic-ref', 'HEAD') or die "$!";
+	}
 	my ($bra) = <$fh>;
 	chomp($bra);
+	close $fh or die "$!";
 	$bra =~ s|^refs/heads/||;
 	if ($bra ne 'master') {
 		$bra = " into $bra";
 	} else {
 		$bra = "";
 	}
-
 	return $bra;
 }
 
 sub shortlog {
 	my ($tip, $limit) = @_;
 	my ($fh, @result);
-	open $fh, '-|', ('git-log', "--max-count=$limit", '--topo-order',
-			 '--pretty=oneline', $tip, '^HEAD')
-	    or die "$!";
+	my $pid = open($fh, '-|');
+	die "$!" unless defined $pid;
+	if (!$pid) {
+	    exec('git-log', "--max-count=$limit", '--topo-order',
+		 '--pretty=oneline', $tip, '^HEAD') or die "$!";
+	}
 	while (<$fh>) {
 		s/^[0-9a-f]{40}\s+//;
 		push @result, $_;
-- 
1.2.2.g5be4ea

^ permalink raw reply related

* [PATCH] rerere: avoid open "-|" list form for Perl 5.6
From: Junio C Hamano @ 2006-02-20 22:12 UTC (permalink / raw)
  To: git; +Cc: Eric Wong
In-Reply-To: <7vr75xbs8w.fsf_-_@assigned-by-dhcp.cox.net>


Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 git-rerere.perl |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

46fa107ab91b25eb928a9945ce4e9143b9c36df3
diff --git a/git-rerere.perl b/git-rerere.perl
index df11951..d3664ff 100755
--- a/git-rerere.perl
+++ b/git-rerere.perl
@@ -131,7 +131,11 @@ sub record_preimage {
 sub find_conflict {
 	my $in;
 	local $/ = "\0";
-	open $in, '-|', qw(git ls-files -z -u) or die "$!: ls-files";
+	my $pid = open($in, '-|');
+	die "$!" unless defined $pid;
+	if (!$pid) {
+		exec(qw(git ls-files -z -u)) or die "$!: ls-files";
+	}
 	my %path = ();
 	my @path = ();
 	while (<$in>) {
-- 
1.2.2.g5be4ea

^ permalink raw reply related

* [PATCH] svmimport: avoid open "-|" list form for Perl 5.6
From: Junio C Hamano @ 2006-02-20 22:12 UTC (permalink / raw)
  To: git; +Cc: Eric Wong, Matthias Urlichs
In-Reply-To: <7vr75xbs8w.fsf_-_@assigned-by-dhcp.cox.net>


Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 git-svnimport.perl |   20 ++++++++++++++++----
 1 files changed, 16 insertions(+), 4 deletions(-)

f7e8f8415c5c88082daecac44cfbba561113a3d9
diff --git a/git-svnimport.perl b/git-svnimport.perl
index c536d70..ee2940f 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -10,7 +10,6 @@
 # The head revision is on branch "origin" by default.
 # You can change that with the '-o' option.
 
-require 5.008; # for shell-safe open("-|",LIST)
 use strict;
 use warnings;
 use Getopt::Std;
@@ -322,8 +321,12 @@ sub get_file($$$) {
 		return undef unless defined $name;
 	}
 
-	open my $F, '-|', "git-hash-object", "-w", $name
+	my $pid = open(my $F, '-|');
+	die $! unless defined $pid;
+	if (!$pid) {
+	    exec("git-hash-object", "-w", $name)
 		or die "Cannot create object: $!\n";
+	}
 	my $sha = <$F>;
 	chomp $sha;
 	close $F;
@@ -398,7 +401,12 @@ sub copy_path($$$$$$$$) {
 			$srcpath =~ s#/*$#/#;
 	}
 	
-	open my $f,"-|","git-ls-tree","-r","-z",$gitrev,$srcpath;
+	my $pid = open my $f,'-|';
+	die $! unless defined $pid;
+	if (!$pid) {
+		exec("git-ls-tree","-r","-z",$gitrev,$srcpath)
+			or die $!;
+	}
 	local $/ = "\0";
 	while(<$f>) {
 		chomp;
@@ -554,7 +562,11 @@ sub commit {
 				@o1 = @old;
 				@old = ();
 			}
-			open my $F, "-|", "git-ls-files", "-z", @o1 or die $!;
+			my $pid = open my $F, "-|";
+			die "$!" unless defined $pid;
+			if (!$pid) {
+				exec("git-ls-files", "-z", @o1) or die $!;
+			}
 			@o1 = ();
 			local $/ = "\0";
 			while(<$F>) {
-- 
1.2.2.g5be4ea

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox