Skip to content

Commit

Permalink
wt-status.c: rework the way changes to the index and work tree are su…
Browse files Browse the repository at this point in the history
…mmarized

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>
  • Loading branch information
gitster committed Aug 6, 2009
1 parent 26da1d7 commit 50b7e70
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 50 deletions.
13 changes: 8 additions & 5 deletions builtin-commit.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -217,12 +217,15 @@ static void create_base_index(void)
exit(128); /* We've already reported the error, finish dying */ exit(128); /* We've already reported the error, finish dying */
} }


static char *prepare_index(int argc, const char **argv, const char *prefix) static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status)
{ {
int fd; int fd;
struct string_list partial; struct string_list partial;
const char **pathspec = NULL; const char **pathspec = NULL;
int refresh_flags = REFRESH_QUIET;


if (is_status)
refresh_flags |= REFRESH_UNMERGED;
if (interactive) { if (interactive) {
if (interactive_add(argc, argv, prefix) != 0) if (interactive_add(argc, argv, prefix) != 0)
die("interactive add failed"); die("interactive add failed");
Expand Down Expand Up @@ -253,7 +256,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
if (all || (also && pathspec && *pathspec)) { if (all || (also && pathspec && *pathspec)) {
int fd = hold_locked_index(&index_lock, 1); int fd = hold_locked_index(&index_lock, 1);
add_files_to_cache(also ? prefix : NULL, pathspec, 0); add_files_to_cache(also ? prefix : NULL, pathspec, 0);
refresh_cache(REFRESH_QUIET); refresh_cache(refresh_flags);
if (write_cache(fd, active_cache, active_nr) || if (write_cache(fd, active_cache, active_nr) ||
close_lock_file(&index_lock)) close_lock_file(&index_lock))
die("unable to write new_index file"); die("unable to write new_index file");
Expand All @@ -272,7 +275,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
*/ */
if (!pathspec || !*pathspec) { if (!pathspec || !*pathspec) {
fd = hold_locked_index(&index_lock, 1); fd = hold_locked_index(&index_lock, 1);
refresh_cache(REFRESH_QUIET); refresh_cache(refresh_flags);
if (write_cache(fd, active_cache, active_nr) || if (write_cache(fd, active_cache, active_nr) ||
commit_locked_index(&index_lock)) commit_locked_index(&index_lock))
die("unable to write new_index file"); die("unable to write new_index file");
Expand Down Expand Up @@ -825,7 +828,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)


argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix); argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix);


index_file = prepare_index(argc, argv, prefix); index_file = prepare_index(argc, argv, prefix, 1);


commitable = run_status(stdout, index_file, prefix, 0); commitable = run_status(stdout, index_file, prefix, 0);


Expand Down Expand Up @@ -907,7 +910,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)


argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix); argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix);


index_file = prepare_index(argc, argv, prefix); index_file = prepare_index(argc, argv, prefix, 0);


/* Set up everything for writing the commit object. This includes /* Set up everything for writing the commit object. This includes
running hooks, writing the trees, and interacting with the user. */ running hooks, writing the trees, and interacting with the user. */
Expand Down
226 changes: 181 additions & 45 deletions wt-status.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ void wt_status_prepare(struct wt_status *s)
s->reference = "HEAD"; s->reference = "HEAD";
s->fp = stdout; s->fp = stdout;
s->index_file = get_index_file(); s->index_file = get_index_file();
s->change.strdup_strings = 1;
} }


static void wt_status_print_cached_header(struct wt_status *s) static void wt_status_print_cached_header(struct wt_status *s)
Expand Down Expand Up @@ -98,18 +99,35 @@ static void wt_status_print_trailer(struct wt_status *s)


#define quote_path quote_path_relative #define quote_path quote_path_relative


