Skip to content

Commit 9297f77

Browse files
jlehmanngitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c7e1a73 commit 9297f77

File tree

5 files changed

+46
-12
lines changed

5 files changed

+46
-12
lines changed

diff-lib.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
180180
changed = ce_match_stat(ce, &st, ce_option);
181181
if (S_ISGITLINK(ce->ce_mode)
182182
&& !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))) {
184185
dirty_submodule = is_submodule_modified(ce->name);
185186
if (dirty_submodule)
186187
changed = 1;
@@ -243,7 +244,8 @@ static int get_stat_data(struct cache_entry *ce,
243244
changed = ce_match_stat(ce, &st, 0);
244245
if (S_ISGITLINK(ce->ce_mode)
245246
&& !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))) {
247249
*dirty_submodule = is_submodule_modified(ce->name);
248250
if (*dirty_submodule)
249251
changed = 1;

diff.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
6969
#define DIFF_OPT_ALLOW_TEXTCONV (1 << 21)
7070
#define DIFF_OPT_DIFF_FROM_CONTENTS (1 << 22)
7171
#define DIFF_OPT_SUBMODULE_LOG (1 << 23)
72+
#define DIFF_OPT_DIRTY_SUBMODULES (1 << 24)
7273

7374
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
7475
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)

t/t7506-status-submodule.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ test_expect_success 'status with modified file in submodule' '
3434
(cd sub && git reset --hard) &&
3535
echo "changed" >sub/foo &&
3636
git status >output &&
37-
grep "modified: sub" output
37+
grep "modified: sub (new commits, modified content)" output
3838
'
3939

4040
test_expect_success 'status with modified file in submodule (porcelain)' '
@@ -49,7 +49,7 @@ test_expect_success 'status with modified file in submodule (porcelain)' '
4949
test_expect_success 'status with added file in submodule' '
5050
(cd sub && git reset --hard && echo >foo && git add foo) &&
5151
git status >output &&
52-
grep "modified: sub" output
52+
grep "modified: sub (new commits, modified content)" output
5353
'
5454

5555
test_expect_success 'status with added file in submodule (porcelain)' '
@@ -64,7 +64,7 @@ test_expect_success 'status with untracked file in submodule' '
6464
(cd sub && git reset --hard) &&
6565
echo "content" >sub/new-file &&
6666
git status >output &&
67-
grep "modified: sub" output
67+
grep "modified: sub (new commits, untracked content)" output
6868
'
6969

7070
test_expect_success 'status with untracked file in submodule (porcelain)' '

wt-status.c

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ static void wt_status_print_cached_header(struct wt_status *s)
7878
}
7979

8080
static void wt_status_print_dirty_header(struct wt_status *s,
81-
int has_deleted)
81+
int has_deleted,
82+
int has_dirty_submodules)
8283
{
8384
const char *c = color(WT_STATUS_HEADER, s);
8485

@@ -90,6 +91,8 @@ static void wt_status_print_dirty_header(struct wt_status *s,
9091
else
9192
color_fprintf_ln(s->fp, c, "# (use \"git add/rm <file>...\" to update what will be committed)");
9293
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)");
9396
color_fprintf_ln(s->fp, c, "#");
9497
}
9598

@@ -144,6 +147,7 @@ static void wt_status_print_change_data(struct wt_status *s,
144147
char *two_name;
145148
const char *one, *two;
146149
struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;
150+
struct strbuf extra = STRBUF_INIT;
147151

148152
one_name = two_name = it->string;
149153
switch (change_type) {
@@ -153,6 +157,17 @@ static void wt_status_print_change_data(struct wt_status *s,
153157
one_name = d->head_path;
154158
break;
155159
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+
}
156171
status = d->worktree_status;
157172
break;
158173
}
@@ -189,6 +204,10 @@ static void wt_status_print_change_data(struct wt_status *s,
189204
default:
190205
die("bug: unhandled diff status %c", status);
191206
}
207+
if (extra.len) {
208+
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "%s", extra.buf);
209+
strbuf_release(&extra);
210+
}
192211
fprintf(s->fp, "\n");
193212
strbuf_release(&onebuf);
194213
strbuf_release(&twobuf);
@@ -218,6 +237,9 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
218237
}
219238
if (!d->worktree_status)
220239
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);
221243
}
222244
}
223245

@@ -281,6 +303,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
281303
init_revisions(&rev, NULL);
282304
setup_revisions(0, NULL, &rev, NULL);
283305
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
306+
DIFF_OPT_SET(&rev.diffopt, DIRTY_SUBMODULES);
284307
rev.diffopt.format_callback = wt_status_collect_changed_cb;
285308
rev.diffopt.format_callback_data = s;
286309
rev.prune_data = s->pathspec;
@@ -418,33 +441,39 @@ static void wt_status_print_updated(struct wt_status *s)
418441
* 0 : no change
419442
* 1 : some change but no delete
420443
*/
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)
422446
{
423447
int i;
424448
int changes = 0;
425449

450+
*dirty_submodules = 0;
451+
426452
for (i = 0; i < s->change.nr; i++) {
427453
struct wt_status_change_data *d;
428454
d = s->change.items[i].util;
429455
if (!d->worktree_status ||
430456
d->worktree_status == DIFF_STATUS_UNMERGED)
431457
continue;
432-
changes = 1;
458+
if (!changes)
459+
changes = 1;
460+
if (d->dirty_submodule)
461+
*dirty_submodules = 1;
433462
if (d->worktree_status == DIFF_STATUS_DELETED)
434-
return -1;
463+
changes = -1;
435464
}
436465
return changes;
437466
}
438467

439468
static void wt_status_print_changed(struct wt_status *s)
440469
{
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);
443472

444473
if (!worktree_changes)
445474
return;
446475

447-
wt_status_print_dirty_header(s, worktree_changes < 0);
476+
wt_status_print_dirty_header(s, worktree_changes < 0, dirty_submodules);
448477

449478
for (i = 0; i < s->change.nr; i++) {
450479
struct wt_status_change_data *d;

wt-status.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ struct wt_status_change_data {
2525
int index_status;
2626
int stagemask;
2727
char *head_path;
28+
unsigned dirty_submodule : 2;
29+
unsigned new_submodule_commits : 1;
2830
};
2931

3032
struct wt_status {

0 commit comments

Comments
 (0)