summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 50b7e70)
raw | patch | inline | side by side (parent: 50b7e70)
author | Junio C Hamano <gitster@pobox.com> | |
Wed, 5 Aug 2009 07:04:51 +0000 (00:04 -0700) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Fri, 7 Aug 2009 04:16:01 +0000 (21:16 -0700) |
When a path is unmerged in the index, we used to always say "unmerged" in
the "Changed but not updated" section, even when the path was deleted in
the work tree.
Remove unmerged entries from the "Updated" section, and create a new
section "Unmerged paths". Describe how the different stages conflict
in more detail in this new section.
Note that with the current 3-way merge policy (with or without recursive),
certain combinations of index stages should never happen. For example,
having only stage #2 means that a path that did not exist in the common
ancestor was added by us while the other branch did not do anything to it,
which would have autoresolved to take our addition. The code nevertheless
prepares for the possibility that future merge policies may leave a path
in such a state.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
the "Changed but not updated" section, even when the path was deleted in
the work tree.
Remove unmerged entries from the "Updated" section, and create a new
section "Unmerged paths". Describe how the different stages conflict
in more detail in this new section.
Note that with the current 3-way merge policy (with or without recursive),
certain combinations of index stages should never happen. For example,
having only stage #2 means that a path that did not exist in the common
ancestor was added by us while the other branch did not do anything to it,
which would have autoresolved to take our addition. The code nevertheless
prepares for the possibility that future merge policies may leave a path
in such a state.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/t7060-wtstatus.sh | patch | blob | history | |
wt-status.c | patch | blob | history | |
wt-status.h | patch | blob | history |
diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh
index 5ad2cd1d049271e4cfda6e5033d45d92d8268076..1044aa65494f6c908aa4d70c1590a5577b288f50 100755 (executable)
--- a/t/t7060-wtstatus.sh
+++ b/t/t7060-wtstatus.sh
test_cmp expect actual
'
+cat >expect <<EOF
+# On branch side
+# Unmerged paths:
+# (use "git reset HEAD <file>..." to unstage)
+# (use "git add <file>..." to mark resolution)
+#
+# deleted by us: foo
+#
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
+
+test_expect_success 'M/D conflict does not segfault' '
+ mkdir mdconflict &&
+ (
+ cd mdconflict &&
+ git init &&
+ test_commit initial foo "" &&
+ test_commit modify foo foo &&
+ git checkout -b side HEAD^ &&
+ git rm foo &&
+ git commit -m delete &&
+ test_must_fail git merge master &&
+ test_must_fail git status > ../actual
+ ) &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/wt-status.c b/wt-status.c
index 9aab56775389e8a2c0ffd38e15baba2e984ced31..97fedfaa196777277577b0057743ae9f5f25ecc2 100644 (file)
--- a/wt-status.c
+++ b/wt-status.c
GIT_COLOR_RED, /* WT_STATUS_CHANGED */
GIT_COLOR_RED, /* WT_STATUS_UNTRACKED */
GIT_COLOR_RED, /* WT_STATUS_NOBRANCH */
+ GIT_COLOR_RED, /* WT_STATUS_UNMERGED */
};
enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
return WT_STATUS_UNTRACKED;
if (!strcasecmp(var+offset, "nobranch"))
return WT_STATUS_NOBRANCH;
+ if (!strcasecmp(var+offset, "unmerged"))
+ return WT_STATUS_UNMERGED;
die("bad config variable '%s'", var);
}
s->change.strdup_strings = 1;
}
+static void wt_status_print_unmerged_header(struct wt_status *s)
+{
+ const char *c = color(WT_STATUS_HEADER);
+ color_fprintf_ln(s->fp, c, "# Unmerged paths:");
+ if (!s->is_initial)
+ color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference);
+ else
+ color_fprintf_ln(s->fp, c, "# (use \"git rm --cached <file>...\" to unstage)");
+ color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to mark resolution)");
+ color_fprintf_ln(s->fp, c, "#");
+}
+
static void wt_status_print_cached_header(struct wt_status *s)
{
const char *c = color(WT_STATUS_HEADER);
#define quote_path quote_path_relative
+static void wt_status_print_unmerged_data(struct wt_status *s,
+ struct string_list_item *it)
+{
+ const char *c = color(WT_STATUS_UNMERGED);
+ struct wt_status_change_data *d = it->util;
+ struct strbuf onebuf = STRBUF_INIT;
+ const char *one, *how = "bug";
+
+ one = quote_path(it->string, -1, &onebuf, s->prefix);
+ color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
+ switch (d->stagemask) {
+ case 1: how = "both deleted:"; break;
+ case 2: how = "added by us:"; break;
+ case 3: how = "deleted by them:"; break;
+ case 4: how = "added by them:"; break;
+ case 5: how = "deleted by us:"; break;
+ case 6: how = "both added:"; break;
+ case 7: how = "both modified:"; break;
+ }
+ color_fprintf(s->fp, c, "%-20s%s\n", how, one);
+ strbuf_release(&onebuf);
+}
+
static void wt_status_print_change_data(struct wt_status *s,
int change_type,
struct string_list_item *it)
}
}
+static int unmerged_mask(const char *path)
+{
+ int pos, mask;
+ struct cache_entry *ce;
+
+ pos = cache_name_pos(path, strlen(path));
+ if (0 <= pos)
+ return 0;
+
+ mask = 0;
+ pos = -pos-1;
+ while (pos < active_nr) {
+ ce = active_cache[pos++];
+ if (strcmp(ce->name, path) || !ce_stage(ce))
+ break;
+ mask |= (1 << (ce_stage(ce) - 1));
+ }
+ return mask;
+}
+
static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
struct diff_options *options,
void *data)
case DIFF_STATUS_RENAMED:
d->head_path = xstrdup(p->one->path);
break;
+ case DIFF_STATUS_UNMERGED:
+ d->stagemask = unmerged_mask(p->two->path);
+ break;
}
}
}
d = xcalloc(1, sizeof(*d));
it->util = d;
}
- if (ce_stage(ce))
+ if (ce_stage(ce)) {
d->index_status = DIFF_STATUS_UNMERGED;
+ d->stagemask |= (1 << (ce_stage(ce) - 1));
+ }
else
d->index_status = DIFF_STATUS_ADDED;
}
wt_status_collect_changes_index(s);
}
+static void wt_status_print_unmerged(struct wt_status *s)
+{
+ int shown_header = 0;
+ int i;
+
+ for (i = 0; i < s->change.nr; i++) {
+ struct wt_status_change_data *d;
+ struct string_list_item *it;
+ it = &(s->change.items[i]);
+ d = it->util;
+ if (!d->stagemask)
+ continue;
+ if (!shown_header) {
+ wt_status_print_unmerged_header(s);
+ shown_header = 1;
+ }
+ wt_status_print_unmerged_data(s, it);
+ }
+ if (shown_header)
+ wt_status_print_trailer(s);
+
+}
+
static void wt_status_print_updated(struct wt_status *s)
{
int shown_header = 0;
for (i = 0; i < s->change.nr; i++) {
struct wt_status_change_data *d;
d = s->change.items[i].util;
- if (!d->worktree_status)
+ if (!d->worktree_status ||
+ d->worktree_status == DIFF_STATUS_UNMERGED)
continue;
changes = 1;
if (d->worktree_status == DIFF_STATUS_DELETED)
struct string_list_item *it;
it = &(s->change.items[i]);
d = it->util;
- if (!d->worktree_status)
+ if (!d->worktree_status ||
+ d->worktree_status == DIFF_STATUS_UNMERGED)
continue;
wt_status_print_change_data(s, WT_STATUS_CHANGED, it);
}
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
}
+ wt_status_print_unmerged(s);
wt_status_print_updated(s);
wt_status_print_changed(s);
if (wt_status_submodule_summary)
diff --git a/wt-status.h b/wt-status.h
index 82a602b3bbd0921d52f5ef528fdd4af146c4b796..f80142ffdecb928d7c9e3f72e0d9f9d27102118c 100644 (file)
--- a/wt-status.h
+++ b/wt-status.h
WT_STATUS_CHANGED,
WT_STATUS_UNTRACKED,
WT_STATUS_NOBRANCH,
+ WT_STATUS_UNMERGED,
};
enum untracked_status_type {