diff options
Diffstat (limited to 'wt-status.c')
-rw-r--r-- | wt-status.c | 127 |
1 files changed, 81 insertions, 46 deletions
diff --git a/wt-status.c b/wt-status.c index f5debcd2b4..5ffab61015 100644 --- a/wt-status.c +++ b/wt-status.c @@ -136,7 +136,11 @@ void wt_status_prepare(struct wt_status *s) s->ignored.strdup_strings = 1; s->show_branch = -1; /* unspecified */ s->show_stash = 0; + s->ahead_behind_flags = AHEAD_BEHIND_UNSPECIFIED; s->display_comment_prefix = 0; + s->detect_rename = -1; + s->rename_score = -1; + s->rename_limit = -1; } static void wt_longstatus_print_unmerged_header(struct wt_status *s) @@ -263,7 +267,7 @@ static const char *wt_status_unmerged_status_string(int stagemask) case 7: return _("both modified:"); default: - die("BUG: unhandled unmerged status %x", stagemask); + BUG("unhandled unmerged status %x", stagemask); } } @@ -376,7 +380,7 @@ static void wt_longstatus_print_change_data(struct wt_status *s, status = d->worktree_status; break; default: - die("BUG: unhandled change_type %d in wt_longstatus_print_change_data", + BUG("unhandled change_type %d in wt_longstatus_print_change_data", change_type); } @@ -394,7 +398,7 @@ static void wt_longstatus_print_change_data(struct wt_status *s, status_printf(s, color(WT_STATUS_HEADER, s), "\t"); what = wt_status_diff_status_string(status); if (!what) - die("BUG: unhandled diff status %c", status); + BUG("unhandled diff status %c", status); len = label_width - utf8_strwidth(what); assert(len >= 0); if (one_name != two_name) @@ -469,7 +473,7 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q, case DIFF_STATUS_COPIED: case DIFF_STATUS_RENAMED: if (d->rename_status) - die("BUG: multiple renames on the same target? how?"); + BUG("multiple renames on the same target? how?"); d->rename_source = xstrdup(p->one->path); d->rename_score = p->score * 100 / MAX_SCORE; d->rename_status = p->status; @@ -483,7 +487,7 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q, break; default: - die("BUG: unhandled diff-files status '%c'", p->status); + BUG("unhandled diff-files status '%c'", p->status); break; } @@ -546,7 +550,7 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q, case DIFF_STATUS_COPIED: case DIFF_STATUS_RENAMED: if (d->rename_status) - die("BUG: multiple renames on the same target? how?"); + BUG("multiple renames on the same target? how?"); d->rename_source = xstrdup(p->one->path); d->rename_score = p->score * 100 / MAX_SCORE; d->rename_status = p->status; @@ -568,7 +572,7 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q, break; default: - die("BUG: unhandled diff-index status '%c'", p->status); + BUG("unhandled diff-index status '%c'", p->status); break; } } @@ -591,6 +595,9 @@ static void wt_status_collect_changes_worktree(struct wt_status *s) } 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; + rev.diffopt.rename_limit = s->rename_limit >= 0 ? s->rename_limit : rev.diffopt.rename_limit; + 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); } @@ -602,7 +609,7 @@ static void wt_status_collect_changes_index(struct wt_status *s) init_revisions(&rev, NULL); memset(&opt, 0, sizeof(opt)); - opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference; + opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference; setup_revisions(0, NULL, &rev, &opt); rev.diffopt.flags.override_submodule_config = 1; @@ -624,9 +631,9 @@ static void wt_status_collect_changes_index(struct wt_status *s) rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = wt_status_collect_updated_cb; rev.diffopt.format_callback_data = s; - rev.diffopt.detect_rename = DIFF_DETECT_RENAME; - rev.diffopt.rename_limit = 200; - rev.diffopt.break_opt = 0; + rev.diffopt.detect_rename = s->detect_rename >= 0 ? s->detect_rename : rev.diffopt.detect_rename; + rev.diffopt.rename_limit = s->rename_limit >= 0 ? s->rename_limit : rev.diffopt.rename_limit; + 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); } @@ -640,7 +647,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s) struct wt_status_change_data *d; const struct cache_entry *ce = active_cache[i]; - if (!ce_path_match(ce, &s->pathspec, NULL)) + if (!ce_path_match(&the_index, ce, &s->pathspec, NULL)) continue; if (ce_intent_to_add(ce)) continue; @@ -696,7 +703,7 @@ static void wt_status_collect_untracked(struct wt_status *s) 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(ent, &s->pathspec, 0, NULL)) + dir_path_match(&the_index, ent, &s->pathspec, 0, NULL)) string_list_insert(&s->untracked, ent->name); free(ent); } @@ -704,7 +711,7 @@ static void wt_status_collect_untracked(struct wt_status *s) 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(ent, &s->pathspec, 0, NULL)) + dir_path_match(&the_index, ent, &s->pathspec, 0, NULL)) string_list_insert(&s->ignored, ent->name); free(ent); } @@ -980,11 +987,13 @@ static void wt_longstatus_print_verbose(struct wt_status *s) rev.diffopt.ita_invisible_in_index = 1; memset(&opt, 0, sizeof(opt)); - opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference; + opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference; setup_revisions(0, NULL, &rev, &opt); rev.diffopt.output_format |= DIFF_FORMAT_PATCH; - rev.diffopt.detect_rename = DIFF_DETECT_RENAME; + rev.diffopt.detect_rename = s->detect_rename >= 0 ? s->detect_rename : rev.diffopt.detect_rename; + rev.diffopt.rename_limit = s->rename_limit >= 0 ? s->rename_limit : rev.diffopt.rename_limit; + rev.diffopt.rename_score = s->rename_score >= 0 ? s->rename_score : rev.diffopt.rename_score; rev.diffopt.file = s->fp; rev.diffopt.close_file = 0; /* @@ -1032,7 +1041,7 @@ static void wt_longstatus_print_tracking(struct wt_status *s) if (!skip_prefix(s->branch, "refs/heads/", &branch_name)) return; branch = branch_get(branch_name); - if (!format_tracking_info(branch, &sb)) + if (!format_tracking_info(branch, &sb, s->ahead_behind_flags)) return; i = 0; @@ -1187,7 +1196,7 @@ static void abbrev_sha1_in_line(struct strbuf *line) strbuf_trim(split[1]); if (!get_oid(split[1]->buf, &oid)) { strbuf_reset(split[1]); - strbuf_add_unique_abbrev(split[1], oid.hash, + strbuf_add_unique_abbrev(split[1], &oid, DEFAULT_ABBREV); strbuf_addch(split[1], ' '); strbuf_reset(line); @@ -1308,7 +1317,7 @@ static void show_rebase_in_progress(struct wt_status *s, 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(), &st)) { + } else if (state->rebase_in_progress || !stat(git_path_merge_msg(the_repository), &st)) { print_rebase_state(s, state, color); if (s->hints) status_printf_ln(s, color, @@ -1349,7 +1358,7 @@ 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(state->cherry_pick_head_sha1, DEFAULT_ABBREV)); + find_unique_abbrev(&state->cherry_pick_head_oid, DEFAULT_ABBREV)); if (s->hints) { if (has_unmerged(s)) status_printf_ln(s, color, @@ -1368,7 +1377,7 @@ 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(state->revert_head_sha1, DEFAULT_ABBREV)); + find_unique_abbrev(&state->revert_head_oid, DEFAULT_ABBREV)); if (s->hints) { if (has_unmerged(s)) status_printf_ln(s, color, @@ -1421,7 +1430,7 @@ static char *get_branch(const struct worktree *wt, const char *path) ; else if (!get_oid_hex(sb.buf, &oid)) { strbuf_reset(&sb); - strbuf_add_unique_abbrev(&sb, oid.hash, DEFAULT_ABBREV); + strbuf_add_unique_abbrev(&sb, &oid, DEFAULT_ABBREV); } else if (!strcmp(sb.buf, "detached HEAD")) /* rebase */ goto got_nothing; else /* bisect */ @@ -1458,7 +1467,7 @@ static int grab_1st_switch(struct object_id *ooid, struct object_id *noid, if (!strcmp(cb->buf.buf, "HEAD")) { /* HEAD is relative. Resolve it to the right reflog entry. */ strbuf_reset(&cb->buf); - strbuf_add_unique_abbrev(&cb->buf, noid->hash, DEFAULT_ABBREV); + strbuf_add_unique_abbrev(&cb->buf, noid, DEFAULT_ABBREV); } return 1; } @@ -1480,7 +1489,7 @@ static void wt_status_get_detached_from(struct wt_status_state *state) /* sha1 is a commit? match without further lookup */ (!oidcmp(&cb.noid, &oid) || /* perhaps sha1 is a tag, try to dereference to a commit */ - ((commit = lookup_commit_reference_gently(&oid, 1)) != NULL && + ((commit = lookup_commit_reference_gently(the_repository, &oid, 1)) != NULL && !oidcmp(&cb.noid, &commit->object.oid)))) { const char *from = ref; if (!skip_prefix(from, "refs/tags/", &from)) @@ -1488,10 +1497,10 @@ static void wt_status_get_detached_from(struct wt_status_state *state) state->detached_from = xstrdup(from); } else state->detached_from = - xstrdup(find_unique_abbrev(cb.noid.hash, DEFAULT_ABBREV)); - hashcpy(state->detached_sha1, cb.noid.hash); + xstrdup(find_unique_abbrev(&cb.noid, DEFAULT_ABBREV)); + oidcpy(&state->detached_oid, &cb.noid); state->detached_at = !get_oid("HEAD", &oid) && - !hashcmp(oid.hash, state->detached_sha1); + !oidcmp(&oid, &state->detached_oid); free(ref); strbuf_release(&cb.buf); @@ -1543,20 +1552,20 @@ void wt_status_get_state(struct wt_status_state *state, struct stat st; struct object_id oid; - if (!stat(git_path_merge_head(), &st)) { + if (!stat(git_path_merge_head(the_repository), &st)) { state->merge_in_progress = 1; } else if (wt_status_check_rebase(NULL, state)) { ; /* all set */ - } else if (!stat(git_path_cherry_pick_head(), &st) && + } else if (!stat(git_path_cherry_pick_head(the_repository), &st) && !get_oid("CHERRY_PICK_HEAD", &oid)) { state->cherry_pick_in_progress = 1; - hashcpy(state->cherry_pick_head_sha1, oid.hash); + oidcpy(&state->cherry_pick_head_oid, &oid); } wt_status_check_bisect(NULL, state); - if (!stat(git_path_revert_head(), &st) && + if (!stat(git_path_revert_head(the_repository), &st) && !get_oid("REVERT_HEAD", &oid)) { state->revert_in_progress = 1; - hashcpy(state->revert_head_sha1, oid.hash); + oidcpy(&state->revert_head_oid, &oid); } if (get_detached_from) @@ -1793,7 +1802,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s) const char *base; char *short_base; const char *branch_name; - int num_ours, num_theirs; + int num_ours, num_theirs, sti; int upstream_is_gone = 0; color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## "); @@ -1819,7 +1828,9 @@ static void wt_shortstatus_print_tracking(struct wt_status *s) color_fprintf(s->fp, branch_color_local, "%s", branch_name); - if (stat_tracking_info(branch, &num_ours, &num_theirs, &base) < 0) { + sti = stat_tracking_info(branch, &num_ours, &num_theirs, &base, + s->ahead_behind_flags); + if (sti < 0) { if (!base) goto conclude; @@ -1831,12 +1842,14 @@ static void wt_shortstatus_print_tracking(struct wt_status *s) color_fprintf(s->fp, branch_color_remote, "%s", short_base); free(short_base); - if (!upstream_is_gone && !num_ours && !num_theirs) + if (!upstream_is_gone && !sti) goto conclude; color_fprintf(s->fp, header_color, " ["); if (upstream_is_gone) { color_fprintf(s->fp, header_color, LABEL(N_("gone"))); + } else if (s->ahead_behind_flags == AHEAD_BEHIND_QUICK) { + color_fprintf(s->fp, header_color, LABEL(N_("different"))); } else if (!num_ours) { color_fprintf(s->fp, header_color, LABEL(N_("behind "))); color_fprintf(s->fp, branch_color_remote, "%d", num_theirs); @@ -1905,18 +1918,19 @@ static void wt_porcelain_print(struct wt_status *s) * * <upstream> ::= the upstream branch name, when set. * - * <ahead> ::= integer ahead value, when upstream set - * and the commit is present (not gone). - * - * <behind> ::= integer behind value, when upstream set - * and commit is present. + * <ahead> ::= integer ahead value or '?'. * + * <behind> ::= integer behind value or '?'. * * The end-of-line is defined by the -z flag. * * <eol> ::= NUL when -z, * LF when NOT -z. * + * When an upstream is set and present, the 'branch.ab' line will + * be printed with the ahead/behind counts for the branch and the + * upstream. When AHEAD_BEHIND_QUICK is requested and the branches + * are different, '?' will be substituted for the actual count. */ static void wt_porcelain_v2_print_tracking(struct wt_status *s) { @@ -1956,14 +1970,25 @@ static void wt_porcelain_v2_print_tracking(struct wt_status *s) /* Lookup stats on the upstream tracking branch, if set. */ branch = branch_get(branch_name); base = NULL; - ab_info = (stat_tracking_info(branch, &nr_ahead, &nr_behind, &base) == 0); + ab_info = stat_tracking_info(branch, &nr_ahead, &nr_behind, + &base, s->ahead_behind_flags); if (base) { base = shorten_unambiguous_ref(base, 0); fprintf(s->fp, "# branch.upstream %s%c", base, eol); free((char *)base); - if (ab_info) - fprintf(s->fp, "# branch.ab +%d -%d%c", nr_ahead, nr_behind, eol); + if (ab_info > 0) { + /* different */ + if (nr_ahead || nr_behind) + fprintf(s->fp, "# branch.ab +%d -%d%c", + nr_ahead, nr_behind, eol); + else + fprintf(s->fp, "# branch.ab +? -?%c", + eol); + } else if (!ab_info) { + /* same */ + fprintf(s->fp, "# branch.ab +0 -0%c", eol); + } } } @@ -2141,7 +2166,7 @@ static void wt_porcelain_v2_print_unmerged_entry( case 6: key = "AA"; break; /* both added */ case 7: key = "UU"; break; /* both modified */ default: - die("BUG: unhandled unmerged status %x", d->stagemask); + BUG("unhandled unmerged status %x", d->stagemask); } /* @@ -2168,7 +2193,7 @@ static void wt_porcelain_v2_print_unmerged_entry( sum |= (1 << (stage - 1)); } if (sum != d->stagemask) - die("BUG: observed stagemask 0x%x != expected stagemask 0x%x", sum, d->stagemask); + BUG("observed stagemask 0x%x != expected stagemask 0x%x", sum, d->stagemask); if (s->null_termination) path_index = it->string; @@ -2272,7 +2297,7 @@ void wt_status_print(struct wt_status *s) wt_porcelain_v2_print(s); break; case STATUS_FORMAT_UNSPECIFIED: - die("BUG: finalize_deferred_config() should have been called"); + BUG("finalize_deferred_config() should have been called"); break; case STATUS_FORMAT_NONE: case STATUS_FORMAT_LONG: @@ -2315,7 +2340,17 @@ int has_uncommitted_changes(int ignore_submodules) if (ignore_submodules) rev_info.diffopt.flags.ignore_submodules = 1; rev_info.diffopt.flags.quick = 1; + add_head_to_pending(&rev_info); + if (!rev_info.pending.nr) { + /* + * 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); + add_pending_object(&rev_info, &tree->object, ""); + } + diff_setup_done(&rev_info.diffopt); result = run_diff_index(&rev_info, 1); return diff_result_code(&rev_info.diffopt, result); |