static void wt_status_print_filepair(struct wt_status *s, static void wt_status_print_change_data(struct wt_status *s,
int t, struct diff_filepair *p) int change_type,
struct string_list_item *it)
{ {
const char *c = color(t); struct wt_status_change_data *d = it->util;
const char *c = color(change_type);
int status = status;
char *one_name;
char *two_name;
const char *one, *two; const char *one, *two;
struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT; struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;


one = quote_path(p->one->path, -1, &onebuf, s->prefix); one_name = two_name = it->string;
two = quote_path(p->two->path, -1, &twobuf, s->prefix); switch (change_type) {
case WT_STATUS_UPDATED:
status = d->index_status;
if (d->head_path)
one_name = d->head_path;
break;
case WT_STATUS_CHANGED:
status = d->worktree_status;
break;
}

one = quote_path(one_name, -1, &onebuf, s->prefix);
two = quote_path(two_name, -1, &twobuf, s->prefix);


color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t"); color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
switch (p->status) { switch (status) {
case DIFF_STATUS_ADDED: case DIFF_STATUS_ADDED:
color_fprintf(s->fp, c, "new file: %s", one); color_fprintf(s->fp, c, "new file: %s", one);
break; break;
Expand All @@ -135,80 +153,196 @@ static void wt_status_print_filepair(struct wt_status *s,
color_fprintf(s->fp, c, "unmerged: %s", one); color_fprintf(s->fp, c, "unmerged: %s", one);
break; break;
default: default:
die("bug: unhandled diff status %c", p->status); die("bug: unhandled diff status %c", status);
} }
fprintf(s->fp, "\n"); fprintf(s->fp, "\n");
strbuf_release(&onebuf); strbuf_release(&onebuf);
strbuf_release(&twobuf); strbuf_release(&twobuf);
} }


static void wt_status_print_updated_cb(struct diff_queue_struct *q, static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
struct diff_options *options, struct diff_options *options,
void *data) void *data)
{ {
struct wt_status *s = data; struct wt_status *s = data;
int shown_header = 0;
int i; int i;

if (!q->nr)
return;
s->workdir_dirty = 1;
for (i = 0; i < q->nr; i++) { for (i = 0; i < q->nr; i++) {
if (q->queue[i]->status == 'U') struct diff_filepair *p;
continue; struct string_list_item *it;
if (!shown_header) { struct wt_status_change_data *d;
wt_status_print_cached_header(s);
s->commitable = 1; p = q->queue[i];
shown_header = 1; it = string_list_insert(p->one->path, &s->change);
d = it->util;
if (!d) {
d = xcalloc(1, sizeof(*d));
it->util = d;
} }
wt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]); if (!d->worktree_status)
d->worktree_status = p->status;
} }
if (shown_header)
wt_status_print_trailer(s);
} }


static void wt_status_print_changed_cb(struct diff_queue_struct *q, static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
struct diff_options *options, struct diff_options *options,
void *data) void *data)
{ {
struct wt_status *s = data; struct wt_status *s = data;
int i; int i;
if (q->nr) {
int has_deleted = 0; for (i = 0; i < q->nr; i++) {
s->workdir_dirty = 1; struct diff_filepair *p;
for (i = 0; i < q->nr; i++) struct string_list_item *it;
if (q->queue[i]->status == DIFF_STATUS_DELETED) { struct wt_status_change_data *d;
has_deleted = 1;
break; p = q->queue[i];
} it = string_list_insert(p->two->path, &s->change);
wt_status_print_dirty_header(s, has_deleted); d = it->util;
if (!d) {
d = xcalloc(1, sizeof(*d));
it->util = d;
}
if (!d->index_status)
d->index_status = p->status;
switch (p->status) {
case DIFF_STATUS_COPIED:
case DIFF_STATUS_RENAMED:
d->head_path = xstrdup(p->one->path);
break;
}
} }
for (i = 0; i < q->nr; i++)
wt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);
if (q->nr)
wt_status_print_trailer(s);
} }


static void wt_status_print_updated(struct wt_status *s) static void wt_status_collect_changes_worktree(struct wt_status *s)
{ {
struct rev_info rev; struct rev_info rev;

init_revisions(&rev, NULL);
setup_revisions(0, NULL, &rev, NULL);
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = wt_status_collect_changed_cb;
rev.diffopt.format_callback_data = s;
run_diff_files(&rev, 0);
}

static void wt_status_collect_changes_index(struct wt_status *s)
{
struct rev_info rev;

init_revisions(&rev, NULL); init_revisions(&rev, NULL);
setup_revisions(0, NULL, &rev, setup_revisions(0, NULL, &rev,
s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference); s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference);
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = wt_status_print_updated_cb; rev.diffopt.format_callback = wt_status_collect_updated_cb;
rev.diffopt.format_callback_data = s; rev.diffopt.format_callback_data = s;
rev.diffopt.detect_rename = 1; rev.diffopt.detect_rename = 1;
rev.diffopt.rename_limit = 200; rev.diffopt.rename_limit = 200;
rev.diffopt.break_opt = 0; rev.diffopt.break_opt = 0;
run_diff_index(&rev, 1); run_diff_index(&rev, 1);
} }


