Merge branch 'js/libify-require-clean-work-tree'
authorJunio C Hamano <gitster@pobox.com>
Wed, 26 Oct 2016 20:14:44 +0000 (13:14 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 26 Oct 2016 20:14:44 +0000 (13:14 -0700)
The require_clean_work_tree() helper was recreated in C when "git
pull" was rewritten from shell; the helper is now made available to
other callers in preparation for upcoming "rebase -i" work.

* js/libify-require-clean-work-tree:
wt-status: begin error messages with lower-case
wt-status: teach has_{unstaged,uncommitted}_changes() about submodules
wt-status: export also the has_un{staged,committed}_changes() functions
wt-status: make the require_clean_work_tree() function reusable
pull: make code more similar to the shell script again
pull: drop confusing prefix parameter of die_on_unclean_work_tree()

1  2 
wt-status.c
diff --combined wt-status.c
index ca5c45f94522f5487e3a93438cbccf8aecb65d5d,7dbd1e1c926b96a94cb74bd8fbbaa2171b10743f..0bd2781225a2a9fa3e7a553aaf49112745743244
@@@ -16,6 -16,7 +16,7 @@@
  #include "strbuf.h"
  #include "utf8.h"
  #include "worktree.h"
+ #include "lockfile.h"
  
  static const char cut_line[] =
  "------------------------ >8 ------------------------\n";
@@@ -367,11 -368,11 +368,11 @@@ static void wt_longstatus_print_change_
                if (d->new_submodule_commits || d->dirty_submodule) {
                        strbuf_addstr(&extra, " (");
                        if (d->new_submodule_commits)
 -                              strbuf_addf(&extra, _("new commits, "));
 +                              strbuf_addstr(&extra, _("new commits, "));
                        if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
 -                              strbuf_addf(&extra, _("modified content, "));
 +                              strbuf_addstr(&extra, _("modified content, "));
                        if (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
 -                              strbuf_addf(&extra, _("untracked content, "));
 +                              strbuf_addstr(&extra, _("untracked content, "));
                        strbuf_setlen(&extra, extra.len - 2);
                        strbuf_addch(&extra, ')');
                }
@@@ -623,7 -624,7 +624,7 @@@ static void wt_status_collect_changes_i
                        d->index_status = DIFF_STATUS_ADDED;
                        /* Leave {mode,oid}_head zero for adds. */
                        d->mode_index = ce->ce_mode;
 -                      hashcpy(d->oid_index.hash, ce->sha1);
 +                      hashcpy(d->oid_index.hash, ce->oid.hash);
                }
        }
  }
@@@ -1110,6 -1111,7 +1111,6 @@@ static void abbrev_sha1_in_line(struct 
        split = strbuf_split_max(line, ' ', 3);
        if (split[0] && split[1]) {
                unsigned char sha1[20];
 -              const char *abbrev;
  
                /*
                 * strbuf_split_max left a space. Trim it and re-add
                 */
                strbuf_trim(split[1]);
                if (!get_sha1(split[1]->buf, sha1)) {
 -                      abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
                        strbuf_reset(split[1]);
 -                      strbuf_addf(split[1], "%s ", abbrev);
 +                      strbuf_add_unique_abbrev(split[1], sha1,
 +                                               DEFAULT_ABBREV);
 +                      strbuf_addch(split[1], ' ');
                        strbuf_reset(line);
                        for (i = 0; split[i]; i++)
                                strbuf_addbuf(line, split[i]);
@@@ -1343,8 -1344,10 +1344,8 @@@ static char *get_branch(const struct wo
        else if (starts_with(sb.buf, "refs/"))
                ;
        else if (!get_sha1_hex(sb.buf, sha1)) {
 -              const char *abbrev;
 -              abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
                strbuf_reset(&sb);
 -              strbuf_addstr(&sb, abbrev);
 +              strbuf_add_unique_abbrev(&sb, sha1, DEFAULT_ABBREV);
        } else if (!strcmp(sb.buf, "detached HEAD")) /* rebase */
                goto got_nothing;
        else                    /* bisect */
@@@ -1381,7 -1384,8 +1382,7 @@@ static int grab_1st_switch(unsigned cha
        if (!strcmp(cb->buf.buf, "HEAD")) {
                /* HEAD is relative. Resolve it to the right reflog entry. */
                strbuf_reset(&cb->buf);
 -              strbuf_addstr(&cb->buf,
 -                            find_unique_abbrev(nsha1, DEFAULT_ABBREV));
 +              strbuf_add_unique_abbrev(&cb->buf, nsha1, DEFAULT_ABBREV);
        }
        return 1;
  }
@@@ -2090,7 -2094,7 +2091,7 @@@ static void wt_porcelain_v2_print_unmer
                if (strcmp(ce->name, it->string) || !stage)
                        break;
                stages[stage - 1].mode = ce->ce_mode;
 -              hashcpy(stages[stage - 1].oid.hash, ce->sha1);
 +              hashcpy(stages[stage - 1].oid.hash, ce->oid.hash);
                sum |= (1 << (stage - 1));
        }
        if (sum != d->stagemask)
@@@ -2206,3 -2210,80 +2207,80 @@@ void wt_status_print(struct wt_status *
                break;
        }
  }
+ /**
+  * Returns 1 if there are unstaged changes, 0 otherwise.
+  */
+ int has_unstaged_changes(int ignore_submodules)
+ {
+       struct rev_info rev_info;
+       int result;
+       init_revisions(&rev_info, NULL);
+       if (ignore_submodules)
+               DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
+       DIFF_OPT_SET(&rev_info.diffopt, QUICK);
+       diff_setup_done(&rev_info.diffopt);
+       result = run_diff_files(&rev_info, 0);
+       return diff_result_code(&rev_info.diffopt, result);
+ }
+ /**
+  * Returns 1 if there are uncommitted changes, 0 otherwise.
+  */
+ int has_uncommitted_changes(int ignore_submodules)
+ {
+       struct rev_info rev_info;
+       int result;
+       if (is_cache_unborn())
+               return 0;
+       init_revisions(&rev_info, NULL);
+       if (ignore_submodules)
+               DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
+       DIFF_OPT_SET(&rev_info.diffopt, QUICK);
+       add_head_to_pending(&rev_info);
+       diff_setup_done(&rev_info.diffopt);
+       result = run_diff_index(&rev_info, 1);
+       return diff_result_code(&rev_info.diffopt, result);
+ }
+ /**
+  * If the work tree has unstaged or uncommitted changes, dies with the
+  * appropriate message.
+  */
+ int require_clean_work_tree(const char *action, const char *hint, int ignore_submodules, int gently)
+ {
+       struct lock_file *lock_file = xcalloc(1, sizeof(*lock_file));
+       int err = 0;
+       hold_locked_index(lock_file, 0);
+       refresh_cache(REFRESH_QUIET);
+       update_index_if_able(&the_index, lock_file);
+       rollback_lock_file(lock_file);
+       if (has_unstaged_changes(ignore_submodules)) {
+               /* TRANSLATORS: the action is e.g. "pull with rebase" */
+               error(_("cannot %s: You have unstaged changes."), _(action));
+               err = 1;
+       }
+       if (has_uncommitted_changes(ignore_submodules)) {
+               if (err)
+                       error(_("additionally, your index contains uncommitted changes."));
+               else
+                       error(_("cannot %s: Your index contains uncommitted changes."),
+                             _(action));
+               err = 1;
+       }
+       if (err) {
+               if (hint)
+                       error("%s", hint);
+               if (!gently)
+                       exit(128);
+       }
+       return err;
+ }