From 76e2f7ce323c7ddb3a7c29e56407da6a69a4fa53 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 7 Aug 2009 23:31:57 -0700 Subject: [PATCH 01/20] git stat: the beginning of "status that is not a dry-run of commit" Tentatively add "git stat" as a new command. This is not "preview of commit with the same arguments"; the path parameters are not paths to be added to the pristine index (aka "--only" option), but are taken as pathspecs to limit the output. Later in 1.7.0 release, it will take over "git status". Signed-off-by: Junio C Hamano --- Makefile | 1 + builtin-commit.c | 75 +++++++++++++++++++++++++++++++++++++++++------- builtin.h | 1 + git.c | 1 + wt-status.c | 10 ++++--- wt-status.h | 1 + 6 files changed, 75 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index daf4296706..39dd334385 100644 --- a/Makefile +++ b/Makefile @@ -378,6 +378,7 @@ BUILT_INS += git-init$X BUILT_INS += git-merge-subtree$X BUILT_INS += git-peek-remote$X BUILT_INS += git-repo-config$X +BUILT_INS += git-stat$X BUILT_INS += git-show$X BUILT_INS += git-stage$X BUILT_INS += git-status$X diff --git a/builtin-commit.c b/builtin-commit.c index 200ffdaad4..5e23ef1f0a 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -24,6 +24,7 @@ #include "string-list.h" #include "rerere.h" #include "unpack-trees.h" +#include "quote.h" static const char * const builtin_commit_usage[] = { "git commit [options] [--] ...", @@ -35,6 +36,11 @@ static const char * const builtin_status_usage[] = { NULL }; +static const char * const builtin_stat_usage[] = { + "git stat [options]", + NULL +}; + static unsigned char head_sha1[20], merge_head_sha1[20]; static char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; @@ -346,6 +352,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn, struct wt_status *s) { + unsigned char sha1[20]; + if (s->relative_paths) s->prefix = prefix; @@ -357,7 +365,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int s->index_file = index_file; s->fp = fp; s->nowarn = nowarn; + s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0; + wt_status_collect(s); wt_status_print(s); return s->commitable; @@ -691,6 +701,21 @@ static const char *find_author_by_nickname(const char *name) die("No existing author found with '%s'", name); } + +static void handle_untracked_files_arg(struct wt_status *s) +{ + if (!untracked_files_arg) + ; /* default already initialized */ + else if (!strcmp(untracked_files_arg, "no")) + s->show_untracked_files = SHOW_NO_UNTRACKED_FILES; + else if (!strcmp(untracked_files_arg, "normal")) + s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; + else if (!strcmp(untracked_files_arg, "all")) + s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; + else + die("Invalid untracked files mode '%s'", untracked_files_arg); +} + static int parse_and_validate_options(int argc, const char *argv[], const char * const usage[], const char *prefix, @@ -794,16 +819,7 @@ static int parse_and_validate_options(int argc, const char *argv[], else die("Invalid cleanup mode %s", cleanup_arg); - if (!untracked_files_arg) - ; /* default already initialized */ - else if (!strcmp(untracked_files_arg, "no")) - s->show_untracked_files = SHOW_NO_UNTRACKED_FILES; - else if (!strcmp(untracked_files_arg, "normal")) - s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; - else if (!strcmp(untracked_files_arg, "all")) - s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; - else - die("Invalid untracked files mode '%s'", untracked_files_arg); + handle_untracked_files_arg(s); if (all && argc > 0) die("Paths with -a does not make sense."); @@ -886,6 +902,45 @@ static int git_status_config(const char *k, const char *v, void *cb) return git_diff_ui_config(k, v, NULL); } +int cmd_stat(int argc, const char **argv, const char *prefix) +{ + struct wt_status s; + unsigned char sha1[20]; + static struct option builtin_stat_options[] = { + OPT__VERBOSE(&verbose), + { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, + "mode", + "show untracked files, optional modes: all, normal, no. (Default: all)", + PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, + OPT_END(), + }; + + wt_status_prepare(&s); + git_config(git_status_config, &s); + argc = parse_options(argc, argv, prefix, + builtin_stat_options, + builtin_stat_usage, 0); + handle_untracked_files_arg(&s); + + if (*argv) + s.pathspec = get_pathspec(prefix, argv); + + read_cache(); + refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED); + s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0; + wt_status_collect(&s); + + s.verbose = verbose; + if (s.relative_paths) + s.prefix = prefix; + if (s.use_color == -1) + s.use_color = git_use_color_default; + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; + wt_status_print(&s); + return 0; +} + int cmd_status(int argc, const char **argv, const char *prefix) { struct wt_status s; diff --git a/builtin.h b/builtin.h index 20427d2963..eeaf0b6cf5 100644 --- a/builtin.h +++ b/builtin.h @@ -95,6 +95,7 @@ extern int cmd_send_pack(int argc, const char **argv, const char *prefix); extern int cmd_shortlog(int argc, const char **argv, const char *prefix); extern int cmd_show(int argc, const char **argv, const char *prefix); extern int cmd_show_branch(int argc, const char **argv, const char *prefix); +extern int cmd_stat(int argc, const char **argv, const char *prefix); extern int cmd_status(int argc, const char **argv, const char *prefix); extern int cmd_stripspace(int argc, const char **argv, const char *prefix); extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix); diff --git a/git.c b/git.c index 807d875ae0..de7fcf6dfb 100644 --- a/git.c +++ b/git.c @@ -350,6 +350,7 @@ static void handle_internal_command(int argc, const char **argv) { "shortlog", cmd_shortlog, USE_PAGER }, { "show-branch", cmd_show_branch, RUN_SETUP }, { "show", cmd_show, RUN_SETUP | USE_PAGER }, + { "stat", cmd_stat, RUN_SETUP | NEED_WORK_TREE }, { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE }, { "stripspace", cmd_stripspace }, { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP }, diff --git a/wt-status.c b/wt-status.c index 63598ce40c..249227c382 100644 --- a/wt-status.c +++ b/wt-status.c @@ -269,6 +269,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s) rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = wt_status_collect_changed_cb; rev.diffopt.format_callback_data = s; + rev.prune_data = s->pathspec; run_diff_files(&rev, 0); } @@ -285,6 +286,7 @@ static void wt_status_collect_changes_index(struct wt_status *s) rev.diffopt.detect_rename = 1; rev.diffopt.rename_limit = 200; rev.diffopt.break_opt = 0; + rev.prune_data = s->pathspec; run_diff_index(&rev, 1); } @@ -297,6 +299,8 @@ static void wt_status_collect_changes_initial(struct wt_status *s) struct wt_status_change_data *d; struct cache_entry *ce = active_cache[i]; + if (!ce_path_match(ce, s->pathspec)) + continue; it = string_list_insert(ce->name, &s->change); d = it->util; if (!d) { @@ -330,6 +334,8 @@ static void wt_status_collect_untracked(struct wt_status *s) struct dir_entry *ent = dir.entries[i]; if (!cache_name_is_other(ent->name, ent->len)) continue; + if (!match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL)) + continue; s->workdir_untracked = 1; string_list_insert(ent->name, &s->untracked); } @@ -533,10 +539,8 @@ static void wt_status_print_tracking(struct wt_status *s) void wt_status_print(struct wt_status *s) { - unsigned char sha1[20]; const char *branch_color = color(WT_STATUS_HEADER, s); - s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0; if (s->branch) { const char *on_what = "On branch "; const char *branch_name = s->branch; @@ -553,8 +557,6 @@ void wt_status_print(struct wt_status *s) wt_status_print_tracking(s); } - wt_status_collect(s); - if (s->is_initial) { color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# Initial commit"); diff --git a/wt-status.h b/wt-status.h index a0e75177be..09fd9f1091 100644 --- a/wt-status.h +++ b/wt-status.h @@ -31,6 +31,7 @@ struct wt_status { int is_initial; char *branch; const char *reference; + const char **pathspec; int verbose; int amend; int nowarn; From 173e6c8852be3c543689f8613ddf3fdafd9ca7b9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 4 Aug 2009 23:55:22 -0700 Subject: [PATCH 02/20] git stat -s: short status output Give -s(hort) option to "git stat" that shows the status of paths in a more concise way. XY PATH1 -> PATH2 format to be more machine readable than output from "git status", which is about previewing of "git commit" with the same arguments. PATH1 is the path in the HEAD, and " -> PATH2" part is shown only when PATH1 corresponds to a different path in the index/worktree. For unmerged entries, X shows the status of stage #2 (i.e. ours) and Y shows the status of stage #3 (i.e. theirs). For entries that do not have conflicts, X shows the status of the index, and Y shows the status of the work tree. For untracked paths, XY are "??". X Y Meaning ------------------------------------------------- [MD] not updated M [ MD] updated in index A [ MD] added to index D [ MD] deleted from index R [ MD] renamed in index C [ MD] copied in index [MARC] index and work tree matches [ MARC] M work tree changed since index [ MARC] D deleted in work tree D D unmerged, both deleted A U unmerged, added by us U D unmerged, deleted by them U A unmerged, added by them D U unmerged, deleted by us A A unmerged, both added U U unmerged, both modified ? ? untracked When given -z option, the records are terminated by NUL characters for better machine readability. Because the traditional long format is designed for human consumption, NUL termination does not make sense. For this reason, -z option implies -s (short output). Signed-off-by: Junio C Hamano --- builtin-commit.c | 114 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 8 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 5e23ef1f0a..1a360cb37c 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -902,12 +902,87 @@ static int git_status_config(const char *k, const char *v, void *cb) return git_diff_ui_config(k, v, NULL); } +#define quote_path quote_path_relative + +static void short_unmerged(int null_termination, struct string_list_item *it, + struct wt_status *s) +{ + struct wt_status_change_data *d = it->util; + const char *how = "??"; + + switch (d->stagemask) { + case 1: how = "DD"; break; /* both deleted */ + case 2: how = "AU"; break; /* added by us */ + case 3: how = "UD"; break; /* deleted by them */ + case 4: how = "UA"; break; /* added by them */ + case 5: how = "DU"; break; /* deleted by us */ + case 6: how = "AA"; break; /* both added */ + case 7: how = "UU"; break; /* both modified */ + } + printf("%s ", how); + if (null_termination) { + fprintf(stdout, "%s%c", it->string, 0); + } else { + struct strbuf onebuf = STRBUF_INIT; + const char *one; + one = quote_path(it->string, -1, &onebuf, s->prefix); + printf("%s\n", one); + strbuf_release(&onebuf); + } +} + +static void short_status(int null_termination, struct string_list_item *it, + struct wt_status *s) +{ + struct wt_status_change_data *d = it->util; + + printf("%c%c ", + !d->index_status ? ' ' : d->index_status, + !d->worktree_status ? ' ' : d->worktree_status); + if (null_termination) { + fprintf(stdout, "%s%c", it->string, 0); + if (d->head_path) + fprintf(stdout, "%s%c", d->head_path, 0); + } else { + struct strbuf onebuf = STRBUF_INIT; + const char *one; + if (d->head_path) { + one = quote_path(d->head_path, -1, &onebuf, s->prefix); + printf("%s -> ", one); + strbuf_release(&onebuf); + } + one = quote_path(it->string, -1, &onebuf, s->prefix); + printf("%s\n", one); + strbuf_release(&onebuf); + } +} + +static void short_untracked(int null_termination, struct string_list_item *it, + struct wt_status *s) +{ + if (null_termination) { + fprintf(stdout, "?? %s%c", it->string, 0); + } else { + struct strbuf onebuf = STRBUF_INIT; + const char *one; + one = quote_path(it->string, -1, &onebuf, s->prefix); + printf("?? %s\n", one); + strbuf_release(&onebuf); + } +} + int cmd_stat(int argc, const char **argv, const char *prefix) { struct wt_status s; + static int null_termination, shortstatus; + int i; unsigned char sha1[20]; static struct option builtin_stat_options[] = { OPT__VERBOSE(&verbose), + OPT_BOOLEAN('s', "short", &shortstatus, + "show status concicely"), + OPT_BOOLEAN('z', "null", &null_termination, + "terminate entries with NUL"), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", @@ -915,6 +990,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix) OPT_END(), }; + if (null_termination) + shortstatus = 1; + wt_status_prepare(&s); git_config(git_status_config, &s); argc = parse_options(argc, argv, prefix, @@ -930,14 +1008,34 @@ int cmd_stat(int argc, const char **argv, const char *prefix) s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0; wt_status_collect(&s); - s.verbose = verbose; - if (s.relative_paths) - s.prefix = prefix; - if (s.use_color == -1) - s.use_color = git_use_color_default; - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; - wt_status_print(&s); + if (shortstatus) { + 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) + short_unmerged(null_termination, it, &s); + else + short_status(null_termination, it, &s); + } + for (i = 0; i < s.untracked.nr; i++) { + struct string_list_item *it; + + it = &(s.untracked.items[i]); + short_untracked(null_termination, it, &s); + } + } else { + s.verbose = verbose; + if (s.relative_paths) + s.prefix = prefix; + if (s.use_color == -1) + s.use_color = git_use_color_default; + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; + wt_status_print(&s); + } return 0; } From 9e4b7ab652561e1807702fe5288e04b8873fc437 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 15 Aug 2009 02:27:39 -0700 Subject: [PATCH 03/20] git status: not "commit --dry-run" anymore This removes tentative "git stat" and make it take over "git status". There are some tests that expect "git status" to exit with non-zero status when there is something staged. Some tests expect "git status path..." to show the status for a partial commit. For these, replace "git status" with "git commit --dry-run". For the ones that do not attempt a dry-run of a partial commit that check the output from the command, check the output from "git status" as well, as they should be identical. Signed-off-by: Junio C Hamano --- Documentation/git-status.txt | 77 +++++++++++++++++++++++++++++++----- Makefile | 1 - builtin-commit.c | 29 ++------------ builtin.h | 1 - git.c | 1 - t/t6040-tracking-info.sh | 2 +- t/t7060-wtstatus.sh | 8 ++-- t/t7506-status-submodule.sh | 6 +-- t/t7508-status.sh | 12 +++--- 9 files changed, 88 insertions(+), 49 deletions(-) diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index 84f60f3407..b5939d6b58 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -8,7 +8,7 @@ git-status - Show the working tree status SYNOPSIS -------- -'git status' ... +'git status' [...] [--] [...] DESCRIPTION ----------- @@ -20,25 +20,85 @@ are what you _would_ commit by running `git commit`; the second and third are what you _could_ commit by running 'git-add' before running `git commit`. -The command takes the same set of options as 'git-commit'; it -shows what would be committed if the same options are given to -'git-commit'. +OPTIONS +------- -If there is no path that is different between the index file and -the current HEAD commit (i.e., there is nothing to commit by running -`git commit`), the command exits with non-zero status. +-s:: +--short:: + Give the output in the short-format. + +-u[]:: +--untracked-files[=]:: + Show untracked files (Default: 'all'). ++ +The mode parameter is optional, and is used to specify +the handling of untracked files. The possible options are: ++ +-- + - 'no' - Show no untracked files + - 'normal' - Shows untracked files and directories + - 'all' - Also shows individual files in untracked directories. +-- ++ +See linkgit:git-config[1] for configuration variable +used to change the default for when the option is not +specified. + +-z:: + Terminate entries with NUL, instead of LF. This implies `-s` + (short status) output format. OUTPUT ------ The output from this command is designed to be used as a commit template comment, and all the output lines are prefixed with '#'. +The default, long format, is designed to be human readable, +verbose and descriptive. They are subject to change in any time. The paths mentioned in the output, unlike many other git commands, are made relative to the current directory if you are working in a subdirectory (this is on purpose, to help cutting and pasting). See the status.relativePaths config option below. +In short-format, the status of each path is shown as + + XY PATH1 -> PATH2 + +where `PATH1` is the path in the `HEAD`, and ` -> PATH2` part is +shown only when `PATH1` corresponds to a different path in the +index/worktree (i.e. renamed). + +For unmerged entries, `X` shows the status of stage #2 (i.e. ours) and `Y` +shows the status of stage #3 (i.e. theirs). + +For entries that do not have conflicts, `X` shows the status of the index, +and `Y` shows the status of the work tree. For untracked paths, `XY` are +`??`. + + X Y Meaning + ------------------------------------------------- + [MD] not updated + M [ MD] updated in index + A [ MD] added to index + D [ MD] deleted from index + R [ MD] renamed in index + C [ MD] copied in index + [MARC] index and work tree matches + [ MARC] M work tree changed since index + [ MARC] D deleted in work tree + ------------------------------------------------- + D D unmerged, both deleted + A U unmerged, added by us + U D unmerged, deleted by them + U A unmerged, added by them + D U unmerged, deleted by us + A A unmerged, both added + U U unmerged, both modified + ------------------------------------------------- + ? ? untracked + ------------------------------------------------- + CONFIGURATION ------------- @@ -63,8 +123,7 @@ linkgit:gitignore[5] Author ------ -Written by Linus Torvalds and -Junio C Hamano . +Written by Junio C Hamano . Documentation -------------- diff --git a/Makefile b/Makefile index 39dd334385..daf4296706 100644 --- a/Makefile +++ b/Makefile @@ -378,7 +378,6 @@ BUILT_INS += git-init$X BUILT_INS += git-merge-subtree$X BUILT_INS += git-peek-remote$X BUILT_INS += git-repo-config$X -BUILT_INS += git-stat$X BUILT_INS += git-show$X BUILT_INS += git-stage$X BUILT_INS += git-status$X diff --git a/builtin-commit.c b/builtin-commit.c index 1a360cb37c..6cb0e40484 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -36,11 +36,6 @@ static const char * const builtin_status_usage[] = { NULL }; -static const char * const builtin_stat_usage[] = { - "git stat [options]", - NULL -}; - static unsigned char head_sha1[20], merge_head_sha1[20]; static char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; @@ -971,13 +966,13 @@ static void short_untracked(int null_termination, struct string_list_item *it, } } -int cmd_stat(int argc, const char **argv, const char *prefix) +int cmd_status(int argc, const char **argv, const char *prefix) { struct wt_status s; static int null_termination, shortstatus; int i; unsigned char sha1[20]; - static struct option builtin_stat_options[] = { + static struct option builtin_status_options[] = { OPT__VERBOSE(&verbose), OPT_BOOLEAN('s', "short", &shortstatus, "show status concicely"), @@ -996,8 +991,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix) wt_status_prepare(&s); git_config(git_status_config, &s); argc = parse_options(argc, argv, prefix, - builtin_stat_options, - builtin_stat_usage, 0); + builtin_status_options, + builtin_status_usage, 0); handle_untracked_files_arg(&s); if (*argv) @@ -1039,22 +1034,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix) return 0; } -int cmd_status(int argc, const char **argv, const char *prefix) -{ - struct wt_status s; - - wt_status_prepare(&s); - git_config(git_status_config, &s); - if (s.use_color == -1) - s.use_color = git_use_color_default; - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; - - argc = parse_and_validate_options(argc, argv, builtin_status_usage, - prefix, &s); - return dry_run_commit(argc, argv, prefix, &s); -} - static void print_summary(const char *prefix, const unsigned char *sha1) { struct rev_info rev; diff --git a/builtin.h b/builtin.h index eeaf0b6cf5..20427d2963 100644 --- a/builtin.h +++ b/builtin.h @@ -95,7 +95,6 @@ extern int cmd_send_pack(int argc, const char **argv, const char *prefix); extern int cmd_shortlog(int argc, const char **argv, const char *prefix); extern int cmd_show(int argc, const char **argv, const char *prefix); extern int cmd_show_branch(int argc, const char **argv, const char *prefix); -extern int cmd_stat(int argc, const char **argv, const char *prefix); extern int cmd_status(int argc, const char **argv, const char *prefix); extern int cmd_stripspace(int argc, const char **argv, const char *prefix); extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix); diff --git a/git.c b/git.c index de7fcf6dfb..807d875ae0 100644 --- a/git.c +++ b/git.c @@ -350,7 +350,6 @@ static void handle_internal_command(int argc, const char **argv) { "shortlog", cmd_shortlog, USE_PAGER }, { "show-branch", cmd_show_branch, RUN_SETUP }, { "show", cmd_show, RUN_SETUP | USE_PAGER }, - { "stat", cmd_stat, RUN_SETUP | NEED_WORK_TREE }, { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE }, { "stripspace", cmd_stripspace }, { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP }, diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh index 00e1de9627..664b0f8052 100755 --- a/t/t6040-tracking-info.sh +++ b/t/t6040-tracking-info.sh @@ -69,7 +69,7 @@ test_expect_success 'status' ' cd test && git checkout b1 >/dev/null && # reports nothing to commit - test_must_fail git status + test_must_fail git commit --dry-run ) >actual && grep "have 1 and 1 different" actual ' diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index 1044aa6549..7b5db8066f 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -50,9 +50,11 @@ test_expect_success 'M/D conflict does not segfault' ' git rm foo && git commit -m delete && test_must_fail git merge master && - test_must_fail git status > ../actual - ) && - test_cmp expect actual + test_must_fail git commit --dry-run >../actual && + test_cmp ../expect ../actual && + git status >../actual && + test_cmp ../expect ../actual + ) ' test_done diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh index d9a08aac56..3ca17abad1 100755 --- a/t/t7506-status-submodule.sh +++ b/t/t7506-status-submodule.sh @@ -19,8 +19,8 @@ test_expect_success 'status clean' ' git status | grep "nothing to commit" ' -test_expect_success 'status -a clean' ' - git status -a | +test_expect_success 'commit --dry-run -a clean' ' + git commit --dry-run -a | grep "nothing to commit" ' test_expect_success 'rm submodule contents' ' @@ -31,7 +31,7 @@ test_expect_success 'status clean (empty submodule dir)' ' grep "nothing to commit" ' test_expect_success 'status -a clean (empty submodule dir)' ' - git status -a | + git commit --dry-run -a | grep "nothing to commit" ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 93f875f500..1173dbb36e 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -248,8 +248,8 @@ cat <expect # output # untracked EOF -test_expect_success 'status of partial commit excluding new file in index' ' - git status dir1/modified >output && +test_expect_success 'dry-run of partial commit excluding new file in index' ' + git commit --dry-run dir1/modified >output && test_cmp expect output ' @@ -358,7 +358,9 @@ EOF test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && - test_must_fail git status >output && + test_must_fail git commit --dry-run >output && + test_cmp expect output && + git status >output && test_cmp expect output ' @@ -391,9 +393,9 @@ cat >expect <output && + git commit --dry-run --amend >output && test_cmp expect output ' From 9b4fe22990dd3fab9494927935c371b072ee7c8f Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 5 Sep 2009 04:50:26 -0400 Subject: [PATCH 04/20] status: typo fix in usage Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-commit.c b/builtin-commit.c index 6cb0e40484..812470e63d 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -975,7 +975,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) static struct option builtin_status_options[] = { OPT__VERBOSE(&verbose), OPT_BOOLEAN('s', "short", &shortstatus, - "show status concicely"), + "show status concisely"), OPT_BOOLEAN('z', "null", &null_termination, "terminate entries with NUL"), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, From 01d8ba187d6e8a6bfa908fbef16a36d1186981dd Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 5 Sep 2009 04:53:48 -0400 Subject: [PATCH 05/20] status: refactor short-mode printing to its own function We want to be able to call it from multiple places. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-commit.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 812470e63d..5b42179fe7 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -966,11 +966,32 @@ static void short_untracked(int null_termination, struct string_list_item *it, } } +static void short_print(struct wt_status *s, int null_termination) +{ + 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) + short_unmerged(null_termination, it, s); + else + short_status(null_termination, it, s); + } + for (i = 0; i < s->untracked.nr; i++) { + struct string_list_item *it; + + it = &(s->untracked.items[i]); + short_untracked(null_termination, it, s); + } +} + int cmd_status(int argc, const char **argv, const char *prefix) { struct wt_status s; static int null_termination, shortstatus; - int i; unsigned char sha1[20]; static struct option builtin_status_options[] = { OPT__VERBOSE(&verbose), @@ -1003,25 +1024,9 @@ int cmd_status(int argc, const char **argv, const char *prefix) s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0; wt_status_collect(&s); - if (shortstatus) { - 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) - short_unmerged(null_termination, it, &s); - else - short_status(null_termination, it, &s); - } - for (i = 0; i < s.untracked.nr; i++) { - struct string_list_item *it; - - it = &(s.untracked.items[i]); - short_untracked(null_termination, it, &s); - } - } else { + if (shortstatus) + short_print(&s, null_termination); + else { s.verbose = verbose; if (s.relative_paths) s.prefix = prefix; From dd2be243d62260d4c825c22fdd2f61a7da12de22 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 5 Sep 2009 04:54:14 -0400 Subject: [PATCH 06/20] status: refactor format option parsing This makes it possible to have more than two formats. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-commit.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 5b42179fe7..aa4a358799 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -991,12 +991,16 @@ static void short_print(struct wt_status *s, int null_termination) int cmd_status(int argc, const char **argv, const char *prefix) { struct wt_status s; - static int null_termination, shortstatus; + static int null_termination; + static enum { + STATUS_FORMAT_LONG, + STATUS_FORMAT_SHORT, + } status_format = STATUS_FORMAT_LONG; unsigned char sha1[20]; static struct option builtin_status_options[] = { OPT__VERBOSE(&verbose), - OPT_BOOLEAN('s', "short", &shortstatus, - "show status concisely"), + OPT_SET_INT('s', "short", &status_format, + "show status concisely", STATUS_FORMAT_SHORT), OPT_BOOLEAN('z', "null", &null_termination, "terminate entries with NUL"), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, @@ -1006,8 +1010,8 @@ int cmd_status(int argc, const char **argv, const char *prefix) OPT_END(), }; - if (null_termination) - shortstatus = 1; + if (null_termination && status_format == STATUS_FORMAT_LONG) + status_format = STATUS_FORMAT_SHORT; wt_status_prepare(&s); git_config(git_status_config, &s); @@ -1024,9 +1028,11 @@ int cmd_status(int argc, const char **argv, const char *prefix) s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0; wt_status_collect(&s); - if (shortstatus) + switch (status_format) { + case STATUS_FORMAT_SHORT: short_print(&s, null_termination); - else { + break; + case STATUS_FORMAT_LONG: s.verbose = verbose; if (s.relative_paths) s.prefix = prefix; @@ -1035,6 +1041,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; wt_status_print(&s); + break; } return 0; } From 6f15787181a163e158c6fee1d79085b97692ac2f Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 5 Sep 2009 04:55:37 -0400 Subject: [PATCH 07/20] status: add --porcelain output format The "short" format was added to "git status" recently to provide a less verbose way of looking at the same information. This has two practical uses: 1. Users who want a more dense display of the information. 2. Scripts which want to parse the information and need a stable, easy-to-parse interface. For now, the "--short" format covers both of those uses. However, as time goes on, users of (1) may want additional format tweaks, or for "git status" to change its behavior based on configuration variables. Those wishes will be at odds with (2), which wants to stability for scripts. This patch introduces a separate --porcelain option early to avoid problems later on. Right now the --short and --porcelain outputs are identical. However, as time goes on, we will have the freedom to customize --short for human consumption while keeping --porcelain stable. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Documentation/git-status.txt | 9 +++++++-- builtin-commit.c | 9 ++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index b5939d6b58..e9363d9978 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -27,6 +27,11 @@ OPTIONS --short:: Give the output in the short-format. +--porcelain:: + Give the output in a stable, easy-to-parse format for scripts. + Currently this is identical to --short output, but is guaranteed + not to change in the future, making it safe for scripts. + -u[]:: --untracked-files[=]:: Show untracked files (Default: 'all'). @@ -45,8 +50,8 @@ used to change the default for when the option is not specified. -z:: - Terminate entries with NUL, instead of LF. This implies `-s` - (short status) output format. + Terminate entries with NUL, instead of LF. This implies + the `--porcelain` output format if no other format is given. OUTPUT diff --git a/builtin-commit.c b/builtin-commit.c index aa4a358799..ffdee31bbf 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -995,12 +995,16 @@ int cmd_status(int argc, const char **argv, const char *prefix) static enum { STATUS_FORMAT_LONG, STATUS_FORMAT_SHORT, + STATUS_FORMAT_PORCELAIN, } status_format = STATUS_FORMAT_LONG; unsigned char sha1[20]; static struct option builtin_status_options[] = { OPT__VERBOSE(&verbose), OPT_SET_INT('s', "short", &status_format, "show status concisely", STATUS_FORMAT_SHORT), + OPT_SET_INT(0, "porcelain", &status_format, + "show porcelain output format", + STATUS_FORMAT_PORCELAIN), OPT_BOOLEAN('z', "null", &null_termination, "terminate entries with NUL"), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, @@ -1011,7 +1015,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) }; if (null_termination && status_format == STATUS_FORMAT_LONG) - status_format = STATUS_FORMAT_SHORT; + status_format = STATUS_FORMAT_PORCELAIN; wt_status_prepare(&s); git_config(git_status_config, &s); @@ -1032,6 +1036,9 @@ int cmd_status(int argc, const char **argv, const char *prefix) case STATUS_FORMAT_SHORT: short_print(&s, null_termination); break; + case STATUS_FORMAT_PORCELAIN: + short_print(&s, null_termination); + break; case STATUS_FORMAT_LONG: s.verbose = verbose; if (s.relative_paths) From 7c9f7038e923e6eb135b27c6fca9a010b034bc27 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 5 Sep 2009 04:59:56 -0400 Subject: [PATCH 08/20] commit: support alternate status formats The status command recently grew "short" and "porcelain" options for alternate output formats. Since status is no longer "commit --dry-run", these formats are inaccessible to people who do want to see a dry-run in a parseable form. This patch makes those formats available to "git commit", implying the "dry-run" option when they are used. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Documentation/git-commit.txt | 14 +++++++++++++ builtin-commit.c | 39 +++++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 64f94cfe12..c45fbe4f97 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -75,6 +75,20 @@ OPTIONS and paths that are untracked, similar to the one that is given in the commit log editor. +--short:: + When doing a dry-run, give the output in the short-format. See + linkgit:git-status[1] for details. Implies `--dry-run`. + +--porcelain:: + When doing a dry-run, give the output in a porcelain-ready + format. See linkgit:git-status[1] for details. Implies + `--dry-run`. + +-z:: + When showing `short` or `porcelain` status output, terminate + entries in the status output with NUL, instead of LF. If no + format is given, implies the `--porcelain` output format. + -F :: --file=:: Take the commit message from the given file. Use '-' to diff --git a/builtin-commit.c b/builtin-commit.c index ffdee31bbf..f2fd0a4580 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -72,6 +72,15 @@ static int use_editor = 1, initial_commit, in_merge; static const char *only_include_assumed; static struct strbuf message; +static int null_termination; +static enum { + STATUS_FORMAT_LONG, + STATUS_FORMAT_SHORT, + STATUS_FORMAT_PORCELAIN, +} status_format = STATUS_FORMAT_LONG; + +static void short_print(struct wt_status *s, int null_termination); + static int opt_parse_m(const struct option *opt, const char *arg, int unset) { struct strbuf *buf = opt->value; @@ -105,6 +114,12 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN('o', "only", &only, "commit only specified files"), OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"), + OPT_SET_INT(0, "short", &status_format, "show status concisely", + STATUS_FORMAT_SHORT), + OPT_SET_INT(0, "porcelain", &status_format, + "show porcelain output format", STATUS_FORMAT_PORCELAIN), + OPT_BOOLEAN('z', "null", &null_termination, + "terminate entries with NUL"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"), @@ -363,7 +378,18 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0; wt_status_collect(s); - wt_status_print(s); + + switch (status_format) { + case STATUS_FORMAT_SHORT: + short_print(s, null_termination); + break; + case STATUS_FORMAT_PORCELAIN: + short_print(s, null_termination); + break; + case STATUS_FORMAT_LONG: + wt_status_print(s); + break; + } return s->commitable; } @@ -821,6 +847,11 @@ static int parse_and_validate_options(int argc, const char *argv[], else if (interactive && argc > 0) die("Paths with --interactive does not make sense."); + if (null_termination && status_format == STATUS_FORMAT_LONG) + status_format = STATUS_FORMAT_PORCELAIN; + if (status_format != STATUS_FORMAT_LONG) + dry_run = 1; + return argc; } @@ -991,12 +1022,6 @@ static void short_print(struct wt_status *s, int null_termination) int cmd_status(int argc, const char **argv, const char *prefix) { struct wt_status s; - static int null_termination; - static enum { - STATUS_FORMAT_LONG, - STATUS_FORMAT_SHORT, - STATUS_FORMAT_PORCELAIN, - } status_format = STATUS_FORMAT_LONG; unsigned char sha1[20]; static struct option builtin_status_options[] = { OPT__VERBOSE(&verbose), From 46b77a6b487fceeeb297a9473631939aefd7e6fd Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 5 Sep 2009 04:52:18 -0400 Subject: [PATCH 09/20] docs: note that status configuration affects only long format The short format does not respect any of the usual status.* configuration. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Documentation/git-status.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index e9363d9978..58d35fb3c2 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -114,13 +114,13 @@ compatibility) and `color.status.` configuration variables to colorize its output. If the config variable `status.relativePaths` is set to false, then all -paths shown are relative to the repository root, not to the current -directory. +paths shown in the long format are relative to the repository root, not +to the current directory. If `status.submodulesummary` is set to a non zero number or true (identical -to -1 or an unlimited number), the submodule summary will be enabled and a -summary of commits for modified submodules will be shown (see --summary-limit -option of linkgit:git-submodule[1]). +to -1 or an unlimited number), the submodule summary will be enabled for +the long format and a summary of commits for modified submodules will be +shown (see --summary-limit option of linkgit:git-submodule[1]). SEE ALSO -------- From 482a6c106132bea454bf839f458c014f84ddbd99 Mon Sep 17 00:00:00 2001 From: Michael J Gruber Date: Thu, 26 Nov 2009 16:24:38 +0100 Subject: [PATCH 10/20] status -s: respect the status.relativePaths option Otherwise, 'status' and 'status -s' in a subdir would produce different names. This change is all the more important because status.relativePaths is on by default. Signed-off-by: Michael J Gruber Signed-off-by: Junio C Hamano --- Documentation/git-status.txt | 4 ++-- builtin-commit.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index 58d35fb3c2..b3dfa42cc0 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -114,8 +114,8 @@ compatibility) and `color.status.` configuration variables to colorize its output. If the config variable `status.relativePaths` is set to false, then all -paths shown in the long format are relative to the repository root, not -to the current directory. +paths shown are relative to the repository root, not to the current +directory. If `status.submodulesummary` is set to a non zero number or true (identical to -1 or an unlimited number), the submodule summary will be enabled for diff --git a/builtin-commit.c b/builtin-commit.c index f2fd0a4580..f49b598cbd 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -1059,6 +1059,8 @@ int cmd_status(int argc, const char **argv, const char *prefix) switch (status_format) { case STATUS_FORMAT_SHORT: + if (s.relative_paths) + s.prefix = prefix; short_print(&s, null_termination); break; case STATUS_FORMAT_PORCELAIN: From 14ed05ddd6a8cdd3cb792e2c991207d1640943d1 Mon Sep 17 00:00:00 2001 From: Michael J Gruber Date: Fri, 27 Nov 2009 22:29:30 +0100 Subject: [PATCH 11/20] t7508-status.sh: Add tests for status -s The new short status has been completely untested so far. Introduce tests by duplicating all tests which are present for the long format. Signed-off-by: Michael J Gruber Signed-off-by: Junio C Hamano --- t/t7508-status.sh | 166 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 1173dbb36e..99a74bda6f 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -68,6 +68,24 @@ test_expect_success 'status (2)' ' ' +cat > expect << \EOF + M dir1/modified +A dir2/added +?? dir1/untracked +?? dir2/modified +?? dir2/untracked +?? expect +?? output +?? untracked +EOF + +test_expect_success 'status -s (2)' ' + + git status -s > output && + test_cmp expect output + +' + cat >expect <expect << EOF + M dir1/modified +A dir2/added +EOF +test_expect_success 'status -s -uno' ' + git config --unset status.showuntrackedfiles + git status -s -uno >output && + test_cmp expect output +' + +test_expect_success 'status -s (status.showUntrackedFiles no)' ' + git config status.showuntrackedfiles no + git status -s >output && + test_cmp expect output +' + cat >expect <expect <output && + test_cmp expect output +' + +test_expect_success 'status -s (status.showUntrackedFiles normal)' ' + git config status.showuntrackedfiles normal + git status -s >output && + test_cmp expect output +' + cat >expect <expect <output && + test_cmp expect output +' +test_expect_success 'status -s (status.showUntrackedFiles all)' ' + git config status.showuntrackedfiles all + git status -s >output && + rm -rf dir3 && + git config --unset status.showuntrackedfiles && + test_cmp expect output +' + cat > expect << \EOF # On branch master # Changes to be committed: @@ -200,6 +280,23 @@ test_expect_success 'status with relative paths' ' ' +cat > expect << \EOF + M modified +A ../dir2/added +?? untracked +?? ../dir2/modified +?? ../dir2/untracked +?? ../expect +?? ../output +?? ../untracked +EOF +test_expect_success 'status -s with relative paths' ' + + (cd dir1 && git status -s) > output && + test_cmp expect output + +' + cat > expect << \EOF # On branch master # Changes to be committed: @@ -232,6 +329,24 @@ test_expect_success 'status without relative paths' ' ' +cat > expect << \EOF + M dir1/modified +A dir2/added +?? dir1/untracked +?? dir2/modified +?? dir2/untracked +?? expect +?? output +?? untracked +EOF + +test_expect_success 'status -s without relative paths' ' + + (cd dir1 && git status -s) > output && + test_cmp expect output + +' + cat <expect # On branch master # Changes to be committed: @@ -298,6 +413,28 @@ test_expect_success 'status --untracked-files=all does not show submodule' ' test_cmp expect output ' +cat >expect <output && + test_cmp expect output +' + +# we expect the same as the previous test +test_expect_success 'status -s --untracked-files=all does not show submodule' ' + git status -s --untracked-files=all >output && + test_cmp expect output +' + head=$(cd sm && git rev-parse --short=7 --verify HEAD) cat >expect <expect <output && + test_cmp expect output +' cat >expect <expect <output && + test_cmp expect output +' + cat >expect < Date: Sat, 5 Dec 2009 16:04:37 +0100 Subject: [PATCH 12/20] builtin-commit: refactor short-status code into wt-status.c Currently, builtin-commit.c contains most code producing the short-status output, whereas wt-status.c contains most of the code for the long format. Refactor so that most of the long and short format producing code resides in wt-status.c and is named analogously. Signed-off-by: Michael J Gruber Signed-off-by: Junio C Hamano --- builtin-commit.c | 101 ++--------------------------------------------- wt-status.c | 89 +++++++++++++++++++++++++++++++++++++++++ wt-status.h | 2 + 3 files changed, 95 insertions(+), 97 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index f49b598cbd..8411236fda 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -79,8 +79,6 @@ static enum { STATUS_FORMAT_PORCELAIN, } status_format = STATUS_FORMAT_LONG; -static void short_print(struct wt_status *s, int null_termination); - static int opt_parse_m(const struct option *opt, const char *arg, int unset) { struct strbuf *buf = opt->value; @@ -381,10 +379,10 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int switch (status_format) { case STATUS_FORMAT_SHORT: - short_print(s, null_termination); + wt_shortstatus_print(s, null_termination); break; case STATUS_FORMAT_PORCELAIN: - short_print(s, null_termination); + wt_shortstatus_print(s, null_termination); break; case STATUS_FORMAT_LONG: wt_status_print(s); @@ -928,97 +926,6 @@ static int git_status_config(const char *k, const char *v, void *cb) return git_diff_ui_config(k, v, NULL); } -#define quote_path quote_path_relative - -static void short_unmerged(int null_termination, struct string_list_item *it, - struct wt_status *s) -{ - struct wt_status_change_data *d = it->util; - const char *how = "??"; - - switch (d->stagemask) { - case 1: how = "DD"; break; /* both deleted */ - case 2: how = "AU"; break; /* added by us */ - case 3: how = "UD"; break; /* deleted by them */ - case 4: how = "UA"; break; /* added by them */ - case 5: how = "DU"; break; /* deleted by us */ - case 6: how = "AA"; break; /* both added */ - case 7: how = "UU"; break; /* both modified */ - } - printf("%s ", how); - if (null_termination) { - fprintf(stdout, "%s%c", it->string, 0); - } else { - struct strbuf onebuf = STRBUF_INIT; - const char *one; - one = quote_path(it->string, -1, &onebuf, s->prefix); - printf("%s\n", one); - strbuf_release(&onebuf); - } -} - -static void short_status(int null_termination, struct string_list_item *it, - struct wt_status *s) -{ - struct wt_status_change_data *d = it->util; - - printf("%c%c ", - !d->index_status ? ' ' : d->index_status, - !d->worktree_status ? ' ' : d->worktree_status); - if (null_termination) { - fprintf(stdout, "%s%c", it->string, 0); - if (d->head_path) - fprintf(stdout, "%s%c", d->head_path, 0); - } else { - struct strbuf onebuf = STRBUF_INIT; - const char *one; - if (d->head_path) { - one = quote_path(d->head_path, -1, &onebuf, s->prefix); - printf("%s -> ", one); - strbuf_release(&onebuf); - } - one = quote_path(it->string, -1, &onebuf, s->prefix); - printf("%s\n", one); - strbuf_release(&onebuf); - } -} - -static void short_untracked(int null_termination, struct string_list_item *it, - struct wt_status *s) -{ - if (null_termination) { - fprintf(stdout, "?? %s%c", it->string, 0); - } else { - struct strbuf onebuf = STRBUF_INIT; - const char *one; - one = quote_path(it->string, -1, &onebuf, s->prefix); - printf("?? %s\n", one); - strbuf_release(&onebuf); - } -} - -static void short_print(struct wt_status *s, int null_termination) -{ - 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) - short_unmerged(null_termination, it, s); - else - short_status(null_termination, it, s); - } - for (i = 0; i < s->untracked.nr; i++) { - struct string_list_item *it; - - it = &(s->untracked.items[i]); - short_untracked(null_termination, it, s); - } -} - int cmd_status(int argc, const char **argv, const char *prefix) { struct wt_status s; @@ -1061,10 +968,10 @@ int cmd_status(int argc, const char **argv, const char *prefix) case STATUS_FORMAT_SHORT: if (s.relative_paths) s.prefix = prefix; - short_print(&s, null_termination); + wt_shortstatus_print(&s, null_termination); break; case STATUS_FORMAT_PORCELAIN: - short_print(&s, null_termination); + wt_shortstatus_print(&s, null_termination); break; case STATUS_FORMAT_LONG: s.verbose = verbose; diff --git a/wt-status.c b/wt-status.c index 249227c382..8ef824e0d9 100644 --- a/wt-status.c +++ b/wt-status.c @@ -592,3 +592,92 @@ void wt_status_print(struct wt_status *s) printf("nothing to commit (working directory clean)\n"); } } + +static void wt_shortstatus_unmerged(int null_termination, struct string_list_item *it, + struct wt_status *s) +{ + struct wt_status_change_data *d = it->util; + const char *how = "??"; + + switch (d->stagemask) { + case 1: how = "DD"; break; /* both deleted */ + case 2: how = "AU"; break; /* added by us */ + case 3: how = "UD"; break; /* deleted by them */ + case 4: how = "UA"; break; /* added by them */ + case 5: how = "DU"; break; /* deleted by us */ + case 6: how = "AA"; break; /* both added */ + case 7: how = "UU"; break; /* both modified */ + } + printf("%s ", how); + if (null_termination) { + fprintf(stdout, "%s%c", it->string, 0); + } else { + struct strbuf onebuf = STRBUF_INIT; + const char *one; + one = quote_path(it->string, -1, &onebuf, s->prefix); + printf("%s\n", one); + strbuf_release(&onebuf); + } +} + +static void wt_shortstatus_status(int null_termination, struct string_list_item *it, + struct wt_status *s) +{ + struct wt_status_change_data *d = it->util; + + printf("%c%c ", + !d->index_status ? ' ' : d->index_status, + !d->worktree_status ? ' ' : d->worktree_status); + if (null_termination) { + fprintf(stdout, "%s%c", it->string, 0); + if (d->head_path) + fprintf(stdout, "%s%c", d->head_path, 0); + } else { + struct strbuf onebuf = STRBUF_INIT; + const char *one; + if (d->head_path) { + one = quote_path(d->head_path, -1, &onebuf, s->prefix); + printf("%s -> ", one); + strbuf_release(&onebuf); + } + one = quote_path(it->string, -1, &onebuf, s->prefix); + printf("%s\n", one); + strbuf_release(&onebuf); + } +} + +static void wt_shortstatus_untracked(int null_termination, struct string_list_item *it, + struct wt_status *s) +{ + if (null_termination) { + fprintf(stdout, "?? %s%c", it->string, 0); + } else { + struct strbuf onebuf = STRBUF_INIT; + const char *one; + one = quote_path(it->string, -1, &onebuf, s->prefix); + printf("?? %s\n", one); + strbuf_release(&onebuf); + } +} + +void wt_shortstatus_print(struct wt_status *s, int null_termination) +{ + 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) + wt_shortstatus_unmerged(null_termination, it, s); + else + wt_shortstatus_status(null_termination, it, s); + } + for (i = 0; i < s->untracked.nr; i++) { + struct string_list_item *it; + + it = &(s->untracked.items[i]); + wt_shortstatus_untracked(null_termination, it, s); + } +} diff --git a/wt-status.h b/wt-status.h index 09fd9f1091..39c9aef7a5 100644 --- a/wt-status.h +++ b/wt-status.h @@ -56,4 +56,6 @@ void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s); void wt_status_collect(struct wt_status *s); +void wt_shortstatus_print(struct wt_status *s, int null_termination); + #endif /* STATUS_H */ From 3fe2a894e98566dd91e69982552454cfb381cf24 Mon Sep 17 00:00:00 2001 From: Michael J Gruber Date: Sat, 5 Dec 2009 16:04:38 +0100 Subject: [PATCH 13/20] status -s: obey color.status Make the short version of status obey the color.status boolean. We color the status letters only, because they carry the state information and are potentially colored differently, such as for a file with staged changes as well as changes in the worktree against the index. Signed-off-by: Michael J Gruber Signed-off-by: Junio C Hamano --- builtin-commit.c | 4 ++++ wt-status.c | 21 ++++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 8411236fda..07cc76c04a 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -968,6 +968,10 @@ int cmd_status(int argc, const char **argv, const char *prefix) case STATUS_FORMAT_SHORT: if (s.relative_paths) s.prefix = prefix; + if (s.use_color == -1) + s.use_color = git_use_color_default; + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; wt_shortstatus_print(&s, null_termination); break; case STATUS_FORMAT_PORCELAIN: diff --git a/wt-status.c b/wt-status.c index 8ef824e0d9..696c6b0bf1 100644 --- a/wt-status.c +++ b/wt-status.c @@ -608,14 +608,14 @@ static void wt_shortstatus_unmerged(int null_termination, struct string_list_ite case 6: how = "AA"; break; /* both added */ case 7: how = "UU"; break; /* both modified */ } - printf("%s ", how); + color_fprintf(s->fp, color(WT_STATUS_UNMERGED, s), "%s", how); if (null_termination) { - fprintf(stdout, "%s%c", it->string, 0); + fprintf(stdout, " %s%c", it->string, 0); } else { struct strbuf onebuf = STRBUF_INIT; const char *one; one = quote_path(it->string, -1, &onebuf, s->prefix); - printf("%s\n", one); + printf(" %s\n", one); strbuf_release(&onebuf); } } @@ -625,9 +625,15 @@ static void wt_shortstatus_status(int null_termination, struct string_list_item { struct wt_status_change_data *d = it->util; - printf("%c%c ", - !d->index_status ? ' ' : d->index_status, - !d->worktree_status ? ' ' : d->worktree_status); + if (d->index_status) + color_fprintf(s->fp, color(WT_STATUS_UPDATED, s), "%c", d->index_status); + else + putchar(' '); + if (d->worktree_status) + color_fprintf(s->fp, color(WT_STATUS_CHANGED, s), "%c", d->worktree_status); + else + putchar(' '); + putchar(' '); if (null_termination) { fprintf(stdout, "%s%c", it->string, 0); if (d->head_path) @@ -655,7 +661,8 @@ static void wt_shortstatus_untracked(int null_termination, struct string_list_it struct strbuf onebuf = STRBUF_INIT; const char *one; one = quote_path(it->string, -1, &onebuf, s->prefix); - printf("?? %s\n", one); + color_fprintf(s->fp, color(WT_STATUS_UNTRACKED, s), "??"); + printf(" %s\n", one); strbuf_release(&onebuf); } } From 4a7cc2fdf39c90e6eff84d30b86490cac2c33705 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 7 Dec 2009 00:17:15 -0500 Subject: [PATCH 14/20] status: disable color for porcelain format The porcelain format is identical to the shortstatus format, except that it should not respect any user configuration, including color. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-commit.c | 4 ++-- wt-status.c | 6 ++++++ wt-status.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 07cc76c04a..ded58984ac 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -382,7 +382,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int wt_shortstatus_print(s, null_termination); break; case STATUS_FORMAT_PORCELAIN: - wt_shortstatus_print(s, null_termination); + wt_porcelain_print(s, null_termination); break; case STATUS_FORMAT_LONG: wt_status_print(s); @@ -975,7 +975,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) wt_shortstatus_print(&s, null_termination); break; case STATUS_FORMAT_PORCELAIN: - wt_shortstatus_print(&s, null_termination); + wt_porcelain_print(&s, null_termination); break; case STATUS_FORMAT_LONG: s.verbose = verbose; diff --git a/wt-status.c b/wt-status.c index 696c6b0bf1..756defea1a 100644 --- a/wt-status.c +++ b/wt-status.c @@ -688,3 +688,9 @@ void wt_shortstatus_print(struct wt_status *s, int null_termination) wt_shortstatus_untracked(null_termination, it, s); } } + +void wt_porcelain_print(struct wt_status *s, int null_termination) +{ + s->use_color = 0; + wt_shortstatus_print(s, null_termination); +} diff --git a/wt-status.h b/wt-status.h index 39c9aef7a5..a4bddcf8db 100644 --- a/wt-status.h +++ b/wt-status.h @@ -57,5 +57,6 @@ void wt_status_print(struct wt_status *s); void wt_status_collect(struct wt_status *s); void wt_shortstatus_print(struct wt_status *s, int null_termination); +void wt_porcelain_print(struct wt_status *s, int null_termination); #endif /* STATUS_H */ From 8661768fc9cfdeeaae76693501b82940cfcbedc2 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 7 Dec 2009 00:26:25 -0500 Subject: [PATCH 15/20] status: reduce duplicated setup code We have three output formats: short, porcelain, and long. The short and long formats respect user-config, and the porcelain one does not. This led to us repeating config-related setup code for the short and long formats. Since the last commit, color config is explicitly cleared when showing the porcelain format. Let's do the same with relative-path configuration, which enables us to hoist the duplicated code from the switch statement in cmd_status. As a bonus, this fixes "commit --dry-run --porcelain", which was unconditionally setting up that configuration, anyway. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-commit.c | 19 +++++++------------ wt-status.c | 2 ++ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index ded58984ac..b39295fbf2 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -964,14 +964,15 @@ int cmd_status(int argc, const char **argv, const char *prefix) s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0; wt_status_collect(&s); + if (s.relative_paths) + s.prefix = prefix; + if (s.use_color == -1) + s.use_color = git_use_color_default; + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; + switch (status_format) { case STATUS_FORMAT_SHORT: - if (s.relative_paths) - s.prefix = prefix; - if (s.use_color == -1) - s.use_color = git_use_color_default; - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; wt_shortstatus_print(&s, null_termination); break; case STATUS_FORMAT_PORCELAIN: @@ -979,12 +980,6 @@ int cmd_status(int argc, const char **argv, const char *prefix) break; case STATUS_FORMAT_LONG: s.verbose = verbose; - if (s.relative_paths) - s.prefix = prefix; - if (s.use_color == -1) - s.use_color = git_use_color_default; - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; wt_status_print(&s); break; } diff --git a/wt-status.c b/wt-status.c index 756defea1a..3fdcf97e11 100644 --- a/wt-status.c +++ b/wt-status.c @@ -692,5 +692,7 @@ void wt_shortstatus_print(struct wt_status *s, int null_termination) void wt_porcelain_print(struct wt_status *s, int null_termination) { s->use_color = 0; + s->relative_paths = 0; + s->prefix = NULL; wt_shortstatus_print(s, null_termination); } From c521bb7114e081d81eb7cd77cf5989d30160d0a2 Mon Sep 17 00:00:00 2001 From: Michael J Gruber Date: Tue, 8 Dec 2009 11:12:01 +0100 Subject: [PATCH 16/20] t7508-status: status --porcelain ignores relative paths setting Signed-off-by: Michael J Gruber Signed-off-by: Junio C Hamano --- t/t7508-status.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 99a74bda6f..8e7727e5d4 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -297,6 +297,24 @@ test_expect_success 'status -s with relative paths' ' ' +cat > expect << \EOF + M dir1/modified +A dir2/added +?? dir1/untracked +?? dir2/modified +?? dir2/untracked +?? expect +?? output +?? untracked +EOF + +test_expect_success 'status --porcelain ignores relative paths setting' ' + + (cd dir1 && git status --porcelain) > output && + test_cmp expect output + +' + cat > expect << \EOF # On branch master # Changes to be committed: From 68cfc6f551a02d29a2bc48c6473fad6ab42a476f Mon Sep 17 00:00:00 2001 From: Michael J Gruber Date: Tue, 8 Dec 2009 11:12:02 +0100 Subject: [PATCH 17/20] t7508-status: test all modes with color Move a useful script function to decode colored output to text form from t4034 and use it in this test as well. Signed-off-by: Michael J Gruber Signed-off-by: Junio C Hamano --- t/t4034-diff-words.sh | 23 ++---- t/t7508-status.sh | 166 +++++++++++++++++++++++++++++++++++------- t/test-lib.sh | 11 +++ 3 files changed, 156 insertions(+), 44 deletions(-) diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 4508effcaa..17621dd5a4 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -11,18 +11,9 @@ test_expect_success setup ' ' -decrypt_color () { - sed \ - -e 's/.\[1m//g' \ - -e 's/.\[31m//g' \ - -e 's/.\[32m//g' \ - -e 's/.\[36m//g' \ - -e 's/.\[m//g' -} - word_diff () { test_must_fail git diff --no-index "$@" pre post > output && - decrypt_color < output > output.decrypted && + test_decode_color output.decrypted && test_cmp expect output.decrypted } @@ -47,7 +38,7 @@ cat > expect <<\EOF index 330b04f..5ed8eff 100644 --- a/pre +++ b/post -@@ -1,3 +1,7 @@ +@@ -1,3 +1,7 @@ h(4)h(4),hh[44] a = b + c @@ -68,7 +59,7 @@ cat > expect <<\EOF index 330b04f..5ed8eff 100644 --- a/pre +++ b/post -@@ -1,3 +1,7 @@ +@@ -1,3 +1,7 @@ h(4),hh[44] a = b + c @@ -104,7 +95,7 @@ cat > expect <<\EOF index 330b04f..5ed8eff 100644 --- a/pre +++ b/post -@@ -1,3 +1,7 @@ +@@ -1,3 +1,7 @@ h(4),hh[44] a = b + c @@ -146,7 +137,7 @@ cat > expect <<\EOF index 330b04f..5ed8eff 100644 --- a/pre +++ b/post -@@ -1,3 +1,7 @@ +@@ -1,3 +1,7 @@ h(4),hh[44] a = b + c @@ -168,7 +159,7 @@ cat > expect <<\EOF index c29453b..be22f37 100644 --- a/pre +++ b/post -@@ -1 +1 @@ +@@ -1 +1 @@ aaa (aaa) aaa EOF @@ -187,7 +178,7 @@ cat > expect <<\EOF index 289cb9d..2d06f37 100644 --- a/pre +++ b/post -@@ -1 +1 @@ +@@ -1 +1 @@ (: EOF diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 8e7727e5d4..cf67fe3a4a 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -8,26 +8,26 @@ test_description='git status' . ./test-lib.sh test_expect_success 'setup' ' - : > tracked && - : > modified && + : >tracked && + : >modified && mkdir dir1 && - : > dir1/tracked && - : > dir1/modified && + : >dir1/tracked && + : >dir1/modified && mkdir dir2 && - : > dir1/tracked && - : > dir1/modified && + : >dir1/tracked && + : >dir1/modified && git add . && git status >output && test_tick && git commit -m initial && - : > untracked && - : > dir1/untracked && - : > dir2/untracked && - echo 1 > dir1/modified && - echo 2 > dir2/modified && - echo 3 > dir2/added && + : >untracked && + : >dir1/untracked && + : >dir2/untracked && + echo 1 >dir1/modified && + echo 2 >dir2/modified && + echo 3 >dir2/added && git add dir2/added ' @@ -37,7 +37,7 @@ test_expect_success 'status (1)' ' ' -cat > expect << \EOF +cat >expect <<\EOF # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) @@ -63,12 +63,12 @@ EOF test_expect_success 'status (2)' ' - git status > output && + git status >output && test_cmp expect output ' -cat > expect << \EOF +cat >expect <<\EOF M dir1/modified A dir2/added ?? dir1/untracked @@ -81,7 +81,7 @@ EOF test_expect_success 'status -s (2)' ' - git status -s > output && + git status -s >output && test_cmp expect output ' @@ -103,8 +103,8 @@ cat >expect < dir3/untracked1 && - : > dir3/untracked2 && + : >dir3/untracked1 && + : >dir3/untracked2 && git status -uno >output && test_cmp expect output ' @@ -249,7 +249,7 @@ test_expect_success 'status -s (status.showUntrackedFiles all)' ' test_cmp expect output ' -cat > expect << \EOF +cat >expect <<\EOF # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) @@ -275,12 +275,12 @@ EOF test_expect_success 'status with relative paths' ' - (cd dir1 && git status) > output && + (cd dir1 && git status) >output && test_cmp expect output ' -cat > expect << \EOF +cat >expect <<\EOF M modified A ../dir2/added ?? untracked @@ -292,12 +292,12 @@ A ../dir2/added EOF test_expect_success 'status -s with relative paths' ' - (cd dir1 && git status -s) > output && + (cd dir1 && git status -s) >output && test_cmp expect output ' -cat > expect << \EOF +cat >expect <<\EOF M dir1/modified A dir2/added ?? dir1/untracked @@ -310,12 +310,121 @@ EOF test_expect_success 'status --porcelain ignores relative paths setting' ' - (cd dir1 && git status --porcelain) > output && + (cd dir1 && git status --porcelain) >output && test_cmp expect output ' -cat > expect << \EOF +test_expect_success 'setup unique colors' ' + + git config status.color.untracked blue + +' + +cat >expect <<\EOF +# On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# new file: dir2/added +# +# Changed but not updated: +# (use "git add ..." to update what will be committed) +# (use "git checkout -- ..." to discard changes in working directory) +# +# modified: dir1/modified +# +# Untracked files: +# (use "git add ..." to include in what will be committed) +# +# dir1/untracked +# dir2/modified +# dir2/untracked +# expect +# output +# untracked +EOF + +test_expect_success 'status with color.ui' ' + + git config color.ui always && + git status | test_decode_color >output && + test_cmp expect output + +' + +test_expect_success 'status with color.status' ' + + git config --unset color.ui && + git config color.status always && + git status | test_decode_color >output && + test_cmp expect output + +' + +cat >expect <<\EOF + M dir1/modified +A dir2/added +?? dir1/untracked +?? dir2/modified +?? dir2/untracked +?? expect +?? output +?? untracked +EOF + +test_expect_success 'status -s with color.ui' ' + + git config --unset color.status && + git config color.ui always && + git status -s | test_decode_color >output && + test_cmp expect output + +' + +test_expect_success 'status -s with color.status' ' + + git config --unset color.ui && + git config color.status always && + git status -s | test_decode_color >output && + test_cmp expect output + +' + +cat >expect <<\EOF + M dir1/modified +A dir2/added +?? dir1/untracked +?? dir2/modified +?? dir2/untracked +?? expect +?? output +?? untracked +EOF + +test_expect_success 'status --porcelain ignores color.ui' ' + + git config --unset color.status && + git config color.ui always && + git status --porcelain | test_decode_color >output && + test_cmp expect output + +' + +test_expect_success 'status --porcelain ignores color.status' ' + + git config --unset color.ui && + git config color.status always && + git status --porcelain | test_decode_color >output && + test_cmp expect output + +' + +# recover unconditionally from color tests +git config --unset color.status +git config --unset color.ui + +cat >expect <<\EOF # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) @@ -339,15 +448,16 @@ cat > expect << \EOF # untracked EOF + test_expect_success 'status without relative paths' ' git config status.relativePaths false - (cd dir1 && git status) > output && + (cd dir1 && git status) >output && test_cmp expect output ' -cat > expect << \EOF +cat >expect <<\EOF M dir1/modified A dir2/added ?? dir1/untracked @@ -360,7 +470,7 @@ EOF test_expect_success 'status -s without relative paths' ' - (cd dir1 && git status -s) > output && + (cd dir1 && git status -s) >output && test_cmp expect output ' diff --git a/t/test-lib.sh b/t/test-lib.sh index 5fdc5d94a2..d63ad2d870 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -208,6 +208,17 @@ test_set_editor () { export VISUAL } +test_decode_color () { + sed -e 's/.\[1m//g' \ + -e 's/.\[31m//g' \ + -e 's/.\[32m//g' \ + -e 's/.\[33m//g' \ + -e 's/.\[34m//g' \ + -e 's/.\[35m//g' \ + -e 's/.\[36m//g' \ + -e 's/.\[m//g' +} + test_tick () { if test -z "${test_tick+set}" then From 309883015ff3af6ce14ff9fe401e06cfce8adb13 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 11 Dec 2009 23:45:24 -0800 Subject: [PATCH 18/20] commit/status: check $GIT_DIR/MERGE_HEAD only once The code checked for the MERGE_HEAD file to see if we were about to commit a merge twice in the codepath; also one of them used a variable merge_head_sha1[] which was set but was never used. Just check it once, but do so also in "git status", too, as we will be using this for status generation in the next patch. Signed-off-by: Junio C Hamano --- builtin-commit.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index b39295fbf2..17dd462173 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -36,7 +36,7 @@ static const char * const builtin_status_usage[] = { NULL }; -static unsigned char head_sha1[20], merge_head_sha1[20]; +static unsigned char head_sha1[20]; static char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; static struct lock_file index_lock; /* real index */ @@ -319,7 +319,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int */ commit_style = COMMIT_PARTIAL; - if (file_exists(git_path("MERGE_HEAD"))) + if (in_merge) die("cannot do a partial commit during a merge."); memset(&partial, 0, sizeof(partial)); @@ -758,9 +758,6 @@ static int parse_and_validate_options(int argc, const char *argv[], if (get_sha1("HEAD", head_sha1)) initial_commit = 1; - if (!get_sha1("MERGE_HEAD", merge_head_sha1)) - in_merge = 1; - /* Sanity check options */ if (amend && initial_commit) die("You have nothing to amend."); @@ -951,6 +948,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) wt_status_prepare(&s); git_config(git_status_config, &s); + in_merge = file_exists(git_path("MERGE_HEAD")); argc = parse_options(argc, argv, prefix, builtin_status_options, builtin_status_usage, 0); @@ -1057,10 +1055,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix) wt_status_prepare(&s); git_config(git_commit_config, &s); + in_merge = file_exists(git_path("MERGE_HEAD")); if (s.use_color == -1) s.use_color = git_use_color_default; - argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix, &s); if (dry_run) { From dd20f8af1ae54773569b78b1b71d1ea663705d2c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 12 Dec 2009 00:18:12 -0800 Subject: [PATCH 19/20] commit/status: "git add " is not necessarily how to resolve When the desired resolution is to remove the path, "git rm " is the command the user needs to use. Just like in "Changed but not updated" section, suggest to use "git add/rm" as appropriate. Signed-off-by: Junio C Hamano --- t/t7060-wtstatus.sh | 2 +- wt-status.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index 7b5db8066f..0919ec46f6 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -32,7 +32,7 @@ cat >expect <..." to unstage) -# (use "git add ..." to mark resolution) +# (use "git add/rm ..." as appropriate to mark resolution) # # deleted by us: foo # diff --git a/wt-status.c b/wt-status.c index 3fdcf97e11..56cd8741c0 100644 --- a/wt-status.c +++ b/wt-status.c @@ -52,7 +52,7 @@ static void wt_status_print_unmerged_header(struct wt_status *s) color_fprintf_ln(s->fp, c, "# (use \"git reset %s ...\" to unstage)", s->reference); else color_fprintf_ln(s->fp, c, "# (use \"git rm --cached ...\" to unstage)"); - color_fprintf_ln(s->fp, c, "# (use \"git add ...\" to mark resolution)"); + color_fprintf_ln(s->fp, c, "# (use \"git add/rm ...\" as appropriate to mark resolution)"); color_fprintf_ln(s->fp, c, "#"); } From 3c5884536563518ce6cd4dc782b0ebb670bf3b6d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 11 Dec 2009 23:53:41 -0800 Subject: [PATCH 20/20] status/commit: do not suggest "reset HEAD " while merging Suggesting "'reset HEAD ' to unstage" is dead wrong if we are about to record a merge commit. For either an unmerged path (i.e. with unresolved conflicts), or an updated path, it would result in discarding what the other branch did. Note that we do not do anything special in a case where we are amending a merge. The user is making an evil merge starting from an already committed merge, and running "reset HEAD " is the right way to get rid of the local edit that has been added to the index. Once "reset --unresolve " becomes available, we might want to suggest it for a merged path that has unresolve information, but until then, just remove the incorrect advice. We might also want to suggest "checkout --conflict " to revert the file in the work tree to the state of failed automerge for an unmerged path, but we never did that, and this commit does not change that. Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 ++ t/t7060-wtstatus.sh | 1 - wt-status.c | 14 ++++++++++---- wt-status.h | 1 + 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 17dd462173..7218454d1e 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -960,6 +960,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) read_cache(); refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED); s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0; + s.in_merge = in_merge; wt_status_collect(&s); if (s.relative_paths) @@ -1056,6 +1057,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) wt_status_prepare(&s); git_config(git_commit_config, &s); in_merge = file_exists(git_path("MERGE_HEAD")); + s.in_merge = in_merge; if (s.use_color == -1) s.use_color = git_use_color_default; diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index 0919ec46f6..fcac472598 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -31,7 +31,6 @@ test_expect_success 'Report new path with conflict' ' cat >expect <..." to unstage) # (use "git add/rm ..." as appropriate to mark resolution) # # deleted by us: foo diff --git a/wt-status.c b/wt-status.c index 56cd8741c0..c4589055bb 100644 --- a/wt-status.c +++ b/wt-status.c @@ -47,8 +47,11 @@ void wt_status_prepare(struct wt_status *s) static void wt_status_print_unmerged_header(struct wt_status *s) { const char *c = color(WT_STATUS_HEADER, s); + color_fprintf_ln(s->fp, c, "# Unmerged paths:"); - if (!s->is_initial) + if (s->in_merge) + ; + else if (!s->is_initial) color_fprintf_ln(s->fp, c, "# (use \"git reset %s ...\" to unstage)", s->reference); else color_fprintf_ln(s->fp, c, "# (use \"git rm --cached ...\" to unstage)"); @@ -59,12 +62,14 @@ static void wt_status_print_unmerged_header(struct wt_status *s) static void wt_status_print_cached_header(struct wt_status *s) { const char *c = color(WT_STATUS_HEADER, s); + color_fprintf_ln(s->fp, c, "# Changes to be committed:"); - if (!s->is_initial) { + if (s->in_merge) + ; /* NEEDSWORK: use "git reset --unresolve"??? */ + else if (!s->is_initial) color_fprintf_ln(s->fp, c, "# (use \"git reset %s ...\" to unstage)", s->reference); - } else { + else color_fprintf_ln(s->fp, c, "# (use \"git rm --cached ...\" to unstage)"); - } color_fprintf_ln(s->fp, c, "#"); } @@ -72,6 +77,7 @@ static void wt_status_print_dirty_header(struct wt_status *s, int has_deleted) { const char *c = color(WT_STATUS_HEADER, s); + color_fprintf_ln(s->fp, c, "# Changed but not updated:"); if (!has_deleted) color_fprintf_ln(s->fp, c, "# (use \"git add ...\" to update what will be committed)"); diff --git a/wt-status.h b/wt-status.h index a4bddcf8db..c60f40a34a 100644 --- a/wt-status.h +++ b/wt-status.h @@ -34,6 +34,7 @@ struct wt_status { const char **pathspec; int verbose; int amend; + int in_merge; int nowarn; int use_color; int relative_paths;