summaryrefslogtreecommitdiff
path: root/wt-status.c
diff options
context:
space:
mode:
Diffstat (limited to 'wt-status.c')
-rw-r--r--wt-status.c433
1 files changed, 285 insertions, 148 deletions
diff --git a/wt-status.c b/wt-status.c
index a24711374c..42b6735716 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -8,7 +8,7 @@
#include "diffcore.h"
#include "quote.h"
#include "run-command.h"
-#include "argv-array.h"
+#include "strvec.h"
#include "remote.h"
#include "refs.h"
#include "submodule.h"
@@ -17,6 +17,9 @@
#include "utf8.h"
#include "worktree.h"
#include "lockfile.h"
+#include "sequencer.h"
+
+#define AB_DELAY_WARNING_IN_MS (2 * 1000)
static const char cut_line[] =
"------------------------ >8 ------------------------\n";
@@ -119,9 +122,10 @@ static void status_printf_more(struct wt_status *s, const char *color,
va_end(ap);
}
-void wt_status_prepare(struct wt_status *s)
+void wt_status_prepare(struct repository *r, struct wt_status *s)
{
memset(s, 0, sizeof(*s));
+ s->repo = r;
memcpy(s->color_palette, default_wt_status_colors,
sizeof(default_wt_status_colors));
s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
@@ -177,9 +181,15 @@ static void wt_longstatus_print_unmerged_header(struct wt_status *s)
return;
if (s->whence != FROM_COMMIT)
;
- else if (!s->is_initial)
- status_printf_ln(s, c, _(" (use \"git reset %s <file>...\" to unstage)"), s->reference);
- else
+ else if (!s->is_initial) {
+ if (!strcmp(s->reference, "HEAD"))
+ status_printf_ln(s, c,
+ _(" (use \"git restore --staged <file>...\" to unstage)"));
+ else
+ status_printf_ln(s, c,
+ _(" (use \"git restore --source=%s --staged <file>...\" to unstage)"),
+ s->reference);
+ } else
status_printf_ln(s, c, _(" (use \"git rm --cached <file>...\" to unstage)"));
if (!both_deleted) {
@@ -192,7 +202,6 @@ static void wt_longstatus_print_unmerged_header(struct wt_status *s)
} else {
status_printf_ln(s, c, _(" (use \"git add/rm <file>...\" as appropriate to mark resolution)"));
}
- status_printf_ln(s, c, "%s", "");
}
static void wt_longstatus_print_cached_header(struct wt_status *s)
@@ -204,11 +213,16 @@ static void wt_longstatus_print_cached_header(struct wt_status *s)
return;
if (s->whence != FROM_COMMIT)
; /* NEEDSWORK: use "git reset --unresolve"??? */
- else if (!s->is_initial)
- status_printf_ln(s, c, _(" (use \"git reset %s <file>...\" to unstage)"), s->reference);
- else
+ else if (!s->is_initial) {
+ if (!strcmp(s->reference, "HEAD"))
+ status_printf_ln(s, c
+ , _(" (use \"git restore --staged <file>...\" to unstage)"));
+ else
+ status_printf_ln(s, c,
+ _(" (use \"git restore --source=%s --staged <file>...\" to unstage)"),
+ s->reference);
+ } else
status_printf_ln(s, c, _(" (use \"git rm --cached <file>...\" to unstage)"));
- status_printf_ln(s, c, "%s", "");
}
static void wt_longstatus_print_dirty_header(struct wt_status *s,
@@ -224,10 +238,9 @@ static void wt_longstatus_print_dirty_header(struct wt_status *s,
status_printf_ln(s, c, _(" (use \"git add <file>...\" to update what will be committed)"));
else
status_printf_ln(s, c, _(" (use \"git add/rm <file>...\" to update what will be committed)"));
- status_printf_ln(s, c, _(" (use \"git checkout -- <file>...\" to discard changes in working directory)"));
+ status_printf_ln(s, c, _(" (use \"git restore <file>...\" to discard changes in working directory)"));
if (has_dirty_submodules)
status_printf_ln(s, c, _(" (commit or discard the untracked or modified content in submodules)"));
- status_printf_ln(s, c, "%s", "");
}
static void wt_longstatus_print_other_header(struct wt_status *s,
@@ -239,7 +252,6 @@ static void wt_longstatus_print_other_header(struct wt_status *s,
if (!s->hints)
return;
status_printf_ln(s, c, _(" (use \"git %s <file>...\" to include in what will be committed)"), how);
- status_printf_ln(s, c, "%s", "");
}
static void wt_longstatus_print_trailer(struct wt_status *s)
@@ -247,8 +259,6 @@ static void wt_longstatus_print_trailer(struct wt_status *s)
status_printf_ln(s, color(WT_STATUS_HEADER, s), "%s", "");
}
-#define quote_path quote_path_relative
-
static const char *wt_status_unmerged_status_string(int stagemask)
{
switch (stagemask) {
@@ -326,7 +336,7 @@ static void wt_longstatus_print_unmerged_data(struct wt_status *s,
memset(padding, ' ', label_width);
}
- one = quote_path(it->string, s->prefix, &onebuf);
+ one = quote_path(it->string, s->prefix, &onebuf, 0);
status_printf(s, color(WT_STATUS_HEADER, s), "\t");
how = wt_status_unmerged_status_string(d->stagemask);
@@ -392,8 +402,8 @@ static void wt_longstatus_print_change_data(struct wt_status *s,
if (d->rename_status == status)
one_name = d->rename_source;
- one = quote_path(one_name, s->prefix, &onebuf);
- two = quote_path(two_name, s->prefix, &twobuf);
+ one = quote_path(one_name, s->prefix, &onebuf, 0);
+ two = quote_path(two_name, s->prefix, &twobuf, 0);
status_printf(s, color(WT_STATUS_HEADER, s), "\t");
what = wt_status_diff_status_string(status);
@@ -446,7 +456,7 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
it = string_list_insert(&s->change, p->two->path);
d = it->util;
if (!d) {
- d = xcalloc(1, sizeof(*d));
+ CALLOC_ARRAY(d, 1);
it->util = d;
}
if (!d->worktree_status)
@@ -494,19 +504,19 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
}
}
-static int unmerged_mask(const char *path)
+static int unmerged_mask(struct index_state *istate, const char *path)
{
int pos, mask;
const struct cache_entry *ce;
- pos = cache_name_pos(path, strlen(path));
+ pos = index_name_pos(istate, path, strlen(path));
if (0 <= pos)
return 0;
mask = 0;
pos = -pos-1;
- while (pos < active_nr) {
- ce = active_cache[pos++];
+ while (pos < istate->cache_nr) {
+ ce = istate->cache[pos++];
if (strcmp(ce->name, path) || !ce_stage(ce))
break;
mask |= (1 << (ce_stage(ce) - 1));
@@ -530,7 +540,7 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
it = string_list_insert(&s->change, p->two->path);
d = it->util;
if (!d) {
- d = xcalloc(1, sizeof(*d));
+ CALLOC_ARRAY(d, 1);
it->util = d;
}
if (!d->index_status)
@@ -566,7 +576,8 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
s->committable = 1;
break;
case DIFF_STATUS_UNMERGED:
- d->stagemask = unmerged_mask(p->two->path);
+ d->stagemask = unmerged_mask(s->repo->index,
+ p->two->path);
/*
* Don't bother setting {mode,oid}_{head,index} since the print
* code will output the stage values directly and not use the
@@ -585,7 +596,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
{
struct rev_info rev;
- repo_init_revisions(the_repository, &rev, NULL);
+ repo_init_revisions(s->repo, &rev, NULL);
setup_revisions(0, NULL, &rev, NULL);
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
rev.diffopt.flags.dirty_submodules = 1;
@@ -595,7 +606,9 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
if (s->ignore_submodule_arg) {
rev.diffopt.flags.override_submodule_config = 1;
handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);
- }
+ } else if (!rev.diffopt.flags.ignore_submodule_set &&
+ s->show_untracked_files != SHOW_NO_UNTRACKED_FILES)
+ handle_ignore_submodules_arg(&rev.diffopt, "none");
rev.diffopt.format_callback = wt_status_collect_changed_cb;
rev.diffopt.format_callback_data = s;
rev.diffopt.detect_rename = s->detect_rename >= 0 ? s->detect_rename : rev.diffopt.detect_rename;
@@ -603,6 +616,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
rev.diffopt.rename_score = s->rename_score >= 0 ? s->rename_score : rev.diffopt.rename_score;
copy_pathspec(&rev.prune_data, &s->pathspec);
run_diff_files(&rev, 0);
+ clear_pathspec(&rev.prune_data);
}
static void wt_status_collect_changes_index(struct wt_status *s)
@@ -610,7 +624,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)
struct rev_info rev;
struct setup_revision_opt opt;
- repo_init_revisions(the_repository, &rev, NULL);
+ repo_init_revisions(s->repo, &rev, NULL);
memset(&opt, 0, sizeof(opt));
opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference;
setup_revisions(0, NULL, &rev, &opt);
@@ -639,25 +653,28 @@ static void wt_status_collect_changes_index(struct wt_status *s)
rev.diffopt.rename_score = s->rename_score >= 0 ? s->rename_score : rev.diffopt.rename_score;
copy_pathspec(&rev.prune_data, &s->pathspec);
run_diff_index(&rev, 1);
+ object_array_clear(&rev.pending);
+ clear_pathspec(&rev.prune_data);
}
static void wt_status_collect_changes_initial(struct wt_status *s)
{
+ struct index_state *istate = s->repo->index;
int i;
- for (i = 0; i < active_nr; i++) {
+ for (i = 0; i < istate->cache_nr; i++) {
struct string_list_item *it;
struct wt_status_change_data *d;
- const struct cache_entry *ce = active_cache[i];
+ const struct cache_entry *ce = istate->cache[i];
- if (!ce_path_match(&the_index, ce, &s->pathspec, NULL))
+ if (!ce_path_match(istate, ce, &s->pathspec, NULL))
continue;
if (ce_intent_to_add(ce))
continue;
it = string_list_insert(&s->change, ce->name);
d = it->util;
if (!d) {
- d = xcalloc(1, sizeof(*d));
+ CALLOC_ARRAY(d, 1);
it->util = d;
}
if (ce_stage(ce)) {
@@ -684,11 +701,12 @@ static void wt_status_collect_untracked(struct wt_status *s)
int i;
struct dir_struct dir;
uint64_t t_begin = getnanotime();
+ struct index_state *istate = s->repo->index;
if (!s->show_untracked_files)
return;
- memset(&dir, 0, sizeof(dir));
+ dir_init(&dir);
if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
dir.flags |=
DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
@@ -698,32 +716,26 @@ static void wt_status_collect_untracked(struct wt_status *s)
if (s->show_ignored_mode == SHOW_MATCHING_IGNORED)
dir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING;
} else {
- dir.untracked = the_index.untracked;
+ dir.untracked = istate->untracked;
}
setup_standard_excludes(&dir);
- fill_directory(&dir, &the_index, &s->pathspec);
+ fill_directory(&dir, istate, &s->pathspec);
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
- if (cache_name_is_other(ent->name, ent->len) &&
- dir_path_match(&the_index, ent, &s->pathspec, 0, NULL))
+ if (index_name_is_other(istate, ent->name, ent->len))
string_list_insert(&s->untracked, ent->name);
- free(ent);
}
for (i = 0; i < dir.ignored_nr; i++) {
struct dir_entry *ent = dir.ignored[i];
- if (cache_name_is_other(ent->name, ent->len) &&
- dir_path_match(&the_index, ent, &s->pathspec, 0, NULL))
+ if (index_name_is_other(istate, ent->name, ent->len))
string_list_insert(&s->ignored, ent->name);
- free(ent);
}
- free(dir.entries);
- free(dir.ignored);
- clear_directory(&dir);
+ dir_clear(&dir);
if (advice_status_u_option)
s->untracked_in_ms = (getnanotime() - t_begin) / 1000000;
@@ -744,23 +756,39 @@ static int has_unmerged(struct wt_status *s)
void wt_status_collect(struct wt_status *s)
{
+ trace2_region_enter("status", "worktrees", s->repo);
wt_status_collect_changes_worktree(s);
- if (s->is_initial)
+ trace2_region_leave("status", "worktrees", s->repo);
+
+ if (s->is_initial) {
+ trace2_region_enter("status", "initial", s->repo);
wt_status_collect_changes_initial(s);
- else
+ trace2_region_leave("status", "initial", s->repo);
+ } else {
+ trace2_region_enter("status", "index", s->repo);
wt_status_collect_changes_index(s);
+ trace2_region_leave("status", "index", s->repo);
+ }
+
+ trace2_region_enter("status", "untracked", s->repo);
wt_status_collect_untracked(s);
+ trace2_region_leave("status", "untracked", s->repo);
- wt_status_get_state(&s->state, s->branch && !strcmp(s->branch, "HEAD"));
+ wt_status_get_state(s->repo, &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);
+ wt_status_state_free_buffers(&s->state);
+}
+
+void wt_status_state_free_buffers(struct wt_status_state *state)
+{
+ FREE_AND_NULL(state->branch);
+ FREE_AND_NULL(state->onto);
+ FREE_AND_NULL(state->detached_from);
}
static void wt_longstatus_print_unmerged(struct wt_status *s)
@@ -889,17 +917,16 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom
struct strbuf summary = STRBUF_INIT;
char *summary_content;
- argv_array_pushf(&sm_summary.env_array, "GIT_INDEX_FILE=%s",
- s->index_file);
+ strvec_pushf(&sm_summary.env_array, "GIT_INDEX_FILE=%s", s->index_file);
- argv_array_push(&sm_summary.args, "submodule");
- argv_array_push(&sm_summary.args, "summary");
- argv_array_push(&sm_summary.args, uncommitted ? "--files" : "--cached");
- argv_array_push(&sm_summary.args, "--for-status");
- argv_array_push(&sm_summary.args, "--summary-limit");
- argv_array_pushf(&sm_summary.args, "%d", s->submodule_summary);
+ strvec_push(&sm_summary.args, "submodule");
+ strvec_push(&sm_summary.args, "summary");
+ strvec_push(&sm_summary.args, uncommitted ? "--files" : "--cached");
+ strvec_push(&sm_summary.args, "--for-status");
+ strvec_push(&sm_summary.args, "--summary-limit");
+ strvec_pushf(&sm_summary.args, "%d", s->submodule_summary);
if (!uncommitted)
- argv_array_push(&sm_summary.args, s->amend ? "HEAD^" : "HEAD");
+ strvec_push(&sm_summary.args, s->amend ? "HEAD^" : "HEAD");
sm_summary.git_cmd = 1;
sm_summary.no_stdin = 1;
@@ -947,7 +974,7 @@ static void wt_longstatus_print_other(struct wt_status *s,
struct string_list_item *it;
const char *path;
it = &(l->items[i]);
- path = quote_path(it->string, s->prefix, &buf);
+ path = quote_path(it->string, s->prefix, &buf, 0);
if (column_active(s->colopts)) {
string_list_append(&output, path);
continue;
@@ -991,13 +1018,19 @@ size_t wt_status_locate_end(const char *s, size_t len)
return len;
}
-void wt_status_add_cut_line(FILE *fp)
+void wt_status_append_cut_line(struct strbuf *buf)
{
const char *explanation = _("Do not modify or remove the line above.\nEverything below it will be ignored.");
+
+ strbuf_commented_addf(buf, "%s", cut_line);
+ strbuf_add_commented_lines(buf, explanation, strlen(explanation));
+}
+
+void wt_status_add_cut_line(FILE *fp)
+{
struct strbuf buf = STRBUF_INIT;
- fprintf(fp, "%c %s", comment_line_char, cut_line);
- strbuf_add_commented_lines(&buf, explanation, strlen(explanation));
+ wt_status_append_cut_line(&buf);
fputs(buf.buf, fp);
strbuf_release(&buf);
}
@@ -1009,7 +1042,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s)
int dirty_submodules;
const char *c = color(WT_STATUS_HEADER, s);
- repo_init_revisions(the_repository, &rev, NULL);
+ repo_init_revisions(s->repo, &rev, NULL);
rev.diffopt.flags.allow_textconv = 1;
rev.diffopt.ita_invisible_in_index = 1;
@@ -1063,14 +1096,29 @@ static void wt_longstatus_print_tracking(struct wt_status *s)
struct branch *branch;
char comment_line_string[3];
int i;
+ uint64_t t_begin = 0;
assert(s->branch && !s->is_initial);
if (!skip_prefix(s->branch, "refs/heads/", &branch_name))
return;
branch = branch_get(branch_name);
+
+ t_begin = getnanotime();
+
if (!format_tracking_info(branch, &sb, s->ahead_behind_flags))
return;
+ if (advice_status_ahead_behind_warning &&
+ s->ahead_behind_flags == AHEAD_BEHIND_FULL) {
+ uint64_t t_delta_in_ms = (getnanotime() - t_begin) / 1000000;
+ if (t_delta_in_ms > AB_DELAY_WARNING_IN_MS) {
+ strbuf_addf(&sb, _("\n"
+ "It took %.2f seconds to compute the branch ahead/behind values.\n"
+ "You can use '--no-ahead-behind' to avoid this.\n"),
+ t_delta_in_ms / 1000.0);
+ }
+ }
+
i = 0;
if (s->display_comment_prefix) {
comment_line_string[i++] = comment_line_char;
@@ -1187,13 +1235,15 @@ static int split_commit_in_progress(struct wt_status *s)
* The function assumes that the line does not contain useless spaces
* before or after the command.
*/
-static void abbrev_sha1_in_line(struct strbuf *line)
+static void abbrev_oid_in_line(struct strbuf *line)
{
struct strbuf **split;
int i;
if (starts_with(line->buf, "exec ") ||
- starts_with(line->buf, "x "))
+ starts_with(line->buf, "x ") ||
+ starts_with(line->buf, "label ") ||
+ starts_with(line->buf, "l "))
return;
split = strbuf_split_max(line, ' ', 3);
@@ -1235,7 +1285,7 @@ static int read_rebase_todolist(const char *fname, struct string_list *lines)
strbuf_trim(&line);
if (!line.len)
continue;
- abbrev_sha1_in_line(&line);
+ abbrev_oid_in_line(&line);
string_list_append(lines, line.buf);
}
fclose(f);
@@ -1326,7 +1376,7 @@ static void show_rebase_in_progress(struct wt_status *s,
_(" (use \"git rebase --abort\" to check out the original branch)"));
}
} else if (s->state.rebase_in_progress ||
- !stat(git_path_merge_msg(the_repository), &st)) {
+ !stat(git_path_merge_msg(s->repo), &st)) {
print_rebase_state(s, color);
if (s->hints)
status_printf_ln(s, color,
@@ -1365,16 +1415,28 @@ static void show_rebase_in_progress(struct wt_status *s,
static void show_cherry_pick_in_progress(struct wt_status *s,
const char *color)
{
- status_printf_ln(s, color, _("You are currently cherry-picking commit %s."),
- find_unique_abbrev(&s->state.cherry_pick_head_oid, DEFAULT_ABBREV));
+ if (is_null_oid(&s->state.cherry_pick_head_oid))
+ status_printf_ln(s, color,
+ _("Cherry-pick currently in progress."));
+ else
+ status_printf_ln(s, color,
+ _("You are currently cherry-picking commit %s."),
+ find_unique_abbrev(&s->state.cherry_pick_head_oid,
+ DEFAULT_ABBREV));
+
if (s->hints) {
if (has_unmerged(s))
status_printf_ln(s, color,
_(" (fix conflicts and run \"git cherry-pick --continue\")"));
+ else if (is_null_oid(&s->state.cherry_pick_head_oid))
+ status_printf_ln(s, color,
+ _(" (run \"git cherry-pick --continue\" to continue)"));
else
status_printf_ln(s, color,
_(" (all conflicts fixed: run \"git cherry-pick --continue\")"));
status_printf_ln(s, color,
+ _(" (use \"git cherry-pick --skip\" to skip this patch)"));
+ status_printf_ln(s, color,
_(" (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"));
}
wt_longstatus_print_trailer(s);
@@ -1383,16 +1445,27 @@ static void show_cherry_pick_in_progress(struct wt_status *s,
static void show_revert_in_progress(struct wt_status *s,
const char *color)
{
- status_printf_ln(s, color, _("You are currently reverting commit %s."),
- find_unique_abbrev(&s->state.revert_head_oid, DEFAULT_ABBREV));
+ if (is_null_oid(&s->state.revert_head_oid))
+ status_printf_ln(s, color,
+ _("Revert currently in progress."));
+ else
+ status_printf_ln(s, color,
+ _("You are currently reverting commit %s."),
+ find_unique_abbrev(&s->state.revert_head_oid,
+ DEFAULT_ABBREV));
if (s->hints) {
if (has_unmerged(s))
status_printf_ln(s, color,
_(" (fix conflicts and run \"git revert --continue\")"));
+ else if (is_null_oid(&s->state.revert_head_oid))
+ status_printf_ln(s, color,
+ _(" (run \"git revert --continue\" to continue)"));
else
status_printf_ln(s, color,
_(" (all conflicts fixed: run \"git revert --continue\")"));
status_printf_ln(s, color,
+ _(" (use \"git revert --skip\" to skip this patch)"));
+ status_printf_ln(s, color,
_(" (use \"git revert --abort\" to cancel the revert operation)"));
}
wt_longstatus_print_trailer(s);
@@ -1414,6 +1487,18 @@ static void show_bisect_in_progress(struct wt_status *s,
wt_longstatus_print_trailer(s);
}
+static void show_sparse_checkout_in_use(struct wt_status *s,
+ const char *color)
+{
+ if (s->state.sparse_checkout_percentage == SPARSE_CHECKOUT_DISABLED)
+ return;
+
+ status_printf_ln(s, color,
+ _("You are in a sparse checkout with %d%% of tracked files present."),
+ s->state.sparse_checkout_percentage);
+ wt_longstatus_print_trailer(s);
+}
+
/*
* Extract branch information from rebase/bisect
*/
@@ -1478,7 +1563,8 @@ static int grab_1st_switch(struct object_id *ooid, struct object_id *noid,
return 1;
}
-static void wt_status_get_detached_from(struct wt_status_state *state)
+static void wt_status_get_detached_from(struct repository *r,
+ struct wt_status_state *state)
{
struct grab_1st_switch_cbdata cb;
struct commit *commit;
@@ -1491,11 +1577,11 @@ static void wt_status_get_detached_from(struct wt_status_state *state)
return;
}
- if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref) == 1 &&
- /* sha1 is a commit? match without further lookup */
+ if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref, 1) == 1 &&
+ /* oid is a commit? match without further lookup */
(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 &&
+ /* perhaps oid is a tag, try to dereference to a commit */
+ ((commit = lookup_commit_reference_gently(r, &oid, 1)) != NULL &&
oideq(&cb.noid, &commit->object.oid)))) {
const char *from = ref;
if (!skip_prefix(from, "refs/tags/", &from))
@@ -1552,31 +1638,67 @@ int wt_status_check_bisect(const struct worktree *wt,
return 0;
}
-void wt_status_get_state(struct wt_status_state *state,
+static void wt_status_check_sparse_checkout(struct repository *r,
+ struct wt_status_state *state)
+{
+ int skip_worktree = 0;
+ int i;
+
+ if (!core_apply_sparse_checkout || r->index->cache_nr == 0) {
+ /*
+ * Don't compute percentage of checked out files if we
+ * aren't in a sparse checkout or would get division by 0.
+ */
+ state->sparse_checkout_percentage = SPARSE_CHECKOUT_DISABLED;
+ return;
+ }
+
+ for (i = 0; i < r->index->cache_nr; i++) {
+ struct cache_entry *ce = r->index->cache[i];
+ if (ce_skip_worktree(ce))
+ skip_worktree++;
+ }
+
+ state->sparse_checkout_percentage =
+ 100 - (100 * skip_worktree)/r->index->cache_nr;
+}
+
+void wt_status_get_state(struct repository *r,
+ struct wt_status_state *state,
int get_detached_from)
{
struct stat st;
struct object_id oid;
+ enum replay_action action;
- if (!stat(git_path_merge_head(the_repository), &st)) {
+ if (!stat(git_path_merge_head(r), &st)) {
wt_status_check_rebase(NULL, state);
state->merge_in_progress = 1;
} else if (wt_status_check_rebase(NULL, state)) {
; /* all set */
- } else if (!stat(git_path_cherry_pick_head(the_repository), &st) &&
- !get_oid("CHERRY_PICK_HEAD", &oid)) {
+ } else if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
+ !get_oid("CHERRY_PICK_HEAD", &oid)) {
state->cherry_pick_in_progress = 1;
oidcpy(&state->cherry_pick_head_oid, &oid);
}
wt_status_check_bisect(NULL, state);
- if (!stat(git_path_revert_head(the_repository), &st) &&
+ if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") &&
!get_oid("REVERT_HEAD", &oid)) {
state->revert_in_progress = 1;
oidcpy(&state->revert_head_oid, &oid);
}
-
+ if (!sequencer_get_last_command(r, &action)) {
+ if (action == REPLAY_PICK) {
+ state->cherry_pick_in_progress = 1;
+ oidcpy(&state->cherry_pick_head_oid, null_oid());
+ } else {
+ state->revert_in_progress = 1;
+ oidcpy(&state->revert_head_oid, null_oid());
+ }
+ }
if (get_detached_from)
- wt_status_get_detached_from(state);
+ wt_status_get_detached_from(r, state);
+ wt_status_check_sparse_checkout(r, state);
}
static void wt_longstatus_print_state(struct wt_status *s)
@@ -1600,6 +1722,9 @@ static void wt_longstatus_print_state(struct wt_status *s)
show_revert_in_progress(s, state_color);
if (state->bisect_in_progress)
show_bisect_in_progress(s, state_color);
+
+ if (state->sparse_checkout_percentage != SPARSE_CHECKOUT_DISABLED)
+ show_sparse_checkout_in_use(s, state_color);
}
static void wt_longstatus_print(struct wt_status *s)
@@ -1684,29 +1809,36 @@ static void wt_longstatus_print(struct wt_status *s)
; /* nothing */
else if (s->workdir_dirty) {
if (s->hints)
- printf(_("no changes added to commit "
- "(use \"git add\" and/or \"git commit -a\")\n"));
+ fprintf(s->fp, _("no changes added to commit "
+ "(use \"git add\" and/or "
+ "\"git commit -a\")\n"));
else
- printf(_("no changes added to commit\n"));
+ fprintf(s->fp, _("no changes added to "
+ "commit\n"));
} else if (s->untracked.nr) {
if (s->hints)
- printf(_("nothing added to commit but untracked files "
- "present (use \"git add\" to track)\n"));
+ fprintf(s->fp, _("nothing added to commit but "
+ "untracked files present (use "
+ "\"git add\" to track)\n"));
else
- printf(_("nothing added to commit but untracked files present\n"));
+ fprintf(s->fp, _("nothing added to commit but "
+ "untracked files present\n"));
} else if (s->is_initial) {
if (s->hints)
- printf(_("nothing to commit (create/copy files "
- "and use \"git add\" to track)\n"));
+ fprintf(s->fp, _("nothing to commit (create/"
+ "copy files and use \"git "
+ "add\" to track)\n"));
else
- printf(_("nothing to commit\n"));
+ fprintf(s->fp, _("nothing to commit\n"));
} else if (!s->show_untracked_files) {
if (s->hints)
- printf(_("nothing to commit (use -u to show untracked files)\n"));
+ fprintf(s->fp, _("nothing to commit (use -u to "
+ "show untracked files)\n"));
else
- printf(_("nothing to commit\n"));
+ fprintf(s->fp, _("nothing to commit\n"));
} else
- printf(_("nothing to commit, working tree clean\n"));
+ fprintf(s->fp, _("nothing to commit, working tree "
+ "clean\n"));
}
if(s->show_stash)
wt_longstatus_print_stash_summary(s);
@@ -1729,12 +1861,12 @@ static void wt_shortstatus_unmerged(struct string_list_item *it,
}
color_fprintf(s->fp, color(WT_STATUS_UNMERGED, s), "%s", how);
if (s->null_termination) {
- fprintf(stdout, " %s%c", it->string, 0);
+ fprintf(s->fp, " %s%c", it->string, 0);
} else {
struct strbuf onebuf = STRBUF_INIT;
const char *one;
- one = quote_path(it->string, s->prefix, &onebuf);
- printf(" %s\n", one);
+ one = quote_path(it->string, s->prefix, &onebuf, QUOTE_PATH_QUOTE_SP);
+ fprintf(s->fp, " %s\n", one);
strbuf_release(&onebuf);
}
}
@@ -1747,37 +1879,28 @@ static void wt_shortstatus_status(struct string_list_item *it,
if (d->index_status)
color_fprintf(s->fp, color(WT_STATUS_UPDATED, s), "%c", d->index_status);
else
- putchar(' ');
+ fputc(' ', s->fp);
if (d->worktree_status)
color_fprintf(s->fp, color(WT_STATUS_CHANGED, s), "%c", d->worktree_status);
else
- putchar(' ');
- putchar(' ');
+ fputc(' ', s->fp);
+ fputc(' ', s->fp);
if (s->null_termination) {
- fprintf(stdout, "%s%c", it->string, 0);
+ fprintf(s->fp, "%s%c", it->string, 0);
if (d->rename_source)
- fprintf(stdout, "%s%c", d->rename_source, 0);
+ fprintf(s->fp, "%s%c", d->rename_source, 0);
} else {
struct strbuf onebuf = STRBUF_INIT;
const char *one;
if (d->rename_source) {
- one = quote_path(d->rename_source, s->prefix, &onebuf);
- if (*one != '"' && strchr(one, ' ') != NULL) {
- putchar('"');
- strbuf_addch(&onebuf, '"');
- one = onebuf.buf;
- }
- printf("%s -> ", one);
+ one = quote_path(d->rename_source, s->prefix, &onebuf,
+ QUOTE_PATH_QUOTE_SP);
+ fprintf(s->fp, "%s -> ", one);
strbuf_release(&onebuf);
}
- one = quote_path(it->string, s->prefix, &onebuf);
- if (*one != '"' && strchr(one, ' ') != NULL) {
- putchar('"');
- strbuf_addch(&onebuf, '"');
- one = onebuf.buf;
- }
- printf("%s\n", one);
+ one = quote_path(it->string, s->prefix, &onebuf, QUOTE_PATH_QUOTE_SP);
+ fprintf(s->fp, "%s\n", one);
strbuf_release(&onebuf);
}
}
@@ -1786,13 +1909,13 @@ static void wt_shortstatus_other(struct string_list_item *it,
struct wt_status *s, const char *sign)
{
if (s->null_termination) {
- fprintf(stdout, "%s %s%c", sign, it->string, 0);
+ fprintf(s->fp, "%s %s%c", sign, it->string, 0);
} else {
struct strbuf onebuf = STRBUF_INIT;
const char *one;
- one = quote_path(it->string, s->prefix, &onebuf);
+ one = quote_path(it->string, s->prefix, &onebuf, QUOTE_PATH_QUOTE_SP);
color_fprintf(s->fp, color(WT_STATUS_UNTRACKED, s), "%s", sign);
- printf(" %s\n", one);
+ fprintf(s->fp, " %s\n", one);
strbuf_release(&onebuf);
}
}
@@ -1834,7 +1957,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
color_fprintf(s->fp, branch_color_local, "%s", branch_name);
sti = stat_tracking_info(branch, &num_ours, &num_theirs, &base,
- s->ahead_behind_flags);
+ 0, s->ahead_behind_flags);
if (sti < 0) {
if (!base)
goto conclude;
@@ -1913,7 +2036,7 @@ static void wt_porcelain_print(struct wt_status *s)
* [# branch.upstream <upstream><eol>
* [# branch.ab +<ahead> -<behind><eol>]]
*
- * <commit> ::= the current commit hash or the the literal
+ * <commit> ::= the current commit hash or the literal
* "(initial)" to indicate an initialized repo
* with no commits.
*
@@ -1946,7 +2069,7 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s)
char eol = s->null_termination ? '\0' : '\n';
fprintf(s->fp, "# branch.oid %s%c",
- (s->is_initial ? "(initial)" : sha1_to_hex(s->sha1_commit)),
+ (s->is_initial ? "(initial)" : oid_to_hex(&s->oid_commit)),
eol);
if (!s->branch)
@@ -1973,7 +2096,7 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s)
branch = branch_get(branch_name);
base = NULL;
ab_info = stat_tracking_info(branch, &nr_ahead, &nr_behind,
- &base, s->ahead_behind_flags);
+ &base, 0, s->ahead_behind_flags);
if (base) {
base = shorten_unambiguous_ref(base, 0);
fprintf(s->fp, "# branch.upstream %s%c", base, eol);
@@ -2022,9 +2145,7 @@ static void wt_porcelain_v2_submodule_state(
/*
* Fix-up changed entries before we print them.
*/
-static void wt_porcelain_v2_fix_up_changed(
- struct string_list_item *it,
- struct wt_status *s)
+static void wt_porcelain_v2_fix_up_changed(struct string_list_item *it)
{
struct wt_status_change_data *d = it->util;
@@ -2084,7 +2205,7 @@ static void wt_porcelain_v2_print_changed_entry(
char submodule_token[5];
char sep_char, eol_char;
- wt_porcelain_v2_fix_up_changed(it, s);
+ wt_porcelain_v2_fix_up_changed(it);
wt_porcelain_v2_submodule_state(d, submodule_token);
key[0] = d->index_status ? d->index_status : '.';
@@ -2109,9 +2230,9 @@ static void wt_porcelain_v2_print_changed_entry(
*/
sep_char = '\t';
eol_char = '\n';
- path = quote_path(it->string, s->prefix, &buf);
+ path = quote_path(it->string, s->prefix, &buf, 0);
if (d->rename_source)
- path_from = quote_path(d->rename_source, s->prefix, &buf_from);
+ path_from = quote_path(d->rename_source, s->prefix, &buf_from, 0);
}
if (path_from)
@@ -2140,6 +2261,7 @@ static void wt_porcelain_v2_print_unmerged_entry(
struct wt_status *s)
{
struct wt_status_change_data *d = it->util;
+ struct index_state *istate = s->repo->index;
const struct cache_entry *ce;
struct strbuf buf_index = STRBUF_INIT;
const char *path_index = NULL;
@@ -2178,11 +2300,11 @@ static void wt_porcelain_v2_print_unmerged_entry(
*/
memset(stages, 0, sizeof(stages));
sum = 0;
- pos = cache_name_pos(it->string, strlen(it->string));
+ pos = index_name_pos(istate, it->string, strlen(it->string));
assert(pos < 0);
pos = -pos-1;
- while (pos < active_nr) {
- ce = active_cache[pos++];
+ while (pos < istate->cache_nr) {
+ ce = istate->cache[pos++];
stage = ce_stage(ce);
if (strcmp(ce->name, it->string) || !stage)
break;
@@ -2196,7 +2318,7 @@ static void wt_porcelain_v2_print_unmerged_entry(
if (s->null_termination)
path_index = it->string;
else
- path_index = quote_path(it->string, s->prefix, &buf_index);
+ path_index = quote_path(it->string, s->prefix, &buf_index, 0);
fprintf(s->fp, "%c %s %s %06o %06o %06o %06o %s %s %s %s%c",
unmerged_prefix, key, submodule_token,
@@ -2229,7 +2351,7 @@ static void wt_porcelain_v2_print_other(
path = it->string;
eol_char = '\0';
} else {
- path = quote_path(it->string, s->prefix, &buf);
+ path = quote_path(it->string, s->prefix, &buf, 0);
eol_char = '\n';
}
@@ -2284,6 +2406,13 @@ static void wt_porcelain_v2_print(struct wt_status *s)
void wt_status_print(struct wt_status *s)
{
+ trace2_data_intmax("status", s->repo, "count/changed", s->change.nr);
+ trace2_data_intmax("status", s->repo, "count/untracked",
+ s->untracked.nr);
+ trace2_data_intmax("status", s->repo, "count/ignored", s->ignored.nr);
+
+ trace2_region_enter("status", "print", s->repo);
+
switch (s->status_format) {
case STATUS_FORMAT_SHORT:
wt_shortstatus_print(s);
@@ -2302,17 +2431,19 @@ void wt_status_print(struct wt_status *s)
wt_longstatus_print(s);
break;
}
+
+ trace2_region_leave("status", "print", s->repo);
}
/**
* Returns 1 if there are unstaged changes, 0 otherwise.
*/
-int has_unstaged_changes(int ignore_submodules)
+int has_unstaged_changes(struct repository *r, int ignore_submodules)
{
struct rev_info rev_info;
int result;
- repo_init_revisions(the_repository, &rev_info, NULL);
+ repo_init_revisions(r, &rev_info, NULL);
if (ignore_submodules) {
rev_info.diffopt.flags.ignore_submodules = 1;
rev_info.diffopt.flags.override_submodule_config = 1;
@@ -2326,15 +2457,16 @@ int has_unstaged_changes(int ignore_submodules)
/**
* Returns 1 if there are uncommitted changes, 0 otherwise.
*/
-int has_uncommitted_changes(int ignore_submodules)
+int has_uncommitted_changes(struct repository *r,
+ int ignore_submodules)
{
struct rev_info rev_info;
int result;
- if (is_cache_unborn())
+ if (is_index_unborn(r->index))
return 0;
- repo_init_revisions(the_repository, &rev_info, NULL);
+ repo_init_revisions(r, &rev_info, NULL);
if (ignore_submodules)
rev_info.diffopt.flags.ignore_submodules = 1;
rev_info.diffopt.flags.quick = 1;
@@ -2345,12 +2477,13 @@ int has_uncommitted_changes(int ignore_submodules)
* We have no head (or it's corrupt); use the empty tree,
* which will complain if the index is non-empty.
*/
- struct tree *tree = lookup_tree(the_repository, the_hash_algo->empty_tree);
+ struct tree *tree = lookup_tree(r, the_hash_algo->empty_tree);
add_pending_object(&rev_info, &tree->object, "");
}
diff_setup_done(&rev_info.diffopt);
result = run_diff_index(&rev_info, 1);
+ object_array_clear(&rev_info.pending);
return diff_result_code(&rev_info.diffopt, result);
}
@@ -2358,24 +2491,28 @@ int has_uncommitted_changes(int ignore_submodules)
* 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)
+int require_clean_work_tree(struct repository *r,
+ const char *action,
+ const char *hint,
+ int ignore_submodules,
+ int gently)
{
struct lock_file lock_file = LOCK_INIT;
int err = 0, fd;
- fd = hold_locked_index(&lock_file, 0);
- refresh_cache(REFRESH_QUIET);
+ fd = repo_hold_locked_index(r, &lock_file, 0);
+ refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
if (0 <= fd)
- update_index_if_able(&the_index, &lock_file);
+ repo_update_index_if_able(r, &lock_file);
rollback_lock_file(&lock_file);
- if (has_unstaged_changes(ignore_submodules)) {
+ if (has_unstaged_changes(r, 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 (has_uncommitted_changes(r, ignore_submodules)) {
if (err)
error(_("additionally, your index contains uncommitted changes."));
else