Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit a8bd582

Browse files
committed
Merge branch 'jk/maint-status-porcelain-z-b' into maint
"git status --porcelain" ignored "--branch" option by mistake. The output for "git status --branch -z" was also incorrect and did not terminate the record for the current branch name with NUL as asked. By Jeff King * jk/maint-status-porcelain-z-b: status: respect "-b" for porcelain format status: fix null termination with "-b" status: refactor null_termination option commit: refactor option parsing
2 parents 17a9ac7 + d4a6bf1 commit a8bd582

File tree

5 files changed

+105
-89
lines changed

5 files changed

+105
-89
lines changed

Documentation/git-status.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ order is reversed (e.g 'from \-> to' becomes 'to from'). Second, a NUL
177177
and the terminating newline (but a space still separates the status
178178
field from the first filename). Third, filenames containing special
179179
characters are not specially formatted; no quoting or
180-
backslash-escaping is performed. Fourth, there is no branch line.
180+
backslash-escaping is performed.
181181

182182
CONFIGURATION
183183
-------------

builtin/commit.c

Lines changed: 67 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,11 @@ static int show_ignored_in_status;
109109
static const char *only_include_assumed;
110110
static struct strbuf message = STRBUF_INIT;
111111

112-
static int null_termination;
113112
static enum {
114113
STATUS_FORMAT_LONG,
115114
STATUS_FORMAT_SHORT,
116115
STATUS_FORMAT_PORCELAIN
117116
} status_format = STATUS_FORMAT_LONG;
118-
static int status_show_branch;
119117

120118
static int opt_parse_m(const struct option *opt, const char *arg, int unset)
121119
{
@@ -129,59 +127,6 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
129127
return 0;
130128
}
131129

