@matheusbsbs / matheus-bagliano / commits / c7e1a73641
Fork 0

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 "