@matheusbsbs / matheus-bagliano / commits / 9297f77e6d
Fork 0

git status: Show detailed dirty status of submodules in long format

Since 1.7.0 there are three reasons a submodule is considered modified against the work tree: It contains new commits, modified content or untracked content. Lets show all reasons in the long format of git status, so the user can better asses the nature of the modification. This change does not affect the short and porcelain formats. Two new members are added to "struct wt_status_change_data" to store the information gathered by run_diff_files(). wt-status.c uses the new flag DIFF_OPT_DIRTY_SUBMODULES to tell diff-lib.c it wants to get detailed dirty information about submodules. A hint line for submodules is printed in the dirty header when dirty submodules are present. Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jens Lehmann committed Mar 8, 2010 at 13:53 UTC 9297f77e6d350f33de961e149dc33c77e7392db4
5 files changed +46 -12
diff-lib.c
+4 -2
@@ -180,7 +180,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
180 changed = ce_match_stat(ce, &st, ce_option);
181 if (S_ISGITLINK(ce->ce_mode)
182 && !DIFF_OPT_TST(&revs->diffopt, IGNORE_SUBMODULES)
183 - && (!changed || (revs->diffopt.output_format & DIFF_FORMAT_PATCH))) {
183 + && (!changed || (revs->diffopt.output_format & DIFF_FORMAT_PATCH)
184 + || DIFF_OPT_TST(&revs->diffopt, DIRTY_SUBMODULES))) {
185 dirty_submodule = is_submodule_modified(ce->name);
186 if (dirty_submodule)
187 changed = 1;
@@ -243,7 +244,8 @@ static int get_stat_data(struct cache_entry *ce,
244 changed = ce_match_stat(ce, &st, 0);
245 if (S_ISGITLINK(ce->ce_mode)
246 && !DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES)
246 - && (!changed || (diffopt->output_format & DIFF_FORMAT_PATCH))) {
247 + && (!changed || (diffopt->output_format & DIFF_FORMAT_PATCH)
248 + || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES))) {
249 *dirty_submodule = is_submodule_modified(ce->name);
250 if (*dirty_submodule)
251 changed = 1;
diff.h
+1
@@ -69,6 +69,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
69 #define DIFF_OPT_ALLOW_TEXTCONV (1 << 21)
70 #define DIFF_OPT_DIFF_FROM_CONTENTS (1 << 22)
71 #define DIFF_OPT_SUBMODULE_LOG (1 << 23)
72 +#define DIFF_OPT_DIRTY_SUBMODULES (1 << 24)
73
74 #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
75 #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
t/t7506-status-submodule.sh
+3 -3
@@ -34,7 +34,7 @@ test_expect_success 'status with modified file in submodule' '
34 (cd sub && git reset --hard) &&
35 echo "changed" >sub/foo &&
36 git status >output &&
37 - grep "modified: sub" output
37 + grep "modified: sub (new commits, modified content)" output
38 '
39
40 test_expect_success 'status with modified file in submodule (porcelain)' '
@@ -49,7 +49,7 @@ test_expect_success 'status with modified file in submodule (porcelain)' '
49 test_expect_success 'status with added file in submodule' '
50 (cd sub && git reset --hard && echo >foo && git add foo) &&
51 git status >output &&
52 - grep "modified: sub" output
52 + grep "modified: sub (new commits, modified content)" output
53 '
54
55 test_expect_success 'status with added file in submodule (porcelain)' '
@@ -64,7 +64,7 @@ test_expect_success 'status with untracked file in submodule' '
64 (cd sub && git reset --hard) &&
65 echo "content" >sub/new-file &&
66 git status >output &&
67 - grep "modified: sub" output
67 + grep "modified: sub (new commits, untracked content)" output
68 '
69
70 test_expect_success 'status with untracked file in submodule (porcelain)' '
wt-status.c
+36 -7
@@ -78,7 +78,8 @@ static void wt_status_print_cached_header(struct wt_status *s)
78 }
79
80 static void wt_status_print_dirty_header(struct wt_status *s,
81 - int has_deleted)
81 + int has_deleted,
82 + int has_dirty_submodules)
83 {
84 const char *c = color(WT_STATUS_HEADER, s);
85
@@ -90,6 +91,8 @@ static void wt_status_print_dirty_header(struct wt_status *s,
91 else
92 color_fprintf_ln(s->fp, c, "# (use \"git add/rm <file>...\" to update what will be committed)");
93 color_fprintf_ln(s->fp, c, "# (use \"git checkout -- <file>...\" to discard changes in working directory)");
94 + if (has_dirty_submodules)
95 + color_fprintf_ln(s->fp, c, "# (commit or discard the untracked or modified content in submodules)");
96 color_fprintf_ln(s->fp, c, "#");
97 }
98
@@ -144,6 +147,7 @@ static void wt_status_print_change_data(struct wt_status *s,
147 char *two_name;
148 const char *one, *two;
149 struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;
150 + struct strbuf extra = STRBUF_INIT;
151
152 one_name = two_name = it->string;
153 switch (change_type) {
@@ -153,6 +157,17 @@ static void wt_status_print_change_data(struct wt_status *s,
157 one_name = d->head_path;
158 break;
159 case WT_STATUS_CHANGED:
160 + if (d->new_submodule_commits || d->dirty_submodule) {
161 + strbuf_addstr(&extra, " (");
162 + if (d->new_submodule_commits)
163 + strbuf_addf(&extra, "new commits, ");
164 + if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
165 + strbuf_addf(&extra, "modified content, ");
166 + if (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
167 + strbuf_addf(&extra, "untracked content, ");
168 + strbuf_setlen(&extra, extra.len - 2);
169 + strbuf_addch(&extra, ')');
170 + }
171 status = d->worktree_status;
172 break;
173 }
@@ -189,6 +204,10 @@ static void wt_status_print_change_data(struct wt_status *s,
204 default:
205 die("bug: unhandled diff status %c", status);
206 }
207 + if (extra.len) {
208 + color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "%s", extra.buf);
209 + strbuf_release(&extra);
210 + }
211 fprintf(s->fp, "\n");
212 strbuf_release(&onebuf);
213 strbuf_release(&twobuf);
@@ -218,6 +237,9 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
237 }
238 if (!d->worktree_status)
239 d->worktree_status = p->status;
240 + d->dirty_submodule = p->two->dirty_submodule;
241 + if (S_ISGITLINK(p->two->mode))
242 + d->new_submodule_commits = !!hashcmp(p->one->sha1, p->two->sha1);
243 }
244 }
245
@@ -281,6 +303,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
303 init_revisions(&rev, NULL);
304 setup_revisions(0, NULL, &rev, NULL);
305 rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
306 + DIFF_OPT_SET(&rev.diffopt, DIRTY_SUBMODULES);
307 rev.diffopt.format_callback = wt_status_collect_changed_cb;
308 rev.diffopt.format_callback_data = s;
309 rev.prune_data = s->pathspec;
@@ -418,33 +441,39 @@ static void wt_status_print_updated(struct wt_status *s)
441 * 0 : no change
442 * 1 : some change but no delete
443 */
421 -static int wt_status_check_worktree_changes(struct wt_status *s)
444 +static int wt_status_check_worktree_changes(struct wt_status *s,
445 + int *dirty_submodules)
446 {
447 int i;
448 int changes = 0;
449
450 + *dirty_submodules = 0;
451 +
452 for (i = 0; i < s->change.nr; i++) {
453 struct wt_status_change_data *d;
454 d = s->change.items[i].util;
455 if (!d->worktree_status ||
456 d->worktree_status == DIFF_STATUS_UNMERGED)
457 continue;
432 - changes = 1;
458 + if (!changes)
459 + changes = 1;
460 + if (d->dirty_submodule)
461 + *dirty_submodules = 1;
462 if (d->worktree_status == DIFF_STATUS_DELETED)
434 - return -1;
463 + changes = -1;
464 }
465 return changes;
466 }
467
468 static void wt_status_print_changed(struct wt_status *s)
469 {
441 - int i;
442 - int worktree_changes = wt_status_check_worktree_changes(s);
470 + int i, dirty_submodules;
471 + int worktree_changes = wt_status_check_worktree_changes(s, &dirty_submodules);
472
473 if (!worktree_changes)
474 return;
475
447 - wt_status_print_dirty_header(s, worktree_changes < 0);
476 + wt_status_print_dirty_header(s, worktree_changes < 0, dirty_submodules);
477
478 for (i = 0; i < s->change.nr; i++) {
479 struct wt_status_change_data *d;
wt-status.h
+2
@@ -25,6 +25,8 @@ struct wt_status_change_data {
25 int index_status;
26 int stagemask;
27 char *head_path;
28 + unsigned dirty_submodule : 2;
29 + unsigned new_submodule_commits : 1;
30 };
31
32 struct wt_status {