summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xt/t7060-wtstatus.sh27
-rw-r--r--wt-status.c95
-rw-r--r--wt-status.h1
3 files changed, 120 insertions, 3 deletions
diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh
index 5ad2cd1..1044aa6 100755
--- a/t/t7060-wtstatus.sh
+++ b/t/t7060-wtstatus.sh
@@ -28,4 +28,31 @@ test_expect_success 'Report new path with conflict' '
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 9aab567..97fedfa 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -20,6 +20,7 @@ static char wt_status_colors[][COLOR_MAXLEN] = {
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;
@@ -37,6 +38,8 @@ static int parse_status_slot(const char *var, int offset)
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);
}
@@ -59,6 +62,18 @@ void wt_status_prepare(struct wt_status *s)
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);
@@ -99,6 +114,29 @@ static void wt_status_print_trailer(struct wt_status *s)
#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)
@@ -187,6 +225,26 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
}
}
+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)
@@ -213,6 +271,9 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
case DIFF_STATUS_RENAMED:
d->head_path = xstrdup(p->one->path);
break;
+ case DIFF_STATUS_UNMERGED:
+ d->stagemask = unmerged_mask(p->two->path);
+ break;
}
}
}
@@ -260,8 +321,10 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
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;
}
@@ -277,6 +340,29 @@ void wt_status_collect_changes(struct wt_status *s)
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;
@@ -314,7 +400,8 @@ static int wt_status_check_worktree_changes(struct wt_status *s)
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)
@@ -338,7 +425,8 @@ static void wt_status_print_changed(struct wt_status *s)
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);
}
@@ -479,6 +567,7 @@ void wt_status_print(struct wt_status *s)
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 82a602b..f80142f 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -10,6 +10,7 @@ enum color_wt_status {
WT_STATUS_CHANGED,
WT_STATUS_UNTRACKED,
WT_STATUS_NOBRANCH,
+ WT_STATUS_UNMERGED,
};
enum untracked_status_type {