@matheusbsbs / matheus-bagliano / commits / 50b7e70f33
Fork 0

wt-status.c: rework the way changes to the index and work tree are summarized

Introduce a new infrastructure to find and summarize changes in a single string list, and rewrite wt_status_print_{updated,changed} functions using it. The goal of this change is to give more information on conflicted paths in the status output. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Aug 4, 2009 at 23:49 UTC 50b7e70f338e54f3534ee1b14c3bdb4c80d0dcf7
3 files changed +199 -50
builtin-commit.c
+8 -5
@@ -217,12 +217,15 @@ static void create_base_index(void)
217 exit(128); /* We've already reported the error, finish dying */
218 }
219
220 -static char *prepare_index(int argc, const char **argv, const char *prefix)
220 +static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status)
221 {
222 int fd;
223 struct string_list partial;
224 const char **pathspec = NULL;
225 + int refresh_flags = REFRESH_QUIET;
226
227 + if (is_status)
228 + refresh_flags |= REFRESH_UNMERGED;
229 if (interactive) {
230 if (interactive_add(argc, argv, prefix) != 0)
231 die("interactive add failed");
@@ -253,7 +256,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
256 if (all || (also && pathspec && *pathspec)) {
257 int fd = hold_locked_index(&index_lock, 1);
258 add_files_to_cache(also ? prefix : NULL, pathspec, 0);
256 - refresh_cache(REFRESH_QUIET);
259 + refresh_cache(refresh_flags);
260 if (write_cache(fd, active_cache, active_nr) ||
261 close_lock_file(&index_lock))
262 die("unable to write new_index file");
@@ -272,7 +275,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
275 */
276 if (!pathspec || !*pathspec) {
277 fd = hold_locked_index(&index_lock, 1);
275 - refresh_cache(REFRESH_QUIET);
278 + refresh_cache(refresh_flags);
279 if (write_cache(fd, active_cache, active_nr) ||
280 commit_locked_index(&index_lock))
281 die("unable to write new_index file");
@@ -825,7 +828,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
828
829 argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix);
830
828 - index_file = prepare_index(argc, argv, prefix);
831 + index_file = prepare_index(argc, argv, prefix, 1);
832
833 commitable = run_status(stdout, index_file, prefix, 0);
834
@@ -907,7 +910,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
910
911 argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix);
912
910 - index_file = prepare_index(argc, argv, prefix);
913 + index_file = prepare_index(argc, argv, prefix, 0);
914
915 /* Set up everything for writing the commit object. This includes
916 running hooks, writing the trees, and interacting with the user. */
wt-status.c
+181 -45
@@ -56,6 +56,7 @@ void wt_status_prepare(struct wt_status *s)
56 s->reference = "HEAD";
57 s->fp = stdout;
58 s->index_file = get_index_file();
59 + s->change.strdup_strings = 1;
60 }
61
62 static void wt_status_print_cached_header(struct wt_status *s)
@@ -98,18 +99,35 @@ static void wt_status_print_trailer(struct wt_status *s)
99
100 #define quote_path quote_path_relative
101
101 -static void wt_status_print_filepair(struct wt_status *s,
102 - int t, struct diff_filepair *p)
102 +static void wt_status_print_change_data(struct wt_status *s,
103 + int change_type,
104 + struct string_list_item *it)
105 {
104 - const char *c = color(t);
106 + struct wt_status_change_data *d = it->util;
107 + const char *c = color(change_type);
108 + int status = status;
109 + char *one_name;
110 + char *two_name;
111 const char *one, *two;
112 struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;
113
108 - one = quote_path(p->one->path, -1, &onebuf, s->prefix);
109 - two = quote_path(p->two->path, -1, &twobuf, s->prefix);
114 + one_name = two_name = it->string;
115 + switch (change_type) {
116 + case WT_STATUS_UPDATED:
117 + status = d->index_status;
118 + if (d->head_path)
119 + one_name = d->head_path;
120 + break;
121 + case WT_STATUS_CHANGED:
122 + status = d->worktree_status;
123 + break;
124 + }
125 +
126 + one = quote_path(one_name, -1, &onebuf, s->prefix);
127 + two = quote_path(two_name, -1, &twobuf, s->prefix);
128
129 color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
112 - switch (p->status) {
130 + switch (status) {
131 case DIFF_STATUS_ADDED:
132 color_fprintf(s->fp, c, "new file: %s", one);
133 break;
@@ -135,64 +153,91 @@ static void wt_status_print_filepair(struct wt_status *s,
153 color_fprintf(s->fp, c, "unmerged: %s", one);
154 break;
155 default:
138 - die("bug: unhandled diff status %c", p->status);
156 + die("bug: unhandled diff status %c", status);
157 }
158 fprintf(s->fp, "\n");
159 strbuf_release(&onebuf);
160 strbuf_release(&twobuf);
161 }
162
145 -static void wt_status_print_updated_cb(struct diff_queue_struct *q,
146 - struct diff_options *options,
147 - void *data)
163 +static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
164 + struct diff_options *options,
165 + void *data)
166 {
167 struct wt_status *s = data;
150 - int shown_header = 0;
168 int i;
169 +
170 + if (!q->nr)
171 + return;
172 + s->workdir_dirty = 1;
173 for (i = 0; i < q->nr; i++) {
153 - if (q->queue[i]->status == 'U')
154 - continue;
155 - if (!shown_header) {
156 - wt_status_print_cached_header(s);
157 - s->commitable = 1;
158 - shown_header = 1;
174 + struct diff_filepair *p;
175 + struct string_list_item *it;
176 + struct wt_status_change_data *d;
177 +
178 + p = q->queue[i];
179 + it = string_list_insert(p->one->path, &s->change);
180 + d = it->util;
181 + if (!d) {
182 + d = xcalloc(1, sizeof(*d));
183 + it->util = d;
184 }
160 - wt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);
185 + if (!d->worktree_status)
186 + d->worktree_status = p->status;
187 }
162 - if (shown_header)
163 - wt_status_print_trailer(s);
188 }
189
166 -static void wt_status_print_changed_cb(struct diff_queue_struct *q,
167 - struct diff_options *options,
168 - void *data)
190 +static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
191 + struct diff_options *options,
192 + void *data)
193 {
194 struct wt_status *s = data;
195 int i;
172 - if (q->nr) {
173 - int has_deleted = 0;
174 - s->workdir_dirty = 1;
175 - for (i = 0; i < q->nr; i++)
176 - if (q->queue[i]->status == DIFF_STATUS_DELETED) {
177 - has_deleted = 1;
178 - break;
179 - }
180 - wt_status_print_dirty_header(s, has_deleted);
196 +
197 + for (i = 0; i < q->nr; i++) {
198 + struct diff_filepair *p;
199 + struct string_list_item *it;
200 + struct wt_status_change_data *d;
201 +
202 + p = q->queue[i];
203 + it = string_list_insert(p->two->path, &s->change);
204 + d = it->util;
205 + if (!d) {
206 + d = xcalloc(1, sizeof(*d));
207 + it->util = d;
208 + }
209 + if (!d->index_status)
210 + d->index_status = p->status;
211 + switch (p->status) {
212 + case DIFF_STATUS_COPIED:
213 + case DIFF_STATUS_RENAMED:
214 + d->head_path = xstrdup(p->one->path);
215 + break;
216 + }
217 }
182 - for (i = 0; i < q->nr; i++)
183 - wt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);
184 - if (q->nr)
185 - wt_status_print_trailer(s);
218 }
219
188 -static void wt_status_print_updated(struct wt_status *s)
220 +static void wt_status_collect_changes_worktree(struct wt_status *s)
221 {
222 struct rev_info rev;
223 +
224 + init_revisions(&rev, NULL);
225 + setup_revisions(0, NULL, &rev, NULL);
226 + rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
227 + rev.diffopt.format_callback = wt_status_collect_changed_cb;
228 + rev.diffopt.format_callback_data = s;
229 + run_diff_files(&rev, 0);
230 +}
231 +
232 +static void wt_status_collect_changes_index(struct wt_status *s)
233 +{
234 + struct rev_info rev;
235 +
236 init_revisions(&rev, NULL);
237 setup_revisions(0, NULL, &rev,
238 s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference);
239 rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
195 - rev.diffopt.format_callback = wt_status_print_updated_cb;
240 + rev.diffopt.format_callback = wt_status_collect_updated_cb;
241 rev.diffopt.format_callback_data = s;
242 rev.diffopt.detect_rename = 1;
243 rev.diffopt.rename_limit = 200;
@@ -200,15 +245,104 @@ static void wt_status_print_updated(struct wt_status *s)
245 run_diff_index(&rev, 1);
246 }
247
248 +static void wt_status_collect_changes_initial(struct wt_status *s)
249 +{
250 + int i;
251 +
252 + for (i = 0; i < active_nr; i++) {
253 + struct string_list_item *it;
254 + struct wt_status_change_data *d;
255 + struct cache_entry *ce = active_cache[i];
256 +
257 + it = string_list_insert(ce->name, &s->change);
258 + d = it->util;
259 + if (!d) {
260 + d = xcalloc(1, sizeof(*d));
261 + it->util = d;
262 + }
263 + if (ce_stage(ce))
264 + d->index_status = DIFF_STATUS_UNMERGED;
265 + else
266 + d->index_status = DIFF_STATUS_ADDED;
267 + }
268 +}
269 +
270 +void wt_status_collect_changes(struct wt_status *s)
271 +{
272 + wt_status_collect_changes_worktree(s);
273 +
274 + if (s->is_initial)
275 + wt_status_collect_changes_initial(s);
276 + else
277 + wt_status_collect_changes_index(s);
278 +}
279 +
280 +static void wt_status_print_updated(struct wt_status *s)
281 +{
282 + int shown_header = 0;
283 + int i;
284 +
285 + for (i = 0; i < s->change.nr; i++) {
286 + struct wt_status_change_data *d;
287 + struct string_list_item *it;
288 + it = &(s->change.items[i]);
289 + d = it->util;
290 + if (!d->index_status ||
291 + d->index_status == DIFF_STATUS_UNMERGED)
292 + continue;
293 + if (!shown_header) {
294 + wt_status_print_cached_header(s);
295 + s->commitable = 1;
296 + shown_header = 1;
297 + }
298 + wt_status_print_change_data(s, WT_STATUS_UPDATED, it);
299 + }
300 + if (shown_header)
301 + wt_status_print_trailer(s);
302 +}
303 +
304 +/*
305 + * -1 : has delete
306 + * 0 : no change
307 + * 1 : some change but no delete
308 + */
309 +static int wt_status_check_worktree_changes(struct wt_status *s)
310 +{
311 + int i;
312 + int changes = 0;
313 +
314 + for (i = 0; i < s->change.nr; i++) {
315 + struct wt_status_change_data *d;
316 + d = s->change.items[i].util;
317 + if (!d->worktree_status)
318 + continue;
319 + changes = 1;
320 + if (d->worktree_status == DIFF_STATUS_DELETED)
321 + return -1;
322 + }
323 + return changes;
324 +}
325 +
326 static void wt_status_print_changed(struct wt_status *s)
327 {
205 - struct rev_info rev;
206 - init_revisions(&rev, "");
207 - setup_revisions(0, NULL, &rev, NULL);
208 - rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
209 - rev.diffopt.format_callback = wt_status_print_changed_cb;
210 - rev.diffopt.format_callback_data = s;
211 - run_diff_files(&rev, 0);
328 + int i;
329 + int worktree_changes = wt_status_check_worktree_changes(s);
330 +
331 + if (!worktree_changes)
332 + return;
333 +
334 + wt_status_print_dirty_header(s, worktree_changes < 0);
335 +
336 + for (i = 0; i < s->change.nr; i++) {
337 + struct wt_status_change_data *d;
338 + struct string_list_item *it;
339 + it = &(s->change.items[i]);
340 + d = it->util;
341 + if (!d->worktree_status)
342 + continue;
343 + wt_status_print_change_data(s, WT_STATUS_CHANGED, it);
344 + }
345 + wt_status_print_trailer(s);
346 }
347
348 static void wt_status_print_submodule_summary(struct wt_status *s)
@@ -337,6 +471,8 @@ void wt_status_print(struct wt_status *s)
471 wt_status_print_tracking(s);
472 }
473
474 + wt_status_collect_changes(s);
475 +
476 if (s->is_initial) {
477 color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
478 color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit");
wt-status.h
+10
@@ -2,6 +2,7 @@
2 #define STATUS_H
3
4 #include <stdio.h>
5 +#include "string-list.h"
6
7 enum color_wt_status {
8 WT_STATUS_HEADER,
@@ -18,6 +19,13 @@ enum untracked_status_type {
19 };
20 extern enum untracked_status_type show_untracked_files;
21
22 +struct wt_status_change_data {
23 + int worktree_status;
24 + int index_status;
25 + int stagemask;
26 + char *head_path;
27 +};
28 +
29 struct wt_status {
30 int is_initial;
31 char *branch;
@@ -33,6 +41,7 @@ struct wt_status {
41 const char *index_file;
42 FILE *fp;
43 const char *prefix;
44 + struct string_list change;
45 };
46
47 int git_status_config(const char *var, const char *value, void *cb);
@@ -40,5 +49,6 @@ extern int wt_status_use_color;
49 extern int wt_status_relative_paths;
50 void wt_status_prepare(struct wt_status *s);
51 void wt_status_print(struct wt_status *s);
52 +void wt_status_collect_changes(struct wt_status *s);
53
54 #endif /* STATUS_H */