Merge branch 'ss/wt-status-committable'
authorJunio C Hamano <gitster@pobox.com>
Fri, 19 Oct 2018 04:34:02 +0000 (13:34 +0900)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Oct 2018 04:34:02 +0000 (13:34 +0900)
Code clean-up in the internal machinery used by "git status" and
"git commit --dry-run".

* ss/wt-status-committable:
  roll wt_status_state into wt_status and populate in the collect phase
  wt-status.c: set the committable flag in the collect phase
  t7501: add test of "commit --dry-run --short"
  wt-status: rename commitable to committable
  wt-status.c: move has_unmerged earlier in the file

1  2 
builtin/commit.c
t/t7501-commit.sh
wt-status.c

diff --combined builtin/commit.c
@@@ -33,8 -33,6 +33,8 @@@
  #include "sequencer.h"
  #include "mailmap.h"
  #include "help.h"
 +#include "commit-reach.h"
 +#include "commit-graph.h"
  
  static const char * const builtin_commit_usage[] = {
        N_("git commit [<options>] [--] <pathspec>..."),
@@@ -508,8 -506,9 +508,9 @@@ static int run_status(FILE *fp, const c
  
        wt_status_collect(s);
        wt_status_print(s);
+       wt_status_collect_free_buffers(s);
  
-       return s->commitable;
+       return s->committable;
  }
  
  static int is_a_merge(const struct commit *current_head)
@@@ -655,7 -654,7 +656,7 @@@ static int prepare_to_commit(const cha
  {
        struct stat statbuf;
        struct strbuf committer_ident = STRBUF_INIT;
-       int commitable;
+       int committable;
        struct strbuf sb = STRBUF_INIT;
        const char *hook_arg1 = NULL;
        const char *hook_arg2 = NULL;
  
                saved_color_setting = s->use_color;
                s->use_color = 0;
-               commitable = run_status(s->fp, index_file, prefix, 1, s);
+               committable = run_status(s->fp, index_file, prefix, 1, s);
                s->use_color = saved_color_setting;
 +              string_list_clear(&s->change, 1);
        } else {
                struct object_id oid;
                const char *parent = "HEAD";
                        for (i = 0; i < active_nr; i++)
                                if (ce_intent_to_add(active_cache[i]))
                                        ita_nr++;
-                       commitable = active_nr - ita_nr > 0;
+                       committable = active_nr - ita_nr > 0;
                } else {
                        /*
                         * Unless the user did explicitly request a submodule
                        if (ignore_submodule_arg &&
                            !strcmp(ignore_submodule_arg, "all"))
                                flags.ignore_submodules = 1;
-                       commitable = index_differs_from(parent, &flags, 1);
+                       committable = index_differs_from(parent, &flags, 1);
                }
        }
        strbuf_release(&committer_ident);
         * explicit --allow-empty. In the cherry-pick case, it may be
         * empty due to conflict resolution, which the user should okay.
         */
-       if (!commitable && whence != FROM_MERGE && !allow_empty &&
+       if (!committable && whence != FROM_MERGE && !allow_empty &&
            !(amend && is_a_merge(current_head))) {
                s->display_comment_prefix = old_display_comment_prefix;
                run_status(stdout, index_file, prefix, 0, s);
@@@ -983,7 -981,7 +984,7 @@@ static const char *find_author_by_nickn
        const char *av[20];
        int ac = 0;
  
 -      init_revisions(&revs, NULL);
 +      repo_init_revisions(the_repository, &revs, NULL);
        strbuf_addf(&buf, "--author=%s", name);
        av[++ac] = "--all";
        av[++ac] = "-i";
@@@ -1189,14 -1187,14 +1190,14 @@@ static int parse_and_validate_options(i
  static int dry_run_commit(int argc, const char **argv, const char *prefix,
                          const struct commit *current_head, struct wt_status *s)
  {
-       int commitable;
+       int committable;
        const char *index_file;
  
        index_file = prepare_index(argc, argv, prefix, current_head, 1);
-       commitable = run_status(stdout, index_file, prefix, 0, s);
+       committable = run_status(stdout, index_file, prefix, 0, s);
        rollback_index_files();
  
-       return commitable ? 0 : 1;
+       return committable ? 0 : 1;
  }
  
  define_list_config_array_extra(color_status_slots, {"added"});
@@@ -1391,6 -1389,8 +1392,8 @@@ int cmd_status(int argc, const char **a
                s.prefix = prefix;
  
        wt_status_print(&s);
+       wt_status_collect_free_buffers(&s);
        return 0;
  }
  
@@@ -1654,10 -1654,7 +1657,10 @@@ int cmd_commit(int argc, const char **a
                      "new_index file. Check that disk is not full and quota is\n"
                      "not exceeded, and then \"git reset HEAD\" to recover."));
  
 -      rerere(0);
 +      if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))
 +              write_commit_graph_reachable(get_object_directory(), 0, 0);
 +
 +      repo_rerere(the_repository, 0);
        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
        run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
        if (amend && !no_post_rewrite) {
diff --combined t/t7501-commit.sh
@@@ -99,12 -99,12 +99,12 @@@ test_expect_success '--dry-run with stu
        git commit -m next -a --dry-run
  '
  
- test_expect_failure '--short with stuff to commit returns ok' '
+ test_expect_success '--short with stuff to commit returns ok' '
        echo bongo bongo bongo >>file &&
        git commit -m next -a --short
  '
  
- test_expect_failure '--porcelain with stuff to commit returns ok' '
+ test_expect_success '--porcelain with stuff to commit returns ok' '
        echo bongo bongo bongo >>file &&
        git commit -m next -a --porcelain
  '
@@@ -517,22 -517,6 +517,22 @@@ Myfooter: x" &
        test_cmp expected actual
  '
  
 +test_expect_success 'signoff not confused by ---' '
 +      cat >expected <<-EOF &&
 +              subject
 +
 +              body
 +              ---
 +              these dashes confuse the parser!
 +
 +              Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
 +      EOF
 +      # should be a noop, since we already signed
 +      git commit --allow-empty --signoff -F expected &&
 +      git log -1 --pretty=format:%B >actual &&
 +      test_cmp expected actual
 +'
 +
  test_expect_success 'multiple -m' '
  
        >negative &&
@@@ -698,4 -682,10 +698,10 @@@ test_expect_success '--dry-run with con
        git commit -m "conflicts fixed from merge."
  '
  
+ test_expect_success '--dry-run --short' '
+       >test-file &&
+       git add test-file &&
+       git commit --dry-run --short
+ '
  test_done
diff --combined wt-status.c
@@@ -453,8 -453,8 +453,8 @@@ static void wt_status_collect_changed_c
                        d->worktree_status = p->status;
                if (S_ISGITLINK(p->two->mode)) {
                        d->dirty_submodule = p->two->dirty_submodule;
 -                      d->new_submodule_commits = !!oidcmp(&p->one->oid,
 -                                                          &p->two->oid);
 +                      d->new_submodule_commits = !oideq(&p->one->oid,
 +                                                        &p->two->oid);
                        if (s->status_format == STATUS_FORMAT_SHORT)
                                d->worktree_status = short_submodule_status(d);
                }
@@@ -540,10 -540,12 +540,12 @@@ static void wt_status_collect_updated_c
                        /* Leave {mode,oid}_head zero for an add. */
                        d->mode_index = p->two->mode;
                        oidcpy(&d->oid_index, &p->two->oid);
+                       s->committable = 1;
                        break;
                case DIFF_STATUS_DELETED:
                        d->mode_head = p->one->mode;
                        oidcpy(&d->oid_head, &p->one->oid);
+                       s->committable = 1;
                        /* Leave {mode,oid}_index zero for a delete. */
                        break;
  
                        d->mode_index = p->two->mode;
                        oidcpy(&d->oid_head, &p->one->oid);
                        oidcpy(&d->oid_index, &p->two->oid);
+                       s->committable = 1;
                        break;
                case DIFF_STATUS_UNMERGED:
                        d->stagemask = unmerged_mask(p->two->path);
@@@ -582,7 -585,7 +585,7 @@@ static void wt_status_collect_changes_w
  {
        struct rev_info rev;
  
 -      init_revisions(&rev, NULL);
 +      repo_init_revisions(the_repository, &rev, NULL);
        setup_revisions(0, NULL, &rev, NULL);
        rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
        rev.diffopt.flags.dirty_submodules = 1;
@@@ -607,7 -610,7 +610,7 @@@ static void wt_status_collect_changes_i
        struct rev_info rev;
        struct setup_revision_opt opt;
  
 -      init_revisions(&rev, NULL);
 +      repo_init_revisions(the_repository, &rev, NULL);
        memset(&opt, 0, sizeof(opt));
        opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference;
        setup_revisions(0, NULL, &rev, &opt);
@@@ -665,11 -668,13 +668,13 @@@ static void wt_status_collect_changes_i
                         * code will output the stage values directly and not use the
                         * values in these fields.
                         */
+                       s->committable = 1;
                } else {
                        d->index_status = DIFF_STATUS_ADDED;
                        /* Leave {mode,oid}_head zero for adds. */
                        d->mode_index = ce->ce_mode;
                        oidcpy(&d->oid_index, &ce->oid);
+                       s->committable = 1;
                }
        }
  }
@@@ -724,15 -729,38 +729,38 @@@ static void wt_status_collect_untracked
                s->untracked_in_ms = (getnanotime() - t_begin) / 1000000;
  }
  
+ static int has_unmerged(struct wt_status *s)
+ {
+       int i;
+       for (i = 0; i < s->change.nr; i++) {
+               struct wt_status_change_data *d;
+               d = s->change.items[i].util;
+               if (d->stagemask)
+                       return 1;
+       }
+       return 0;
+ }
  void wt_status_collect(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);
        wt_status_collect_untracked(s);
+       wt_status_get_state(&s->state, s->branch && !strcmp(s->branch, "HEAD"));
+       if (s->state.merge_in_progress && !has_unmerged(s))
+               s->committable = 1;
+ }
+ void wt_status_collect_free_buffers(struct wt_status *s)
+ {
+       free(s->state.branch);
+       free(s->state.onto);
+       free(s->state.detached_from);
  }
  
  static void wt_longstatus_print_unmerged(struct wt_status *s)