static void wt_status_collect_changes_initial(struct wt_status *s)
{
int i;

for (i = 0; i < active_nr; i++) {
struct string_list_item *it;
struct wt_status_change_data *d;
struct cache_entry *ce = active_cache[i];

it = string_list_insert(ce->name, &s->change);
d = it->util;
if (!d) {
d = xcalloc(1, sizeof(*d));
it->util = d;
}
if (ce_stage(ce))
d->index_status = DIFF_STATUS_UNMERGED;
else
d->index_status = DIFF_STATUS_ADDED;
}
}

void wt_status_collect_changes(struct wt_status *s)
{
wt_status_collect_changes_worktree(s);

if (s->is_initial)
wt_status_collect_changes_initial(s);
else
wt_status_collect_changes_index(s);
}

static void wt_status_print_updated(struct wt_status *s)
{
int shown_header = 0;
int i;

for (i = 0; i < s->change.nr; i++) {
struct wt_status_change_data *d;
struct string_list_item *it;
it = &(s->change.items[i]);
d = it->util;
if (!d->index_status ||
d->index_status == DIFF_STATUS_UNMERGED)
continue;
if (!shown_header) {
wt_status_print_cached_header(s);
s->commitable = 1;
shown_header = 1;
}
wt_status_print_change_data(s, WT_STATUS_UPDATED, it);
}
if (shown_header)
wt_status_print_trailer(s);
}

/*
* -1 : has delete
* 0 : no change
* 1 : some change but no delete
*/
static int wt_status_check_worktree_changes(struct wt_status *s)
{
int i;
int changes = 0;

for (i = 0; i < s->change.nr; i++) {
struct wt_status_change_data *d;
d = s->change.items[i].util;
if (!d->worktree_status)
continue;
changes = 1;
if (d->worktree_status == DIFF_STATUS_DELETED)
return -1;
}
return changes;
}

static void wt_status_print_changed(struct wt_status *s) static void wt_status_print_changed(struct wt_status *s)
{ {
struct rev_info rev; int i;
init_revisions(&rev, ""); int worktree_changes = wt_status_check_worktree_changes(s);
setup_revisions(0, NULL, &rev, NULL);
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; if (!worktree_changes)
rev.diffopt.format_callback = wt_status_print_changed_cb; return;
rev.diffopt.format_callback_data = s;
run_diff_files(&rev, 0); wt_status_print_dirty_header(s, worktree_changes < 0);

for (i = 0; i < s->change.nr; i++) {
struct wt_status_change_data *d;
struct string_list_item *it;
it = &(s->change.items[i]);
d = it->util;
if (!d->worktree_status)
continue;
wt_status_print_change_data(s, WT_STATUS_CHANGED, it);
}
wt_status_print_trailer(s);
} }


static void wt_status_print_submodule_summary(struct wt_status *s) static void wt_status_print_submodule_summary(struct wt_status *s)
Expand Down Expand Up @@ -337,6 +471,8 @@ void wt_status_print(struct wt_status *s)
wt_status_print_tracking(s); wt_status_print_tracking(s);
} }


wt_status_collect_changes(s);

if (s->is_initial) { if (s->is_initial) {
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#"); color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit"); color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit");
Expand Down
10 changes: 10 additions & 0 deletions wt-status.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define STATUS_H #define STATUS_H


#include <stdio.h> #include <stdio.h>
#include "string-list.h"


enum color_wt_status { enum color_wt_status {
WT_STATUS_HEADER, WT_STATUS_HEADER,
Expand All @@ -18,6 +19,13 @@ enum untracked_status_type {
}; };
extern enum untracked_status_type show_untracked_files; extern enum untracked_status_type show_untracked_files;


struct wt_status_change_data {
int worktree_status;
int index_status;
int stagemask;
char *head_path;
};

struct wt_status { struct wt_status {
int is_initial; int is_initial;
char *branch; char *branch;
Expand All @@ -33,12 +41,14 @@ struct wt_status {
const char *index_file; const char *index_file;
FILE *fp; FILE *fp;
const char *prefix; const char *prefix;
struct string_list change;
}; };


int git_status_config(const char *var, const char *value, void *cb); int git_status_config(const char *var, const char *value, void *cb);
extern int wt_status_use_color; extern int wt_status_use_color;
extern int wt_status_relative_paths; extern int wt_status_relative_paths;
void wt_status_prepare(struct wt_status *s); void wt_status_prepare(struct wt_status *s);
void wt_status_print(struct wt_status *s); void wt_status_print(struct wt_status *s);
void wt_status_collect_changes(struct wt_status *s);


#endif /* STATUS_H */ #endif /* STATUS_H */

0 comments on commit 50b7e70

Please sign in to comment.