Fix buggy ref recording
[gitweb.git] / git-svn.perl
index 3327ad36444cb00ff01d6eed69bcab2767127e96..0290850b6639b4865d0941089d00a8c2ac5de366 100755 (executable)
@@ -51,7 +51,8 @@
        $_message, $_file, $_follow_parent, $_no_metadata,
        $_template, $_shared, $_no_default_regex, $_no_graft_copy,
        $_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,
-       $_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m);
+       $_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m,
+       $_merge, $_strategy, $_dry_run);
 my (@_branch_from, %tree_map, %users, %rusers, %equiv);
 my ($_svn_co_url_revs, $_svn_pg_peg_revs);
 my @repo_path_split_cache;
                        { 'message|m=s' => \$_message,
                          'file|F=s' => \$_file,
                        %cmt_opts } ],
+       dcommit => [ \&dcommit, 'Commit several diffs to merge with upstream',
+                       { 'merge|m|M' => \$_merge,
+                         'strategy|s=s' => \$_strategy,
+                         'dry-run|n' => \$_dry_run,
+                       %cmt_opts } ],
 );
 
 my $cmd;
@@ -500,6 +506,8 @@ sub commit_lib {
        my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();
        my $commit_msg = "$GIT_SVN_DIR/.svn-commit.tmp.$$";
 
+       my $repo;
+       ($repo, $SVN_PATH) = repo_path_split($SVN_URL);
        set_svn_commit_env();
        foreach my $c (@revs) {
                my $log_msg = get_commit_message($c, $commit_msg);
@@ -508,6 +516,8 @@ sub commit_lib {
                # can't track down... (it's probably in the SVN code)
                defined(my $pid = open my $fh, '-|') or croak $!;
                if (!$pid) {
+                       $SVN_LOG = libsvn_connect($repo);
+                       $SVN = libsvn_connect($repo);
                        my $ed = SVN::Git::Editor->new(
                                        {       r => $r_last,
                                                ra => $SVN,
@@ -557,6 +567,33 @@ sub commit_lib {
        unlink $commit_msg;
 }
 
+sub dcommit {
+       my $gs = "refs/remotes/$GIT_SVN";
+       chomp(my @refs = safe_qx(qw/git-rev-list --no-merges/, "$gs..HEAD"));
+       foreach my $d (reverse @refs) {
+               if ($_dry_run) {
+                       print "diff-tree $d~1 $d\n";
+               } else {
+                       commit_diff("$d~1", $d);
+               }
+       }
+       return if $_dry_run;
+       fetch();
+       my @diff = safe_qx(qw/git-diff-tree HEAD/, $gs);
+       my @finish;
+       if (@diff) {
+               @finish = qw/rebase/;
+               push @finish, qw/--merge/ if $_merge;
+               push @finish, "--strategy=$_strategy" if $_strategy;
+               print STDERR "W: HEAD and $gs differ, using @finish:\n", @diff;
+       } else {
+               print "No changes between current HEAD and $gs\n",
+                     "Hard resetting to the latest $gs\n";
+               @finish = qw/reset --hard/;
+       }
+       sys('git', @finish, $gs);
+}
+
 sub show_ignore {
        $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url");
        $_use_lib ? show_ignore_lib() : show_ignore_cmd();
@@ -782,6 +819,7 @@ sub commit_diff {
        } else {
                $ed->close_edit;
        }
+       $_message = $_file = undef;
 }
 
 ########################### utility functions #########################
@@ -1158,27 +1196,24 @@ sub repo_path_split {
                }
        }
 
-       my ($url, $path) = ($full_url =~ m!^([a-z\+]+://[^/]*)(.*)$!i);
-       $path =~ s#^/+##;
-       my @paths = split(m#/+#, $path);
-
        if ($_use_lib) {
-               while (1) {
-                       $SVN = libsvn_connect($url);
-                       last if (defined $SVN &&
-                               defined eval { $SVN->get_latest_revnum });
-                       my $n = shift @paths || last;
-                       $url .= "/$n";
-               }
+               my $tmp = libsvn_connect($full_url);
+               my $url = $tmp->get_repos_root;
+               $full_url =~ s#^\Q$url\E/*##;
+               push @repo_path_split_cache, qr/^(\Q$url\E)/;
+               return ($url, $full_url);
        } else {
+               my ($url, $path) = ($full_url =~ m!^([a-z\+]+://[^/]*)(.*)$!i);
+               $path =~ s#^/+##;
+               my @paths = split(m#/+#, $path);
                while (quiet_run(qw/svn ls --non-interactive/, $url)) {
                        my $n = shift @paths || last;
                        $url .= "/$n";
                }
+               push @repo_path_split_cache, qr/^(\Q$url\E)/;
+               $path = join('/',@paths);
+               return ($url, $path);
        }
-       push @repo_path_split_cache, qr/^(\Q$url\E)/;
-       $path = join('/',@paths);
-       return ($url, $path);
 }
 
 sub setup_git_svn {
@@ -2580,7 +2615,9 @@ sub libsvn_connect {
 sub libsvn_get_file {
        my ($gui, $f, $rev) = @_;
        my $p = $f;
-       return unless ($p =~ s#^\Q$SVN_PATH\E/##);
+       if (length $SVN_PATH > 0) {
+               return unless ($p =~ s#^\Q$SVN_PATH\E/##);
+       }
 
        my ($hash, $pid, $in, $out);
        my $pool = SVN::Pool->new;
@@ -2627,6 +2664,7 @@ sub libsvn_log_entry {
        if (defined $_authors && ! defined $users{$author}) {
                die "Author: $author not defined in $_authors file\n";
        }
+       $msg = '' if ($rev == 0 && !defined $msg);
        return { revision => $rev, date => "+0000 $Y-$m-$d $H:$M:$S",
                author => $author, msg => $msg."\n", parents => $parents || [] }
 }