@@@ -773,7 -801,6 +801,6 @@@ static void wt_longstatus_print_updated
                        continue;
                if (!shown_header) {
                        wt_longstatus_print_cached_header(s);
-                       s->commitable = 1;
                        shown_header = 1;
                }
                wt_longstatus_print_change_data(s, WT_STATUS_UPDATED, it);
@@@ -982,7 -1009,7 +1009,7 @@@ static void wt_longstatus_print_verbose
        int dirty_submodules;
        const char *c = color(WT_STATUS_HEADER, s);
  
 -      init_revisions(&rev, NULL);
 +      repo_init_revisions(the_repository, &rev, NULL);
        rev.diffopt.flags.allow_textconv = 1;
        rev.diffopt.ita_invisible_in_index = 1;
  
                rev.diffopt.use_color = 0;
                wt_status_add_cut_line(s->fp);
        }
-       if (s->verbose > 1 && s->commitable) {
+       if (s->verbose > 1 && s->committable) {
                /* print_updated() printed a header, so do we */
                if (s->fp != stdout)
                        wt_longstatus_print_trailer(s);
@@@ -1063,22 -1090,8 +1090,8 @@@ static void wt_longstatus_print_trackin
        strbuf_release(&sb);
  }
  
- static int has_unmerged(struct wt_status *s)
- {
-       int i;
-       for (i = 0; i < s->change.nr; i++) {
-               struct wt_status_change_data *d;
-               d = s->change.items[i].util;
-               if (d->stagemask)
-                       return 1;
-       }
-       return 0;
- }
  static void show_merge_in_progress(struct wt_status *s,
-                               struct wt_status_state *state,
-                               const char *color)
+                                  const char *color)
  {
        if (has_unmerged(s)) {
                status_printf_ln(s, color, _("You have unmerged paths."));
                                         _("  (use \"git merge --abort\" to abort the merge)"));
                }
        } else {
-               s-> commitable = 1;
                status_printf_ln(s, color,
                        _("All conflicts fixed but you are still merging."));
                if (s->hints)
  }
  
  static void show_am_in_progress(struct wt_status *s,
-                               struct wt_status_state *state,
                                const char *color)
  {
        status_printf_ln(s, color,
                _("You are in the middle of an am session."));
-       if (state->am_empty_patch)
+       if (s->state.am_empty_patch)
                status_printf_ln(s, color,
                        _("The current patch is empty."));
        if (s->hints) {
-               if (!state->am_empty_patch)
+               if (!s->state.am_empty_patch)
                        status_printf_ln(s, color,
                                _("  (fix conflicts and then run \"git am --continue\")"));
                status_printf_ln(s, color,
@@@ -1233,10 -1244,9 +1244,9 @@@ static int read_rebase_todolist(const c
  }
  
  static void show_rebase_information(struct wt_status *s,
-                                       struct wt_status_state *state,
-                                       const char *color)
+                                   const char *color)
  {
-       if (state->rebase_interactive_in_progress) {
+       if (s->state.rebase_interactive_in_progress) {
                int i;
                int nr_lines_to_show = 2;
  
  }
  
  static void print_rebase_state(struct wt_status *s,
-                               struct wt_status_state *state,
-                               const char *color)
+                              const char *color)
  {
-       if (state->branch)
+       if (s->state.branch)
                status_printf_ln(s, color,
                                 _("You are currently rebasing branch '%s' on '%s'."),
-                                state->branch,
-                                state->onto);
+                                s->state.branch,
+                                s->state.onto);
        else
                status_printf_ln(s, color,
                                 _("You are currently rebasing."));
  }
  
  static void show_rebase_in_progress(struct wt_status *s,
-                               struct wt_status_state *state,
-                               const char *color)
+                                   const char *color)
  {
        struct stat st;
  
-       show_rebase_information(s, state, color);
+       show_rebase_information(s, color);
        if (has_unmerged(s)) {
-               print_rebase_state(s, state, color);
+               print_rebase_state(s, color);
                if (s->hints) {
                        status_printf_ln(s, color,
                                _("  (fix conflicts and then run \"git rebase --continue\")"));
                        status_printf_ln(s, color,
                                _("  (use \"git rebase --abort\" to check out the original branch)"));
                }
-       } else if (state->rebase_in_progress || !stat(git_path_merge_msg(the_repository), &st)) {
-               print_rebase_state(s, state, color);
+       } else if (s->state.rebase_in_progress ||
+                  !stat(git_path_merge_msg(the_repository), &st)) {
+               print_rebase_state(s, color);
                if (s->hints)
                        status_printf_ln(s, color,
                                _("  (all conflicts fixed: run \"git rebase --continue\")"));
        } else if (split_commit_in_progress(s)) {
-               if (state->branch)
+               if (s->state.branch)
                        status_printf_ln(s, color,
                                         _("You are currently splitting a commit while rebasing branch '%s' on '%s'."),
-                                        state->branch,
-                                        state->onto);
+                                        s->state.branch,
+                                        s->state.onto);
                else
                        status_printf_ln(s, color,
                                         _("You are currently splitting a commit during a rebase."));
                        status_printf_ln(s, color,
                                _("  (Once your working directory is clean, run \"git rebase --continue\")"));
        } else {
-               if (state->branch)
+               if (s->state.branch)
                        status_printf_ln(s, color,
                                         _("You are currently editing a commit while rebasing branch '%s' on '%s'."),
-                                        state->branch,
-                                        state->onto);
+                                        s->state.branch,
+                                        s->state.onto);
                else
                        status_printf_ln(s, color,
                                         _("You are currently editing a commit during a rebase."));
  }
  
  static void show_cherry_pick_in_progress(struct wt_status *s,
-                                       struct wt_status_state *state,
-                                       const char *color)
+                                        const char *color)
  {
        status_printf_ln(s, color, _("You are currently cherry-picking commit %s."),
-                       find_unique_abbrev(&state->cherry_pick_head_oid, DEFAULT_ABBREV));
+                       find_unique_abbrev(&s->state.cherry_pick_head_oid, DEFAULT_ABBREV));
        if (s->hints) {
                if (has_unmerged(s))
                        status_printf_ln(s, color,
  }
  
  static void show_revert_in_progress(struct wt_status *s,
-                                       struct wt_status_state *state,
-                                       const char *color)
+                                   const char *color)
  {
        status_printf_ln(s, color, _("You are currently reverting commit %s."),
-                        find_unique_abbrev(&state->revert_head_oid, DEFAULT_ABBREV));
+                        find_unique_abbrev(&s->state.revert_head_oid, DEFAULT_ABBREV));
        if (s->hints) {
                if (has_unmerged(s))
                        status_printf_ln(s, color,
  }
  
  static void show_bisect_in_progress(struct wt_status *s,
-                               struct wt_status_state *state,
-                               const char *color)
+                                   const char *color)
  {
-       if (state->branch)
+       if (s->state.branch)
                status_printf_ln(s, color,
                                 _("You are currently bisecting, started from branch '%s'."),
-                                state->branch);
+                                s->state.branch);
        else
                status_printf_ln(s, color,
                                 _("You are currently bisecting."));
