Skip to content

Commit 7d7ff15

Browse files
szedergitster
authored andcommitted
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>
1 parent ded2d47 commit 7d7ff15

File tree

3 files changed

+34
-9
lines changed

3 files changed

+34
-9
lines changed

builtin/rerere.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ static time_t rerere_created_at(const char *name)
1919
return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
2020
}
2121

22+
static time_t rerere_last_used_at(const char *name)
23+
{
24+
struct stat st;
25+
return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
26+
}
27+
2228
static void unlink_rr_item(const char *name)
2329
{
2430
unlink(rerere_path(name, "thisimage"));
@@ -53,11 +59,16 @@ static void garbage_collect(struct string_list *rr)
5359
while ((e = readdir(dir))) {
5460
if (is_dot_or_dotdot(e->d_name))
5561
continue;
56-
then = rerere_created_at(e->d_name);
57-
if (!then)
58-
continue;
59-
cutoff = (has_rerere_resolution(e->d_name)
60-
? cutoff_resolve : cutoff_noresolve);
62+
63+
then = rerere_last_used_at(e->d_name);
64+
if (then) {
65+
cutoff = cutoff_resolve;
66+
} else {
67+
then = rerere_created_at(e->d_name);
68+
if (!then)
69+
continue;
70+
cutoff = cutoff_noresolve;
71+
}
6172
if (then < now - cutoff * 86400)
6273
string_list_append(e->d_name, &to_remove);
6374
}

rerere.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,13 @@ static int merge(const char *name, const char *path)
378378
}
379379
ret = ll_merge(&result, path, &base, NULL, &cur, "", &other, "", 0);
380380
if (!ret) {
381-
FILE *f = fopen(path, "w");
381+
FILE *f;
382+
383+
if (utime(rerere_path(name, "postimage"), NULL) < 0)
384+
warning("failed utime() on %s: %s",
385+
rerere_path(name, "postimage"),
386+
strerror(errno));
387+
f = fopen(path, "w");
382388
if (!f)
383389
return error("Could not open %s: %s", path,
384390
strerror(errno));

t/t4200-rerere.sh

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ test_expect_success 'commit succeeds' \
132132

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

135+
oldmtimepost=$(test-chmtime -v -60 $rr/postimage |cut -f 1)
136+
135137
test_expect_success 'another conflicting merge' '
136138
git checkout -b third master &&
137139
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"
144146

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

149+
test_expect_success 'rerere updates postimage timestamp' '
150+
newmtimepost=$(test-chmtime -v +0 $rr/postimage |cut -f 1) &&
151+
test $oldmtimepost -lt $newmtimepost
152+
'
153+
147154
rm $rr/postimage
148155
echo "$sha1 a1" | perl -pe 'y/\012/\000/' > .git/MERGE_RR
149156

@@ -165,15 +172,16 @@ just_over_15_days_ago=$((-1-15*86400))
165172
almost_60_days_ago=$((60-60*86400))
166173
just_over_60_days_ago=$((-1-60*86400))
167174

168-
test-chmtime =$almost_60_days_ago $rr/preimage
175+
test-chmtime =$just_over_60_days_ago $rr/preimage
176+
test-chmtime =$almost_60_days_ago $rr/postimage
169177
test-chmtime =$almost_15_days_ago $rr2/preimage
170178

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

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

176-
test-chmtime =$just_over_60_days_ago $rr/preimage
184+
test-chmtime =$just_over_60_days_ago $rr/postimage
177185
test-chmtime =$just_over_15_days_ago $rr2/preimage
178186

179187
test_expect_success 'garbage collection (part2)' 'git rerere gc'

0 commit comments

Comments
 (0)