From 29796c6ccff3e70622398379fdcdfa3fe43333ac Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 4 Aug 2009 16:25:40 -0700 Subject: [PATCH 01/11] diff-index: report unmerged new entries Since an earlier change to diff-index by d1f2d7e (Make run_diff_index() use unpack_trees(), not read_tree(), 2008-01-19), we stopped reporting an unmerged path that does not exist in the tree, but we should. Signed-off-by: Junio C Hamano --- diff-lib.c | 4 ++-- t/t7060-wtstatus.sh | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100755 t/t7060-wtstatus.sh diff --git a/diff-lib.c b/diff-lib.c index ad2a4cde7..ad5b6cac7 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -348,8 +348,8 @@ static void do_oneway_diff(struct unpack_trees_options *o, match_missing = !revs->ignore_merges; if (cached && idx && ce_stage(idx)) { - if (tree) - diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, idx->sha1); + diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, + idx->sha1); return; } diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh new file mode 100755 index 000000000..5ad2cd1d0 --- /dev/null +++ b/t/t7060-wtstatus.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +test_description='basic work tree status reporting' + +. ./test-lib.sh + +test_expect_success setup ' + test_commit A && + test_commit B oneside added && + git checkout A^0 && + test_commit C oneside created +' + +test_expect_success 'A/A conflict' ' + git checkout B^0 && + test_must_fail git merge C +' + +test_expect_success 'Report path with conflict' ' + git diff --cached --name-status >actual && + echo "U oneside" >expect && + test_cmp expect actual +' + +test_expect_success 'Report new path with conflict' ' + git diff --cached --name-status HEAD^ >actual && + echo "U oneside" >expect && + test_cmp expect actual +' + +test_done From 26da1d78674204c482ec90905dd4de3f6bcd3c5f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 4 Aug 2009 22:08:16 -0700 Subject: [PATCH 02/11] diff-index: keep the original index intact When comparing the index and a tree, we used to read the contents of the tree into stage #1 of the index and compared them with stage #0. In order not to lose sight of entries originally unmerged in the index, we hoisted them to stage #3 before reading the tree. Commit d1f2d7e (Make run_diff_index() use unpack_trees(), not read_tree(), 2008-01-19) changed all this. These days, we instead use unpack_trees() API to traverse the tree and compare the contents with the index, without modifying the index at all. There is no reason to hoist the unmerged entries to stage #3 anymore. Signed-off-by: Junio C Hamano --- diff-lib.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/diff-lib.c b/diff-lib.c index ad5b6cac7..2a82dac10 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -308,22 +308,6 @@ static int show_modified(struct rev_info *revs, return 0; } -/* - * This turns all merge entries into "stage 3". That guarantees that - * when we read in the new tree (into "stage 1"), we won't lose sight - * of the fact that we had unmerged entries. - */ -static void mark_merge_entries(void) -{ - int i; - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - if (!ce_stage(ce)) - continue; - ce->ce_flags |= CE_STAGEMASK; - } -} - /* * This gets a mix of an existing index and a tree, one pathname entry * at a time. The index entry may be a single stage-0 one, but it could @@ -435,8 +419,6 @@ int run_diff_index(struct rev_info *revs, int cached) struct unpack_trees_options opts; struct tree_desc t; - mark_merge_entries(); - ent = revs->pending.objects[0].item; tree_name = revs->pending.objects[0].name; tree = parse_tree_indirect(ent->sha1); From 50b7e70f338e54f3534ee1b14c3bdb4c80d0dcf7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 4 Aug 2009 23:49:33 -0700 Subject: [PATCH 03/11] 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 --- builtin-commit.c | 13 +-- wt-status.c | 226 +++++++++++++++++++++++++++++++++++++---------- wt-status.h | 10 +++ 3 files changed, 199 insertions(+), 50 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 4bcce06fb..6d12c2e8b 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -217,12 +217,15 @@ static void create_base_index(void) 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; struct string_list partial; const char **pathspec = NULL; + int refresh_flags = REFRESH_QUIET; + if (is_status) + refresh_flags |= REFRESH_UNMERGED; if (interactive) { if (interactive_add(argc, argv, prefix) != 0) die("interactive add failed"); @@ -253,7 +256,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) if (all || (also && pathspec && *pathspec)) { int fd = hold_locked_index(&index_lock, 1); 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) || close_lock_file(&index_lock)) die("unable to write new_index file"); @@ -272,7 +275,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) */ if (!pathspec || !*pathspec) { fd = hold_locked_index(&index_lock, 1); - refresh_cache(REFRESH_QUIET); + refresh_cache(refresh_flags); if (write_cache(fd, active_cache, active_nr) || commit_locked_index(&index_lock)) die("unable to write new_index file"); @@ -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); - index_file = prepare_index(argc, argv, prefix); + index_file = prepare_index(argc, argv, prefix, 1); commitable = run_status(stdout, index_file, prefix, 0); @@ -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); - 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 running hooks, writing the trees, and interacting with the user. */ diff --git a/wt-status.c b/wt-status.c index 47735d812..9aab56775 100644 --- a/wt-status.c +++ b/wt-status.c @@ -56,6 +56,7 @@ void wt_status_prepare(struct wt_status *s) s->reference = "HEAD"; s->fp = stdout; s->index_file = get_index_file(); + s->change.strdup_strings = 1; } 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) #define quote_path quote_path_relative -static void wt_status_print_filepair(struct wt_status *s, - int t, struct diff_filepair *p) +static void wt_status_print_change_data(struct wt_status *s, + 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; struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT; - one = quote_path(p->one->path, -1, &onebuf, s->prefix); - two = quote_path(p->two->path, -1, &twobuf, s->prefix); + one_name = two_name = it->string; + 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"); - switch (p->status) { + switch (status) { case DIFF_STATUS_ADDED: color_fprintf(s->fp, c, "new file: %s", one); break; @@ -135,64 +153,91 @@ static void wt_status_print_filepair(struct wt_status *s, color_fprintf(s->fp, c, "unmerged: %s", one); break; default: - die("bug: unhandled diff status %c", p->status); + die("bug: unhandled diff status %c", status); } fprintf(s->fp, "\n"); strbuf_release(&onebuf); strbuf_release(&twobuf); } -static void wt_status_print_updated_cb(struct diff_queue_struct *q, - struct diff_options *options, - void *data) +static void wt_status_collect_changed_cb(struct diff_queue_struct *q, + struct diff_options *options, + void *data) { struct wt_status *s = data; - int shown_header = 0; int i; + + if (!q->nr) + return; + s->workdir_dirty = 1; for (i = 0; i < q->nr; i++) { - if (q->queue[i]->status == 'U') - continue; - if (!shown_header) { - wt_status_print_cached_header(s); - s->commitable = 1; - shown_header = 1; + struct diff_filepair *p; + struct string_list_item *it; + struct wt_status_change_data *d; + + p = q->queue[i]; + 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, - struct diff_options *options, - void *data) +static void wt_status_collect_updated_cb(struct diff_queue_struct *q, + struct diff_options *options, + void *data) { struct wt_status *s = data; int i; - if (q->nr) { - int has_deleted = 0; - s->workdir_dirty = 1; - for (i = 0; i < q->nr; i++) - if (q->queue[i]->status == DIFF_STATUS_DELETED) { - has_deleted = 1; - break; - } - wt_status_print_dirty_header(s, has_deleted); + + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p; + struct string_list_item *it; + struct wt_status_change_data *d; + + p = q->queue[i]; + it = string_list_insert(p->two->path, &s->change); + 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; + + 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); setup_revisions(0, NULL, &rev, s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference); 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.detect_rename = 1; rev.diffopt.rename_limit = 200; @@ -200,15 +245,104 @@ static void wt_status_print_updated(struct wt_status *s) 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) { - struct rev_info rev; - init_revisions(&rev, ""); - setup_revisions(0, NULL, &rev, NULL); - rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; - rev.diffopt.format_callback = wt_status_print_changed_cb; - rev.diffopt.format_callback_data = s; - run_diff_files(&rev, 0); + int i; + int worktree_changes = wt_status_check_worktree_changes(s); + + if (!worktree_changes) + return; + + 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) @@ -337,6 +471,8 @@ void wt_status_print(struct wt_status *s) wt_status_print_tracking(s); } + wt_status_collect_changes(s); + if (s->is_initial) { color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#"); color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit"); diff --git a/wt-status.h b/wt-status.h index 78add09bd..82a602b3b 100644 --- a/wt-status.h +++ b/wt-status.h @@ -2,6 +2,7 @@ #define STATUS_H #include +#include "string-list.h" enum color_wt_status { WT_STATUS_HEADER, @@ -18,6 +19,13 @@ enum untracked_status_type { }; 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 { int is_initial; char *branch; @@ -33,6 +41,7 @@ struct wt_status { const char *index_file; FILE *fp; const char *prefix; + struct string_list change; }; int git_status_config(const char *var, const char *value, void *cb); @@ -40,5 +49,6 @@ extern int wt_status_use_color; extern int wt_status_relative_paths; void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s); +void wt_status_collect_changes(struct wt_status *s); #endif /* STATUS_H */ From 4d4d5726aee31522e90df21ef62ee3377c5d8f8d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 5 Aug 2009 00:04:51 -0700 Subject: [PATCH 04/11] status: show worktree status of conflicted paths separately When a path is unmerged in the index, we used to always say "unmerged" in the "Changed but not updated" section, even when the path was deleted in the work tree. Remove unmerged entries from the "Updated" section, and create a new section "Unmerged paths". Describe how the different stages conflict in more detail in this new section. Note that with the current 3-way merge policy (with or without recursive), certain combinations of index stages should never happen. For example, having only stage #2 means that a path that did not exist in the common ancestor was added by us while the other branch did not do anything to it, which would have autoresolved to take our addition. The code nevertheless prepares for the possibility that future merge policies may leave a path in such a state. Signed-off-by: Junio C Hamano --- t/t7060-wtstatus.sh | 27 +++++++++++++ wt-status.c | 95 +++++++++++++++++++++++++++++++++++++++++++-- wt-status.h | 1 + 3 files changed, 120 insertions(+), 3 deletions(-) diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index 5ad2cd1d0..1044aa654 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -28,4 +28,31 @@ test_expect_success 'Report new path with conflict' ' test_cmp expect actual ' +cat >expect <..." to unstage) +# (use "git add ..." to mark resolution) +# +# deleted by us: foo +# +no changes added to commit (use "git add" and/or "git commit -a") +EOF + +test_expect_success 'M/D conflict does not segfault' ' + mkdir mdconflict && + ( + cd mdconflict && + git init && + test_commit initial foo "" && + test_commit modify foo foo && + git checkout -b side HEAD^ && + git rm foo && + git commit -m delete && + test_must_fail git merge master && + test_must_fail git status > ../actual + ) && + test_cmp expect actual +' + test_done diff --git a/wt-status.c b/wt-status.c index 9aab56775..97fedfaa1 100644 --- a/wt-status.c +++ b/wt-status.c @@ -20,6 +20,7 @@ static char wt_status_colors[][COLOR_MAXLEN] = { GIT_COLOR_RED, /* WT_STATUS_CHANGED */ GIT_COLOR_RED, /* WT_STATUS_UNTRACKED */ GIT_COLOR_RED, /* WT_STATUS_NOBRANCH */ + GIT_COLOR_RED, /* WT_STATUS_UNMERGED */ }; enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; @@ -37,6 +38,8 @@ static int parse_status_slot(const char *var, int offset) return WT_STATUS_UNTRACKED; if (!strcasecmp(var+offset, "nobranch")) return WT_STATUS_NOBRANCH; + if (!strcasecmp(var+offset, "unmerged")) + return WT_STATUS_UNMERGED; die("bad config variable '%s'", var); } @@ -59,6 +62,18 @@ void wt_status_prepare(struct wt_status *s) s->change.strdup_strings = 1; } +static void wt_status_print_unmerged_header(struct wt_status *s) +{ + const char *c = color(WT_STATUS_HEADER); + color_fprintf_ln(s->fp, c, "# Unmerged paths:"); + if (!s->is_initial) + color_fprintf_ln(s->fp, c, "# (use \"git reset %s ...\" to unstage)", s->reference); + else + color_fprintf_ln(s->fp, c, "# (use \"git rm --cached ...\" to unstage)"); + color_fprintf_ln(s->fp, c, "# (use \"git add ...\" to mark resolution)"); + color_fprintf_ln(s->fp, c, "#"); +} + static void wt_status_print_cached_header(struct wt_status *s) { const char *c = color(WT_STATUS_HEADER); @@ -99,6 +114,29 @@ static void wt_status_print_trailer(struct wt_status *s) #define quote_path quote_path_relative +static void wt_status_print_unmerged_data(struct wt_status *s, + struct string_list_item *it) +{ + const char *c = color(WT_STATUS_UNMERGED); + struct wt_status_change_data *d = it->util; + struct strbuf onebuf = STRBUF_INIT; + const char *one, *how = "bug"; + + one = quote_path(it->string, -1, &onebuf, s->prefix); + color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t"); + switch (d->stagemask) { + case 1: how = "both deleted:"; break; + case 2: how = "added by us:"; break; + case 3: how = "deleted by them:"; break; + case 4: how = "added by them:"; break; + case 5: how = "deleted by us:"; break; + case 6: how = "both added:"; break; + case 7: how = "both modified:"; break; + } + color_fprintf(s->fp, c, "%-20s%s\n", how, one); + strbuf_release(&onebuf); +} + static void wt_status_print_change_data(struct wt_status *s, int change_type, struct string_list_item *it) @@ -187,6 +225,26 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q, } } +static int unmerged_mask(const char *path) +{ + int pos, mask; + struct cache_entry *ce; + + pos = cache_name_pos(path, strlen(path)); + if (0 <= pos) + return 0; + + mask = 0; + pos = -pos-1; + while (pos < active_nr) { + ce = active_cache[pos++]; + if (strcmp(ce->name, path) || !ce_stage(ce)) + break; + mask |= (1 << (ce_stage(ce) - 1)); + } + return mask; +} + static void wt_status_collect_updated_cb(struct diff_queue_struct *q, struct diff_options *options, void *data) @@ -213,6 +271,9 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q, case DIFF_STATUS_RENAMED: d->head_path = xstrdup(p->one->path); break; + case DIFF_STATUS_UNMERGED: + d->stagemask = unmerged_mask(p->two->path); + break; } } } @@ -260,8 +321,10 @@ static void wt_status_collect_changes_initial(struct wt_status *s) d = xcalloc(1, sizeof(*d)); it->util = d; } - if (ce_stage(ce)) + if (ce_stage(ce)) { d->index_status = DIFF_STATUS_UNMERGED; + d->stagemask |= (1 << (ce_stage(ce) - 1)); + } else d->index_status = DIFF_STATUS_ADDED; } @@ -277,6 +340,29 @@ void wt_status_collect_changes(struct wt_status *s) wt_status_collect_changes_index(s); } +static void wt_status_print_unmerged(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->stagemask) + continue; + if (!shown_header) { + wt_status_print_unmerged_header(s); + shown_header = 1; + } + wt_status_print_unmerged_data(s, it); + } + if (shown_header) + wt_status_print_trailer(s); + +} + static void wt_status_print_updated(struct wt_status *s) { int shown_header = 0; @@ -314,7 +400,8 @@ static int wt_status_check_worktree_changes(struct wt_status *s) for (i = 0; i < s->change.nr; i++) { struct wt_status_change_data *d; d = s->change.items[i].util; - if (!d->worktree_status) + if (!d->worktree_status || + d->worktree_status == DIFF_STATUS_UNMERGED) continue; changes = 1; if (d->worktree_status == DIFF_STATUS_DELETED) @@ -338,7 +425,8 @@ static void wt_status_print_changed(struct wt_status *s) struct string_list_item *it; it = &(s->change.items[i]); d = it->util; - if (!d->worktree_status) + if (!d->worktree_status || + d->worktree_status == DIFF_STATUS_UNMERGED) continue; wt_status_print_change_data(s, WT_STATUS_CHANGED, it); } @@ -479,6 +567,7 @@ void wt_status_print(struct wt_status *s) color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#"); } + wt_status_print_unmerged(s); wt_status_print_updated(s); wt_status_print_changed(s); if (wt_status_submodule_summary) diff --git a/wt-status.h b/wt-status.h index 82a602b3b..f80142ffd 100644 --- a/wt-status.h +++ b/wt-status.h @@ -10,6 +10,7 @@ enum color_wt_status { WT_STATUS_CHANGED, WT_STATUS_UNTRACKED, WT_STATUS_NOBRANCH, + WT_STATUS_UNMERGED, }; enum untracked_status_type { From 3a5d13a3c32e0f39d8fc83330255fac27af5d853 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 7 Aug 2009 23:03:36 -0700 Subject: [PATCH 05/11] commit: --dry-run This teaches --dry-run option to "git commit". It is the same as "git status", but in the longer term we would want to change the semantics of "git status" not to be the preview of commit, and this is the first step for doing so. Signed-off-by: Junio C Hamano --- Documentation/git-commit.txt | 7 ++++++- builtin-commit.c | 29 ++++++++++++++++------------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index b5d81be7e..d01ff5ada 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -8,7 +8,7 @@ git-commit - Record changes to the repository SYNOPSIS -------- [verse] -'git commit' [-a | --interactive] [-s] [-v] [-u] [--amend] +'git commit' [-a | --interactive] [-s] [-v] [-u] [--amend] [--dry-run] [(-c | -C) ] [-F | -m ] [--allow-empty] [--no-verify] [-e] [--author=] [--cleanup=] [--] [[-i | -o ]...] @@ -198,6 +198,11 @@ specified. --quiet:: Suppress commit summary message. +--dry-run:: + Do not create a commit, but show a list of paths that are + to be committed, paths with local changes that will be left + uncommitted and paths that are untracked. + \--:: Do not interpret any more arguments as options. diff --git a/builtin-commit.c b/builtin-commit.c index 6d12c2e8b..3a7e35d60 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -51,7 +51,7 @@ static const char *template_file; static char *edit_message, *use_message; static char *author_name, *author_email, *author_date; static int all, edit_flag, also, interactive, only, amend, signoff; -static int quiet, verbose, no_verify, allow_empty; +static int quiet, verbose, no_verify, allow_empty, dry_run; static char *untracked_files_arg; /* * The default commit message cleanup mode will remove the lines @@ -103,6 +103,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"), OPT_BOOLEAN('o', "only", &only, "commit only specified files"), OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), + OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"), @@ -813,28 +814,28 @@ static int parse_and_validate_options(int argc, const char *argv[], return argc; } -int cmd_status(int argc, const char **argv, const char *prefix) +static int dry_run_commit(int argc, const char **argv, const char *prefix) { - const char *index_file; int commitable; + const char *index_file; - git_config(git_status_config, NULL); + index_file = prepare_index(argc, argv, prefix, 1); + commitable = run_status(stdout, index_file, prefix, 0); + rollback_index_files(); + return commitable ? 0 : 1; +} + +int cmd_status(int argc, const char **argv, const char *prefix) +{ + git_config(git_status_config, NULL); if (wt_status_use_color == -1) wt_status_use_color = git_use_color_default; - if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix); - - index_file = prepare_index(argc, argv, prefix, 1); - - commitable = run_status(stdout, index_file, prefix, 0); - - rollback_index_files(); - - return commitable ? 0 : 1; + return dry_run_commit(argc, argv, prefix); } static void print_summary(const char *prefix, const unsigned char *sha1) @@ -909,6 +910,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) wt_status_use_color = git_use_color_default; argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix); + if (dry_run) + return dry_run_commit(argc, argv, prefix); index_file = prepare_index(argc, argv, prefix, 0); From d249b098893809c6de6e5e20063a22ac2c629ce7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 9 Aug 2009 21:59:30 -0700 Subject: [PATCH 06/11] wt-status: move many global settings to wt_status structure Turn four global variables (wt_status_use_color, show_tracked_files, wt_status_relative_paths, and wt_status_submodule_summary) into fields of wt_status structure. They can also lose "wt_status_" prefix. Get rid of "untracked" field that was used only to keep track of otherwise available information redundantly. Signed-off-by: Junio C Hamano --- builtin-commit.c | 87 ++++++++++++++++++++++++++---------------------- wt-status.c | 81 ++++++++++++++++++++++---------------------- wt-status.h | 9 ++--- 3 files changed, 93 insertions(+), 84 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 3a7e35d60..716eec832 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -343,27 +343,24 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int return false_lock.filename; } -static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn) +static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn, + struct wt_status *s) { - struct wt_status s; - - wt_status_prepare(&s); - if (wt_status_relative_paths) - s.prefix = prefix; + if (s->relative_paths) + s->prefix = prefix; if (amend) { - s.amend = 1; - s.reference = "HEAD^1"; + s->amend = 1; + s->reference = "HEAD^1"; } - s.verbose = verbose; - s.untracked = (show_untracked_files == SHOW_ALL_UNTRACKED_FILES); - s.index_file = index_file; - s.fp = fp; - s.nowarn = nowarn; + s->verbose = verbose; + s->index_file = index_file; + s->fp = fp; + s->nowarn = nowarn; - wt_status_print(&s); + wt_status_print(s); - return s.commitable; + return s->commitable; } static int is_a_merge(const unsigned char *sha1) @@ -417,7 +414,8 @@ static void determine_author_info(void) author_date = date; } -static int prepare_to_commit(const char *index_file, const char *prefix) +static int prepare_to_commit(const char *index_file, const char *prefix, + struct wt_status *s) { struct stat statbuf; int commitable, saved_color_setting; @@ -559,10 +557,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix) if (ident_shown) fprintf(fp, "#\n"); - saved_color_setting = wt_status_use_color; - wt_status_use_color = 0; - commitable = run_status(fp, index_file, prefix, 1); - wt_status_use_color = saved_color_setting; + saved_color_setting = s->use_color; + s->use_color = 0; + commitable = run_status(fp, index_file, prefix, 1, s); + s->use_color = saved_color_setting; } else { unsigned char sha1[20]; const char *parent = "HEAD"; @@ -583,7 +581,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix) if (!commitable && !in_merge && !allow_empty && !(amend && is_a_merge(head_sha1))) { - run_status(stdout, index_file, prefix, 0); + run_status(stdout, index_file, prefix, 0, s); return 0; } @@ -695,7 +693,8 @@ static const char *find_author_by_nickname(const char *name) static int parse_and_validate_options(int argc, const char *argv[], const char * const usage[], - const char *prefix) + const char *prefix, + struct wt_status *s) { int f = 0; @@ -798,11 +797,11 @@ static int parse_and_validate_options(int argc, const char *argv[], if (!untracked_files_arg) ; /* default already initialized */ else if (!strcmp(untracked_files_arg, "no")) - show_untracked_files = SHOW_NO_UNTRACKED_FILES; + s->show_untracked_files = SHOW_NO_UNTRACKED_FILES; else if (!strcmp(untracked_files_arg, "normal")) - show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; + s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; else if (!strcmp(untracked_files_arg, "all")) - show_untracked_files = SHOW_ALL_UNTRACKED_FILES; + s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; else die("Invalid untracked files mode '%s'", untracked_files_arg); @@ -814,13 +813,14 @@ static int parse_and_validate_options(int argc, const char *argv[], return argc; } -static int dry_run_commit(int argc, const char **argv, const char *prefix) +static int dry_run_commit(int argc, const char **argv, const char *prefix, + struct wt_status *s) { int commitable; const char *index_file; index_file = prepare_index(argc, argv, prefix, 1); - commitable = run_status(stdout, index_file, prefix, 0); + commitable = run_status(stdout, index_file, prefix, 0, s); rollback_index_files(); return commitable ? 0 : 1; @@ -828,14 +828,18 @@ static int dry_run_commit(int argc, const char **argv, const char *prefix) int cmd_status(int argc, const char **argv, const char *prefix) { - git_config(git_status_config, NULL); - if (wt_status_use_color == -1) - wt_status_use_color = git_use_color_default; + struct wt_status s; + + wt_status_prepare(&s); + git_config(git_status_config, &s); + if (s.use_color == -1) + s.use_color = git_use_color_default; if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; - argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix); - return dry_run_commit(argc, argv, prefix); + argc = parse_and_validate_options(argc, argv, builtin_status_usage, + prefix, &s); + return dry_run_commit(argc, argv, prefix, &s); } static void print_summary(const char *prefix, const unsigned char *sha1) @@ -887,10 +891,12 @@ static void print_summary(const char *prefix, const unsigned char *sha1) static int git_commit_config(const char *k, const char *v, void *cb) { + struct wt_status *s = cb; + if (!strcmp(k, "commit.template")) return git_config_string(&template_file, k, v); - return git_status_config(k, v, cb); + return git_status_config(k, v, s); } int cmd_commit(int argc, const char **argv, const char *prefix) @@ -903,21 +909,24 @@ int cmd_commit(int argc, const char **argv, const char *prefix) struct commit_list *parents = NULL, **pptr = &parents; struct stat statbuf; int allow_fast_forward = 1; + struct wt_status s; - git_config(git_commit_config, NULL); + wt_status_prepare(&s); + git_config(git_commit_config, &s); - if (wt_status_use_color == -1) - wt_status_use_color = git_use_color_default; + if (s.use_color == -1) + s.use_color = git_use_color_default; - argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix); + argc = parse_and_validate_options(argc, argv, builtin_commit_usage, + prefix, &s); if (dry_run) - return dry_run_commit(argc, argv, prefix); + return dry_run_commit(argc, argv, prefix, &s); index_file = prepare_index(argc, argv, prefix, 0); /* Set up everything for writing the commit object. This includes running hooks, writing the trees, and interacting with the user. */ - if (!prepare_to_commit(index_file, prefix)) { + if (!prepare_to_commit(index_file, prefix, &s)) { rollback_index_files(); return 1; } diff --git a/wt-status.c b/wt-status.c index 97fedfaa1..af93bb52d 100644 --- a/wt-status.c +++ b/wt-status.c @@ -11,9 +11,6 @@ #include "run-command.h" #include "remote.h" -int wt_status_relative_paths = 1; -int wt_status_use_color = -1; -static int wt_status_submodule_summary; static char wt_status_colors[][COLOR_MAXLEN] = { GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */ GIT_COLOR_GREEN, /* WT_STATUS_UPDATED */ @@ -23,8 +20,6 @@ static char wt_status_colors[][COLOR_MAXLEN] = { GIT_COLOR_RED, /* WT_STATUS_UNMERGED */ }; -enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; - static int parse_status_slot(const char *var, int offset) { if (!strcasecmp(var+offset, "header")) @@ -43,9 +38,9 @@ static int parse_status_slot(const char *var, int offset) die("bad config variable '%s'", var); } -static const char *color(int slot) +static const char *color(int slot, struct wt_status *s) { - return wt_status_use_color > 0 ? wt_status_colors[slot] : ""; + return s->use_color > 0 ? wt_status_colors[slot] : ""; } void wt_status_prepare(struct wt_status *s) @@ -54,6 +49,9 @@ void wt_status_prepare(struct wt_status *s) const char *head; memset(s, 0, sizeof(*s)); + s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; + s->use_color = -1; + s->relative_paths = 1; head = resolve_ref("HEAD", sha1, 0, NULL); s->branch = head ? xstrdup(head) : NULL; s->reference = "HEAD"; @@ -64,7 +62,7 @@ void wt_status_prepare(struct wt_status *s) static void wt_status_print_unmerged_header(struct wt_status *s) { - const char *c = color(WT_STATUS_HEADER); + const char *c = color(WT_STATUS_HEADER, s); color_fprintf_ln(s->fp, c, "# Unmerged paths:"); if (!s->is_initial) color_fprintf_ln(s->fp, c, "# (use \"git reset %s ...\" to unstage)", s->reference); @@ -76,7 +74,7 @@ static void wt_status_print_unmerged_header(struct wt_status *s) static void wt_status_print_cached_header(struct wt_status *s) { - const char *c = color(WT_STATUS_HEADER); + const char *c = color(WT_STATUS_HEADER, s); color_fprintf_ln(s->fp, c, "# Changes to be committed:"); if (!s->is_initial) { color_fprintf_ln(s->fp, c, "# (use \"git reset %s ...\" to unstage)", s->reference); @@ -89,7 +87,7 @@ static void wt_status_print_cached_header(struct wt_status *s) static void wt_status_print_dirty_header(struct wt_status *s, int has_deleted) { - const char *c = color(WT_STATUS_HEADER); + const char *c = color(WT_STATUS_HEADER, s); color_fprintf_ln(s->fp, c, "# Changed but not updated:"); if (!has_deleted) color_fprintf_ln(s->fp, c, "# (use \"git add ...\" to update what will be committed)"); @@ -101,7 +99,7 @@ static void wt_status_print_dirty_header(struct wt_status *s, static void wt_status_print_untracked_header(struct wt_status *s) { - const char *c = color(WT_STATUS_HEADER); + const char *c = color(WT_STATUS_HEADER, s); color_fprintf_ln(s->fp, c, "# Untracked files:"); color_fprintf_ln(s->fp, c, "# (use \"git add ...\" to include in what will be committed)"); color_fprintf_ln(s->fp, c, "#"); @@ -109,7 +107,7 @@ static void wt_status_print_untracked_header(struct wt_status *s) static void wt_status_print_trailer(struct wt_status *s) { - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#"); + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); } #define quote_path quote_path_relative @@ -117,13 +115,13 @@ static void wt_status_print_trailer(struct wt_status *s) static void wt_status_print_unmerged_data(struct wt_status *s, struct string_list_item *it) { - const char *c = color(WT_STATUS_UNMERGED); + const char *c = color(WT_STATUS_UNMERGED, s); struct wt_status_change_data *d = it->util; struct strbuf onebuf = STRBUF_INIT; const char *one, *how = "bug"; one = quote_path(it->string, -1, &onebuf, s->prefix); - color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t"); + color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t"); switch (d->stagemask) { case 1: how = "both deleted:"; break; case 2: how = "added by us:"; break; @@ -142,7 +140,7 @@ static void wt_status_print_change_data(struct wt_status *s, struct string_list_item *it) { struct wt_status_change_data *d = it->util; - const char *c = color(change_type); + const char *c = color(change_type, s); int status = status; char *one_name; char *two_name; @@ -164,7 +162,7 @@ static void wt_status_print_change_data(struct wt_status *s, 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, s), "#\t"); switch (status) { case DIFF_STATUS_ADDED: color_fprintf(s->fp, c, "new file: %s", one); @@ -450,7 +448,7 @@ static void wt_status_print_submodule_summary(struct wt_status *s) NULL }; - sprintf(summary_limit, "%d", wt_status_submodule_summary); + sprintf(summary_limit, "%d", s->submodule_summary); snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file); memset(&sm_summary, 0, sizeof(sm_summary)); @@ -471,8 +469,7 @@ static void wt_status_print_untracked(struct wt_status *s) struct strbuf buf = STRBUF_INIT; memset(&dir, 0, sizeof(dir)); - - if (!s->untracked) + if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES) dir.flags |= DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; setup_standard_excludes(&dir); @@ -487,8 +484,8 @@ static void wt_status_print_untracked(struct wt_status *s) wt_status_print_untracked_header(s); shown_header = 1; } - color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t"); - color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%s", + color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t"); + color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED, s), "%s", quote_path(ent->name, ent->len, &buf, s->prefix)); } @@ -532,15 +529,15 @@ static void wt_status_print_tracking(struct wt_status *s) return; for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1) - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# %.*s", (int)(ep - cp), cp); - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#"); + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); } void wt_status_print(struct wt_status *s) { unsigned char sha1[20]; - const char *branch_color = color(WT_STATUS_HEADER); + const char *branch_color = color(WT_STATUS_HEADER, s); s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0; if (s->branch) { @@ -550,10 +547,10 @@ void wt_status_print(struct wt_status *s) branch_name += 11; else if (!strcmp(branch_name, "HEAD")) { branch_name = ""; - branch_color = color(WT_STATUS_NOBRANCH); + branch_color = color(WT_STATUS_NOBRANCH, s); on_what = "Not currently on any branch."; } - color_fprintf(s->fp, color(WT_STATUS_HEADER), "# "); + color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "# "); color_fprintf_ln(s->fp, branch_color, "%s%s", on_what, branch_name); if (!s->is_initial) wt_status_print_tracking(s); @@ -562,17 +559,17 @@ void wt_status_print(struct wt_status *s) wt_status_collect_changes(s); if (s->is_initial) { - 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), "#"); + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# Initial commit"); + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); } wt_status_print_unmerged(s); wt_status_print_updated(s); wt_status_print_changed(s); - if (wt_status_submodule_summary) + if (s->submodule_summary) wt_status_print_submodule_summary(s); - if (show_untracked_files) + if (s->show_untracked_files) wt_status_print_untracked(s); else if (s->commitable) fprintf(s->fp, "# Untracked files not listed (use -u option to show untracked files)\n"); @@ -590,7 +587,7 @@ void wt_status_print(struct wt_status *s) printf("nothing added to commit but untracked files present (use \"git add\" to track)\n"); else if (s->is_initial) printf("nothing to commit (create/copy files and use \"git add\" to track)\n"); - else if (!show_untracked_files) + else if (!s->show_untracked_files) printf("nothing to commit (use -u to show untracked files)\n"); else printf("nothing to commit (working directory clean)\n"); @@ -599,15 +596,17 @@ void wt_status_print(struct wt_status *s) int git_status_config(const char *k, const char *v, void *cb) { + struct wt_status *s = cb; + if (!strcmp(k, "status.submodulesummary")) { int is_bool; - wt_status_submodule_summary = git_config_bool_or_int(k, v, &is_bool); - if (is_bool && wt_status_submodule_summary) - wt_status_submodule_summary = -1; + s->submodule_summary = git_config_bool_or_int(k, v, &is_bool); + if (is_bool && s->submodule_summary) + s->submodule_summary = -1; return 0; } if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) { - wt_status_use_color = git_config_colorbool(k, v, -1); + s->use_color = git_config_colorbool(k, v, -1); return 0; } if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) { @@ -618,21 +617,21 @@ int git_status_config(const char *k, const char *v, void *cb) return 0; } if (!strcmp(k, "status.relativepaths")) { - wt_status_relative_paths = git_config_bool(k, v); + s->relative_paths = git_config_bool(k, v); return 0; } if (!strcmp(k, "status.showuntrackedfiles")) { if (!v) return config_error_nonbool(k); else if (!strcmp(v, "no")) - show_untracked_files = SHOW_NO_UNTRACKED_FILES; + s->show_untracked_files = SHOW_NO_UNTRACKED_FILES; else if (!strcmp(v, "normal")) - show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; + s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; else if (!strcmp(v, "all")) - show_untracked_files = SHOW_ALL_UNTRACKED_FILES; + s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; else return error("Invalid untracked files mode '%s'", v); return 0; } - return git_diff_ui_config(k, v, cb); + return git_diff_ui_config(k, v, NULL); } diff --git a/wt-status.h b/wt-status.h index f80142ffd..cd06a4d95 100644 --- a/wt-status.h +++ b/wt-status.h @@ -18,7 +18,6 @@ enum untracked_status_type { SHOW_NORMAL_UNTRACKED_FILES, SHOW_ALL_UNTRACKED_FILES }; -extern enum untracked_status_type show_untracked_files; struct wt_status_change_data { int worktree_status; @@ -33,8 +32,12 @@ struct wt_status { const char *reference; int verbose; int amend; - int untracked; int nowarn; + int use_color; + int relative_paths; + int submodule_summary; + enum untracked_status_type show_untracked_files; + /* These are computed during processing of the individual sections */ int commitable; int workdir_dirty; @@ -46,8 +49,6 @@ struct wt_status { }; int git_status_config(const char *var, const char *value, void *cb); -extern int wt_status_use_color; -extern int wt_status_relative_paths; void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s); void wt_status_collect_changes(struct wt_status *s); From 23900a964608bbfda6989a0a2cd4342f19f9194c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 9 Aug 2009 23:08:40 -0700 Subject: [PATCH 07/11] wt-status: move wt_status_colors[] into wt_status structure The benefit of this one alone is somewhat iffy, but for completeness this moves the wt_status_colors[] color palette to the wt_status structure to complete the libification started by the previous commit. Signed-off-by: Junio C Hamano --- wt-status.c | 9 +++++---- wt-status.h | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/wt-status.c b/wt-status.c index af93bb52d..cfbaf309a 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1,6 +1,5 @@ #include "cache.h" #include "wt-status.h" -#include "color.h" #include "object.h" #include "dir.h" #include "commit.h" @@ -11,7 +10,7 @@ #include "run-command.h" #include "remote.h" -static char wt_status_colors[][COLOR_MAXLEN] = { +static char default_wt_status_colors[][COLOR_MAXLEN] = { GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */ GIT_COLOR_GREEN, /* WT_STATUS_UPDATED */ GIT_COLOR_RED, /* WT_STATUS_CHANGED */ @@ -40,7 +39,7 @@ static int parse_status_slot(const char *var, int offset) static const char *color(int slot, struct wt_status *s) { - return s->use_color > 0 ? wt_status_colors[slot] : ""; + return s->use_color > 0 ? s->color_palette[slot] : ""; } void wt_status_prepare(struct wt_status *s) @@ -49,6 +48,8 @@ void wt_status_prepare(struct wt_status *s) const char *head; memset(s, 0, sizeof(*s)); + memcpy(s->color_palette, default_wt_status_colors, + sizeof(default_wt_status_colors)); s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; s->use_color = -1; s->relative_paths = 1; @@ -613,7 +614,7 @@ int git_status_config(const char *k, const char *v, void *cb) int slot = parse_status_slot(k, 13); if (!v) return config_error_nonbool(k); - color_parse(v, k, wt_status_colors[slot]); + color_parse(v, k, s->color_palette[slot]); return 0; } if (!strcmp(k, "status.relativepaths")) { diff --git a/wt-status.h b/wt-status.h index cd06a4d95..0297fabdc 100644 --- a/wt-status.h +++ b/wt-status.h @@ -3,9 +3,10 @@ #include #include "string-list.h" +#include "color.h" enum color_wt_status { - WT_STATUS_HEADER, + WT_STATUS_HEADER = 0, WT_STATUS_UPDATED, WT_STATUS_CHANGED, WT_STATUS_UNTRACKED, @@ -37,6 +38,7 @@ struct wt_status { int relative_paths; int submodule_summary; enum untracked_status_type show_untracked_files; + char color_palette[WT_STATUS_UNMERGED+1][COLOR_MAXLEN]; /* These are computed during processing of the individual sections */ int commitable; From f766b36783c7ceeb0427f5e1af862b9a67ae1c4c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 9 Aug 2009 23:12:19 -0700 Subject: [PATCH 08/11] Make git_status_config() file scope static to builtin-commit.c Signed-off-by: Junio C Hamano --- builtin-commit.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ wt-status.c | 60 ------------------------------------------------ wt-status.h | 1 - 3 files changed, 60 insertions(+), 61 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 716eec832..1c200eb96 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -826,6 +826,66 @@ static int dry_run_commit(int argc, const char **argv, const char *prefix, return commitable ? 0 : 1; } +static int parse_status_slot(const char *var, int offset) +{ + if (!strcasecmp(var+offset, "header")) + return WT_STATUS_HEADER; + if (!strcasecmp(var+offset, "updated") + || !strcasecmp(var+offset, "added")) + return WT_STATUS_UPDATED; + if (!strcasecmp(var+offset, "changed")) + return WT_STATUS_CHANGED; + if (!strcasecmp(var+offset, "untracked")) + return WT_STATUS_UNTRACKED; + if (!strcasecmp(var+offset, "nobranch")) + return WT_STATUS_NOBRANCH; + if (!strcasecmp(var+offset, "unmerged")) + return WT_STATUS_UNMERGED; + die("bad config variable '%s'", var); +} + +static int git_status_config(const char *k, const char *v, void *cb) +{ + struct wt_status *s = cb; + + if (!strcmp(k, "status.submodulesummary")) { + int is_bool; + s->submodule_summary = git_config_bool_or_int(k, v, &is_bool); + if (is_bool && s->submodule_summary) + s->submodule_summary = -1; + return 0; + } + if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) { + s->use_color = git_config_colorbool(k, v, -1); + return 0; + } + if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) { + int slot = parse_status_slot(k, 13); + if (!v) + return config_error_nonbool(k); + color_parse(v, k, s->color_palette[slot]); + return 0; + } + if (!strcmp(k, "status.relativepaths")) { + s->relative_paths = git_config_bool(k, v); + return 0; + } + if (!strcmp(k, "status.showuntrackedfiles")) { + if (!v) + return config_error_nonbool(k); + else if (!strcmp(v, "no")) + s->show_untracked_files = SHOW_NO_UNTRACKED_FILES; + else if (!strcmp(v, "normal")) + s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; + else if (!strcmp(v, "all")) + s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; + else + return error("Invalid untracked files mode '%s'", v); + return 0; + } + return git_diff_ui_config(k, v, NULL); +} + int cmd_status(int argc, const char **argv, const char *prefix) { struct wt_status s; diff --git a/wt-status.c b/wt-status.c index cfbaf309a..4cbe03a70 100644 --- a/wt-status.c +++ b/wt-status.c @@ -19,24 +19,6 @@ static char default_wt_status_colors[][COLOR_MAXLEN] = { GIT_COLOR_RED, /* WT_STATUS_UNMERGED */ }; -static int parse_status_slot(const char *var, int offset) -{ - if (!strcasecmp(var+offset, "header")) - return WT_STATUS_HEADER; - if (!strcasecmp(var+offset, "updated") - || !strcasecmp(var+offset, "added")) - return WT_STATUS_UPDATED; - if (!strcasecmp(var+offset, "changed")) - return WT_STATUS_CHANGED; - if (!strcasecmp(var+offset, "untracked")) - return WT_STATUS_UNTRACKED; - if (!strcasecmp(var+offset, "nobranch")) - return WT_STATUS_NOBRANCH; - if (!strcasecmp(var+offset, "unmerged")) - return WT_STATUS_UNMERGED; - die("bad config variable '%s'", var); -} - static const char *color(int slot, struct wt_status *s) { return s->use_color > 0 ? s->color_palette[slot] : ""; @@ -594,45 +576,3 @@ void wt_status_print(struct wt_status *s) printf("nothing to commit (working directory clean)\n"); } } - -int git_status_config(const char *k, const char *v, void *cb) -{ - struct wt_status *s = cb; - - if (!strcmp(k, "status.submodulesummary")) { - int is_bool; - s->submodule_summary = git_config_bool_or_int(k, v, &is_bool); - if (is_bool && s->submodule_summary) - s->submodule_summary = -1; - return 0; - } - if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) { - s->use_color = git_config_colorbool(k, v, -1); - return 0; - } - if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) { - int slot = parse_status_slot(k, 13); - if (!v) - return config_error_nonbool(k); - color_parse(v, k, s->color_palette[slot]); - return 0; - } - if (!strcmp(k, "status.relativepaths")) { - s->relative_paths = git_config_bool(k, v); - return 0; - } - if (!strcmp(k, "status.showuntrackedfiles")) { - if (!v) - return config_error_nonbool(k); - else if (!strcmp(v, "no")) - s->show_untracked_files = SHOW_NO_UNTRACKED_FILES; - else if (!strcmp(v, "normal")) - s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; - else if (!strcmp(v, "all")) - s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; - else - return error("Invalid untracked files mode '%s'", v); - return 0; - } - return git_diff_ui_config(k, v, NULL); -} diff --git a/wt-status.h b/wt-status.h index 0297fabdc..95f5af890 100644 --- a/wt-status.h +++ b/wt-status.h @@ -50,7 +50,6 @@ struct wt_status { struct string_list change; }; -int git_status_config(const char *var, const char *value, void *cb); void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s); void wt_status_collect_changes(struct wt_status *s); From 7637868362ab64fe22521c645006ba70c4ef83a9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 10 Aug 2009 00:36:33 -0700 Subject: [PATCH 09/11] wt-status: collect untracked files in a separate "collect" phase In a way similar to updated and locally modified files are collected. Signed-off-by: Junio C Hamano --- wt-status.c | 58 +++++++++++++++++++++++++++++++++-------------------- wt-status.h | 3 ++- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/wt-status.c b/wt-status.c index 4cbe03a70..63598ce40 100644 --- a/wt-status.c +++ b/wt-status.c @@ -41,6 +41,7 @@ void wt_status_prepare(struct wt_status *s) s->fp = stdout; s->index_file = get_index_file(); s->change.strdup_strings = 1; + s->untracked.strdup_strings = 1; } static void wt_status_print_unmerged_header(struct wt_status *s) @@ -311,7 +312,30 @@ static void wt_status_collect_changes_initial(struct wt_status *s) } } -void wt_status_collect_changes(struct wt_status *s) +static void wt_status_collect_untracked(struct wt_status *s) +{ + int i; + struct dir_struct dir; + + if (!s->show_untracked_files) + return; + memset(&dir, 0, sizeof(dir)); + if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES) + dir.flags |= + DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; + setup_standard_excludes(&dir); + + fill_directory(&dir, NULL); + for(i = 0; i < dir.nr; i++) { + struct dir_entry *ent = dir.entries[i]; + if (!cache_name_is_other(ent->name, ent->len)) + continue; + s->workdir_untracked = 1; + string_list_insert(ent->name, &s->untracked); + } +} + +void wt_status_collect(struct wt_status *s) { wt_status_collect_changes_worktree(s); @@ -319,6 +343,7 @@ void wt_status_collect_changes(struct wt_status *s) wt_status_collect_changes_initial(s); else wt_status_collect_changes_index(s); + wt_status_collect_untracked(s); } static void wt_status_print_unmerged(struct wt_status *s) @@ -446,31 +471,20 @@ static void wt_status_print_submodule_summary(struct wt_status *s) static void wt_status_print_untracked(struct wt_status *s) { - struct dir_struct dir; int i; - int shown_header = 0; struct strbuf buf = STRBUF_INIT; - memset(&dir, 0, sizeof(dir)); - if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES) - dir.flags |= - DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; - setup_standard_excludes(&dir); + if (!s->untracked.nr) + return; - fill_directory(&dir, NULL); - for(i = 0; i < dir.nr; i++) { - struct dir_entry *ent = dir.entries[i]; - if (!cache_name_is_other(ent->name, ent->len)) - continue; - if (!shown_header) { - s->workdir_untracked = 1; - wt_status_print_untracked_header(s); - shown_header = 1; - } + wt_status_print_untracked_header(s); + for (i = 0; i < s->untracked.nr; i++) { + struct string_list_item *it; + it = &(s->untracked.items[i]); color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t"); color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED, s), "%s", - quote_path(ent->name, ent->len, - &buf, s->prefix)); + quote_path(it->string, strlen(it->string), + &buf, s->prefix)); } strbuf_release(&buf); } @@ -539,7 +553,7 @@ void wt_status_print(struct wt_status *s) wt_status_print_tracking(s); } - wt_status_collect_changes(s); + wt_status_collect(s); if (s->is_initial) { color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); @@ -566,7 +580,7 @@ void wt_status_print(struct wt_status *s) ; /* nothing */ else if (s->workdir_dirty) printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"); - else if (s->workdir_untracked) + else if (s->untracked.nr) printf("nothing added to commit but untracked files present (use \"git add\" to track)\n"); else if (s->is_initial) printf("nothing to commit (create/copy files and use \"git add\" to track)\n"); diff --git a/wt-status.h b/wt-status.h index 95f5af890..a0e75177b 100644 --- a/wt-status.h +++ b/wt-status.h @@ -48,10 +48,11 @@ struct wt_status { FILE *fp; const char *prefix; struct string_list change; + struct string_list untracked; }; void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s); -void wt_status_collect_changes(struct wt_status *s); +void wt_status_collect(struct wt_status *s); #endif /* STATUS_H */ From 60c2993c92fa1aa7f4d4aab7de6d8769052ced6f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 15 Aug 2009 01:58:37 -0700 Subject: [PATCH 10/11] Documentation/git-commit.txt: describe --dry-run Signed-off-by: Junio C Hamano --- Documentation/git-commit.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index d01ff5ada..64f94cfe1 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'git commit' [-a | --interactive] [-s] [-v] [-u] [--amend] [--dry-run] - [(-c | -C) ] [-F | -m ] + [(-c | -C) ] [-F | -m ] [--dry-run] [--allow-empty] [--no-verify] [-e] [--author=] [--cleanup=] [--] [[-i | -o ]...] @@ -42,10 +42,9 @@ The content to be added can be specified in several ways: by one which files should be part of the commit, before finalizing the operation. Currently, this is done by invoking 'git-add --interactive'. -The 'git-status' command can be used to obtain a +The `--dry-run` option can be used to obtain a summary of what is included by any of the above for the next -commit by giving the same set of parameters you would give to -this command. +commit by giving the same set of parameters (options and paths). If you make a commit and then find a mistake immediately after that, you can recover from it with 'git-reset'. @@ -70,6 +69,12 @@ OPTIONS Like '-C', but with '-c' the editor is invoked, so that the user can further edit the commit message. +--dry-run:: + Do not actually make a commit, but show the list of paths + with updates in the index, paths with changes in the work tree, + and paths that are untracked, similar to the one that is given + in the commit log editor. + -F :: --file=:: Take the commit message from the given file. Use '-' to From 3fa509dfbdb8526453f4213f79b371bdfa493f0e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 15 Aug 2009 02:14:14 -0700 Subject: [PATCH 11/11] git commit --dry-run -v: show diff in color when asked The earlier implementation of --dry-run didn't duplicate the use of color "git status -v" set up for diff output. Signed-off-by: Junio C Hamano --- builtin-commit.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/builtin-commit.c b/builtin-commit.c index 1c200eb96..200ffdaad 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -979,9 +979,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix) argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix, &s); - if (dry_run) + if (dry_run) { + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; return dry_run_commit(argc, argv, prefix, &s); - + } index_file = prepare_index(argc, argv, prefix, 0); /* Set up everything for writing the commit object. This includes