зеркало из https://github.com/microsoft/git.git
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 <gitster@pobox.com>
This commit is contained in:
Родитель
629716d256
Коммит
1be1e85115
85
rerere.c
85
rerere.c
|
@ -1081,29 +1081,16 @@ int rerere_forget(struct pathspec *pathspec)
|
||||||
* Garbage collection support
|
* Garbage collection support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
static time_t rerere_created_at(struct rerere_id *id)
|
||||||
* Note that this is not reentrant but is used only one-at-a-time
|
|
||||||
* so it does not matter right now.
|
|
||||||
*/
|
|
||||||
static struct rerere_id *dirname_to_id(const char *name)
|
|
||||||
{
|
|
||||||
static struct rerere_id id;
|
|
||||||
id.collection = find_rerere_dir(name);
|
|
||||||
return &id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static time_t rerere_created_at(const char *dir_name)
|
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct rerere_id *id = dirname_to_id(dir_name);
|
|
||||||
|
|
||||||
return stat(rerere_path(id, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
|
return stat(rerere_path(id, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
static time_t rerere_last_used_at(const char *dir_name)
|
static time_t rerere_last_used_at(struct rerere_id *id)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct rerere_id *id = dirname_to_id(dir_name);
|
|
||||||
|
|
||||||
return stat(rerere_path(id, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
|
return stat(rerere_path(id, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
|
||||||
}
|
}
|
||||||
|
@ -1113,15 +1100,28 @@ static time_t rerere_last_used_at(const char *dir_name)
|
||||||
*/
|
*/
|
||||||
static void unlink_rr_item(struct rerere_id *id)
|
static void unlink_rr_item(struct rerere_id *id)
|
||||||
{
|
{
|
||||||
unlink(rerere_path(id, "thisimage"));
|
unlink_or_warn(rerere_path(id, "thisimage"));
|
||||||
unlink(rerere_path(id, "preimage"));
|
remove_variant(id);
|
||||||
unlink(rerere_path(id, "postimage"));
|
id->collection->status[id->variant] = 0;
|
||||||
/*
|
}
|
||||||
* NEEDSWORK: what if this rmdir() fails? Wouldn't we then
|
|
||||||
* assume that we already have preimage recorded in
|
static void prune_one(struct rerere_id *id, time_t now,
|
||||||
* do_plain_rerere()?
|
int cutoff_resolve, int cutoff_noresolve)
|
||||||
*/
|
{
|
||||||
rmdir(rerere_path(id, NULL));
|
time_t then;
|
||||||
|
int cutoff;
|
||||||
|
|
||||||
|
then = rerere_last_used_at(id);
|
||||||
|
if (then)
|
||||||
|
cutoff = cutoff_resolve;
|
||||||
|
else {
|
||||||
|
then = rerere_created_at(id);
|
||||||
|
if (!then)
|
||||||
|
return;
|
||||||
|
cutoff = cutoff_noresolve;
|
||||||
|
}
|
||||||
|
if (then < now - cutoff * 86400)
|
||||||
|
unlink_rr_item(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rerere_gc(struct string_list *rr)
|
void rerere_gc(struct string_list *rr)
|
||||||
|
@ -1129,8 +1129,8 @@ void rerere_gc(struct string_list *rr)
|
||||||
struct string_list to_remove = STRING_LIST_INIT_DUP;
|
struct string_list to_remove = STRING_LIST_INIT_DUP;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *e;
|
struct dirent *e;
|
||||||
int i, cutoff;
|
int i;
|
||||||
time_t now = time(NULL), then;
|
time_t now = time(NULL);
|
||||||
int cutoff_noresolve = 15;
|
int cutoff_noresolve = 15;
|
||||||
int cutoff_resolve = 60;
|
int cutoff_resolve = 60;
|
||||||
|
|
||||||
|
@ -1142,25 +1142,32 @@ void rerere_gc(struct string_list *rr)
|
||||||
die_errno("unable to open rr-cache directory");
|
die_errno("unable to open rr-cache directory");
|
||||||
/* Collect stale conflict IDs ... */
|
/* Collect stale conflict IDs ... */
|
||||||
while ((e = readdir(dir))) {
|
while ((e = readdir(dir))) {
|
||||||
|
struct rerere_dir *rr_dir;
|
||||||
|
struct rerere_id id;
|
||||||
|
int now_empty;
|
||||||
|
|
||||||
if (is_dot_or_dotdot(e->d_name))
|
if (is_dot_or_dotdot(e->d_name))
|
||||||
continue;
|
continue;
|
||||||
|
rr_dir = find_rerere_dir(e->d_name);
|
||||||
|
if (!rr_dir)
|
||||||
|
continue; /* or should we remove e->d_name? */
|
||||||
|
|
||||||
then = rerere_last_used_at(e->d_name);
|
now_empty = 1;
|
||||||
if (then) {
|
for (id.variant = 0, id.collection = rr_dir;
|
||||||
cutoff = cutoff_resolve;
|
id.variant < id.collection->status_nr;
|
||||||
} else {
|
id.variant++) {
|
||||||
then = rerere_created_at(e->d_name);
|
prune_one(&id, now, cutoff_resolve, cutoff_noresolve);
|
||||||
if (!then)
|
if (id.collection->status[id.variant])
|
||||||
continue;
|
now_empty = 0;
|
||||||
cutoff = cutoff_noresolve;
|
|
||||||
}
|
}
|
||||||
if (then < now - cutoff * 86400)
|
if (now_empty)
|
||||||
string_list_append(&to_remove, e->d_name);
|
string_list_append(&to_remove, e->d_name);
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
/* ... and then remove them one-by-one */
|
|
||||||
|
/* ... and then remove the empty directories */
|
||||||
for (i = 0; i < to_remove.nr; i++)
|
for (i = 0; i < to_remove.nr; i++)
|
||||||
unlink_rr_item(dirname_to_id(to_remove.items[i].string));
|
rmdir(git_path("rr-cache/%s", to_remove.items[i].string));
|
||||||
string_list_clear(&to_remove, 0);
|
string_list_clear(&to_remove, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1177,8 +1184,10 @@ void rerere_clear(struct string_list *merge_rr)
|
||||||
|
|
||||||
for (i = 0; i < merge_rr->nr; i++) {
|
for (i = 0; i < merge_rr->nr; i++) {
|
||||||
struct rerere_id *id = merge_rr->items[i].util;
|
struct rerere_id *id = merge_rr->items[i].util;
|
||||||
if (!has_rerere_resolution(id))
|
if (!has_rerere_resolution(id)) {
|
||||||
unlink_rr_item(id);
|
unlink_rr_item(id);
|
||||||
|
rmdir(rerere_path(id, NULL));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
unlink_or_warn(git_path("MERGE_RR"));
|
unlink_or_warn(git_path("MERGE_RR"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -412,6 +412,39 @@ concat_insert () {
|
||||||
cat early && printf "%s\n" "$@" && cat late "$last"
|
cat early && printf "%s\n" "$@" && cat late "$last"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
count_pre_post () {
|
||||||
|
find .git/rr-cache/ -type f -name "preimage*" >actual &&
|
||||||
|
test_line_count = "$1" actual &&
|
||||||
|
find .git/rr-cache/ -type f -name "postimage*" >actual &&
|
||||||
|
test_line_count = "$2" actual
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success 'rerere gc' '
|
||||||
|
find .git/rr-cache -type f >original &&
|
||||||
|
xargs test-chmtime -172800 <original &&
|
||||||
|
|
||||||
|
git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
|
||||||
|
find .git/rr-cache -type f >actual &&
|
||||||
|
test_cmp original actual &&
|
||||||
|
|
||||||
|
git -c gc.rerereresolved=5 -c gc.rerereunresolved=0 rerere gc &&
|
||||||
|
find .git/rr-cache -type f >actual &&
|
||||||
|
test_cmp original actual &&
|
||||||
|
|
||||||
|
git -c gc.rerereresolved=0 -c gc.rerereunresolved=0 rerere gc &&
|
||||||
|
find .git/rr-cache -type f >actual &&
|
||||||
|
>expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
merge_conflict_resolve () {
|
||||||
|
git reset --hard &&
|
||||||
|
test_must_fail git merge six.1 &&
|
||||||
|
# Resolution is to replace 7 with 6.1 and 6.2 (i.e. take both)
|
||||||
|
concat_insert short 6.1 6.2 >file1 &&
|
||||||
|
concat_insert long 6.1 6.2 >file2
|
||||||
|
}
|
||||||
|
|
||||||
test_expect_success 'multiple identical conflicts' '
|
test_expect_success 'multiple identical conflicts' '
|
||||||
git reset --hard &&
|
git reset --hard &&
|
||||||
|
|
||||||
|
@ -441,7 +474,7 @@ test_expect_success 'multiple identical conflicts' '
|
||||||
# - six.1 replaces these 7s with 6.1
|
# - six.1 replaces these 7s with 6.1
|
||||||
# - six.2 replaces these 7s with 6.2
|
# - six.2 replaces these 7s with 6.2
|
||||||
|
|
||||||
test_must_fail git merge six.1 &&
|
merge_conflict_resolve &&
|
||||||
|
|
||||||
# Check that rerere knows that file1 and file2 have conflicts
|
# Check that rerere knows that file1 and file2 have conflicts
|
||||||
|
|
||||||
|
@ -452,19 +485,43 @@ test_expect_success 'multiple identical conflicts' '
|
||||||
git rerere status | sort >actual &&
|
git rerere status | sort >actual &&
|
||||||
test_cmp expect actual &&
|
test_cmp expect actual &&
|
||||||
|
|
||||||
# Resolution is to replace 7 with 6.1 and 6.2 (i.e. take both)
|
|
||||||
concat_insert short 6.1 6.2 >file1 &&
|
|
||||||
concat_insert long 6.1 6.2 >file2 &&
|
|
||||||
|
|
||||||
git rerere remaining >actual &&
|
git rerere remaining >actual &&
|
||||||
test_cmp expect actual &&
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
count_pre_post 2 0 &&
|
||||||
|
|
||||||
|
# Pretend that the conflicts were made quite some time ago
|
||||||
|
find .git/rr-cache/ -type f | xargs test-chmtime -172800 &&
|
||||||
|
|
||||||
|
# Unresolved entries have not expired yet
|
||||||
|
git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
|
||||||
|
count_pre_post 2 0 &&
|
||||||
|
|
||||||
|
# Unresolved entries have expired
|
||||||
|
git -c gc.rerereresolved=5 -c gc.rerereunresolved=1 rerere gc &&
|
||||||
|
count_pre_post 0 0 &&
|
||||||
|
|
||||||
|
# Recreate the conflicted state
|
||||||
|
merge_conflict_resolve &&
|
||||||
|
count_pre_post 2 0 &&
|
||||||
|
|
||||||
|
# Clear it
|
||||||
|
git rerere clear &&
|
||||||
|
count_pre_post 0 0 &&
|
||||||
|
|
||||||
|
# Recreate the conflicted state
|
||||||
|
merge_conflict_resolve &&
|
||||||
|
count_pre_post 2 0 &&
|
||||||
|
|
||||||
# We resolved file1 and file2
|
# We resolved file1 and file2
|
||||||
git rerere &&
|
git rerere &&
|
||||||
>expect &&
|
>expect &&
|
||||||
git rerere remaining >actual &&
|
git rerere remaining >actual &&
|
||||||
test_cmp expect actual &&
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
# We must have recorded both of them
|
||||||
|
count_pre_post 2 2 &&
|
||||||
|
|
||||||
# Now we should be able to resolve them both
|
# Now we should be able to resolve them both
|
||||||
git reset --hard &&
|
git reset --hard &&
|
||||||
test_must_fail git merge six.1 &&
|
test_must_fail git merge six.1 &&
|
||||||
|
@ -477,7 +534,19 @@ test_expect_success 'multiple identical conflicts' '
|
||||||
concat_insert short 6.1 6.2 >file1.expect &&
|
concat_insert short 6.1 6.2 >file1.expect &&
|
||||||
concat_insert long 6.1 6.2 >file2.expect &&
|
concat_insert long 6.1 6.2 >file2.expect &&
|
||||||
test_cmp file1.expect file1 &&
|
test_cmp file1.expect file1 &&
|
||||||
test_cmp file2.expect file2
|
test_cmp file2.expect file2 &&
|
||||||
|
|
||||||
|
# Pretend that the resolutions are old again
|
||||||
|
find .git/rr-cache/ -type f | xargs test-chmtime -172800 &&
|
||||||
|
|
||||||
|
# Resolved entries have not expired yet
|
||||||
|
git -c gc.rerereresolved=5 -c gc.rerereunresolved=5 rerere gc &&
|
||||||
|
|
||||||
|
count_pre_post 2 2 &&
|
||||||
|
|
||||||
|
# Resolved entries have expired
|
||||||
|
git -c gc.rerereresolved=1 -c gc.rerereunresolved=5 rerere gc &&
|
||||||
|
count_pre_post 0 0
|
||||||
'
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
Загрузка…
Ссылка в новой задаче