rerere: fix overeager gc
'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>
This commit is contained in:
parent
ded2d47668
commit
7d7ff15b39
@ -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;
|
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)
|
static void unlink_rr_item(const char *name)
|
||||||
{
|
{
|
||||||
unlink(rerere_path(name, "thisimage"));
|
unlink(rerere_path(name, "thisimage"));
|
||||||
@ -53,11 +59,16 @@ static void garbage_collect(struct string_list *rr)
|
|||||||
while ((e = readdir(dir))) {
|
while ((e = readdir(dir))) {
|
||||||
if (is_dot_or_dotdot(e->d_name))
|
if (is_dot_or_dotdot(e->d_name))
|
||||||
continue;
|
continue;
|
||||||
then = rerere_created_at(e->d_name);
|
|
||||||
if (!then)
|
then = rerere_last_used_at(e->d_name);
|
||||||
continue;
|
if (then) {
|
||||||
cutoff = (has_rerere_resolution(e->d_name)
|
cutoff = cutoff_resolve;
|
||||||
? cutoff_resolve : cutoff_noresolve);
|
} else {
|
||||||
|
then = rerere_created_at(e->d_name);
|
||||||
|
if (!then)
|
||||||
|
continue;
|
||||||
|
cutoff = cutoff_noresolve;
|
||||||
|
}
|
||||||
if (then < now - cutoff * 86400)
|
if (then < now - cutoff * 86400)
|
||||||
string_list_append(e->d_name, &to_remove);
|
string_list_append(e->d_name, &to_remove);
|
||||||
}
|
}
|
||||||
|
8
rerere.c
8
rerere.c
@ -378,7 +378,13 @@ static int merge(const char *name, const char *path)
|
|||||||
}
|
}
|
||||||
ret = ll_merge(&result, path, &base, NULL, &cur, "", &other, "", 0);
|
ret = ll_merge(&result, path, &base, NULL, &cur, "", &other, "", 0);
|
||||||
if (!ret) {
|
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)
|
if (!f)
|
||||||
return error("Could not open %s: %s", path,
|
return error("Could not open %s: %s", path,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
@ -132,6 +132,8 @@ test_expect_success 'commit succeeds' \
|
|||||||
|
|
||||||
test_expect_success 'recorded postimage' "test -f $rr/postimage"
|
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' '
|
test_expect_success 'another conflicting merge' '
|
||||||
git checkout -b third master &&
|
git checkout -b third master &&
|
||||||
git show second^:a1 | sed "s/To die: t/To die! T/" > a1 &&
|
git show second^:a1 | sed "s/To die: t/To die! T/" > a1 &&
|
||||||
@ -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 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
|
rm $rr/postimage
|
||||||
echo "$sha1 a1" | perl -pe 'y/\012/\000/' > .git/MERGE_RR
|
echo "$sha1 a1" | perl -pe 'y/\012/\000/' > .git/MERGE_RR
|
||||||
|
|
||||||
@ -165,15 +172,16 @@ just_over_15_days_ago=$((-1-15*86400))
|
|||||||
almost_60_days_ago=$((60-60*86400))
|
almost_60_days_ago=$((60-60*86400))
|
||||||
just_over_60_days_ago=$((-1-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-chmtime =$almost_15_days_ago $rr2/preimage
|
||||||
|
|
||||||
test_expect_success 'garbage collection (part1)' 'git rerere gc'
|
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 -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-chmtime =$just_over_15_days_ago $rr2/preimage
|
||||||
|
|
||||||
test_expect_success 'garbage collection (part2)' 'git rerere gc'
|
test_expect_success 'garbage collection (part2)' 'git rerere gc'
|
||||||
|
Loading…
Reference in New Issue
Block a user