summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-rerere.txt35
-rwxr-xr-xgit-am.sh8
-rwxr-xr-xgit-rebase.sh8
-rwxr-xr-xgit-rerere.perl57
4 files changed, 106 insertions, 2 deletions
diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt
index 8b6b651237..116dca4c06 100644
--- a/Documentation/git-rerere.txt
+++ b/Documentation/git-rerere.txt
@@ -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
----------
diff --git a/git-am.sh b/git-am.sh
index afe322b20f..5df6787a3f 100755
--- 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
diff --git a/git-rebase.sh b/git-rebase.sh
index 25530dfdc5..2b4f3477fa 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -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"
diff --git a/git-rerere.perl b/git-rerere.perl
index 2e8dbbd4ea..fdd6854896 100755
--- a/git-rerere.perl
+++ b/git-rerere.perl
@@ -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