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 */