git-fetch: fix dumb protocol transport to fetch from pack-pruned ref
[gitweb.git] / git-svn.perl
index 37ecc517879aa2c18cc909c60d3bf6ceed82fb48..bb8935afe6ab9eb67ae19b13a040cebe54246c37 100755 (executable)
@@ -134,6 +134,7 @@ sub nag_lib {
        'commit-diff' => [ \&commit_diff, 'Commit a diff between two trees',
                        { 'message|m=s' => \$_message,
                          'file|F=s' => \$_file,
+                         'revision|r=s' => \$_revision,
                        %cmt_opts } ],
        dcommit => [ \&dcommit, 'Commit several diffs to merge with upstream',
                        { 'merge|m|M' => \$_merge,
@@ -231,7 +232,7 @@ sub rebuild {
                my @commit = grep(/^git-svn-id: /,`git-cat-file commit $c`);
                next if (!@commit); # skip merges
                my ($url, $rev, $uuid) = extract_metadata($commit[$#commit]);
-               if (!$rev || !$uuid) {
+               if (!defined $rev || !$uuid) {
                        croak "Unable to extract revision or UUID from ",
                                "$c, $commit[$#commit]\n";
                }
@@ -586,11 +587,28 @@ sub commit_lib {
 sub dcommit {
        my $gs = "refs/remotes/$GIT_SVN";
        chomp(my @refs = safe_qx(qw/git-rev-list --no-merges/, "$gs..HEAD"));
+       my $last_rev;
        foreach my $d (reverse @refs) {
+               if (quiet_run('git-rev-parse','--verify',"$d~1") != 0) {
+                       die "Commit $d\n",
+                           "has no parent commit, and therefore ",
+                           "nothing to diff against.\n",
+                           "You should be working from a repository ",
+                           "originally created by git-svn\n";
+               }
+               unless (defined $last_rev) {
+                       (undef, $last_rev, undef) = cmt_metadata("$d~1");
+                       unless (defined $last_rev) {
+                               die "Unable to extract revision information ",
+                                   "from commit $d~1\n";
+                       }
+               }
                if ($_dry_run) {
                        print "diff-tree $d~1 $d\n";
                } else {
-                       commit_diff("$d~1", $d);
+                       if (my $r = commit_diff("$d~1", $d, undef, $last_rev)) {
+                               $last_rev = $r;
+                       } # else: no changes, same $last_rev
                }
        }
        return if $_dry_run;
@@ -605,7 +623,7 @@ sub dcommit {
        } else {
                print "No changes between current HEAD and $gs\n",
                      "Hard resetting to the latest $gs\n";
-               @finish = qw/reset --hard/;
+               @finish = qw/reset --mixed/;
        }
        sys('git', @finish, $gs);
 }
@@ -814,6 +832,14 @@ sub commit_diff {
                print STDERR "Needed URL or usable git-svn id command-line\n";
                commit_diff_usage();
        }
+       my $r = shift;
+       unless (defined $r) {
+               if (defined $_revision) {
+                       $r = $_revision
+               } else {
+                       die "-r|--revision is a required argument\n";
+               }
+       }
        if (defined $_message && defined $_file) {
                print STDERR "Both --message/-m and --file/-F specified ",
                                "for the commit message.\n",
@@ -830,13 +856,22 @@ sub commit_diff {
        ($repo, $SVN_PATH) = repo_path_split($SVN_URL);
        $SVN_LOG ||= libsvn_connect($repo);
        $SVN ||= libsvn_connect($repo);
+       if ($r eq 'HEAD') {
+               $r = $SVN->get_latest_revnum;
+       } elsif ($r !~ /^\d+$/) {
+               die "revision argument: $r not understood by git-svn\n";
+       }
        my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();
-       my $ed = SVN::Git::Editor->new({        r => $SVN->get_latest_revnum,
+       my $rev_committed;
+       my $ed = SVN::Git::Editor->new({        r => $r,
                                                ra => $SVN_LOG, c => $tb,
                                                svn_path => $SVN_PATH
                                        },
                                $SVN->get_commit_editor($_message,
-                                       sub {print "Committed $_[0]\n"},@lock)
+                                       sub {
+                                               $rev_committed = $_[0];
+                                               print "Committed $_[0]\n";
+                                       }, @lock)
                                );
        my $mods = libsvn_checkout_tree($ta, $tb, $ed);
        if (@$mods == 0) {
@@ -846,6 +881,7 @@ sub commit_diff {
                $ed->close_edit;
        }
        $_message = $_file = undef;
+       return $rev_committed;
 }
 
 ########################### utility functions #########################
@@ -2463,7 +2499,7 @@ sub extract_metadata {
        my $id = shift or return (undef, undef, undef);
        my ($url, $rev, $uuid) = ($id =~ /^git-svn-id:\s(\S+?)\@(\d+)
                                                        \s([a-f\d\-]+)$/x);
-       if (!$rev || !$uuid || !$url) {
+       if (!defined $rev || !$uuid || !$url) {
                # some of the original repositories I made had
                # identifiers like this:
                ($rev, $uuid) = ($id =~/^git-svn-id:\s(\d+)\@([a-f\d\-]+)/);
@@ -2662,11 +2698,12 @@ sub libsvn_connect {
 }
 
 sub libsvn_get_file {
-       my ($gui, $f, $rev) = @_;
+       my ($gui, $f, $rev, $chg) = @_;
        my $p = $f;
        if (length $SVN_PATH > 0) {
                return unless ($p =~ s#^\Q$SVN_PATH\E/##);
        }
+       print "\t$chg\t$f\n" unless $_q;
 
        my ($hash, $pid, $in, $out);
        my $pool = SVN::Pool->new;
@@ -2769,8 +2806,7 @@ sub libsvn_fetch {
                $pool->clear;
        }
        foreach (@amr) {
-               print "\t$_->[0]\t$_->[1]\n" unless $_q;
-               libsvn_get_file($gui, $_->[1], $rev)
+               libsvn_get_file($gui, $_->[1], $rev, $_->[0]);
        }
        close $gui or croak $?;
        return libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]);
@@ -2848,8 +2884,7 @@ sub libsvn_traverse {
                        if (defined $files) {
                                push @$files, $file;
                        } else {
-                               print "\tA\t$file\n" unless $_q;
-                               libsvn_get_file($gui, $file, $rev);
+                               libsvn_get_file($gui, $file, $rev, 'A');
                        }
                }
        }
@@ -3140,7 +3175,7 @@ sub copy_remote_ref {
        my $ref = "refs/remotes/$GIT_SVN";
        if (safe_qx('git-ls-remote', $origin, $ref)) {
                sys(qw/git fetch/, $origin, "$ref:$ref");
-       } else {
+       } elsif ($_cp_remote && !$_upgrade) {
                die "Unable to find remote reference: ",
                                "refs/remotes/$GIT_SVN on $origin\n";
        }