@@@ -1487,10 -1493,10 +1493,10 @@@ static void wt_status_get_detached_from
  
        if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref) == 1 &&
            /* sha1 is a commit? match without further lookup */
 -          (!oidcmp(&cb.noid, &oid) ||
 +          (oideq(&cb.noid, &oid) ||
             /* perhaps sha1 is a tag, try to dereference to a commit */
             ((commit = lookup_commit_reference_gently(the_repository, &oid, 1)) != NULL &&
 -            !oidcmp(&cb.noid, &commit->object.oid)))) {
 +            oideq(&cb.noid, &commit->object.oid)))) {
                const char *from = ref;
                if (!skip_prefix(from, "refs/tags/", &from))
                        skip_prefix(from, "refs/remotes/", &from);
                        xstrdup(find_unique_abbrev(&cb.noid, DEFAULT_ABBREV));
        oidcpy(&state->detached_oid, &cb.noid);
        state->detached_at = !get_oid("HEAD", &oid) &&
 -                           !oidcmp(&oid, &state->detached_oid);
 +                           oideq(&oid, &state->detached_oid);
  
        free(ref);
        strbuf_release(&cb.buf);
@@@ -1572,48 -1578,45 +1578,45 @@@ void wt_status_get_state(struct wt_stat
                wt_status_get_detached_from(state);
  }
  
- static void wt_longstatus_print_state(struct wt_status *s,
-                                     struct wt_status_state *state)
+ static void wt_longstatus_print_state(struct wt_status *s)
  {
        const char *state_color = color(WT_STATUS_HEADER, s);
+       struct wt_status_state *state = &s->state;
        if (state->merge_in_progress)
-               show_merge_in_progress(s, state, state_color);
+               show_merge_in_progress(s, state_color);
        else if (state->am_in_progress)
-               show_am_in_progress(s, state, state_color);
+               show_am_in_progress(s, state_color);
        else if (state->rebase_in_progress || state->rebase_interactive_in_progress)
-               show_rebase_in_progress(s, state, state_color);
+               show_rebase_in_progress(s, state_color);
        else if (state->cherry_pick_in_progress)
-               show_cherry_pick_in_progress(s, state, state_color);
+               show_cherry_pick_in_progress(s, state_color);
        else if (state->revert_in_progress)
-               show_revert_in_progress(s, state, state_color);
+               show_revert_in_progress(s, state_color);
        if (state->bisect_in_progress)
-               show_bisect_in_progress(s, state, state_color);
+               show_bisect_in_progress(s, state_color);
  }
  
  static void wt_longstatus_print(struct wt_status *s)
  {
        const char *branch_color = color(WT_STATUS_ONBRANCH, s);
        const char *branch_status_color = color(WT_STATUS_HEADER, s);
-       struct wt_status_state state;
-       memset(&state, 0, sizeof(state));
-       wt_status_get_state(&state,
-                           s->branch && !strcmp(s->branch, "HEAD"));
  
        if (s->branch) {
                const char *on_what = _("On branch ");
                const char *branch_name = s->branch;
                if (!strcmp(branch_name, "HEAD")) {
                        branch_status_color = color(WT_STATUS_NOBRANCH, s);
-                       if (state.rebase_in_progress || state.rebase_interactive_in_progress) {
-                               if (state.rebase_interactive_in_progress)
+                       if (s->state.rebase_in_progress ||
+                           s->state.rebase_interactive_in_progress) {
+                               if (s->state.rebase_interactive_in_progress)
                                        on_what = _("interactive rebase in progress; onto ");
                                else
                                        on_what = _("rebase in progress; onto ");
-                               branch_name = state.onto;
-                       } else if (state.detached_from) {
-                               branch_name = state.detached_from;
-                               if (state.detached_at)
+                               branch_name = s->state.onto;
+                       } else if (s->state.detached_from) {
+                               branch_name = s->state.detached_from;
+                               if (s->state.detached_at)
                                        on_what = _("HEAD detached at ");
                                else
                                        on_what = _("HEAD detached from ");
                        wt_longstatus_print_tracking(s);
        }
  
-       wt_longstatus_print_state(s, &state);
-       free(state.branch);
-       free(state.onto);
-       free(state.detached_from);
+       wt_longstatus_print_state(s);
  
        if (s->is_initial) {
                status_printf_ln(s, color(WT_STATUS_HEADER, s), "%s", "");
                                           "new files yourself (see 'git help status')."),
                                         s->untracked_in_ms / 1000.0);
                }
-       } else if (s->commitable)
+       } else if (s->committable)
                status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
                        s->hints
                        ? _(" (use -u option to show untracked files)") : "");
  
        if (s->verbose)
                wt_longstatus_print_verbose(s);
