git diff --submodule: Show detailed dirty status of submodules
When encountering a dirty submodule while doing "git diff --submodule" print an extra line for new untracked content and another for modified but already tracked content. And if the HEAD of the submodule is equal to the ref diffed against in the superproject, drop the output which would just show the same SHA1s and no commit message headlines. To achieve that, the dirty_submodule bitfield is expanded to two bits. The output of "git status" inside the submodule is parsed to set the according bits. Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jens Lehmann committed
Mar 4, 2010 at 22:20 UTC
c7e1a73641e24340bf93f6f1792220fa9154cda3
5 files changed
+58
-21
diff-lib.c
+8
-8
@@ -180,10 +180,10 @@ 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))
184
- && is_submodule_modified(ce->name)) {
185
- changed = 1;
186
- dirty_submodule = 1;
183
+ && (!changed || (revs->diffopt.output_format & DIFF_FORMAT_PATCH))) {
184
+ dirty_submodule = is_submodule_modified(ce->name);
185
+ if (dirty_submodule)
186
+ changed = 1;
187
}
188
if (!changed) {
189
ce_mark_uptodate(ce);
@@ -243,10 +243,10 @@ static int get_stat_data(struct cache_entry *ce,
243
changed = ce_match_stat(ce, &st, 0);
244
if (S_ISGITLINK(ce->ce_mode)
245
&& !DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES)
246
- && (!changed || (diffopt->output_format & DIFF_FORMAT_PATCH))
247
- && is_submodule_modified(ce->name)) {
248
- changed = 1;
249
- *dirty_submodule = 1;
246
+ && (!changed || (diffopt->output_format & DIFF_FORMAT_PATCH))) {
247
+ *dirty_submodule = is_submodule_modified(ce->name);
248
+ if (*dirty_submodule)
249
+ changed = 1;
250
}
251
if (changed) {
252
mode = ce_mode_from_stat(ce, st.st_mode);
diffcore.h
+3
-1
@@ -42,7 +42,9 @@ struct diff_filespec {
42
#define DIFF_FILE_VALID(spec) (((spec)->mode) != 0)
43
unsigned should_free : 1; /* data should be free()'ed */
44
unsigned should_munmap : 1; /* data should be munmap()'ed */
45
- unsigned dirty_submodule : 1; /* For submodules: its work tree is dirty */
45
+ unsigned dirty_submodule : 2; /* For submodules: its work tree is dirty */
46
+#define DIRTY_SUBMODULE_UNTRACKED 1
47
+#define DIRTY_SUBMODULE_MODIFIED 2
48
49
struct userdiff_driver *driver;
50
/* data should be considered "binary"; -1 means "don't know yet" */
submodule.c
+35
-5
@@ -5,6 +5,7 @@
5
#include "commit.h"
6
#include "revision.h"
7
#include "run-command.h"
8
+#include "diffcore.h"
9
10
static int add_submodule_odb(const char *path)
11
{
@@ -85,13 +86,21 @@ void show_submodule_summary(FILE *f, const char *path,
86
message = "(revision walker failed)";
87
}
88
89
+ if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
90
+ fprintf(f, "Submodule %s contains untracked content\n", path);
91
+ if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
92
+ fprintf(f, "Submodule %s contains modified content\n", path);
93
+
94
+ if (!hashcmp(one, two)) {
95
+ strbuf_release(&sb);
96
+ return;
97
+ }
98
+
99
strbuf_addf(&sb, "Submodule %s %s..", path,
100
find_unique_abbrev(one, DEFAULT_ABBREV));
101
if (!fast_backward && !fast_forward)
102
strbuf_addch(&sb, '.');
103
strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV));
93
- if (dirty_submodule)
94
- strbuf_add(&sb, "-dirty", 6);
104
if (message)
105
strbuf_addf(&sb, " %s\n", message);
106
else
@@ -121,9 +130,10 @@ void show_submodule_summary(FILE *f, const char *path,
130
strbuf_release(&sb);
131
}
132
124
-int is_submodule_modified(const char *path)
133
+unsigned is_submodule_modified(const char *path)
134
{
126
- int len, i;
135
+ int i;
136
+ ssize_t len;
137
struct child_process cp;
138
const char *argv[] = {
139
"status",
@@ -132,6 +142,8 @@ int is_submodule_modified(const char *path)
142
};
143
const char *env[LOCAL_REPO_ENV_SIZE + 3];
144
struct strbuf buf = STRBUF_INIT;
145
+ unsigned dirty_submodule = 0;
146
+ const char *line, *next_line;
147
148
for (i = 0; i < LOCAL_REPO_ENV_SIZE; i++)
149
env[i] = local_repo_env[i];
@@ -161,6 +173,24 @@ int is_submodule_modified(const char *path)
173
die("Could not run git status --porcelain");
174
175
len = strbuf_read(&buf, cp.out, 1024);
176
+ line = buf.buf;
177
+ while (len > 2) {
178
+ if ((line[0] == '?') && (line[1] == '?')) {
179
+ dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
180
+ if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
181
+ break;
182
+ } else {
183
+ dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
184
+ if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
185
+ break;
186
+ }
187
+ next_line = strchr(line, '\n');
188
+ if (!next_line)
189
+ break;
190
+ next_line++;
191
+ len -= (next_line - line);
192
+ line = next_line;
193
+ }
194
close(cp.out);
195
196
if (finish_command(&cp))
@@ -169,5 +199,5 @@ int is_submodule_modified(const char *path)
199
for (i = LOCAL_REPO_ENV_SIZE; env[i]; i++)
200
free((char *)env[i]);
201
strbuf_release(&buf);
172
- return len != 0;
202
+ return dirty_submodule;
203
}
submodule.h
+1
-1
@@ -5,6 +5,6 @@ void show_submodule_summary(FILE *f, const char *path,
5
unsigned char one[20], unsigned char two[20],
6
unsigned dirty_submodule,
7
const char *del, const char *add, const char *reset);
8
-int is_submodule_modified(const char *path);
8
+unsigned is_submodule_modified(const char *path);
9
10
#endif
t/t4041-diff-submodule.sh
+11
-6
@@ -201,7 +201,7 @@ test_expect_success 'submodule contains untracked content' "
201
echo new > sm1/new-file &&
202
git diff-index -p --submodule=log HEAD >actual &&
203
diff actual - <<-EOF
204
-Submodule sm1 $head6..$head6-dirty:
204
+Submodule sm1 contains untracked content
205
EOF
206
"
207
@@ -209,7 +209,8 @@ test_expect_success 'submodule contains untracked and modifed content' "
209
echo new > sm1/foo6 &&
210
git diff-index -p --submodule=log HEAD >actual &&
211
diff actual - <<-EOF
212
-Submodule sm1 $head6..$head6-dirty:
212
+Submodule sm1 contains untracked content
213
+Submodule sm1 contains modified content
214
EOF
215
"
216
@@ -217,7 +218,7 @@ test_expect_success 'submodule contains modifed content' "
218
rm -f sm1/new-file &&
219
git diff-index -p --submodule=log HEAD >actual &&
220
diff actual - <<-EOF
220
-Submodule sm1 $head6..$head6-dirty:
221
+Submodule sm1 contains modified content
222
EOF
223
"
224
@@ -235,7 +236,8 @@ test_expect_success 'modified submodule contains untracked content' "
236
echo new > sm1/new-file &&
237
git diff-index -p --submodule=log HEAD >actual &&
238
diff actual - <<-EOF
238
-Submodule sm1 $head6..$head8-dirty:
239
+Submodule sm1 contains untracked content
240
+Submodule sm1 $head6..$head8:
241
> change
242
EOF
243
"
@@ -244,7 +246,9 @@ test_expect_success 'modified submodule contains untracked and modifed content'
246
echo modification >> sm1/foo6 &&
247
git diff-index -p --submodule=log HEAD >actual &&
248
diff actual - <<-EOF
247
-Submodule sm1 $head6..$head8-dirty:
249
+Submodule sm1 contains untracked content
250
+Submodule sm1 contains modified content
251
+Submodule sm1 $head6..$head8:
252
> change
253
EOF
254
"
@@ -253,7 +257,8 @@ test_expect_success 'modified submodule contains modifed content' "
257
rm -f sm1/new-file &&
258
git diff-index -p --submodule=log HEAD >actual &&
259
diff actual - <<-EOF
256
-Submodule sm1 $head6..$head8-dirty:
260
+Submodule sm1 contains modified content
261
+Submodule sm1 $head6..$head8:
262
> change
263
EOF
264
"