From: Junio C Hamano Date: Wed, 26 Oct 2016 20:14:44 +0000 (-0700) Subject: Merge branch 'js/libify-require-clean-work-tree' X-Git-Tag: v2.11.0-rc0~48 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/2bee56be7e241db75774fc6a7a235b8125936943?hp=-c Merge branch 'js/libify-require-clean-work-tree' 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() --- 2bee56be7e241db75774fc6a7a235b8125936943 diff --combined wt-status.c index ca5c45f945,7dbd1e1c92..0bd2781225 --- a/wt-status.c +++ b/wt-status.c @@@ -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 @@@ -1117,10 -1119,9 +1118,10 @@@ */ 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; + }