mirror of
https://github.com/git/git.git
synced 2024-11-28 20:44:04 +08:00
rerere: do use multiple variants
This enables the multiple-variant support for real. Multiple conflicts of the same shape can have differences in contexts where they appear, interfering the replaying of recorded resolution of one conflict to another, and in such a case, their resolutions are recorded as different variants under the same conflict ID. We still need to adjust garbage collection codepaths for this change, but the basic "replay" functionality is functional with this change. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
82efa6e27e
commit
629716d256
100
rerere.c
100
rerere.c
@ -74,7 +74,9 @@ static void assign_variant(struct rerere_id *id)
|
||||
|
||||
variant = id->variant;
|
||||
if (variant < 0) {
|
||||
variant = 0; /* for now */
|
||||
for (variant = 0; variant < rr_dir->status_nr; variant++)
|
||||
if (!rr_dir->status[variant])
|
||||
break;
|
||||
}
|
||||
fit_variant(rr_dir, variant);
|
||||
id->variant = variant;
|
||||
@ -177,15 +179,6 @@ static int has_rerere_resolution(const struct rerere_id *id)
|
||||
return ((id->collection->status[variant] & both) == both);
|
||||
}
|
||||
|
||||
static int has_rerere_preimage(const struct rerere_id *id)
|
||||
{
|
||||
int variant = id->variant;
|
||||
|
||||
if (variant < 0)
|
||||
return 0;
|
||||
return (id->collection->status[variant] & RR_HAS_PREIMAGE);
|
||||
}
|
||||
|
||||
static struct rerere_id *new_rerere_id_hex(char *hex)
|
||||
{
|
||||
struct rerere_id *id = xmalloc(sizeof(*id));
|
||||
@ -818,6 +811,13 @@ static void update_paths(struct string_list *update)
|
||||
rollback_lock_file(&index_lock);
|
||||
}
|
||||
|
||||
static void remove_variant(struct rerere_id *id)
|
||||
{
|
||||
unlink_or_warn(rerere_path(id, "postimage"));
|
||||
unlink_or_warn(rerere_path(id, "preimage"));
|
||||
id->collection->status[id->variant] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The path indicated by rr_item may still have conflict for which we
|
||||
* have a recorded resolution, in which case replay it and optionally
|
||||
@ -830,32 +830,46 @@ static void do_rerere_one_path(struct string_list_item *rr_item,
|
||||
{
|
||||
const char *path = rr_item->string;
|
||||
struct rerere_id *id = rr_item->util;
|
||||
struct rerere_dir *rr_dir = id->collection;
|
||||
int variant;
|
||||
|
||||
if (id->variant < 0)
|
||||
assign_variant(id);
|
||||
variant = id->variant;
|
||||
|
||||
if (!has_rerere_preimage(id)) {
|
||||
/*
|
||||
* We are the first to encounter this conflict. Ask
|
||||
* handle_file() to write the normalized contents to
|
||||
* the "preimage" file.
|
||||
*/
|
||||
handle_file(path, NULL, rerere_path(id, "preimage"));
|
||||
if (id->collection->status[variant] & RR_HAS_POSTIMAGE) {
|
||||
const char *path = rerere_path(id, "postimage");
|
||||
if (unlink(path))
|
||||
die_errno("cannot unlink stray '%s'", path);
|
||||
id->collection->status[variant] &= ~RR_HAS_POSTIMAGE;
|
||||
/* Has the user resolved it already? */
|
||||
if (variant >= 0) {
|
||||
if (!handle_file(path, NULL, NULL)) {
|
||||
copy_file(rerere_path(id, "postimage"), path, 0666);
|
||||
id->collection->status[variant] |= RR_HAS_POSTIMAGE;
|
||||
fprintf(stderr, "Recorded resolution for '%s'.\n", path);
|
||||
free_rerere_id(rr_item);
|
||||
rr_item->util = NULL;
|
||||
return;
|
||||
}
|
||||
id->collection->status[variant] |= RR_HAS_PREIMAGE;
|
||||
fprintf(stderr, "Recorded preimage for '%s'\n", path);
|
||||
return;
|
||||
} else if (has_rerere_resolution(id)) {
|
||||
/* Is there a recorded resolution we could attempt to apply? */
|
||||
if (merge(id, path))
|
||||
return; /* failed to replay */
|
||||
/*
|
||||
* There may be other variants that can cleanly
|
||||
* replay. Try them and update the variant number for
|
||||
* this one.
|
||||
*/
|
||||
}
|
||||
|
||||
/* Does any existing resolution apply cleanly? */
|
||||
for (variant = 0; variant < rr_dir->status_nr; variant++) {
|
||||
const int both = RR_HAS_PREIMAGE | RR_HAS_POSTIMAGE;
|
||||
struct rerere_id vid = *id;
|
||||
|
||||
if ((rr_dir->status[variant] & both) != both)
|
||||
continue;
|
||||
|
||||
vid.variant = variant;
|
||||
if (merge(&vid, path))
|
||||
continue; /* failed to replay */
|
||||
|
||||
/*
|
||||
* If there already is a different variant that applies
|
||||
* cleanly, there is no point maintaining our own variant.
|
||||
*/
|
||||
if (0 <= id->variant && id->variant != variant)
|
||||
remove_variant(id);
|
||||
|
||||
if (rerere_autoupdate)
|
||||
string_list_insert(update, path);
|
||||
@ -863,16 +877,24 @@ static void do_rerere_one_path(struct string_list_item *rr_item,
|
||||
fprintf(stderr,
|
||||
"Resolved '%s' using previous resolution.\n",
|
||||
path);
|
||||
} else if (!handle_file(path, NULL, NULL)) {
|
||||
/* The user has resolved it. */
|
||||
copy_file(rerere_path(id, "postimage"), path, 0666);
|
||||
id->collection->status[variant] |= RR_HAS_POSTIMAGE;
|
||||
fprintf(stderr, "Recorded resolution for '%s'.\n", path);
|
||||
} else {
|
||||
free_rerere_id(rr_item);
|
||||
rr_item->util = NULL;
|
||||
return;
|
||||
}
|
||||
free_rerere_id(rr_item);
|
||||
rr_item->util = NULL;
|
||||
|
||||
/* None of the existing one applies; we need a new variant */
|
||||
assign_variant(id);
|
||||
|
||||
variant = id->variant;
|
||||
handle_file(path, NULL, rerere_path(id, "preimage"));
|
||||
if (id->collection->status[variant] & RR_HAS_POSTIMAGE) {
|
||||
const char *path = rerere_path(id, "postimage");
|
||||
if (unlink(path))
|
||||
die_errno("cannot unlink stray '%s'", path);
|
||||
id->collection->status[variant] &= ~RR_HAS_POSTIMAGE;
|
||||
}
|
||||
id->collection->status[variant] |= RR_HAS_PREIMAGE;
|
||||
fprintf(stderr, "Recorded preimage for '%s'\n", path);
|
||||
}
|
||||
|
||||
static int do_plain_rerere(struct string_list *rr, int fd)
|
||||
|
@ -412,7 +412,7 @@ concat_insert () {
|
||||
cat early && printf "%s\n" "$@" && cat late "$last"
|
||||
}
|
||||
|
||||
test_expect_failure 'multiple identical conflicts' '
|
||||
test_expect_success 'multiple identical conflicts' '
|
||||
git reset --hard &&
|
||||
|
||||
test_seq 1 6 >early &&
|
||||
|
Loading…
Reference in New Issue
Block a user