Skip to content

Commit 1be1e85

Browse files
committed
rerere: gc and clear
Adjust "git rerere gc" and "git rerere clear" to the new world order with rerere database with multiple variants for the same shape of conflicts. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 629716d commit 1be1e85

File tree

2 files changed

+123
-45
lines changed

2 files changed

+123
-45
lines changed

rerere.c

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,29 +1081,16 @@ int rerere_forget(struct pathspec *pathspec)
10811081
* Garbage collection support
10821082
*/
10831083

1084-
/*
1085-
* Note that this is not reentrant but is used only one-at-a-time
1086-
* so it does not matter right now.
1087-
*/
1088-
static struct rerere_id *dirname_to_id(const char *name)
1089-
{
1090-
static struct rerere_id id;
1091-
id.collection = find_rerere_dir(name);
1092-
return &id;
1093-
}
1094-
1095-
static time_t rerere_created_at(const char *dir_name)
1084+
static time_t rerere_created_at(struct rerere_id *id)
10961085
{
10971086
struct stat st;
1098-
struct rerere_id *id = dirname_to_id(dir_name);
10991087

11001088
return stat(rerere_path(id, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
11011089
}
11021090

1103-
static time_t rerere_last_used_at(const char *dir_name)
1091+
static time_t rerere_last_used_at(struct rerere_id *id)
11041092
{
11051093
struct stat st;
1106-
struct rerere_id *id = dirname_to_id(dir_name);
11071094

11081095
return stat(rerere_path(id, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
11091096
}
@@ -1113,24 +1100,37 @@ static time_t rerere_last_used_at(const char *dir_name)
11131100
*/
11141101
static void unlink_rr_item(struct rerere_id *id)
11151102
{
1116-
unlink(rerere_path(id, "thisimage"));
1117-
unlink(rerere_path(id, "preimage"));
1118-
unlink(rerere_path(id, "postimage"));
1119-
/*
1120-
* NEEDSWORK: what if this rmdir() fails? Wouldn't we then
1121-
* assume that we already have preimage recorded in
1122-
* do_plain_rerere()?
1123-
*/
1124-
rmdir(rerere_path(id, NULL));
1103+
unlink_or_warn(rerere_path(id, "thisimage"));
1104+
remove_variant(id);
1105+
id->collection->status[id->variant] = 0;
1106+
}
1107+
1108+
static void prune_one(struct rerere_id *id, time_t now,
1109+
int cutoff_resolve, int cutoff_noresolve)
1110+
{
1111+
time_t then;
1112+
int cutoff;
1113+
1114+
then = rerere_last_used_at(id);
1115+
if (then)
1116+
cutoff = cutoff_resolve;
1117+
else {
1118+
then = rerere_created_at(id);
1119+
if (!then)
1120+
return;
1121+
cutoff = cutoff_noresolve;
1122+
}
1123+
if (then < now - cutoff * 86400)
1124+
unlink_rr_item(id);
11251125
}
11261126

11271127
void rerere_gc(struct string_list *rr)
11281128
{
11291129
struct string_list to_remove = STRING_LIST_INIT_DUP;
11301130
DIR *dir;
11311131
struct dirent *e;
1132-
int i, cutoff;
1133-
time_t now = time(NULL), then;
1132+
int i;
1133+
time_t now = time(NULL);
11341134
int cutoff_noresolve = 15;
11351135
int cutoff_resolve = 60;
11361136

@@ -1142,25 +1142,32 @@ void rerere_gc(struct string_list *rr)
11421142
die_errno("unable to open rr-cache directory");
11431143
/* Collect stale conflict IDs ... */
11441144
while ((e = readdir(dir))) {
1145+
struct rerere_dir *rr_dir;
1146+
struct rerere_id id;
1147+
int now_empty;
1148+
11451149
if (is_dot_or_dotdot(e->d_name))
11461150
continue;
1147-
1148-
then = rerere_last_used_at(e->d_name);
1149-
if (then) {
1150-
cutoff = cutoff_resolve;
1151-
} else {
1152-
then = rerere_created_at(e->d_name);
1153-
if (!then)
1154-
continue;
1155-
cutoff = cutoff_noresolve;
1151+
rr_dir = find_rerere_dir(e->d_name);
1152+
if (!rr_dir)
1153+
continue; /* or should we remove e->d_name? */
1154+
1155+
now_empty = 1;
1156+
for (id.variant = 0, id.collection = rr_dir;
1157+
id.variant < id.collection->status_nr;
1158+
id.variant++) {
1159+
prune_one(&id, now, cutoff_resolve, cutoff_noresolve);
1160+
if (id.collection->status[id.variant])
1161+
now_empty = 0;
11561162
}
1157-
if (then < now - cutoff * 86400)
1163+
if (now_empty)
11581164
string_list_append(&to_remove, e->d_name);
11591165
}
11601166
closedir(dir);
1161-
/* ... and then remove them one-by-one */
1167+
1168+
/* ... and then remove the empty directories */
11621169
for (i = 0; i < to_remove.nr; i++)
1163-
unlink_rr_item(dirname_to_id(to_remove.items[i].string));
1170+
rmdir(git_path("rr-cache/%s", to_remove.items[i].string));
11641171
string_list_clear(&to_remove, 0);
11651172
}
11661173

@@ -1177,8 +1184,10 @@ void rerere_clear(struct string_list *merge_rr)
11771184

11781185
for (i = 0; i < merge_rr->nr; i++) {
11791186
struct rerere_id *id = merge_rr->items[i].util;
1180-
if (!has_rerere_resolution(id))
1187+
if (!has_rerere_resolution(id)) {
11811188
unlink_rr_item(id);
1189+
rmdir(rerere_path(id, NULL));
1190+
}
11821191
}
11831192
unlink_or_warn(git_path("MERGE_RR"));
11841193
}

t/t4200-rerere.sh

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,39 @@ concat_insert () {
412412
cat early && printf "%s\n" "$@" && cat late "$last"
413413
}
414414

415+
count_pre_post () {
416+
find .git/rr-cache/ -type f -name "preimage*" >actual &&
417+
test_line_count = "$1" actual &&
418+
find .git/rr-cache/ -type f -name "postimage*" >actual &&
419+
test_line_count = "$2" actual
420+
}
421+
422+
test_expect_success 'rerere gc' '
423+
find .git/rr-cache -type f >original &&
424+
xargs test-chmtime -172800 <original &&
425+
426+
git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
427+
find .git/rr-cache -type f >actual &&
428+
test_cmp original actual &&
429+
430+
git -c gc.rerereresolved=5 -c gc.rerereunresolved=0 rerere gc &&
431+
find .git/rr-cache -type f >actual &&
432+
test_cmp original actual &&
433+
434+
git -c gc.rerereresolved=0 -c gc.rerereunresolved=0 rerere gc &&
435+
find .git/rr-cache -type f >actual &&
436+
>expect &&
437+
test_cmp expect actual
438+
'
439+
440+
merge_conflict_resolve () {
441+
git reset --hard &&
442+
test_must_fail git merge six.1 &&
443+
# Resolution is to replace 7 with 6.1 and 6.2 (i.e. take both)
444+
concat_insert short 6.1 6.2 >file1 &&
445+
concat_insert long 6.1 6.2 >file2
446+
}
447+
415448
test_expect_success 'multiple identical conflicts' '
416449
git reset --hard &&
417450
@@ -441,7 +474,7 @@ test_expect_success 'multiple identical conflicts' '
441474
# - six.1 replaces these 7s with 6.1
442475
# - six.2 replaces these 7s with 6.2
443476
444-
test_must_fail git merge six.1 &&
477+
merge_conflict_resolve &&
445478
446479
# Check that rerere knows that file1 and file2 have conflicts
447480
@@ -452,19 +485,43 @@ test_expect_success 'multiple identical conflicts' '
452485
git rerere status | sort >actual &&
453486
test_cmp expect actual &&
454487
455-
# Resolution is to replace 7 with 6.1 and 6.2 (i.e. take both)
456-
concat_insert short 6.1 6.2 >file1 &&
457-
concat_insert long 6.1 6.2 >file2 &&
458-
459488
git rerere remaining >actual &&
460489
test_cmp expect actual &&
461490
491+
count_pre_post 2 0 &&
492+
493+
# Pretend that the conflicts were made quite some time ago
494+
find .git/rr-cache/ -type f | xargs test-chmtime -172800 &&
495+
496+
# Unresolved entries have not expired yet
497+
git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
498+
count_pre_post 2 0 &&
499+
500+
# Unresolved entries have expired
501+
git -c gc.rerereresolved=5 -c gc.rerereunresolved=1 rerere gc &&
502+
count_pre_post 0 0 &&
503+
504+
# Recreate the conflicted state
505+
merge_conflict_resolve &&
506+
count_pre_post 2 0 &&
507+
508+
# Clear it
509+
git rerere clear &&
510+
count_pre_post 0 0 &&
511+
512+
# Recreate the conflicted state
513+
merge_conflict_resolve &&
514+
count_pre_post 2 0 &&
515+
462516
# We resolved file1 and file2
463517
git rerere &&
464518
>expect &&
465519
git rerere remaining >actual &&
466520
test_cmp expect actual &&
467521
522+
# We must have recorded both of them
523+
count_pre_post 2 2 &&
524+
468525
# Now we should be able to resolve them both
469526
git reset --hard &&
470527
test_must_fail git merge six.1 &&
@@ -477,7 +534,19 @@ test_expect_success 'multiple identical conflicts' '
477534
concat_insert short 6.1 6.2 >file1.expect &&
478535
concat_insert long 6.1 6.2 >file2.expect &&
479536
test_cmp file1.expect file1 &&
480-
test_cmp file2.expect file2
537+
test_cmp file2.expect file2 &&
538+
539+
# Pretend that the resolutions are old again
540+
find .git/rr-cache/ -type f | xargs test-chmtime -172800 &&
541+
542+
# Resolved entries have not expired yet
543+
git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
544+
545+
count_pre_post 2 2 &&
546+
547+
# Resolved entries have expired
548+
git -c gc.rerereresolved=1 -c gc.rerereunresolved=5 rerere gc &&
549+
count_pre_post 0 0
481550
'
482551

483552
test_done

0 commit comments

Comments
 (0)