Skip to content

Commit

Permalink
rerere: fix overeager gc
Browse files Browse the repository at this point in the history
'rerere gc' prunes resolutions of conflicted merges that occurred long
time ago, and when doing so it takes the creation time of the
conflicted automerge results into account.  This can cause the loss of
frequently used conflict resolutions (e.g. long-living topic branches
are merged into a regularly rebuilt integration branch (think of git's
pu)) when they become old enough to exceed 'rerere gc's threshold.

To prevent the loss of valuable merge resolutions 'rerere' will (1)
update the timestamp of the recorded conflict resolution (i.e.
'postimage') each time when encountering and resolving the same merge
conflict, and (2) take this timestamp, i.e. the time of the last usage
into account when gc'ing.

Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
SZEDER Gábor authored and Junio C Hamano committed Jul 14, 2010
1 parent ded2d47 commit 7d7ff15
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 9 deletions.
21 changes: 16 additions & 5 deletions builtin/rerere.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ static time_t rerere_created_at(const char *name)
return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
}

static time_t rerere_last_used_at(const char *name)
{
struct stat st;
return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
}

static void unlink_rr_item(const char *name)
{
unlink(rerere_path(name, "thisimage"));
Expand Down Expand Up @@ -53,11 +59,16 @@ static void garbage_collect(struct string_list *rr)
while ((e = readdir(dir))) {
if (is_dot_or_dotdot(e->d_name))
continue;
then = rerere_created_at(e->d_name);
if (!then)
continue;
cutoff = (has_rerere_resolution(e->d_name)
? cutoff_resolve : cutoff_noresolve);

then = rerere_last_used_at(e->d_name);
if (then) {
cutoff = cutoff_resolve;
} else {
then = rerere_created_at(e->d_name);
if (!then)
continue;
cutoff = cutoff_noresolve;
}
if (then < now - cutoff * 86400)
string_list_append(e->d_name, &to_remove);
}
Expand Down
8 changes: 7 additions & 1 deletion rerere.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,13 @@ static int merge(const char *name, const char *path)
}
ret = ll_merge(&result, path, &base, NULL, &cur, "", &other, "", 0);
if (!ret) {
FILE *f = fopen(path, "w");
FILE *f;

if (utime(rerere_path(name, "postimage"), NULL) < 0)
warning("failed utime() on %s: %s",
rerere_path(name, "postimage"),
strerror(errno));
f = fopen(path, "w");
if (!f)
return error("Could not open %s: %s", path,
strerror(errno));
Expand Down
14 changes: 11 additions & 3 deletions t/t4200-rerere.sh
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ test_expect_success 'commit succeeds' \

test_expect_success 'recorded postimage' "test -f $rr/postimage"

oldmtimepost=$(test-chmtime -v -60 $rr/postimage |cut -f 1)

test_expect_success 'another conflicting merge' '
git checkout -b third master &&
git show second^:a1 | sed "s/To die: t/To die! T/" > a1 &&
Expand All @@ -144,6 +146,11 @@ test_expect_success 'rerere kicked in' "! grep ^=======$ a1"

test_expect_success 'rerere prefers first change' 'test_cmp a1 expect'

test_expect_success 'rerere updates postimage timestamp' '
newmtimepost=$(test-chmtime -v +0 $rr/postimage |cut -f 1) &&
test $oldmtimepost -lt $newmtimepost
'

rm $rr/postimage
echo "$sha1 a1" | perl -pe 'y/\012/\000/' > .git/MERGE_RR

Expand All @@ -165,15 +172,16 @@ just_over_15_days_ago=$((-1-15*86400))
almost_60_days_ago=$((60-60*86400))
just_over_60_days_ago=$((-1-60*86400))

test-chmtime =$almost_60_days_ago $rr/preimage
test-chmtime =$just_over_60_days_ago $rr/preimage
test-chmtime =$almost_60_days_ago $rr/postimage
test-chmtime =$almost_15_days_ago $rr2/preimage

test_expect_success 'garbage collection (part1)' 'git rerere gc'

test_expect_success 'young records still live' \
test_expect_success 'young or recently used records still live' \
"test -f $rr/preimage && test -f $rr2/preimage"

test-chmtime =$just_over_60_days_ago $rr/preimage
test-chmtime =$just_over_60_days_ago $rr/postimage
test-chmtime =$just_over_15_days_ago $rr2/preimage

test_expect_success 'garbage collection (part2)' 'git rerere gc'
Expand Down

0 comments on commit 7d7ff15

Please sign in to comment.