Re: git mergetool broken when rerere active
Junio C Hamano <gitster@pobox.com> writes:
> Probably we would need a "git rerere remaining" sobcommand that is similar
> to status but also includes the "punted" paths.
... which may look like this.
Replace use of "git rerere status" in bb0a484 (mergetool: Skip autoresolved paths, 2010-08-17) with "git rerere remainder" and see what happens.
builtin/rerere.c | 12 +++++++++-
rerere.c | 63 +++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 64 insertions(+), 11 deletions(-)
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 642bf35..081fccc 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -8,7 +8,7 @@
#include "xdiff-interface.h"
static const char * const rerere_usage[] = {
- "git rerere [clear | status | diff | gc]",
+ "git rerere [clear | status | remaining | diff | gc]",
NULL,
};
@@ -147,6 +147,8 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[0], "clear")) {
for (i = 0; i < merge_rr.nr; i++) {
const char *name = (const char *)merge_rr.items[i].util;
+ if (!name)
+ continue;
if (!has_rerere_resolution(name))
unlink_rr_item(name);
}
@@ -154,12 +156,20 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
} else if (!strcmp(argv[0], "gc"))
garbage_collect(&merge_rr);
else if (!strcmp(argv[0], "status"))
+ for (i = 0; i < merge_rr.nr; i++) {
+ if (!merge_rr.items[i].util)
+ continue;
+ printf("%s\n", merge_rr.items[i].string);
+ }
+ else if (!strcmp(argv[0], "remaining"))
for (i = 0; i < merge_rr.nr; i++)
printf("%s\n", merge_rr.items[i].string);
else if (!strcmp(argv[0], "diff"))
for (i = 0; i < merge_rr.nr; i++) {
const char *path = merge_rr.items[i].string;
const char *name = (const char *)merge_rr.items[i].util;
+ if (!name)
+ continue;
diff_two(rerere_path(name, "preimage"), path, path, path);
}
else
diff --git a/rerere.c b/rerere.c
index d260843..eb47f97 100644
--- a/rerere.c
+++ b/rerere.c
@@ -350,21 +350,57 @@ static int find_conflict(struct string_list *conflict)
int i;
if (read_cache() < 0)
return error("Could not read index");
- for (i = 0; i+1 < active_nr; i++) {
- struct cache_entry *e2 = active_cache[i];
- struct cache_entry *e3 = active_cache[i+1];
- if (ce_stage(e2) == 2 &&
- ce_stage(e3) == 3 &&
- ce_same_name(e2, e3) &&
- S_ISREG(e2->ce_mode) &&
- S_ISREG(e3->ce_mode)) {
- string_list_insert(conflict, (const char *)e2->name);
- i++; /* skip over both #2 and #3 */
+
+ /*
+ * Collect paths with conflict, mark them with NULL (punted) or
+ * !NULL (eligible) in their ->util field.
+ */
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *e = active_cache[i];
+ struct string_list_item *it;
+
+ if (!ce_stage(e))
+ continue;
+ it = string_list_insert(conflict, (const char *)e->name);
+ it->util = NULL;
+ if (ce_stage(e) == 1) {
+ if (active_nr <= ++i)
+ break;
}
+
+ /* Only handle regular files with both stages #2 and #3 */
+ if (i + 1 < active_nr) {
+ struct cache_entry *e2 = active_cache[i];
+ struct cache_entry *e3 = active_cache[i + 1];
+ if (ce_stage(e2) == 2 &&
+ ce_stage(e3) == 3 &&
+ ce_same_name(e, e3) &&
+ S_ISREG(e2->ce_mode) &&
+ S_ISREG(e3->ce_mode))
+ it->util = (void *) 1;
+ }
+
+ /* Skip the entries with the same name */
+ while (i < active_nr && ce_same_name(e, active_cache[i]))
+ i++;
+ i--; /* compensate for the outer loop */
}
return 0;
}
+static void add_punted(struct string_list *merge_rr)
+{
+ int i;
+ struct string_list conflict = STRING_LIST_INIT_DUP;
+
+ find_conflict(&conflict);
+ for (i = 0; i < conflict.nr; i++) {
+ if (conflict.items[i].util)
+ continue;
+ string_list_insert(merge_rr, conflict.items[i].string);
+ }
+}
+
static int merge(const char *name, const char *path)
{
int ret;
@@ -451,6 +487,8 @@ static int do_plain_rerere(struct string_list *rr, int fd)
for (i = 0; i < conflict.nr; i++) {
const char *path = conflict.items[i].string;
+ if (!conflict.items[i].util)
+ continue; /* punted */
if (!string_list_has_string(rr, path)) {
unsigned char sha1[20];
char *hex;
@@ -478,6 +516,8 @@ static int do_plain_rerere(struct string_list *rr, int fd)
const char *path = rr->items[i].string;
const char *name = (const char *)rr->items[i].util;
+ if (!name)
+ continue;
if (has_rerere_resolution(name)) {
if (!merge(name, path)) {
if (rerere_autoupdate)
@@ -552,6 +592,7 @@ int setup_rerere(struct string_list *merge_rr, int flags)
fd = hold_lock_file_for_update(&write_lock, merge_rr_path,
LOCK_DIE_ON_ERROR);
read_rr(merge_rr);
+ add_punted(merge_rr);
return fd;
}
@@ -607,6 +648,8 @@ int rerere_forget(const char **pathspec)
find_conflict(&conflict);
for (i = 0; i < conflict.nr; i++) {
struct string_list_item *it = &conflict.items[i];
+ if (!conflict.items[i].util)
+ continue; /* punted */
if (!match_pathspec(pathspec, it->string, strlen(it->string),
0, NULL))
continue;