-       if (!s->commitable) {
+       if (!s->committable) {
                if (s->amend)
                        status_printf_ln(s, GIT_COLOR_NORMAL, _("No changes"));
                else if (s->nowarn)
@@@ -1937,13 -1937,9 +1937,9 @@@ static void wt_porcelain_v2_print_track
        struct branch *branch;
        const char *base;
        const char *branch_name;
-       struct wt_status_state state;
        int ab_info, nr_ahead, nr_behind;
        char eol = s->null_termination ? '\0' : '\n';
  
-       memset(&state, 0, sizeof(state));
-       wt_status_get_state(&state, s->branch && !strcmp(s->branch, "HEAD"));
        fprintf(s->fp, "# branch.oid %s%c",
                        (s->is_initial ? "(initial)" : sha1_to_hex(s->sha1_commit)),
                        eol);
                if (!strcmp(s->branch, "HEAD")) {
                        fprintf(s->fp, "# branch.head %s%c", "(detached)", eol);
  
-                       if (state.rebase_in_progress || state.rebase_interactive_in_progress)
-                               branch_name = state.onto;
-                       else if (state.detached_from)
-                               branch_name = state.detached_from;
+                       if (s->state.rebase_in_progress ||
+                           s->state.rebase_interactive_in_progress)
+                               branch_name = s->state.onto;
+                       else if (s->state.detached_from)
+                               branch_name = s->state.detached_from;
                        else
                                branch_name = "";
                } else {
                        }
                }
        }
-       free(state.branch);
-       free(state.onto);
-       free(state.detached_from);
  }
  
  /*
@@@ -2314,7 -2307,7 +2307,7 @@@ int has_unstaged_changes(int ignore_sub
        struct rev_info rev_info;
        int result;
  
 -      init_revisions(&rev_info, NULL);
 +      repo_init_revisions(the_repository, &rev_info, NULL);
        if (ignore_submodules) {
                rev_info.diffopt.flags.ignore_submodules = 1;
                rev_info.diffopt.flags.override_submodule_config = 1;
@@@ -2336,7 -2329,7 +2329,7 @@@ int has_uncommitted_changes(int ignore_
        if (is_cache_unborn())
                return 0;
  
 -      init_revisions(&rev_info, NULL);
 +      repo_init_revisions(the_repository, &rev_info, NULL);
        if (ignore_submodules)
                rev_info.diffopt.flags.ignore_submodules = 1;
        rev_info.diffopt.flags.quick = 1;