Merge branch 'ew/rerere'
authorJunio C Hamano <junkio@cox.net>
Wed, 13 Dec 2006 19:08:35 +0000 (11:08 -0800)
committerJunio C Hamano <junkio@cox.net>
Wed, 13 Dec 2006 19:08:35 +0000 (11:08 -0800)
* ew/rerere:
rerere: record (or avoid misrecording) resolved, skipped or aborted rebase/am
git-rerere: add 'gc' command.
rerere: add clear, diff, and status commands

Documentation/git-rerere.txt
git-am.sh
git-rebase.sh
git-rerere.perl
index 8b6b6512371fd67fbb56d06cf29e826d3ef69d56..116dca4c0668488a0ba55b43a10e89c40f087b59 100644 (file)
@@ -7,8 +7,7 @@ git-rerere - Reuse recorded resolve
 
 SYNOPSIS
 --------
-'git-rerere'
-
+'git-rerere' [clear|diff|status]
 
 DESCRIPTION
 -----------
@@ -27,6 +26,38 @@ results and applying the previously recorded hand resolution.
 You need to create `$GIT_DIR/rr-cache` directory to enable this
 command.
 
+
+COMMANDS
+--------
+
+Normally, git-rerere is run without arguments or user-intervention.
+However, it has several commands that allow it to interact with
+its working state.
+
+'clear'::
+
+This resets the metadata used by rerere if a merge resolution is to be
+is aborted.  Calling gitlink:git-am[1] --skip or gitlink:git-rebase[1]
+[--skip|--abort] will automatcally invoke this command.
+
+'diff'::
+
+This displays diffs for the current state of the resolution.  It is
+useful for tracking what has changed while the user is resolving
+conflicts.  Additional arguments are passed directly to the system
+diff(1) command installed in PATH.
+
+'status'::
+
+Like diff, but this only prints the filenames that will be tracked
+for resolutions.
+
+'gc'::
+
+This command is used to prune records of conflicted merge that
+occurred long time ago.
+
+
 DISCUSSION
 ----------
 
index afe322b20fb0b40dfeb1cb17dc3cad09096e943a..5df6787a3f285f18d3a41c1ab2f0579f407e02de 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -246,6 +246,10 @@ last=`cat "$dotest/last"`
 this=`cat "$dotest/next"`
 if test "$skip" = t
 then
+       if test -d "$GIT_DIR/rr-cache"
+       then
+               git-rerere clear
+       fi
        this=`expr "$this" + 1`
        resume=
 fi
@@ -408,6 +412,10 @@ do
                        stop_here_user_resolve $this
                fi
                apply_status=0
+               if test -d "$GIT_DIR/rr-cache"
+               then
+                       git rerere
+               fi
                ;;
        esac
 
index 25530dfdc5ba3b88ba9f45393d3aace8faa89472..2b4f3477fa941afe4f6450f74f6f8cf43a7567c0 100755 (executable)
@@ -139,6 +139,10 @@ do
        --skip)
                if test -d "$dotest"
                then
+                       if test -d "$GIT_DIR/rr-cache"
+                       then
+                               git-rerere clear
+                       fi
                        prev_head="`cat $dotest/prev_head`"
                        end="`cat $dotest/end`"
                        msgnum="`cat $dotest/msgnum`"
@@ -157,6 +161,10 @@ do
                exit
                ;;
        --abort)
+               if test -d "$GIT_DIR/rr-cache"
+               then
+                       git-rerere clear
+               fi
                if test -d "$dotest"
                then
                        rm -r "$dotest"
index 2e8dbbd4ea0adcf8aee1e87acfc439e41a7289cf..fdd68548961247b38e637f61e280ab4084650475 100755 (executable)
@@ -169,9 +169,66 @@ sub merge {
        return 0;
 }
 
+sub garbage_collect_rerere {
+       # We should allow specifying these from the command line and
+       # that is why the caller gives @ARGV to us, but I am lazy.
+
+       my $cutoff_noresolve = 15; # two weeks
+       my $cutoff_resolve = 60; # two months
+       my @to_remove;
+       while (<$rr_dir/*/preimage>) {
+               my ($dir) = /^(.*)\/preimage$/;
+               my $cutoff = ((-f "$dir/postimage")
+                             ? $cutoff_resolve
+                             : $cutoff_noresolve);
+               my $age = -M "$_";
+               if ($cutoff <= $age) {
+                       push @to_remove, $dir;
+               }
+       }
+       if (@to_remove) {
+               rmtree(\@to_remove);
+       }
+}
+
 -d "$rr_dir" || exit(0);
 
 read_rr();
+
+if (@ARGV) {
+       my $arg = shift @ARGV;
+       if ($arg eq 'clear') {
+               for my $path (keys %merge_rr) {
+                       my $name = $merge_rr{$path};
+                       if (-d "$rr_dir/$name" &&
+                           ! -f "$rr_dir/$name/postimage") {
+                               rmtree(["$rr_dir/$name"]);
+                       }
+               }
+               unlink $merge_rr;
+       }
+       elsif ($arg eq 'status') {
+               for my $path (keys %merge_rr) {
+                       print $path, "\n";
+               }
+       }
+       elsif ($arg eq 'diff') {
+               for my $path (keys %merge_rr) {
+                       my $name = $merge_rr{$path};
+                       system('diff', ((@ARGV == 0) ? ('-u') : @ARGV),
+                               '-L', "a/$path", '-L', "b/$path",
+                               "$rr_dir/$name/preimage", $path);
+               }
+       }
+       elsif ($arg eq 'gc') {
+               garbage_collect_rerere(@ARGV);
+       }
+       else {
+               die "$0 unknown command: $arg\n";
+       }
+       exit 0;
+}
+
 my %conflict = map { $_ => 1 } find_conflict();
 
 # MERGE_RR records paths with conflicts immediately after merge