132-
static struct option builtin_commit_options[] = {
133-
OPT__QUIET(&quiet, "suppress summary after successful commit"),
134-
OPT__VERBOSE(&verbose, "show diff in commit message template"),
135-
136-
OPT_GROUP("Commit message options"),
137-
OPT_FILENAME('F', "file", &logfile, "read message from file"),
138-
OPT_STRING(0, "author", &force_author, "author", "override author for commit"),
139-
OPT_STRING(0, "date", &force_date, "date", "override date for commit"),
140-
OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m),
141-
OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"),
142-
OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
143-
OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
144-
OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
145-
OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C/-c/--amend)"),
146-
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
147-
OPT_FILENAME('t', "template", &template_file, "use specified template file"),
148-
OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
149-
OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
150-
OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
151-
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
152-
"GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
153-
/* end commit message options */
154-
155-
OPT_GROUP("Commit contents options"),
156-
OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
157-
OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
158-
OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
159-
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactively add changes"),
160-
OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
161-
OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
162-
OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
163-
OPT_SET_INT(0, "short", &status_format, "show status concisely",
164-
STATUS_FORMAT_SHORT),
165-
OPT_BOOLEAN(0, "branch", &status_show_branch, "show branch information"),
166-
OPT_SET_INT(0, "porcelain", &status_format,
167-
"machine-readable output", STATUS_FORMAT_PORCELAIN),
168-
OPT_BOOLEAN('z', "null", &null_termination,
169-
"terminate entries with NUL"),
170-
OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
171-
OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"),
172-
{ 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" },
173-
/* end commit contents options */
174-
175-
{ OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
176-
"ok to record an empty change",
177-
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
178-
{ OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
179-
"ok to record a change with an empty message",
180-
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
181-
182-
OPT_END()
183-
};
184-
185130
static void determine_whence(struct wt_status *s)
186131
{
187132
if (file_exists(git_path("MERGE_HEAD")))
@@ -513,10 +458,10 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
513458

514459
switch (status_format) {
515460
case STATUS_FORMAT_SHORT:
516-
wt_shortstatus_print(s, null_termination, status_show_branch);
461+
wt_shortstatus_print(s);
517462
break;
518463
case STATUS_FORMAT_PORCELAIN:
519-
wt_porcelain_print(s, null_termination);
464+
wt_porcelain_print(s);
520465
break;
521466
case STATUS_FORMAT_LONG:
522467
wt_status_print(s);
@@ -1046,15 +991,15 @@ static const char *read_commit_message(const char *name)
1046991
}
1047992

1048993
static int parse_and_validate_options(int argc, const char *argv[],
994+
const struct option *options,
1049995
const char * const usage[],
1050996
const char *prefix,
1051997
struct commit *current_head,
1052998
struct wt_status *s)
1053999
{
10541000
int f = 0;
10551001

1056-
argc = parse_options(argc, argv, prefix, builtin_commit_options, usage,
1057-
0);
1002+
argc = parse_options(argc, argv, prefix, options, usage, 0);
10581003

10591004
if (force_author && !strchr(force_author, '>'))
10601005
force_author = find_author_by_nickname(force_author);
@@ -1135,7 +1080,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
11351080
if (all && argc > 0)
11361081
die(_("Paths with -a does not make sense."));
11371082

1138-
if (null_termination && status_format == STATUS_FORMAT_LONG)
1083+
if (s->null_termination && status_format == STATUS_FORMAT_LONG)
11391084
status_format = STATUS_FORMAT_PORCELAIN;
11401085
if (status_format != STATUS_FORMAT_LONG)
11411086
dry_run = 1;
@@ -1222,19 +1167,19 @@ static int git_status_config(const char *k, const char *v, void *cb)
12221167

12231168
int cmd_status(int argc, const char **argv, const char *prefix)
12241169
{
1225-
struct wt_status s;
1170+
static struct wt_status s;
12261171
int fd;
12271172
unsigned char sha1[20];
12281173
static struct option builtin_status_options[] = {
12291174
OPT__VERBOSE(&verbose, "be verbose"),
12301175
OPT_SET_INT('s', "short", &status_format,
12311176
"show status concisely", STATUS_FORMAT_SHORT),
1232-
OPT_BOOLEAN('b', "branch", &status_show_branch,
1177+
OPT_BOOLEAN('b', "branch", &s.show_branch,
12331178
"show branch information"),
12341179
OPT_SET_INT(0, "porcelain", &status_format,
12351180
"machine-readable output",
12361181
STATUS_FORMAT_PORCELAIN),
1237-
OPT_BOOLEAN('z', "null", &null_termination,
1182+
OPT_BOOLEAN('z', "null", &s.null_termination,
12381183
"terminate entries with NUL"),
12391184
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
12401185
"mode",
@@ -1259,7 +1204,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
12591204
builtin_status_options,
12601205
builtin_status_usage, 0);
12611206

1262-
if (null_termination && status_format == STATUS_FORMAT_LONG)
1207+
if (s.null_termination && status_format == STATUS_FORMAT_LONG)
12631208
status_format = STATUS_FORMAT_PORCELAIN;
12641209

12651210
handle_untracked_files_arg(&s);
@@ -1284,10 +1229,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
12841229

12851230
switch (status_format) {
12861231
case STATUS_FORMAT_SHORT:
1287-
wt_shortstatus_print(&s, null_termination, status_show_branch);
1232+
wt_shortstatus_print(&s);
12881233
break;
12891234
case STATUS_FORMAT_PORCELAIN:
1290-
wt_porcelain_print(&s, null_termination);
1235+
wt_porcelain_print(&s);
12911236
break;
12921237
case STATUS_FORMAT_LONG:
12931238
s.verbose = verbose;
@@ -1422,6 +1367,60 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
14221367

14231368
int cmd_commit(int argc, const char **argv, const char *prefix)
14241369
{
1370+
static struct wt_status s;
1371+
static struct option builtin_commit_options[] = {
1372+
OPT__QUIET(&quiet, "suppress summary after successful commit"),
1373+
OPT__VERBOSE(&verbose, "show diff in commit message template"),
1374+
1375+
OPT_GROUP("Commit message options"),
1376+
OPT_FILENAME('F', "file", &logfile, "read message from file"),
1377+
OPT_STRING(0, "author", &force_author, "author", "override author for commit"),
1378+
OPT_STRING(0, "date", &force_date, "date", "override date for commit"),
1379+
OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m),
1380+
OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"),
1381+
OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
1382+
OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
1383+
OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
1384+
OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C/-c/--amend)"),
1385+
OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
1386+
OPT_FILENAME('t', "template", &template_file, "use specified template file"),
1387+
OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
1388+
OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
1389+
OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
1390+
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
1391+
"GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
1392+
/* end commit message options */
1393+
1394+
OPT_GROUP("Commit contents options"),
1395+
OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
1396+
OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
1397+
OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
1398+
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactively add changes"),
1399+
OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
1400+
OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
1401+
OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
1402+
OPT_SET_INT(0, "short", &status_format, "show status concisely",
1403+
STATUS_FORMAT_SHORT),
1404+
OPT_BOOLEAN(0, "branch", &s.show_branch, "show branch information"),
1405+
OPT_SET_INT(0, "porcelain", &status_format,
1406+
"machine-readable output", STATUS_FORMAT_PORCELAIN),
1407+
OPT_BOOLEAN('z', "null", &s.null_termination,
1408+
"terminate entries with NUL"),
1409+
OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
1410+
OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"),
1411+
{ 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" },
1412+
/* end commit contents options */
1413+
1414+
{ OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
1415+
"ok to record an empty change",
1416+
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
1417+
{ OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
1418+
"ok to record a change with an empty message",
1419+
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
1420+
1421+
OPT_END()
1422+
};
1423+
14251424
struct strbuf sb = STRBUF_INIT;
14261425
struct strbuf author_ident = STRBUF_INIT;
14271426
const char *index_file, *reflog_msg;
@@ -1431,7 +1430,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
14311430
struct commit_list *parents = NULL, **pptr = &parents;
14321431
struct stat statbuf;
14331432
int allow_fast_forward = 1;
1434-
struct wt_status s;
14351433
struct commit *current_head = NULL;
14361434
struct commit_extra_header *extra = NULL;
14371435

@@ -1449,7 +1447,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
14491447
if (!current_head || parse_commit(current_head))
14501448
die(_("could not parse HEAD commit"));
14511449
}
1452-
argc = parse_and_validate_options(argc, argv, builtin_commit_usage,
1450+
argc = parse_and_validate_options(argc, argv, builtin_commit_options,
1451+
builtin_commit_usage,
14531452
prefix, current_head, &s);
14541453
if (dry_run)
14551454
return dry_run_commit(argc, argv, prefix, current_head, &s);

t/t7508-status.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,15 @@ test_expect_success 'status -s -b' '
271271
272272
'
273273

274+
test_expect_success 'status -s -z -b' '
275+
tr "\\n" Q <expect >expect.q &&
276+
mv expect.q expect &&
277+
git status -s -z -b >output &&
278+
nul_to_q <output >output.q &&
279+
mv output.q output &&
280+
test_cmp expect output
281+
'
282+
274283
test_expect_success 'setup dir3' '
275284
mkdir dir3 &&
276285
: >dir3/untracked1 &&
@@ -647,9 +656,14 @@ test_expect_success 'status --porcelain ignores color.status' '
647656
git config --unset color.status
648657
git config --unset color.ui
649658

650-
test_expect_success 'status --porcelain ignores -b' '
659+
test_expect_success 'status --porcelain respects -b' '
651660
652661
git status --porcelain -b >output &&
662+
{
663+
echo "## master" &&
664+
cat expect
665+
} >tmp &&
666+
mv tmp expect &&
653667
test_cmp expect output
654668
655669
'

wt-status.c

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ void wt_status_print(struct wt_status *s)
777777
}
778778
}
779779

780-
static void wt_shortstatus_unmerged(int null_termination, struct string_list_item *it,
780+
static void wt_shortstatus_unmerged(struct string_list_item *it,
781781
struct wt_status *s)
782782
{
783783
struct wt_status_change_data *d = it->util;
@@ -793,7 +793,7 @@ static void wt_shortstatus_unmerged(int null_termination, struct string_list_ite
793793
case 7: how = "UU"; break; /* both modified */
794794
}
795795
color_fprintf(s->fp, color(WT_STATUS_UNMERGED, s), "%s", how);
796-
if (null_termination) {
796+
if (s->null_termination) {
797797
fprintf(stdout, " %s%c", it->string, 0);
798798
} else {
799799
struct strbuf onebuf = STRBUF_INIT;
@@ -804,7 +804,7 @@ static void wt_shortstatus_unmerged(int null_termination, struct string_list_ite
804804
}
805805
}
806806

807-
static void wt_shortstatus_status(int null_termination, struct string_list_item *it,
807+
static void wt_shortstatus_status(struct string_list_item *it,
808808
struct wt_status *s)
809809
{
810810
struct wt_status_change_data *d = it->util;
@@ -818,7 +818,7 @@ static void wt_shortstatus_status(int null_termination, struct string_list_item
818818
else
819819
putchar(' ');
820820
putchar(' ');
821-
if (null_termination) {
821+
if (s->null_termination) {
822822
fprintf(stdout, "%s%c", it->string, 0);
823823
if (d->head_path)
824824
fprintf(stdout, "%s%c", d->head_path, 0);
@@ -846,10 +846,10 @@ static void wt_shortstatus_status(int null_termination, struct string_list_item
846846
}
847847
}
848848

849-
static void wt_shortstatus_other(int null_termination, struct string_list_item *it,
849+
static void wt_shortstatus_other(struct string_list_item *it,
850850
struct wt_status *s, const char *sign)
851851
{
852-
if (null_termination) {
852+
if (s->null_termination) {
853853
fprintf(stdout, "%s %s%c", sign, it->string, 0);
854854
} else {
855855
struct strbuf onebuf = STRBUF_INIT;
@@ -889,8 +889,8 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
889889
if (s->is_initial)
890890
color_fprintf(s->fp, header_color, _("Initial commit on "));
891891
if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
892-
color_fprintf_ln(s->fp, branch_color_local,
893-
"%s", branch_name);
892+
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
893+
fputc(s->null_termination ? '\0' : '\n', s->fp);
894894
return;
895895
}
896896

@@ -914,14 +914,15 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
914914
color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
915915
}
916916

917-
color_fprintf_ln(s->fp, header_color, "]");
917+
color_fprintf(s->fp, header_color, "]");
918+
fputc(s->null_termination ? '\0' : '\n', s->fp);
918919
}
919920

920-
void wt_shortstatus_print(struct wt_status *s, int null_termination, int show_branch)
921+
void wt_shortstatus_print(struct wt_status *s)
921922
{
922923
int i;
923924

924-
if (show_branch)
925+
if (s->show_branch)
925926
wt_shortstatus_print_tracking(s);
926927

927928
for (i = 0; i < s->change.nr; i++) {
@@ -931,28 +932,28 @@ void wt_shortstatus_print(struct wt_status *s, int null_termination, int show_br
931932
it = &(s->change.items[i]);
932933
d = it->util;
933934
if (d->stagemask)
934-
wt_shortstatus_unmerged(null_termination, it, s);
935+
wt_shortstatus_unmerged(it, s);
935936
else
936-
wt_shortstatus_status(null_termination, it, s);
937+
wt_shortstatus_status(it, s);
937938
}
938939
for (i = 0; i < s->untracked.nr; i++) {
939940
struct string_list_item *it;
940941

941942
it = &(s->untracked.items[i]);
942-
wt_shortstatus_other(null_termination, it, s, "??");
943+
wt_shortstatus_other(it, s, "??");
943944
}
944945
for (i = 0; i < s->ignored.nr; i++) {
945946
struct string_list_item *it;
946947

947948
it = &(s->ignored.items[i]);
948-
wt_shortstatus_other(null_termination, it, s, "!!");
949+
wt_shortstatus_other(it, s, "!!");
949950
}
950951
}
951952

952-
void wt_porcelain_print(struct wt_status *s, int null_termination)
953+
void wt_porcelain_print(struct wt_status *s)
953954
{
954955
s->use_color = 0;
955956
s->relative_paths = 0;
956957
s->prefix = NULL;
957-
wt_shortstatus_print(s, null_termination, 0);
958+
wt_shortstatus_print(s);
958959
}

0 commit comments

Comments
 (0)