{"thread":{"id":"20398","subject":"[PATCH 0/5] Revamping \"git status\"","startedAt":"2009-08-05T09:15:41Z","lastAt":"2009-08-06T19:57:05Z","messageCount":22,"participants":["Junio C Hamano","Thomas Rast","Jeff King","Sverre Rabbelier"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"119587","messageId":"1249463746-21538-1-git-send-email-gitster@pobox.com","threadId":"20398","inReplyTo":null,"subject":"[PATCH 0/5] Revamping \"git status\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-05T09:15:41Z","receivedAt":"2009-08-05T09:15:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The first two patches in this series are a small bugfix and an internal\nclean-up for the underlying \"diff-index\" engine used by \"git status\" when\nit inspects how the index differs from the HEAD commit.\n\nThe third one separates the logic to inspect the changes in the index and\nthe work tree from the code to show the result in \"git status\" command, so\nthat collected data can be presented in different formats more easily.\nIt is roughly based on an old patch of mine from October last year, but it\ncollects a bit more detail on conflicted paths.\n\nThe fourth one changes the output from the \"git status\" command when\nunmerged paths are present.  We now have a separate \"Unmerged paths\"\nsection at the beginning and describe the nature of the conflict in more\ndetail.\n\nThe last one is a bit iffy, but shows how the new infrastructure can be\nused to present the \"git status\" output in a more succinct and machine\nreadble format.\n\nJunio C Hamano (5):\n  diff-index: report unmerged new entries\n  diff-index: keep the original index intact\n  wt-status.c: rework the way changes to the index and work tree are\n    summarized\n  status: show worktree status of conflicted paths separately\n  shortstatus: a new command\n\n Makefile            |    1 +\n builtin-commit.c    |  107 +++++++++++++++++-\n builtin.h           |    1 +\n diff-lib.c          |   22 +----\n git.c               |    1 +\n t/t7060-wtstatus.sh |   31 +++++\n wt-status.c         |  314 +++++++++++++++++++++++++++++++++++++++++++--------\n wt-status.h         |   11 ++\n 8 files changed, 418 insertions(+), 70 deletions(-)\n create mode 100755 t/t7060-wtstatus.sh\n"},{"id":"119591","messageId":"1249463746-21538-2-git-send-email-gitster@pobox.com","threadId":"20398","inReplyTo":"1249463746-21538-1-git-send-email-gitster@pobox.com","subject":"[PATCH 1/5] diff-index: report unmerged new entries","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-05T09:15:42Z","receivedAt":"2009-08-05T09:15:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Since an earlier change to diff-index by d1f2d7e (Make run_diff_index()\nuse unpack_trees(), not read_tree(), 2008-01-19), we stopped reporting an\nunmerged path that does not exist in the tree, but we should.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n diff-lib.c          |    4 ++--\n t/t7060-wtstatus.sh |   31 +++++++++++++++++++++++++++++++\n 2 files changed, 33 insertions(+), 2 deletions(-)\n create mode 100755 t/t7060-wtstatus.sh\n\ndiff --git a/diff-lib.c b/diff-lib.c\nindex ad2a4cd..ad5b6ca 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -348,8 +348,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,\n \tmatch_missing = !revs->ignore_merges;\n \n \tif (cached && idx && ce_stage(idx)) {\n-\t\tif (tree)\n-\t\t\tdiff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, idx->sha1);\n+\t\tdiff_unmerge(&revs->diffopt, idx->name, idx->ce_mode,\n+\t\t\t     idx->sha1);\n \t\treturn;\n \t}\n \ndiff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh\nnew file mode 100755\nindex 0000000..5ad2cd1\n--- /dev/null\n+++ b/t/t7060-wtstatus.sh\n@@ -0,0 +1,31 @@\n+#!/bin/sh\n+\n+test_description='basic work tree status reporting'\n+\n+. ./test-lib.sh\n+\n+test_expect_success setup '\n+\ttest_commit A &&\n+\ttest_commit B oneside added &&\n+\tgit checkout A^0 &&\n+\ttest_commit C oneside created\n+'\n+\n+test_expect_success 'A/A conflict' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git merge C\n+'\n+\n+test_expect_success 'Report path with conflict' '\n+\tgit diff --cached --name-status >actual &&\n+\techo \"U\toneside\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'Report new path with conflict' '\n+\tgit diff --cached --name-status HEAD^ >actual &&\n+\techo \"U\toneside\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n1.6.4.18.g07a4a\n"},{"id":"119588","messageId":"1249463746-21538-3-git-send-email-gitster@pobox.com","threadId":"20398","inReplyTo":"1249463746-21538-2-git-send-email-gitster@pobox.com","subject":"[PATCH 2/5] diff-index: keep the original index intact","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-05T09:15:43Z","receivedAt":"2009-08-05T09:15:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When comparing the index and a tree, we used to read the contents of the\ntree into stage #1 of the index and compared them with stage #0.  In order\nnot to lose sight of entries originally unmerged in the index, we hoisted\nthem to stage #3 before reading the tree.\n\nCommit d1f2d7e (Make run_diff_index() use unpack_trees(), not read_tree(),\n2008-01-19) changed all this.  These days, we instead use unpack_trees()\nAPI to traverse the tree and compare the contents with the index, without\nmodifying the index at all.  There is no reason to hoist the unmerged\nentries to stage #3 anymore.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n diff-lib.c |   18 ------------------\n 1 files changed, 0 insertions(+), 18 deletions(-)\n\ndiff --git a/diff-lib.c b/diff-lib.c\nindex ad5b6ca..2a82dac 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -309,22 +309,6 @@ static int show_modified(struct rev_info *revs,\n }\n \n /*\n- * This turns all merge entries into \"stage 3\". That guarantees that\n- * when we read in the new tree (into \"stage 1\"), we won't lose sight\n- * of the fact that we had unmerged entries.\n- */\n-static void mark_merge_entries(void)\n-{\n-\tint i;\n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n-\t\tif (!ce_stage(ce))\n-\t\t\tcontinue;\n-\t\tce->ce_flags |= CE_STAGEMASK;\n-\t}\n-}\n-\n-/*\n  * This gets a mix of an existing index and a tree, one pathname entry\n  * at a time. The index entry may be a single stage-0 one, but it could\n  * also be multiple unmerged entries (in which case idx_pos/idx_nr will\n@@ -435,8 +419,6 @@ int run_diff_index(struct rev_info *revs, int cached)\n \tstruct unpack_trees_options opts;\n \tstruct tree_desc t;\n \n-\tmark_merge_entries();\n-\n \tent = revs->pending.objects[0].item;\n \ttree_name = revs->pending.objects[0].name;\n \ttree = parse_tree_indirect(ent->sha1);\n-- \n1.6.4.18.g07a4a\n"},{"id":"119590","messageId":"1249463746-21538-4-git-send-email-gitster@pobox.com","threadId":"20398","inReplyTo":"1249463746-21538-3-git-send-email-gitster@pobox.com","subject":"[PATCH 3/5] wt-status.c: rework the way changes to the index and work tree are summarized","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-05T09:15:44Z","receivedAt":"2009-08-05T09:15:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Introduce a new infrastructure to find and summarize changes in a single\nstring list, and rewrite wt_status_print_{updated,changed} functions using\nit.\n\nThe goal of this change is to give more information on conflicted paths in\nthe status output.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin-commit.c |   13 ++-\n wt-status.c      |  252 ++++++++++++++++++++++++++++++++++++++++++++----------\n wt-status.h      |   11 +++\n 3 files changed, 226 insertions(+), 50 deletions(-)\n\ndiff --git a/builtin-commit.c b/builtin-commit.c\nindex 4bcce06..6d12c2e 100644\n--- a/builtin-commit.c\n+++ b/builtin-commit.c\n@@ -217,12 +217,15 @@ static void create_base_index(void)\n \t\texit(128); /* We've already reported the error, finish dying */\n }\n \n-static char *prepare_index(int argc, const char **argv, const char *prefix)\n+static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status)\n {\n \tint fd;\n \tstruct string_list partial;\n \tconst char **pathspec = NULL;\n+\tint refresh_flags = REFRESH_QUIET;\n \n+\tif (is_status)\n+\t\trefresh_flags |= REFRESH_UNMERGED;\n \tif (interactive) {\n \t\tif (interactive_add(argc, argv, prefix) != 0)\n \t\t\tdie(\"interactive add failed\");\n@@ -253,7 +256,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)\n \tif (all || (also && pathspec && *pathspec)) {\n \t\tint fd = hold_locked_index(&index_lock, 1);\n \t\tadd_files_to_cache(also ? prefix : NULL, pathspec, 0);\n-\t\trefresh_cache(REFRESH_QUIET);\n+\t\trefresh_cache(refresh_flags);\n \t\tif (write_cache(fd, active_cache, active_nr) ||\n \t\t    close_lock_file(&index_lock))\n \t\t\tdie(\"unable to write new_index file\");\n@@ -272,7 +275,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)\n \t */\n \tif (!pathspec || !*pathspec) {\n \t\tfd = hold_locked_index(&index_lock, 1);\n-\t\trefresh_cache(REFRESH_QUIET);\n+\t\trefresh_cache(refresh_flags);\n \t\tif (write_cache(fd, active_cache, active_nr) ||\n \t\t    commit_locked_index(&index_lock))\n \t\t\tdie(\"unable to write new_index file\");\n@@ -825,7 +828,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \n \targc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix);\n \n-\tindex_file = prepare_index(argc, argv, prefix);\n+\tindex_file = prepare_index(argc, argv, prefix, 1);\n \n \tcommitable = run_status(stdout, index_file, prefix, 0);\n \n@@ -907,7 +910,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \n \targc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix);\n \n-\tindex_file = prepare_index(argc, argv, prefix);\n+\tindex_file = prepare_index(argc, argv, prefix, 0);\n \n \t/* Set up everything for writing the commit object.  This includes\n \t   running hooks, writing the trees, and interacting with the user.  */\ndiff --git a/wt-status.c b/wt-status.c\nindex 47735d8..1614352 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -20,6 +20,7 @@ static char wt_status_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RED,    /* WT_STATUS_CHANGED */\n \tGIT_COLOR_RED,    /* WT_STATUS_UNTRACKED */\n \tGIT_COLOR_RED,    /* WT_STATUS_NOBRANCH */\n+\tGIT_COLOR_YELLOW, /* WT_STATUS_UNMERGED */\n };\n \n enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;\n@@ -56,6 +57,7 @@ void wt_status_prepare(struct wt_status *s)\n \ts->reference = \"HEAD\";\n \ts->fp = stdout;\n \ts->index_file = get_index_file();\n+\ts->change.strdup_strings = 1;\n }\n \n static void wt_status_print_cached_header(struct wt_status *s)\n@@ -98,18 +100,35 @@ static void wt_status_print_trailer(struct wt_status *s)\n \n #define quote_path quote_path_relative\n \n-static void wt_status_print_filepair(struct wt_status *s,\n-\t\t\t\t     int t, struct diff_filepair *p)\n+static void wt_status_print_change_data(struct wt_status *s,\n+\t\t\t\t\tint change_type,\n+\t\t\t\t\tstruct string_list_item *it)\n {\n-\tconst char *c = color(t);\n+\tstruct wt_status_change_data *d = it->util;\n+\tconst char *c = color(change_type);\n+\tint status = status;\n+\tchar *one_name;\n+\tchar *two_name;\n \tconst char *one, *two;\n \tstruct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;\n \n-\tone = quote_path(p->one->path, -1, &onebuf, s->prefix);\n-\ttwo = quote_path(p->two->path, -1, &twobuf, s->prefix);\n+\tone_name = two_name = it->string;\n+\tswitch (change_type) {\n+\tcase WT_STATUS_UPDATED:\n+\t\tstatus = d->index_status;\n+\t\tif (d->head_path)\n+\t\t\tone_name = d->head_path;\n+\t\tbreak;\n+\tcase WT_STATUS_CHANGED:\n+\t\tstatus = d->worktree_status;\n+\t\tbreak;\n+\t}\n+\n+\tone = quote_path(one_name, -1, &onebuf, s->prefix);\n+\ttwo = quote_path(two_name, -1, &twobuf, s->prefix);\n \n \tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n-\tswitch (p->status) {\n+\tswitch (status) {\n \tcase DIFF_STATUS_ADDED:\n \t\tcolor_fprintf(s->fp, c, \"new file:   %s\", one);\n \t\tbreak;\n@@ -135,64 +154,114 @@ static void wt_status_print_filepair(struct wt_status *s,\n \t\tcolor_fprintf(s->fp, c, \"unmerged:   %s\", one);\n \t\tbreak;\n \tdefault:\n-\t\tdie(\"bug: unhandled diff status %c\", p->status);\n+\t\tdie(\"bug: unhandled diff status %c\", status);\n \t}\n \tfprintf(s->fp, \"\\n\");\n \tstrbuf_release(&onebuf);\n \tstrbuf_release(&twobuf);\n }\n \n-static void wt_status_print_updated_cb(struct diff_queue_struct *q,\n-\t\tstruct diff_options *options,\n-\t\tvoid *data)\n+static void wt_status_collect_changed_cb(struct diff_queue_struct *q,\n+\t\t\t\t\t struct diff_options *options,\n+\t\t\t\t\t void *data)\n {\n \tstruct wt_status *s = data;\n-\tint shown_header = 0;\n \tint i;\n+\n+\tif (!q->nr)\n+\t\treturn;\n+\ts->workdir_dirty = 1;\n \tfor (i = 0; i < q->nr; i++) {\n-\t\tif (q->queue[i]->status == 'U')\n-\t\t\tcontinue;\n-\t\tif (!shown_header) {\n-\t\t\twt_status_print_cached_header(s);\n-\t\t\ts->commitable = 1;\n-\t\t\tshown_header = 1;\n+\t\tstruct diff_filepair *p;\n+\t\tstruct string_list_item *it;\n+\t\tstruct wt_status_change_data *d;\n+\n+\t\tp = q->queue[i];\n+\t\tit = string_list_insert(p->one->path, &s->change);\n+\t\td = it->util;\n+\t\tif (!d) {\n+\t\t\td = xcalloc(1, sizeof(*d));\n+\t\t\tit->util = d;\n \t\t}\n-\t\twt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);\n+\t\tif (!d->worktree_status)\n+\t\t\td->worktree_status = p->status;\n \t}\n-\tif (shown_header)\n-\t\twt_status_print_trailer(s);\n }\n \n-static void wt_status_print_changed_cb(struct diff_queue_struct *q,\n-                        struct diff_options *options,\n-                        void *data)\n+static int unmerged_mask(const char *path)\n+{\n+\tint pos, mask;\n+\tstruct cache_entry *ce;\n+\n+\tpos = cache_name_pos(path, strlen(path));\n+\tif (0 <= pos)\n+\t\treturn 0;\n+\n+\tmask = 0;\n+\tpos = -pos-1;\n+\twhile (pos <= active_nr) {\n+\t\tce = active_cache[pos++];\n+\t\tif (strcmp(ce->name, path))\n+\t\t\tbreak;\n+\t\tmask |= (1 << ce_stage(ce));\n+\t}\n+\treturn mask;\n+}\n+\n+static void wt_status_collect_updated_cb(struct diff_queue_struct *q,\n+\t\t\t\t\t struct diff_options *options,\n+\t\t\t\t\t void *data)\n {\n \tstruct wt_status *s = data;\n \tint i;\n-\tif (q->nr) {\n-\t\tint has_deleted = 0;\n-\t\ts->workdir_dirty = 1;\n-\t\tfor (i = 0; i < q->nr; i++)\n-\t\t\tif (q->queue[i]->status == DIFF_STATUS_DELETED) {\n-\t\t\t\thas_deleted = 1;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\twt_status_print_dirty_header(s, has_deleted);\n+\n+\tfor (i = 0; i < q->nr; i++) {\n+\t\tstruct diff_filepair *p;\n+\t\tstruct string_list_item *it;\n+\t\tstruct wt_status_change_data *d;\n+\n+\t\tp = q->queue[i];\n+\t\tit = string_list_insert(p->two->path, &s->change);\n+\t\td = it->util;\n+\t\tif (!d) {\n+\t\t\td = xcalloc(1, sizeof(*d));\n+\t\t\tit->util = d;\n+\t\t}\n+\t\tif (!d->index_status)\n+\t\t\td->index_status = p->status;\n+\t\tswitch (p->status) {\n+\t\tcase DIFF_STATUS_COPIED:\n+\t\tcase DIFF_STATUS_RENAMED:\n+\t\t\td->head_path = xstrdup(p->one->path);\n+\t\t\tbreak;\n+\t\tcase DIFF_STATUS_UNMERGED:\n+\t\t\td->stagemask = unmerged_mask(p->two->path);\n+\t\t\tbreak;\n+\t\t}\n \t}\n-\tfor (i = 0; i < q->nr; i++)\n-\t\twt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);\n-\tif (q->nr)\n-\t\twt_status_print_trailer(s);\n }\n \n-static void wt_status_print_updated(struct wt_status *s)\n+static void wt_status_collect_changes_worktree(struct wt_status *s)\n+{\n+\tstruct rev_info rev;\n+\n+\tinit_revisions(&rev, NULL);\n+\tsetup_revisions(0, NULL, &rev, NULL);\n+\trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n+\trev.diffopt.format_callback = wt_status_collect_changed_cb;\n+\trev.diffopt.format_callback_data = s;\n+\trun_diff_files(&rev, 0);\n+}\n+\n+static void wt_status_collect_changes_index(struct wt_status *s)\n {\n \tstruct rev_info rev;\n+\n \tinit_revisions(&rev, NULL);\n \tsetup_revisions(0, NULL, &rev,\n \t\ts->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference);\n \trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n-\trev.diffopt.format_callback = wt_status_print_updated_cb;\n+\trev.diffopt.format_callback = wt_status_collect_updated_cb;\n \trev.diffopt.format_callback_data = s;\n \trev.diffopt.detect_rename = 1;\n \trev.diffopt.rename_limit = 200;\n@@ -200,15 +269,106 @@ static void wt_status_print_updated(struct wt_status *s)\n \trun_diff_index(&rev, 1);\n }\n \n+static void wt_status_collect_changes_initial(struct wt_status *s)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct string_list_item *it;\n+\t\tstruct wt_status_change_data *d;\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\n+\t\tit = string_list_insert(ce->name, &s->change);\n+\t\td = it->util;\n+\t\tif (!d) {\n+\t\t\td = xcalloc(1, sizeof(*d));\n+\t\t\tit->util = d;\n+\t\t}\n+\t\tif (ce_stage(ce)) {\n+\t\t\td->index_status = DIFF_STATUS_UNMERGED;\n+\t\t\td->stagemask |= (1 << (ce_stage(ce) - 1));\n+\t\t}\n+\t\telse\n+\t\t\td->index_status = DIFF_STATUS_ADDED;\n+\t}\n+}\n+\n+void wt_status_collect_changes(struct wt_status *s)\n+{\n+\twt_status_collect_changes_worktree(s);\n+\n+\tif (s->is_initial)\n+\t\twt_status_collect_changes_initial(s);\n+\telse\n+\t\twt_status_collect_changes_index(s);\n+}\n+\n+static void wt_status_print_updated(struct wt_status *s)\n+{\n+\tint shown_header = 0;\n+\tint i;\n+\n+\tfor (i = 0; i < s->change.nr; i++) {\n+\t\tstruct wt_status_change_data *d;\n+\t\tstruct string_list_item *it;\n+\t\tit = &(s->change.items[i]);\n+\t\td = it->util;\n+\t\tif (!d->index_status ||\n+\t\t    d->index_status == DIFF_STATUS_UNMERGED)\n+\t\t\tcontinue;\n+\t\tif (!shown_header) {\n+\t\t\twt_status_print_cached_header(s);\n+\t\t\ts->commitable = 1;\n+\t\t\tshown_header = 1;\n+\t\t}\n+\t\twt_status_print_change_data(s, WT_STATUS_UPDATED, it);\n+\t}\n+\tif (shown_header)\n+\t\twt_status_print_trailer(s);\n+}\n+\n+/*\n+ * -1 : has delete\n+ *  0 : no change\n+ *  1 : some change but no delete\n+ */\n+static int wt_status_check_worktree_changes(struct wt_status *s)\n+{\n+\tint i;\n+\tint changes = 0;\n+\n+\tfor (i = 0; i < s->change.nr; i++) {\n+\t\tstruct wt_status_change_data *d;\n+\t\td = s->change.items[i].util;\n+\t\tif (!d->worktree_status)\n+\t\t\tcontinue;\n+\t\tchanges = 1;\n+\t\tif (d->worktree_status == DIFF_STATUS_DELETED)\n+\t\t\treturn -1;\n+\t}\n+\treturn changes;\n+}\n+\n static void wt_status_print_changed(struct wt_status *s)\n {\n-\tstruct rev_info rev;\n-\tinit_revisions(&rev, \"\");\n-\tsetup_revisions(0, NULL, &rev, NULL);\n-\trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n-\trev.diffopt.format_callback = wt_status_print_changed_cb;\n-\trev.diffopt.format_callback_data = s;\n-\trun_diff_files(&rev, 0);\n+\tint i;\n+\tint worktree_changes = wt_status_check_worktree_changes(s);\n+\n+\tif (!worktree_changes)\n+\t\treturn;\n+\n+\twt_status_print_dirty_header(s, worktree_changes < 0);\n+\n+\tfor (i = 0; i < s->change.nr; i++) {\n+\t\tstruct wt_status_change_data *d;\n+\t\tstruct string_list_item *it;\n+\t\tit = &(s->change.items[i]);\n+\t\td = it->util;\n+\t\tif (!d->worktree_status)\n+\t\t\tcontinue;\n+\t\twt_status_print_change_data(s, WT_STATUS_CHANGED, it);\n+\t}\n+\twt_status_print_trailer(s);\n }\n \n static void wt_status_print_submodule_summary(struct wt_status *s)\n@@ -337,6 +497,8 @@ void wt_status_print(struct wt_status *s)\n \t\t\twt_status_print_tracking(s);\n \t}\n \n+\twt_status_collect_changes(s);\n+\n \tif (s->is_initial) {\n \t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"#\");\n \t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"# Initial commit\");\ndiff --git a/wt-status.h b/wt-status.h\nindex 78add09..f80142f 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -2,6 +2,7 @@\n #define STATUS_H\n \n #include <stdio.h>\n+#include \"string-list.h\"\n \n enum color_wt_status {\n \tWT_STATUS_HEADER,\n@@ -9,6 +10,7 @@ enum color_wt_status {\n \tWT_STATUS_CHANGED,\n \tWT_STATUS_UNTRACKED,\n \tWT_STATUS_NOBRANCH,\n+\tWT_STATUS_UNMERGED,\n };\n \n enum untracked_status_type {\n@@ -18,6 +20,13 @@ enum untracked_status_type {\n };\n extern enum untracked_status_type show_untracked_files;\n \n+struct wt_status_change_data {\n+\tint worktree_status;\n+\tint index_status;\n+\tint stagemask;\n+\tchar *head_path;\n+};\n+\n struct wt_status {\n \tint is_initial;\n \tchar *branch;\n@@ -33,6 +42,7 @@ struct wt_status {\n \tconst char *index_file;\n \tFILE *fp;\n \tconst char *prefix;\n+\tstruct string_list change;\n };\n \n int git_status_config(const char *var, const char *value, void *cb);\n@@ -40,5 +50,6 @@ extern int wt_status_use_color;\n extern int wt_status_relative_paths;\n void wt_status_prepare(struct wt_status *s);\n void wt_status_print(struct wt_status *s);\n+void wt_status_collect_changes(struct wt_status *s);\n \n #endif /* STATUS_H */\n-- \n1.6.4.18.g07a4a\n"},{"id":"119589","messageId":"1249463746-21538-5-git-send-email-gitster@pobox.com","threadId":"20398","inReplyTo":"1249463746-21538-4-git-send-email-gitster@pobox.com","subject":"[PATCH 4/5] status: show worktree status of conflicted paths separately","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-05T09:15:45Z","receivedAt":"2009-08-05T09:15:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When a path is unmerged in the index, we used to always say \"unmerged\" in\nthe \"Changed but not updated\" section, even when the path was deleted in\nthe work tree.\n\nRemove unmerged entries from the \"Updated\" section, and create a new\nsection \"Unmerged paths\".  Describe how the different stages conflict\nin more detail in this new section.\n\nNote that with the current 3-way merge policy (with or without recursive),\ncertain combinations of index stages should never happen.  For example,\nhaving only stage #2 means that a path that did not exist in the common\nancestor was added by us while the other branch did not do anything to it,\nwhich would have autoresolved to take our addition.  The code nevertheless\nprepares for the possibility that future merge policies may leave a path\nin such a state.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n wt-status.c |   66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 64 insertions(+), 2 deletions(-)\n\ndiff --git a/wt-status.c b/wt-status.c\nindex 1614352..f73bf47 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -20,7 +20,7 @@ static char wt_status_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RED,    /* WT_STATUS_CHANGED */\n \tGIT_COLOR_RED,    /* WT_STATUS_UNTRACKED */\n \tGIT_COLOR_RED,    /* WT_STATUS_NOBRANCH */\n-\tGIT_COLOR_YELLOW, /* WT_STATUS_UNMERGED */\n+\tGIT_COLOR_RED,    /* WT_STATUS_UNMERGED */\n };\n \n enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;\n@@ -38,6 +38,8 @@ static int parse_status_slot(const char *var, int offset)\n \t\treturn WT_STATUS_UNTRACKED;\n \tif (!strcasecmp(var+offset, \"nobranch\"))\n \t\treturn WT_STATUS_NOBRANCH;\n+\tif (!strcasecmp(var+offset, \"unmerged\"))\n+\t\treturn WT_STATUS_UNMERGED;\n \tdie(\"bad config variable '%s'\", var);\n }\n \n@@ -60,6 +62,18 @@ void wt_status_prepare(struct wt_status *s)\n \ts->change.strdup_strings = 1;\n }\n \n+static void wt_status_print_unmerged_header(struct wt_status *s)\n+{\n+\tconst char *c = color(WT_STATUS_HEADER);\n+\tcolor_fprintf_ln(s->fp, c, \"# Unmerged paths:\");\n+\tif (!s->is_initial)\n+\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n+\telse\n+\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n+\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git add <file>...\\\" to mark resolution)\");\n+\tcolor_fprintf_ln(s->fp, c, \"#\");\n+}\n+\n static void wt_status_print_cached_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER);\n@@ -100,6 +114,29 @@ static void wt_status_print_trailer(struct wt_status *s)\n \n #define quote_path quote_path_relative\n \n+static void wt_status_print_unmerged_data(struct wt_status *s,\n+\t\t\t\t\t  struct string_list_item *it)\n+{\n+\tconst char *c = color(WT_STATUS_UNMERGED);\n+\tstruct wt_status_change_data *d = it->util;\n+\tstruct strbuf onebuf = STRBUF_INIT;\n+\tconst char *one, *how = \"bug\";\n+\n+\tone = quote_path(it->string, -1, &onebuf, s->prefix);\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n+\tswitch (d->stagemask >> 1) {\n+\tcase 1: how = \"both deleted\"; break;\n+\tcase 2: how = \"added by us\"; break;\n+\tcase 3: how = \"deleted by them\"; break;\n+\tcase 4: how = \"added by them\"; break;\n+\tcase 5: how = \"deleted by us\"; break;\n+\tcase 6: how = \"both added\"; break;\n+\tcase 7: how = \"both modified\"; break;\n+\t}\n+\tcolor_fprintf(s->fp, c, \"%-20s: %s\\n\", how, one);\n+\tstrbuf_release(&onebuf);\n+}\n+\n static void wt_status_print_change_data(struct wt_status *s,\n \t\t\t\t\tint change_type,\n \t\t\t\t\tstruct string_list_item *it)\n@@ -303,6 +340,29 @@ void wt_status_collect_changes(struct wt_status *s)\n \t\twt_status_collect_changes_index(s);\n }\n \n+static void wt_status_print_unmerged(struct wt_status *s)\n+{\n+\tint shown_header = 0;\n+\tint i;\n+\n+\tfor (i = 0; i < s->change.nr; i++) {\n+\t\tstruct wt_status_change_data *d;\n+\t\tstruct string_list_item *it;\n+\t\tit = &(s->change.items[i]);\n+\t\td = it->util;\n+\t\tif (!d->stagemask)\n+\t\t\tcontinue;\n+\t\tif (!shown_header) {\n+\t\t\twt_status_print_unmerged_header(s);\n+\t\t\tshown_header = 1;\n+\t\t}\n+\t\twt_status_print_unmerged_data(s, it);\n+\t}\n+\tif (shown_header)\n+\t\twt_status_print_trailer(s);\n+\n+}\n+\n static void wt_status_print_updated(struct wt_status *s)\n {\n \tint shown_header = 0;\n@@ -364,7 +424,8 @@ static void wt_status_print_changed(struct wt_status *s)\n \t\tstruct string_list_item *it;\n \t\tit = &(s->change.items[i]);\n \t\td = it->util;\n-\t\tif (!d->worktree_status)\n+\t\tif (!d->worktree_status ||\n+\t\t    d->worktree_status == DIFF_STATUS_UNMERGED)\n \t\t\tcontinue;\n \t\twt_status_print_change_data(s, WT_STATUS_CHANGED, it);\n \t}\n@@ -505,6 +566,7 @@ void wt_status_print(struct wt_status *s)\n \t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"#\");\n \t}\n \n+\twt_status_print_unmerged(s);\n \twt_status_print_updated(s);\n \twt_status_print_changed(s);\n \tif (wt_status_submodule_summary)\n-- \n1.6.4.18.g07a4a\n"},{"id":"119592","messageId":"1249463746-21538-6-git-send-email-gitster@pobox.com","threadId":"20398","inReplyTo":"1249463746-21538-5-git-send-email-gitster@pobox.com","subject":"[PATCH 5/5] shortstatus: a new command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-05T09:15:46Z","receivedAt":"2009-08-05T09:15:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Add a new command that gives the status in\n\n    XY PATH1 -> PATH2\n\nformat to be more machine readable than output from \"git status\", which is\nabout previewing of \"git commit\" with the same arguments.\n\nPATH1 is the path in the HEAD, and \" -> PATH2\" part is shown only when\nPATH1 corresponds to a different path in the index/worktree.\n\nFor unmerged entries, X shows the status of stage #2 (i.e. ours) and Y\nshows the status of stage #3 (i.e. theirs).  For entries that do not have\nconflicts, X shows the status of the index, and Y shows the status of the\nwork tree.\n\n    X          Y     Meaning\n    -------------------------------------------------\n              [MD]   not updated\n    M        [ MD]   updated in index\n    A        [ MD]   added to index\n    D        [ MD]   deleted from index\n    R        [ MD]   renamed in index\n    C        [ MD]   copied in index\n    [MARC]           index and work tree matches\n    [ MARC]     M    work tree changed since index\n    [ MARC]     D    deleted in work tree\n    D           D    unmerged, both deleted\n    A           U    unmerged, added by us\n    U           D    unmerged, deleted by them\n    U           A    unmerged, added by them\n    D           U    unmerged, deleted by us\n    A           A    unmerged, both added\n    U           U    unmerged, both modified\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Makefile         |    1 +\n builtin-commit.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n builtin.h        |    1 +\n git.c            |    1 +\n 4 files changed, 97 insertions(+), 0 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex daf4296..bcefbd3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -378,6 +378,7 @@ BUILT_INS += git-init$X\n BUILT_INS += git-merge-subtree$X\n BUILT_INS += git-peek-remote$X\n BUILT_INS += git-repo-config$X\n+BUILT_INS += git-shortstatus$X\n BUILT_INS += git-show$X\n BUILT_INS += git-stage$X\n BUILT_INS += git-status$X\ndiff --git a/builtin-commit.c b/builtin-commit.c\nindex 6d12c2e..7a4ddab 100644\n--- a/builtin-commit.c\n+++ b/builtin-commit.c\n@@ -24,6 +24,7 @@\n #include \"string-list.h\"\n #include \"rerere.h\"\n #include \"unpack-trees.h\"\n+#include \"quote.h\"\n \n static const char * const builtin_commit_usage[] = {\n \t\"git commit [options] [--] <filepattern>...\",\n@@ -35,6 +36,11 @@ static const char * const builtin_status_usage[] = {\n \tNULL\n };\n \n+static const char * const builtin_shortstatus_usage[] = {\n+\t\"git shortstatus [options]\",\n+\tNULL\n+};\n+\n static unsigned char head_sha1[20], merge_head_sha1[20];\n static char *use_message_buffer;\n static const char commit_editmsg[] = \"COMMIT_EDITMSG\";\n@@ -813,6 +819,94 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \treturn argc;\n }\n \n+#define quote_path quote_path_relative\n+\n+static void show_unmerged(int null_termination, struct string_list_item *it,\n+\t\t\t  struct wt_status *s)\n+{\n+\tstruct wt_status_change_data *d = it->util;\n+\tconst char *how = \"??\";\n+\n+\tswitch (d->stagemask >> 1) {\n+\tcase 1: how = \"DD\"; break; /* both deleted */\n+\tcase 2: how = \"AU\"; break; /* added by us */\n+\tcase 3: how = \"UD\"; break; /* deleted by them */\n+\tcase 4: how = \"UA\"; break; /* added by them */\n+\tcase 5: how = \"DU\"; break; /* deleted by us */\n+\tcase 6: how = \"AA\"; break; /* both added */\n+\tcase 7: how = \"UU\"; break; /* both modified */\n+\t}\n+\tprintf(\"%s \", how);\n+\tif (null_termination) {\n+\t\tfprintf(stdout, \"%s%c\", it->string, 0);\n+\t} else {\n+\t\tstruct strbuf onebuf = STRBUF_INIT;\n+\t\tconst char *one;\n+\t\tone = quote_path(it->string, -1, &onebuf, s->prefix);\n+\t\tprintf(\"%s\\n\", one);\n+\t\tstrbuf_release(&onebuf);\n+\t}\n+}\n+\n+static void show_status(int null_termination, struct string_list_item *it,\n+\t\tstruct wt_status *s)\n+{\n+\tstruct wt_status_change_data *d = it->util;\n+\n+\tprintf(\"%c%c \",\n+\t       !d->index_status ? ' ' : d->index_status,\n+\t       !d->worktree_status ? ' ' : d->worktree_status);\n+\tif (null_termination) {\n+\t\tfprintf(stdout, \"%s%c\", it->string, 0);\n+\t\tif (d->head_path)\n+\t\t\tfprintf(stdout, \"%s%c\", d->head_path, 0);\n+\t} else {\n+\t\tstruct strbuf onebuf = STRBUF_INIT;\n+\t\tconst char *one;\n+\t\tif (d->head_path) {\n+\t\t\tone = quote_path(d->head_path, -1, &onebuf, s->prefix);\n+\t\t\tprintf(\"%s -> \", one);\n+\t\t\tstrbuf_release(&onebuf);\n+\t\t}\n+\t\tone = quote_path(it->string, -1, &onebuf, s->prefix);\n+\t\tprintf(\"%s\\n\", one);\n+\t\tstrbuf_release(&onebuf);\n+\t}\n+}\n+\n+int cmd_shortstatus(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct wt_status s;\n+\tstatic int null_termination;\n+\tint i;\n+\tstatic struct option builtin_shortstatus_options[] = {\n+\t\tOPT_BOOLEAN('z', \"null\", &null_termination,\n+\t\t\t    \"terminate entries with NUL\"),\n+\t\tOPT_END(),\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix,\n+\t\t\t     builtin_shortstatus_options,\n+\t\t\t     builtin_shortstatus_usage, 0);\n+\n+\tread_cache();\n+\trefresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);\n+\twt_status_prepare(&s);\n+\twt_status_collect_changes(&s);\n+\tfor (i = 0; i < s.change.nr; i++) {\n+\t\tstruct wt_status_change_data *d;\n+\t\tstruct string_list_item *it;\n+\n+\t\tit = &(s.change.items[i]);\n+\t\td = it->util;\n+\t\tif (d->stagemask)\n+\t\t\tshow_unmerged(null_termination, it, &s);\n+\t\telse\n+\t\t\tshow_status(null_termination, it, &s);\n+\t}\n+\treturn 0;\n+}\n+\n int cmd_status(int argc, const char **argv, const char *prefix)\n {\n \tconst char *index_file;\ndiff --git a/builtin.h b/builtin.h\nindex 20427d2..825a96f 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -96,6 +96,7 @@ extern int cmd_shortlog(int argc, const char **argv, const char *prefix);\n extern int cmd_show(int argc, const char **argv, const char *prefix);\n extern int cmd_show_branch(int argc, const char **argv, const char *prefix);\n extern int cmd_status(int argc, const char **argv, const char *prefix);\n+extern int cmd_shortstatus(int argc, const char **argv, const char *prefix);\n extern int cmd_stripspace(int argc, const char **argv, const char *prefix);\n extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);\n extern int cmd_tag(int argc, const char **argv, const char *prefix);\ndiff --git a/git.c b/git.c\nindex 807d875..3977d60 100644\n--- a/git.c\n+++ b/git.c\n@@ -348,6 +348,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"rm\", cmd_rm, RUN_SETUP },\n \t\t{ \"send-pack\", cmd_send_pack, RUN_SETUP },\n \t\t{ \"shortlog\", cmd_shortlog, USE_PAGER },\n+\t\t{ \"shortstatus\", cmd_shortstatus, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"show-branch\", cmd_show_branch, RUN_SETUP },\n \t\t{ \"show\", cmd_show, RUN_SETUP | USE_PAGER },\n \t\t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\n-- \n1.6.4.18.g07a4a\n"},{"id":"119593","messageId":"200908051149.40980.trast@student.ethz.ch","threadId":"20398","inReplyTo":"1249463746-21538-1-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 0/5] Revamping \"git status\"","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-08-05T09:49:37Z","receivedAt":"2009-08-05T09:49:37Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano wrote:\n> \n> Junio C Hamano (5):\n>   diff-index: report unmerged new entries\n>   diff-index: keep the original index intact\n>   wt-status.c: rework the way changes to the index and work tree are\n>     summarized\n>   status: show worktree status of conflicted paths separately\n>   shortstatus: a new command\n\nI was quite eager to try this, mainly for 4/5, and I still had the\ntesting repository from the last thread around:\n\n  $ git ls-files -s\n  100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 1       foo\n  100644 d00491fd7e5bb6fa28c517a0bb32b8b506539d4d 2       foo\n\nHere we go!\n\n  $ git status\n  # On branch master                            \n  Segmentation fault\n\nUh oh.  So gdb it is then...\n\n# On branch master                                                           \n\n  Program received signal SIGSEGV, Segmentation fault.\n  0x00007ffff7353844 in strcmp () from /lib64/libc.so.6\n  (gdb) bt                                             \n  #0  0x00007ffff7353844 in strcmp () from /lib64/libc.so.6\n  #1  0x00000000004cc577 in unmerged_mask (path=Cannot access memory at address 0xfffff070                                                                        \n  ) at wt-status.c:241                                                            \n  Backtrace stopped: previous frame inner to this frame (corrupt stack?)\n\n... or maybe not.  valgrind is slightly more helpful:\n\n  ==29421== Invalid read of size 1\n  ==29421==    at 0x4C26101: strcmp (in /usr/lib64/valgrind/amd64-linux/vgpreload_memcheck.so)\n  ==29421==    by 0x4CC576: unmerged_mask (wt-status.c:241)\n  ==29421==    by 0x4CC6AA: wt_status_collect_updated_cb (wt-status.c:275)\n  ==29421==    by 0x484172: diff_flush (diff.c:3337)\n  ==29421==    by 0x47A0E5: run_diff_index (diff-lib.c:445)\n  ==29421==    by 0x4CC804: wt_status_collect_changes_index (wt-status.c:306)\n  ==29421==    by 0x4CC922: wt_status_collect_changes (wt-status.c:340)\n  ==29421==    by 0x4CD1A0: wt_status_print (wt-status.c:561)\n  ==29421==    by 0x41BFBD: run_status (builtin-commit.c:369)\n  ==29421==    by 0x41D97F: cmd_status (builtin-commit.c:927)\n  ==29421==    by 0x4048C2: run_builtin (git.c:246)\n  ==29421==    by 0x404A4D: handle_internal_command (git.c:394)\n  ==29421==  Address 0x48 is not stack'd, malloc'd or (recently) free'd\n  ==29421==\n  ==29421== Process terminating with default action of signal 11 (SIGSEGV)\n  ==29421==  Access not within mapped region at address 0x48\n  ==29421==    at 0x4C26101: strcmp (in /usr/lib64/valgrind/amd64-linux/vgpreload_memcheck.so)\n  ==29421==    by 0x4CC576: unmerged_mask (wt-status.c:241)\n  ==29421==    by 0x4CC6AA: wt_status_collect_updated_cb (wt-status.c:275)\n  ==29421==    by 0x484172: diff_flush (diff.c:3337)\n  ==29421==    by 0x47A0E5: run_diff_index (diff-lib.c:445)\n  ==29421==    by 0x4CC804: wt_status_collect_changes_index (wt-status.c:306)\n  ==29421==    by 0x4CC922: wt_status_collect_changes (wt-status.c:340)\n  ==29421==    by 0x4CD1A0: wt_status_print (wt-status.c:561)\n  ==29421==    by 0x41BFBD: run_status (builtin-commit.c:369)\n  ==29421==    by 0x41D97F: cmd_status (builtin-commit.c:927)\n  ==29421==    by 0x4048C2: run_builtin (git.c:246)\n  ==29421==    by 0x404A4D: handle_internal_command (git.c:394)\n\nI also tried finding out which exact commit was causing this, but 4/5\nstill segfaults and 1-3 don't even compile:\n\n  builtin-commit.c: In function ‘show_unmerged’:                                  \n  builtin-commit.c:827: error: dereferencing pointer to incomplete type           \n  builtin-commit.c: In function ‘show_status’:                                    \n  builtin-commit.c:854: error: dereferencing pointer to incomplete type\n  [etc]\n\nThese are referring to use of a 'struct wt_status_change_data *', but\nthe struct declaration is only in 4/5.  Am I missing something?\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"119632","messageId":"7vbpmub3la.fsf@alter.siamese.dyndns.org","threadId":"20398","inReplyTo":"200908051149.40980.trast@student.ethz.ch","subject":"Re: [PATCH 0/5] Revamping \"git status\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-05T16:57:53Z","receivedAt":"2009-08-05T16:57:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> I also tried finding out which exact commit was causing this, but 4/5\n> still segfaults and 1-3 don't even compile:\n>\n>   builtin-commit.c: In function ‘show_unmerged’:                                  \n>   builtin-commit.c:827: error: dereferencing pointer to incomplete type           \n>   builtin-commit.c: In function ‘show_status’:                                    \n>   builtin-commit.c:854: error: dereferencing pointer to incomplete type\n>   [etc]\n>\n> These are referring to use of a 'struct wt_status_change_data *', but\n> the struct declaration is only in 4/5.  Am I missing something?\n\nI suspect you have a botched patch application.\n\nThe result of applying up to [PATCH 3/5] does not even have\nshow_unmerged/show_status in builtin-commit.c.  These two functions are\nintroduced by [PATCH 5/5] to implement shortstatus.\n\nI've applied what came back on the list on top of 07a4a3b (Fix typos on\npt_BR/gittutorial.txt translation, 2009-07-31) and all five states compile\njust fine.\n\n    $ git rev-list 07a4a3b.. |\n      while read sha1\n      do\n            git rev-parse $sha1^{tree}\n      done\n    86363b25b84041cf14110dcc3136f56915778f71\n    4625f5bbc43e1158d00aca8b2356047606c0babd\n    895698143b2c29af8bfe0cdf6c3f57de3bf080d8\n    3c565041ba6e432ff9064a1d8302f49ef33c2605\n    c0c2b9c2a55e3df9cce448d59e5d557d07d78a4b\n"},{"id":"119638","messageId":"200908051937.36255.trast@student.ethz.ch","threadId":"20398","inReplyTo":"7vbpmub3la.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 0/5] Revamping \"git status\"","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-08-05T17:37:34Z","receivedAt":"2009-08-05T17:37:34Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano wrote:\n> Thomas Rast <trast@student.ethz.ch> writes:\n> \n> > I also tried finding out which exact commit was causing this, but 4/5\n> > still segfaults and 1-3 don't even compile:\n> >\n> >   builtin-commit.c: In function ‘show_unmerged’:                                  \n> >   builtin-commit.c:827: error: dereferencing pointer to incomplete type           \n> >   builtin-commit.c: In function ‘show_status’:                                    \n> >   builtin-commit.c:854: error: dereferencing pointer to incomplete type\n> >   [etc]\n> >\n> > These are referring to use of a 'struct wt_status_change_data *', but\n> > the struct declaration is only in 4/5.  Am I missing something?\n> \n> I suspect you have a botched patch application.\n\nYou're right, sorry.  I indeed had the patches applied in the wrong\norder (through a pilot error with KMail), resulting in 5/5 being first\nin the topic.  So it is no wonder the intermediate states never\ncompiled.\n\n> I've applied what came back on the list on top of 07a4a3b (Fix typos on\n> pt_BR/gittutorial.txt translation, 2009-07-31) and all five states compile\n> just fine.\n> \n>     $ git rev-list 07a4a3b.. |\n>       while read sha1\n>       do\n>             git rev-parse $sha1^{tree}\n>       done\n>     86363b25b84041cf14110dcc3136f56915778f71\n>     4625f5bbc43e1158d00aca8b2356047606c0babd\n>     895698143b2c29af8bfe0cdf6c3f57de3bf080d8\n>     3c565041ba6e432ff9064a1d8302f49ef33c2605\n>     c0c2b9c2a55e3df9cce448d59e5d557d07d78a4b\n\nI did exactly that, and our trees now agree.  However, I'm still\nseeing a crash with this test:\n\n-- 8< --\ndiff --git i/t/t7060-wtstatus.sh w/t/t7060-wtstatus.sh\nindex 5ad2cd1..2cc0833 100755\n--- i/t/t7060-wtstatus.sh\n+++ w/t/t7060-wtstatus.sh\n@@ -28,4 +28,17 @@ test_expect_success 'Report new path with conflict' '\n \ttest_cmp expect actual\n '\n \n+test_expect_failure 'M/D conflict does not segfault' '\n+\tmkdir mdconflict &&\n+\tcd mdconflict &&\n+\tgit init &&\n+\ttest_commit initial foo '' &&\n+\ttest_commit modify foo foo &&\n+\tgit checkout -b side HEAD^ &&\n+\tgit rm foo &&\n+\tgit commit -m delete &&\n+\tgit merge master &&\n+\tgit status\n+'\n+\n test_done\n-- >8 --\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"119639","messageId":"200908051940.48110.trast@student.ethz.ch","threadId":"20398","inReplyTo":"200908051937.36255.trast@student.ethz.ch","subject":"Re: [PATCH 0/5] Revamping \"git status\"","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-08-05T17:40:46Z","receivedAt":"2009-08-05T17:40:46Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Thomas Rast wrote:\n> +test_expect_failure 'M/D conflict does not segfault' '\n> +\tmkdir mdconflict &&\n> +\tcd mdconflict &&\n> +\tgit init &&\n> +\ttest_commit initial foo '' &&\n> +\ttest_commit modify foo foo &&\n> +\tgit checkout -b side HEAD^ &&\n> +\tgit rm foo &&\n> +\tgit commit -m delete &&\n> +\tgit merge master &&\n> +\tgit status\n> +'\n> +\n\nMeh, this stops before the git-status because merge signals a\nconflict.  However, the following really crashes.  Promise.\n\n-- 8< --\ndiff --git i/t/t7060-wtstatus.sh w/t/t7060-wtstatus.sh\nindex 5ad2cd1..a152a26 100755\n--- i/t/t7060-wtstatus.sh\n+++ w/t/t7060-wtstatus.sh\n@@ -28,4 +28,17 @@ test_expect_success 'Report new path with conflict' '\n \ttest_cmp expect actual\n '\n \n+test_expect_failure 'M/D conflict does not segfault' '\n+\tmkdir mdconflict &&\n+\tcd mdconflict &&\n+\tgit init &&\n+\ttest_commit initial foo '' &&\n+\ttest_commit modify foo foo &&\n+\tgit checkout -b side HEAD^ &&\n+\tgit rm foo &&\n+\tgit commit -m delete &&\n+\ttest_must_fail git merge master &&\n+\tgit status\n+'\n+\n test_done\n-- >8 --\n\nSorry for all the confusion.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"119644","messageId":"7v3a869lw1.fsf@alter.siamese.dyndns.org","threadId":"20398","inReplyTo":"200908051940.48110.trast@student.ethz.ch","subject":"Re: [PATCH 0/5] Revamping \"git status\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-05T18:05:34Z","receivedAt":"2009-08-05T18:05:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> Meh, this stops before the git-status because merge signals a\n> conflict.  However, the following really crashes.  Promise.\n\nThanks.\n\n wt-status.c |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/wt-status.c b/wt-status.c\nindex f73bf47..6370fe2 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -236,7 +236,7 @@ static int unmerged_mask(const char *path)\n \n \tmask = 0;\n \tpos = -pos-1;\n-\twhile (pos <= active_nr) {\n+\twhile (pos < active_nr) {\n \t\tce = active_cache[pos++];\n \t\tif (strcmp(ce->name, path))\n \t\t\tbreak;\n"},{"id":"119660","messageId":"200908052052.28067.trast@student.ethz.ch","threadId":"20398","inReplyTo":"7v3a869lw1.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 0/5] Revamping \"git status\"","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-08-05T18:52:26Z","receivedAt":"2009-08-05T18:52:26Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano wrote:\n> \n> -\twhile (pos <= active_nr) {\n> +\twhile (pos < active_nr) {\n\nThanks, that fixes it.\n\nIt gives a weird output now, however:\n\n  # On branch side\n  # Unmerged paths:\n  #   (use \"git reset HEAD <file>...\" to unstage)\n  #   (use \"git add <file>...\" to mark resolution)\n  #\n  #\tdeleted by us       : foo\n  #\n  # Changed but not updated:\n  #   (use \"git add <file>...\" to update what will be committed)\n  #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n  #\n  #\n  no changes added to commit (use \"git add\" and/or \"git commit -a\")\n\nSo it detects there are worktree changes, but then decides not to show\nthem because it's an unmerged entry.  I think the following should go\nin 3/5, but note that I haven't looked at the rest of the code to\ncheck if it breaks anything:\n\n-- 8< --\ndiff --git i/wt-status.c w/wt-status.c\nindex 6370fe2..5a68297 100644\n--- i/wt-status.c\n+++ w/wt-status.c\n@@ -400,7 +400,8 @@ static int wt_status_check_worktree_changes(struct wt_status *s)\n \tfor (i = 0; i < s->change.nr; i++) {\n \t\tstruct wt_status_change_data *d;\n \t\td = s->change.items[i].util;\n-\t\tif (!d->worktree_status)\n+\t\tif (!d->worktree_status\n+\t\t    || d->index_status == DIFF_STATUS_UNMERGED)\n \t\t\tcontinue;\n \t\tchanges = 1;\n \t\tif (d->worktree_status == DIFF_STATUS_DELETED)\n-- >8 --\n\nAnd with that fixed, the test I posted earlier should be changed to\nthe following so that it checks the output (the old version detects\nfailure even for a working git-status, because that exits 1):\n\n-- 8< --\ndiff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh\nindex 5ad2cd1..76b20b2 100755\n--- a/t/t7060-wtstatus.sh\n+++ b/t/t7060-wtstatus.sh\n@@ -28,4 +28,29 @@ test_expect_success 'Report new path with conflict' '\n \ttest_cmp expect actual\n '\n \n+cat > expect <<EOF\n+# On branch side\n+# Unmerged paths:\n+#   (use \"git reset HEAD <file>...\" to unstage)\n+#   (use \"git add <file>...\" to mark resolution)\n+#\n+#\tdeleted by us       : foo\n+#\n+no changes added to commit (use \"git add\" and/or \"git commit -a\")\n+EOF\n+\n+test_expect_success 'M/D conflict does not segfault' '\n+\tmkdir mdconflict &&\n+\tcd mdconflict &&\n+\tgit init &&\n+\ttest_commit initial foo '' &&\n+\ttest_commit modify foo foo &&\n+\tgit checkout -b side HEAD^ &&\n+\tgit rm foo &&\n+\tgit commit -m delete &&\n+\ttest_must_fail git merge master &&\n+\ttest_must_fail git status > ../actual &&\n+\ttest_cmp ../expect ../actual\n+'\n+\n test_done\n-- >8 --\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"119669","messageId":"7v3a862fnj.fsf@alter.siamese.dyndns.org","threadId":"20398","inReplyTo":"200908052052.28067.trast@student.ethz.ch","subject":"Re: [PATCH 0/5] Revamping \"git status\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-05T20:02:08Z","receivedAt":"2009-08-05T20:02:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> So it detects there are worktree changes, but then decides not to show\n> them because it's an unmerged entry.  I think the following should go\n> in 3/5, but note that I haven't looked at the rest of the code to\n> check if it breaks anything:\n\nThanks.  Shouldn't it go in 4/5 instead, though?\n\n> -- 8< --\n> diff --git i/wt-status.c w/wt-status.c\n> index 6370fe2..5a68297 100644\n> --- i/wt-status.c\n> +++ w/wt-status.c\n> @@ -400,7 +400,8 @@ static int wt_status_check_worktree_changes(struct wt_status *s)\n>  \tfor (i = 0; i < s->change.nr; i++) {\n>  \t\tstruct wt_status_change_data *d;\n>  \t\td = s->change.items[i].util;\n> -\t\tif (!d->worktree_status)\n> +\t\tif (!d->worktree_status\n> +\t\t    || d->index_status == DIFF_STATUS_UNMERGED)\n>  \t\t\tcontinue;\n>  \t\tchanges = 1;\n>  \t\tif (d->worktree_status == DIFF_STATUS_DELETED)\n> -- >8 --\n\nNot \"d->worktree_status\"?  That would be more consistent with what\nwt_status_print_changed() actually ends up checking.\n"},{"id":"119671","messageId":"200908052214.13512.trast@student.ethz.ch","threadId":"20398","inReplyTo":"7v3a862fnj.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 0/5] Revamping \"git status\"","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-08-05T20:14:12Z","receivedAt":"2009-08-05T20:14:12Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano wrote:\n> Thomas Rast <trast@student.ethz.ch> writes:\n> \n> > So it detects there are worktree changes, but then decides not to show\n> > them because it's an unmerged entry.  I think the following should go\n> > in 3/5, but note that I haven't looked at the rest of the code to\n> > check if it breaks anything:\n> \n> Thanks.  Shouldn't it go in 4/5 instead, though?\n\nEr, yeah. *sigh*\n\n> > -- 8< --\n> > diff --git i/wt-status.c w/wt-status.c\n> > index 6370fe2..5a68297 100644\n> > --- i/wt-status.c\n> > +++ w/wt-status.c\n> > @@ -400,7 +400,8 @@ static int wt_status_check_worktree_changes(struct wt_status *s)\n> >  \tfor (i = 0; i < s->change.nr; i++) {\n> >  \t\tstruct wt_status_change_data *d;\n> >  \t\td = s->change.items[i].util;\n> > -\t\tif (!d->worktree_status)\n> > +\t\tif (!d->worktree_status\n> > +\t\t    || d->index_status == DIFF_STATUS_UNMERGED)\n> >  \t\t\tcontinue;\n> >  \t\tchanges = 1;\n> >  \t\tif (d->worktree_status == DIFF_STATUS_DELETED)\n> > -- >8 --\n> \n> Not \"d->worktree_status\"?  That would be more consistent with what\n> wt_status_print_changed() actually ends up checking.\n\nHmm, true.  I just picked index_status because unmerged state is an\nindex property.  It's probably better if the two functions agree on\nthe criterion.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"119781","messageId":"20090806144638.GA1970@coredump.intra.peff.net","threadId":"20398","inReplyTo":"1249463746-21538-4-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 3/5] wt-status.c: rework the way changes to the index and work tree are summarized","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-06T14:46:39Z","receivedAt":"2009-08-06T14:46:39Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Aug 05, 2009 at 02:15:44AM -0700, Junio C Hamano wrote:\n\n> diff --git a/wt-status.c b/wt-status.c\n> index 47735d8..1614352 100644\n> --- a/wt-status.c\n> +++ b/wt-status.c\n> @@ -20,6 +20,7 @@ static char wt_status_colors[][COLOR_MAXLEN] = {\n>  \tGIT_COLOR_RED,    /* WT_STATUS_CHANGED */\n>  \tGIT_COLOR_RED,    /* WT_STATUS_UNTRACKED */\n>  \tGIT_COLOR_RED,    /* WT_STATUS_NOBRANCH */\n> +\tGIT_COLOR_YELLOW, /* WT_STATUS_UNMERGED */\n>  };\n\nDoes this belong in 3/5? It looks like the WT_STATUS_UNMERGED symbol is\nnot used at all until 4/5, which seems like the more logical place\n(since it deals explicitly with unmerged entries). Also, why does it\nstart yellow here and then turn to red in the next patch?\n\nAnd related:\n\n> diff --git a/wt-status.h b/wt-status.h\n> index 78add09..f80142f 100644\n> --- a/wt-status.h\n> +++ b/wt-status.h\n> [...]\n>  \tWT_STATUS_NOBRANCH,\n> +\tWT_STATUS_UNMERGED,\n\n-Peff\n"},{"id":"119783","messageId":"20090806145348.GB1970@coredump.intra.peff.net","threadId":"20398","inReplyTo":"1249463746-21538-5-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 4/5] status: show worktree status of conflicted paths separately","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-06T14:53:49Z","receivedAt":"2009-08-06T14:53:49Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Aug 05, 2009 at 02:15:45AM -0700, Junio C Hamano wrote:\n\n> +\tswitch (d->stagemask >> 1) {\n> +\tcase 1: how = \"both deleted\"; break;\n> +\tcase 2: how = \"added by us\"; break;\n> +\tcase 3: how = \"deleted by them\"; break;\n> +\tcase 4: how = \"added by them\"; break;\n> +\tcase 5: how = \"deleted by us\"; break;\n> +\tcase 6: how = \"both added\"; break;\n> +\tcase 7: how = \"both modified\"; break;\n> +\t}\n\nUgh. Can we use symbolic constants for the stagemask instead of a\nbitshift and some magic numbers? I understand it's a mask and not just\nan integer value, but we are clearly enumerating every possibility here.\n\n> +\tcolor_fprintf(s->fp, c, \"%-20s: %s\\n\", how, one);\n\nThis produces output like:\n\n#       both modified       : a\n#       deleted by us       : b\n#       deleted by them     : c\n\nMaybe it is just me, but I think the whitespace with the colon looks\nawful. You could do just:\n\n#       both modified:        a\n#       deleted by us:        b\n#       deleted by them:      c\n\nwhich matches the other status output, or even left-prefix the spaces:\n\n#              both modified: a\n#              deleted by us: b\n#            deleted by them: c\n\n-Peff\n"},{"id":"119795","messageId":"20090806153339.GC1970@coredump.intra.peff.net","threadId":"20398","inReplyTo":"1249463746-21538-6-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 5/5] shortstatus: a new command","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-06T15:33:39Z","receivedAt":"2009-08-06T15:33:39Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Aug 05, 2009 at 02:15:46AM -0700, Junio C Hamano wrote:\n\n> ---\n>  Makefile         |    1 +\n>  builtin-commit.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n>  builtin.h        |    1 +\n>  git.c            |    1 +\n\nMissing docs, of course, and tests would be nice. Is this meant to be\nplumbing? If not, the name is too long to type. ;)\n\n> +int cmd_shortstatus(int argc, const char **argv, const char *prefix)\n> +{\n> +\tstruct wt_status s;\n> +\tstatic int null_termination;\n> +\tint i;\n> +\tstatic struct option builtin_shortstatus_options[] = {\n> +\t\tOPT_BOOLEAN('z', \"null\", &null_termination,\n> +\t\t\t    \"terminate entries with NUL\"),\n> +\t\tOPT_END(),\n> +\t};\n> +\n> +\targc = parse_options(argc, argv, prefix,\n> +\t\t\t     builtin_shortstatus_options,\n> +\t\t\t     builtin_shortstatus_usage, 0);\n\nI think one of the most often-requested things for a \"git status\"\nreplacement is that \"git status <path>\" do path-limiting. Something like\n(the extremely not very well tested):\n\n---\ndiff --git a/builtin-commit.c b/builtin-commit.c\nindex 7a4ddab..8bc6269 100644\n--- a/builtin-commit.c\n+++ b/builtin-commit.c\n@@ -891,7 +891,12 @@ int cmd_shortstatus(int argc, const char **argv, const char *prefix)\n \n \tread_cache();\n \trefresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);\n+\n \twt_status_prepare(&s);\n+\tALLOC_GROW(s.path_limit, s.path_limit_nr + argc, s.path_limit_alloc);\n+\tfor (i = 0; i < argc; i++)\n+\t\ts.path_limit[s.path_limit_nr++] = argv[i];\n+\n \twt_status_collect_changes(&s);\n \tfor (i = 0; i < s.change.nr; i++) {\n \t\tstruct wt_status_change_data *d;\ndiff --git a/wt-status.c b/wt-status.c\nindex 5a68297..7399e1b 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -60,6 +60,12 @@ void wt_status_prepare(struct wt_status *s)\n \ts->fp = stdout;\n \ts->index_file = get_index_file();\n \ts->change.strdup_strings = 1;\n+\n+\ts->path_limit = xmalloc(2 * sizeof(*s->path_limit));\n+\ts->path_limit_nr = 1;\n+\ts->path_limit_alloc = 2;\n+\ts->path_limit[0] = \"dummy argv[0]\";\n+\ts->path_limit[1] = NULL;\n }\n \n static void wt_status_print_unmerged_header(struct wt_status *s)\n@@ -283,7 +289,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)\n \tstruct rev_info rev;\n \n \tinit_revisions(&rev, NULL);\n-\tsetup_revisions(0, NULL, &rev, NULL);\n+\tsetup_revisions(s->path_limit_nr, s->path_limit, &rev, NULL);\n \trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n \trev.diffopt.format_callback = wt_status_collect_changed_cb;\n \trev.diffopt.format_callback_data = s;\n@@ -295,7 +301,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)\n \tstruct rev_info rev;\n \n \tinit_revisions(&rev, NULL);\n-\tsetup_revisions(0, NULL, &rev,\n+\tsetup_revisions(s->path_limit_nr, s->path_limit, &rev,\n \t\ts->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference);\n \trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n \trev.diffopt.format_callback = wt_status_collect_updated_cb;\n@@ -315,6 +321,10 @@ static void wt_status_collect_changes_initial(struct wt_status *s)\n \t\tstruct wt_status_change_data *d;\n \t\tstruct cache_entry *ce = active_cache[i];\n \n+\t\tif (match_pathspec(s->path_limit + 1,\n+\t\t\t\tce->name, strlen(ce->name), 0, NULL))\n+\t\t\tcontinue;\n+\n \t\tit = string_list_insert(ce->name, &s->change);\n \t\td = it->util;\n \t\tif (!d) {\n@@ -477,7 +487,7 @@ static void wt_status_print_untracked(struct wt_status *s)\n \t\t\tDIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;\n \tsetup_standard_excludes(&dir);\n \n-\tfill_directory(&dir, NULL);\n+\tfill_directory(&dir, s->path_limit + 1);\n \tfor(i = 0; i < dir.nr; i++) {\n \t\tstruct dir_entry *ent = dir.entries[i];\n \t\tif (!cache_name_is_other(ent->name, ent->len))\n@@ -559,6 +569,9 @@ void wt_status_print(struct wt_status *s)\n \t\t\twt_status_print_tracking(s);\n \t}\n \n+\tALLOC_GROW(s->path_limit, s->path_limit_nr + 1, s->path_limit_alloc);\n+\ts->path_limit[s->path_limit_nr] = NULL;\n+\n \twt_status_collect_changes(s);\n \n \tif (s->is_initial) {\ndiff --git a/wt-status.h b/wt-status.h\nindex f80142f..3099e99 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -43,6 +43,8 @@ struct wt_status {\n \tFILE *fp;\n \tconst char *prefix;\n \tstruct string_list change;\n+\tconst char **path_limit;\n+\tint path_limit_nr, path_limit_alloc;\n };\n \n int git_status_config(const char *var, const char *value, void *cb);\n"},{"id":"119797","messageId":"7vhbwlndqg.fsf@alter.siamese.dyndns.org","threadId":"20398","inReplyTo":"20090806144638.GA1970@coredump.intra.peff.net","subject":"Re: [PATCH 3/5] wt-status.c: rework the way changes to the index and work tree are summarized","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-06T15:50:15Z","receivedAt":"2009-08-06T15:50:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Wed, Aug 05, 2009 at 02:15:44AM -0700, Junio C Hamano wrote:\n>\n>> diff --git a/wt-status.c b/wt-status.c\n>> index 47735d8..1614352 100644\n>> --- a/wt-status.c\n>> +++ b/wt-status.c\n>> @@ -20,6 +20,7 @@ static char wt_status_colors[][COLOR_MAXLEN] = {\n>>  \tGIT_COLOR_RED,    /* WT_STATUS_CHANGED */\n>>  \tGIT_COLOR_RED,    /* WT_STATUS_UNTRACKED */\n>>  \tGIT_COLOR_RED,    /* WT_STATUS_NOBRANCH */\n>> +\tGIT_COLOR_YELLOW, /* WT_STATUS_UNMERGED */\n>>  };\n>\n> Does this belong in 3/5? It looks like the WT_STATUS_UNMERGED symbol is\n> not used at all until 4/5, which seems like the more logical place\n> (since it deals explicitly with unmerged entries). Also, why does it\n> start yellow here and then turn to red in the next patch?\n>\n> And related:\n>\n>> diff --git a/wt-status.h b/wt-status.h\n>> index 78add09..f80142f 100644\n>> --- a/wt-status.h\n>> +++ b/wt-status.h\n>> [...]\n>>  \tWT_STATUS_NOBRANCH,\n>> +\tWT_STATUS_UNMERGED,\n\nThanks.  For the same reason, stagemask and unmerged_mask() helper\nfunction should move from 3/5 to 4/5.\n"},{"id":"119798","messageId":"7vljlwnc6j.fsf_-_@alter.siamese.dyndns.org","threadId":"20398","inReplyTo":"20090806153339.GC1970@coredump.intra.peff.net","subject":"Breaking \"git status\" (was Re: [PATCH 5/5] shortstatus: a new command)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-06T16:23:48Z","receivedAt":"2009-08-06T16:23:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Missing docs, of course, and tests would be nice. Is this meant to be\n> plumbing? If not, the name is too long to type. ;)\n\nAs I said, this was more of technology demonstration with an iffy UI.\n\nI've been wondering if this should be \"git status -T\" (a la \"ls-files -t\",\nbut nice short-and-sweet -t is taken for rarely used --template).\n\n> I think one of the most often-requested things for a \"git status\"\n> replacement is that \"git status <path>\" do path-limiting.\n\nFor that matter, as 1.7.0 material that potentially breaks backward\ncompatibility in a big way, it is tempting to suggest that we might want\nto depart from the traditional \"status takes the same parameters to commit\nand gives a preview of what would happen\" semantics.  Even though the\ncurrent \"status\" takes the same set of parameters as \"commit\" takes, many\nof the parameters, especially the ones related to message generation, do\nnot make sense.\n\nHere is a possible transition plan.  I am not married to it, but throwing\nit out as a discussion starter:\n\n * Introduce \"git commit --dry-run\", that takes place of the current\n   \"git status\".\n\n   We will keep \"git commit --dry-run\" forever so that people can simply\n   do a \"s/git status/git commit --dry-run/\" to keep their own scripts\n   that currently run \"git status\" before deciding to run \"git commit\" (or\n   runs their own re-implementation of \"git commit\") working.\n\n * Introduce \"status.traditional\" configuration.  In 1.6.5\n\n   - When set to true, \"git status\" behaves as \"git commit --dry-run\";\n\n   - When set to false, \"git status\" uses a new semantics (TBD);\n\n   - When unconfigured, the user gets a big incompatibility warning.\n\n   and in 1.7.0, we will flip the default (i.e. unconfigured case) to\n   false.\n\n * Implement \"git status\" that is not a preview of \"git commit\".  Its new\n   semantics would include:\n\n   - Reject any parameter that traditional \"git status\" ignored (i.e. -m);\n\n   - Pathspecs are not about \"git commit -o\" anymore.  They are path\n     limiters.\n\n   - One of the options, -t, gives the \"shortstatus\".\n\nIf we go a route like this, we do not want to add \"shortstatus\" as a\nstandalone command.\n"},{"id":"119799","messageId":"20090806164247.GA1073@coredump.intra.peff.net","threadId":"20398","inReplyTo":"7vljlwnc6j.fsf_-_@alter.siamese.dyndns.org","subject":"Re: Breaking \"git status\" (was Re: [PATCH 5/5] shortstatus: a new command)","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-08-06T16:42:47Z","receivedAt":"2009-08-06T16:42:47Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Aug 06, 2009 at 09:23:48AM -0700, Junio C Hamano wrote:\n\n> As I said, this was more of technology demonstration with an iffy UI.\n> \n> I've been wondering if this should be \"git status -T\" (a la \"ls-files -t\",\n> but nice short-and-sweet -t is taken for rarely used --template).\n\nIf the output format is the only change, then that probably makes sense,\nbut I think there is a desire for a command that is more substantially\ndifferent.\n\n> Here is a possible transition plan.  I am not married to it, but throwing\n> it out as a discussion starter:\n> \n>  * Introduce \"git commit --dry-run\", that takes place of the current\n>    \"git status\".\n> \n>    We will keep \"git commit --dry-run\" forever so that people can simply\n>    do a \"s/git status/git commit --dry-run/\" to keep their own scripts\n>    that currently run \"git status\" before deciding to run \"git commit\" (or\n>    runs their own re-implementation of \"git commit\") working.\n\nThat makes sense.\n\n>  * Introduce \"status.traditional\" configuration.  In 1.6.5\n> \n>    - When set to true, \"git status\" behaves as \"git commit --dry-run\";\n> \n>    - When set to false, \"git status\" uses a new semantics (TBD);\n> \n>    - When unconfigured, the user gets a big incompatibility warning.\n> \n>    and in 1.7.0, we will flip the default (i.e. unconfigured case) to\n>    false.\n\nI wonder if introducing such a configuration option is not going to\ncause more confusion in the long run than simply switching. As a\nscript-writer, you are not helping me at all because I can't make any\nassumptions about how the user has set the variable.\n\nI guess you are helping those who want to keep \"git status\" as-is\nforever for their own typing. I'm not sure that such people exist, but I\nguess it is better to be conservative.\n\n>  * Implement \"git status\" that is not a preview of \"git commit\".  Its new\n>    semantics would include:\n> \n>    - Reject any parameter that traditional \"git status\" ignored (i.e. -m);\n> \n>    - Pathspecs are not about \"git commit -o\" anymore.  They are path\n>      limiters.\n> \n>    - One of the options, -t, gives the \"shortstatus\".\n\nMakes sense.\n\n> If we go a route like this, we do not want to add \"shortstatus\" as a\n> standalone command.\n\nIt may make sense to do it anyway, just to give a playground for people\nto try out and refine the new interface. In other words, do:\n\n  - introduce shortstatus (or newstatus, or whatever you want to call\n    it)\n\n  - wait a few cycles for it to prove itself\n\n  - proceed with transition plan you described above\n\n  - explain transition as \"status is now newstatus, old status is now\n    commit --dry-run\".\n\n-Peff\n"},{"id":"119814","messageId":"7vhbwklq31.fsf@alter.siamese.dyndns.org","threadId":"20398","inReplyTo":"20090806164247.GA1073@coredump.intra.peff.net","subject":"Re: Breaking \"git status\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-08-06T19:06:26Z","receivedAt":"2009-08-06T19:06:26Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I wonder if introducing such a configuration option is not going to\n> cause more confusion in the long run than simply switching. As a\n> script-writer, you are not helping me at all because I can't make any\n> assumptions about how the user has set the variable.\n>\n> I guess you are helping those who want to keep \"git status\" as-is\n> forever for their own typing.\n\nNot really.  I meant to be helpful to people who would say \"Ok, I read the\ntransition plan, and I understand I eventually need to switch, but I\ncannot afford to right at this momennt.  I'd transition on the timetable\nof my choosing, rather than on the calendar git developers arbitrarily\nset.\"\n\nBut you are right.  This would not really help scripts transition.\n"},{"id":"119825","messageId":"fabb9a1e0908061257j55bbc53bu14fdb19a41149fe7@mail.gmail.com","threadId":"20398","inReplyTo":"7vljlwnc6j.fsf_-_@alter.siamese.dyndns.org","subject":"Re: Breaking \"git status\" (was Re: [PATCH 5/5] shortstatus: a new command)","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2009-08-06T19:57:05Z","receivedAt":"2009-08-06T19:57:05Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Thu, Aug 6, 2009 at 09:23, Junio C Hamano<gitster@pobox.com> wrote:\n> Jeff King <peff@peff.net> writes:\n>  * Implement \"git status\" that is not a preview of \"git commit\".  Its new\n>   semantics would include:\n\nFWIW, I think this is a a great idea, 'git status' being a preview of\n'git commit' has never made sense to me from a UI perspective, and I\nnever actually use 'git status' for that purpose. While I do use it to\nlook at what I'm going to commit, I never use any 'git commit'\nmodifiers in combination with git status.\n\nOn that note, I agree with Jeff that a config option does not make a\nlot of sense, especially if we introduce 'git commit -d|--dry-run'.\n\n-- \nCheers,\n\nSverre Rabbelier\n"}]}