Merge branch 'mg/status-porcelain-no-i18n'
authorJunio C Hamano <gitster@pobox.com>
Fri, 17 Mar 2017 20:50:27 +0000 (13:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 17 Mar 2017 20:50:27 +0000 (13:50 -0700)
"git status --porcelain" is supposed to give a stable output, but a
few strings were left as translatable by mistake.

* mg/status-porcelain-no-i18n:
git-status: make porcelain more robust

1  2 
wt-status.c
diff --combined wt-status.c
index a8d1faf80d73d360eb82dc6b5c588544a0cc812c,0c0b70c4a8b536cc694f0d248b1648d35ae7a607..cc446f26ba40a6813c69b649656210bc6e3f98ae
@@@ -16,7 -16,6 +16,7 @@@
  #include "strbuf.h"
  #include "utf8.h"
  #include "worktree.h"
 +#include "lockfile.h"
  
  static const char cut_line[] =
  "------------------------ >8 ------------------------\n";
@@@ -121,7 -120,7 +121,7 @@@ static void status_printf_more(struct w
  
  void wt_status_prepare(struct wt_status *s)
  {
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
        memset(s, 0, sizeof(*s));
        memcpy(s->color_palette, default_wt_status_colors,
        s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
        s->use_color = -1;
        s->relative_paths = 1;
 -      s->branch = resolve_refdup("HEAD", 0, sha1, NULL);
 +      s->branch = resolve_refdup("HEAD", 0, oid.hash, NULL);
        s->reference = "HEAD";
        s->fp = stdout;
        s->index_file = get_index_file();
        s->display_comment_prefix = 0;
  }
  
 -static void wt_status_print_unmerged_header(struct wt_status *s)
 +static void wt_longstatus_print_unmerged_header(struct wt_status *s)
  {
        int i;
        int del_mod_conflict = 0;
        status_printf_ln(s, c, "%s", "");
  }
  
 -static void wt_status_print_cached_header(struct wt_status *s)
 +static void wt_longstatus_print_cached_header(struct wt_status *s)
  {
        const char *c = color(WT_STATUS_HEADER, s);
  
        status_printf_ln(s, c, "%s", "");
  }
  
 -static void wt_status_print_dirty_header(struct wt_status *s,
 -                                       int has_deleted,
 -                                       int has_dirty_submodules)
 +static void wt_longstatus_print_dirty_header(struct wt_status *s,
 +                                           int has_deleted,
 +                                           int has_dirty_submodules)
  {
        const char *c = color(WT_STATUS_HEADER, s);
  
        status_printf_ln(s, c, "%s", "");
  }
  
 -static void wt_status_print_other_header(struct wt_status *s,
 -                                       const char *what,
 -                                       const char *how)
 +static void wt_longstatus_print_other_header(struct wt_status *s,
 +                                           const char *what,
 +                                           const char *how)
  {
        const char *c = color(WT_STATUS_HEADER, s);
        status_printf_ln(s, c, "%s:", what);
        status_printf_ln(s, c, "%s", "");
  }
  
 -static void wt_status_print_trailer(struct wt_status *s)
 +static void wt_longstatus_print_trailer(struct wt_status *s)
  {
        status_printf_ln(s, color(WT_STATUS_HEADER, s), "%s", "");
  }
@@@ -305,8 -304,8 +305,8 @@@ static int maxwidth(const char *(*label
        return result;
  }
  
 -static void wt_status_print_unmerged_data(struct wt_status *s,
 -                                        struct string_list_item *it)
 +static void wt_longstatus_print_unmerged_data(struct wt_status *s,
 +                                            struct string_list_item *it)
  {
        const char *c = color(WT_STATUS_UNMERGED, s);
        struct wt_status_change_data *d = it->util;
        strbuf_release(&onebuf);
  }
  
 -static void wt_status_print_change_data(struct wt_status *s,
 -                                      int change_type,
 -                                      struct string_list_item *it)
 +static void wt_longstatus_print_change_data(struct wt_status *s,
 +                                          int change_type,
 +                                          struct string_list_item *it)
  {
        struct wt_status_change_data *d = it->util;
        const char *c = color(change_type, s);
                status = d->worktree_status;
                break;
        default:
 -              die("BUG: unhandled change_type %d in wt_status_print_change_data",
 +              die("BUG: unhandled change_type %d in wt_longstatus_print_change_data",
                    change_type);
        }
  
@@@ -435,31 -434,6 +435,31 @@@ static void wt_status_collect_changed_c
                if (S_ISGITLINK(p->two->mode))
                        d->new_submodule_commits = !!oidcmp(&p->one->oid,
                                                            &p->two->oid);
 +
 +              switch (p->status) {
 +              case DIFF_STATUS_ADDED:
 +                      d->mode_worktree = p->two->mode;
 +                      break;
 +
 +              case DIFF_STATUS_DELETED:
 +                      d->mode_index = p->one->mode;
 +                      oidcpy(&d->oid_index, &p->one->oid);
 +                      /* mode_worktree is zero for a delete. */
 +                      break;
 +
 +              case DIFF_STATUS_MODIFIED:
 +              case DIFF_STATUS_TYPE_CHANGED:
 +              case DIFF_STATUS_UNMERGED:
 +                      d->mode_index = p->one->mode;
 +                      d->mode_worktree = p->two->mode;
 +                      oidcpy(&d->oid_index, &p->one->oid);
 +                      break;
 +
 +              case DIFF_STATUS_UNKNOWN:
 +                      die("BUG: worktree status unknown???");
 +                      break;
 +              }
 +
        }
  }
  
@@@ -505,36 -479,12 +505,36 @@@ static void wt_status_collect_updated_c
                if (!d->index_status)
                        d->index_status = p->status;
                switch (p->status) {
 +              case DIFF_STATUS_ADDED:
 +                      /* Leave {mode,oid}_head zero for an add. */
 +                      d->mode_index = p->two->mode;
 +                      oidcpy(&d->oid_index, &p->two->oid);
 +                      break;
 +              case DIFF_STATUS_DELETED:
 +                      d->mode_head = p->one->mode;
 +                      oidcpy(&d->oid_head, &p->one->oid);
 +                      /* Leave {mode,oid}_index zero for a delete. */
 +                      break;
 +
                case DIFF_STATUS_COPIED:
                case DIFF_STATUS_RENAMED:
                        d->head_path = xstrdup(p->one->path);
 +                      d->score = p->score * 100 / MAX_SCORE;
 +                      /* fallthru */
 +              case DIFF_STATUS_MODIFIED:
 +              case DIFF_STATUS_TYPE_CHANGED:
 +                      d->mode_head = p->one->mode;
 +                      d->mode_index = p->two->mode;
 +                      oidcpy(&d->oid_head, &p->one->oid);
 +                      oidcpy(&d->oid_index, &p->two->oid);
                        break;
                case DIFF_STATUS_UNMERGED:
                        d->stagemask = unmerged_mask(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
 +                       * values in these fields.
 +                       */
                        break;
                }
        }
@@@ -548,7 -498,6 +548,7 @@@ static void wt_status_collect_changes_w
        setup_revisions(0, NULL, &rev, NULL);
        rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
        DIFF_OPT_SET(&rev.diffopt, DIRTY_SUBMODULES);
 +      rev.diffopt.ita_invisible_in_index = 1;
        if (!s->show_untracked_files)
                DIFF_OPT_SET(&rev.diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
        if (s->ignore_submodule_arg) {
@@@ -572,7 -521,6 +572,7 @@@ static void wt_status_collect_changes_i
        setup_revisions(0, NULL, &rev, &opt);
  
        DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);
 +      rev.diffopt.ita_invisible_in_index = 1;
        if (s->ignore_submodule_arg) {
                handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);
        } else {
@@@ -608,8 -556,6 +608,8 @@@ static void wt_status_collect_changes_i
  
                if (!ce_path_match(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) {
                if (ce_stage(ce)) {
                        d->index_status = DIFF_STATUS_UNMERGED;
                        d->stagemask |= (1 << (ce_stage(ce) - 1));
 -              }
 -              else
 +                      /*
 +                       * Don't bother setting {mode,oid}_{head,index} since the print
 +                       * code will output the stage values directly and not use the
 +                       * values in these fields.
 +                       */
 +              } 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);
 +              }
        }
  }
  
@@@ -689,7 -627,7 +689,7 @@@ void wt_status_collect(struct wt_statu
        wt_status_collect_untracked(s);
  }
  
 -static void wt_status_print_unmerged(struct wt_status *s)
 +static void wt_longstatus_print_unmerged(struct wt_status *s)
  {
        int shown_header = 0;
        int i;
                if (!d->stagemask)
                        continue;
                if (!shown_header) {
 -                      wt_status_print_unmerged_header(s);
 +                      wt_longstatus_print_unmerged_header(s);
                        shown_header = 1;
                }
 -              wt_status_print_unmerged_data(s, it);
 +              wt_longstatus_print_unmerged_data(s, it);
        }
        if (shown_header)
 -              wt_status_print_trailer(s);
 +              wt_longstatus_print_trailer(s);
  
  }
  
 -static void wt_status_print_updated(struct wt_status *s)
 +static void wt_longstatus_print_updated(struct wt_status *s)
  {
        int shown_header = 0;
        int i;
                    d->index_status == DIFF_STATUS_UNMERGED)
                        continue;
                if (!shown_header) {
 -                      wt_status_print_cached_header(s);
 +                      wt_longstatus_print_cached_header(s);
                        s->commitable = 1;
                        shown_header = 1;
                }
 -              wt_status_print_change_data(s, WT_STATUS_UPDATED, it);
 +              wt_longstatus_print_change_data(s, WT_STATUS_UPDATED, it);
        }
        if (shown_header)
 -              wt_status_print_trailer(s);
 +              wt_longstatus_print_trailer(s);
  }
  
  /*
@@@ -765,7 -703,7 +765,7 @@@ static int wt_status_check_worktree_cha
        return changes;
  }
  
 -static void wt_status_print_changed(struct wt_status *s)
 +static void wt_longstatus_print_changed(struct wt_status *s)
  {
        int i, dirty_submodules;
        int worktree_changes = wt_status_check_worktree_changes(s, &dirty_submodules);
        if (!worktree_changes)
                return;
  
 -      wt_status_print_dirty_header(s, worktree_changes < 0, dirty_submodules);
 +      wt_longstatus_print_dirty_header(s, worktree_changes < 0, dirty_submodules);
  
        for (i = 0; i < s->change.nr; i++) {
                struct wt_status_change_data *d;
                if (!d->worktree_status ||
                    d->worktree_status == DIFF_STATUS_UNMERGED)
                        continue;
 -              wt_status_print_change_data(s, WT_STATUS_CHANGED, it);
 +              wt_longstatus_print_change_data(s, WT_STATUS_CHANGED, it);
        }
 -      wt_status_print_trailer(s);
 +      wt_longstatus_print_trailer(s);
  }
  
 -static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitted)
 +static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncommitted)
  {
        struct child_process sm_summary = CHILD_PROCESS_INIT;
        struct strbuf cmd_stdout = STRBUF_INIT;
        strbuf_release(&summary);
  }
  
 -static void wt_status_print_other(struct wt_status *s,
 -                                struct string_list *l,
 -                                const char *what,
 -                                const char *how)
 +static void wt_longstatus_print_other(struct wt_status *s,
 +                                    struct string_list *l,
 +                                    const char *what,
 +                                    const char *how)
  {
        int i;
        struct strbuf buf = STRBUF_INIT;
        if (!l->nr)
                return;
  
 -      wt_status_print_other_header(s, what, how);
 +      wt_longstatus_print_other_header(s, what, how);
  
        for (i = 0; i < l->nr; i++) {
                struct string_list_item *it;
@@@ -907,7 -845,7 +907,7 @@@ void wt_status_add_cut_line(FILE *fp
        strbuf_release(&buf);
  }
  
 -static void wt_status_print_verbose(struct wt_status *s)
 +static void wt_longstatus_print_verbose(struct wt_status *s)
  {
        struct rev_info rev;
        struct setup_revision_opt opt;
  
        init_revisions(&rev, NULL);
        DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
 +      rev.diffopt.ita_invisible_in_index = 1;
  
        memset(&opt, 0, sizeof(opt));
        opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference;
        if (s->verbose > 1 && s->commitable) {
                /* print_updated() printed a header, so do we */
                if (s->fp != stdout)
 -                      wt_status_print_trailer(s);
 +                      wt_longstatus_print_trailer(s);
                status_printf_ln(s, c, _("Changes to be committed:"));
                rev.diffopt.a_prefix = "c/";
                rev.diffopt.b_prefix = "i/";
        }
  }
  
 -static void wt_status_print_tracking(struct wt_status *s)
 +static void wt_longstatus_print_tracking(struct wt_status *s)
  {
        struct strbuf sb = STRBUF_INIT;
        const char *cp, *ep, *branch_name;
@@@ -1025,7 -962,7 +1025,7 @@@ static void show_merge_in_progress(stru
                        status_printf_ln(s, color,
                                _("  (use \"git commit\" to conclude merge)"));
        }
 -      wt_status_print_trailer(s);
 +      wt_longstatus_print_trailer(s);
  }
  
  static void show_am_in_progress(struct wt_status *s,
                status_printf_ln(s, color,
                        _("  (use \"git am --abort\" to restore the original branch)"));
        }
 -      wt_status_print_trailer(s);
 +      wt_longstatus_print_trailer(s);
  }
  
  static char *read_line_from_git_path(const char *filename)
@@@ -1115,16 -1052,16 +1115,16 @@@ static void abbrev_sha1_in_line(struct 
  
        split = strbuf_split_max(line, ' ', 3);
        if (split[0] && split[1]) {
 -              unsigned char sha1[20];
 +              struct object_id oid;
  
                /*
                 * strbuf_split_max left a space. Trim it and re-add
                 * it after abbreviation.
                 */
                strbuf_trim(split[1]);
 -              if (!get_sha1(split[1]->buf, sha1)) {
 +              if (!get_oid(split[1]->buf, &oid)) {
                        strbuf_reset(split[1]);
 -                      strbuf_add_unique_abbrev(split[1], sha1,
 +                      strbuf_add_unique_abbrev(split[1], oid.hash,
                                                 DEFAULT_ABBREV);
                        strbuf_addch(split[1], ' ');
                        strbuf_reset(line);
        strbuf_list_free(split);
  }
  
 -static void read_rebase_todolist(const char *fname, struct string_list *lines)
 +static int read_rebase_todolist(const char *fname, struct string_list *lines)
  {
        struct strbuf line = STRBUF_INIT;
        FILE *f = fopen(git_path("%s", fname), "r");
  
 -      if (!f)
 +      if (!f) {
 +              if (errno == ENOENT)
 +                      return -1;
                die_errno("Could not open file %s for reading",
                          git_path("%s", fname));
 +      }
        while (!strbuf_getline_lf(&line, f)) {
                if (line.len && line.buf[0] == comment_line_char)
                        continue;
                abbrev_sha1_in_line(&line);
                string_list_append(lines, line.buf);
        }
 +      return 0;
  }
  
  static void show_rebase_information(struct wt_status *s,
                struct string_list yet_to_do = STRING_LIST_INIT_DUP;
  
                read_rebase_todolist("rebase-merge/done", &have_done);
 -              read_rebase_todolist("rebase-merge/git-rebase-todo", &yet_to_do);
 -
 +              if (read_rebase_todolist("rebase-merge/git-rebase-todo",
 +                                       &yet_to_do))
 +                      status_printf_ln(s, color,
 +                              _("git-rebase-todo is missing."));
                if (have_done.nr == 0)
                        status_printf_ln(s, color, _("No commands done."));
                else {
@@@ -1276,7 -1207,7 +1276,7 @@@ static void show_rebase_in_progress(str
                                _("  (use \"git rebase --continue\" once you are satisfied with your changes)"));
                }
        }
 -      wt_status_print_trailer(s);
 +      wt_longstatus_print_trailer(s);
  }
  
  static void show_cherry_pick_in_progress(struct wt_status *s,
                status_printf_ln(s, color,
                        _("  (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"));
        }
 -      wt_status_print_trailer(s);
 +      wt_longstatus_print_trailer(s);
  }
  
  static void show_revert_in_progress(struct wt_status *s,
                status_printf_ln(s, color,
                        _("  (use \"git revert --abort\" to cancel the revert operation)"));
        }
 -      wt_status_print_trailer(s);
 +      wt_longstatus_print_trailer(s);
  }
  
  static void show_bisect_in_progress(struct wt_status *s,
        if (s->hints)
                status_printf_ln(s, color,
                        _("  (use \"git bisect reset\" to get back to the original branch)"));
 -      wt_status_print_trailer(s);
 +      wt_longstatus_print_trailer(s);
  }
  
  /*
  static char *get_branch(const struct worktree *wt, const char *path)
  {
        struct strbuf sb = STRBUF_INIT;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        const char *branch_name;
  
        if (strbuf_read_file(&sb, worktree_git_path(wt, "%s", path), 0) <= 0)
                strbuf_remove(&sb, 0, branch_name - sb.buf);
        else if (starts_with(sb.buf, "refs/"))
                ;
 -      else if (!get_sha1_hex(sb.buf, sha1)) {
 +      else if (!get_oid_hex(sb.buf, &oid)) {
                strbuf_reset(&sb);
 -              strbuf_add_unique_abbrev(&sb, sha1, DEFAULT_ABBREV);
 +              strbuf_add_unique_abbrev(&sb, oid.hash, DEFAULT_ABBREV);
        } else if (!strcmp(sb.buf, "detached HEAD")) /* rebase */
                goto got_nothing;
        else                    /* bisect */
@@@ -1370,10 -1301,10 +1370,10 @@@ got_nothing
  
  struct grab_1st_switch_cbdata {
        struct strbuf buf;
 -      unsigned char nsha1[20];
 +      struct object_id noid;
  };
  
 -static int grab_1st_switch(unsigned char *osha1, unsigned char *nsha1,
 +static int grab_1st_switch(struct object_id *ooid, struct object_id *noid,
                           const char *email, unsigned long timestamp, int tz,
                           const char *message, void *cb_data)
  {
                return 0;
        target += strlen(" to ");
        strbuf_reset(&cb->buf);
 -      hashcpy(cb->nsha1, nsha1);
 +      oidcpy(&cb->noid, noid);
        end = strchrnul(target, '\n');
        strbuf_add(&cb->buf, target, end - target);
        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, nsha1, DEFAULT_ABBREV);
 +              strbuf_add_unique_abbrev(&cb->buf, noid->hash, DEFAULT_ABBREV);
        }
        return 1;
  }
@@@ -1402,7 -1333,7 +1402,7 @@@ static void wt_status_get_detached_from
  {
        struct grab_1st_switch_cbdata cb;
        struct commit *commit;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        char *ref = NULL;
  
        strbuf_init(&cb.buf, 0);
                return;
        }
  
 -      if (dwim_ref(cb.buf.buf, cb.buf.len, sha1, &ref) == 1 &&
 +      if (dwim_ref(cb.buf.buf, cb.buf.len, oid.hash, &ref) == 1 &&
            /* sha1 is a commit? match without further lookup */
 -          (!hashcmp(cb.nsha1, sha1) ||
 +          (!oidcmp(&cb.noid, &oid) ||
             /* perhaps sha1 is a tag, try to dereference to a commit */
 -           ((commit = lookup_commit_reference_gently(sha1, 1)) != NULL &&
 -            !hashcmp(cb.nsha1, commit->object.oid.hash)))) {
 +           ((commit = lookup_commit_reference_gently(oid.hash, 1)) != NULL &&
 +            !oidcmp(&cb.noid, &commit->object.oid)))) {
                const char *from = ref;
                if (!skip_prefix(from, "refs/tags/", &from))
                        skip_prefix(from, "refs/remotes/", &from);
                state->detached_from = xstrdup(from);
        } else
                state->detached_from =
 -                      xstrdup(find_unique_abbrev(cb.nsha1, DEFAULT_ABBREV));
 -      hashcpy(state->detached_sha1, cb.nsha1);
 -      state->detached_at = !get_sha1("HEAD", sha1) &&
 -                           !hashcmp(sha1, state->detached_sha1);
 +                      xstrdup(find_unique_abbrev(cb.noid.hash, DEFAULT_ABBREV));
 +      hashcpy(state->detached_sha1, cb.noid.hash);
 +      state->detached_at = !get_oid("HEAD", &oid) &&
 +                           !hashcmp(oid.hash, state->detached_sha1);
  
        free(ref);
        strbuf_release(&cb.buf);
@@@ -1476,30 -1407,30 +1476,30 @@@ void wt_status_get_state(struct wt_stat
                         int get_detached_from)
  {
        struct stat st;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
        if (!stat(git_path_merge_head(), &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) &&
 -                      !get_sha1("CHERRY_PICK_HEAD", sha1)) {
 +                      !get_oid("CHERRY_PICK_HEAD", &oid)) {
                state->cherry_pick_in_progress = 1;
 -              hashcpy(state->cherry_pick_head_sha1, sha1);
 +              hashcpy(state->cherry_pick_head_sha1, oid.hash);
        }
        wt_status_check_bisect(NULL, state);
        if (!stat(git_path_revert_head(), &st) &&
 -          !get_sha1("REVERT_HEAD", sha1)) {
 +          !get_oid("REVERT_HEAD", &oid)) {
                state->revert_in_progress = 1;
 -              hashcpy(state->revert_head_sha1, sha1);
 +              hashcpy(state->revert_head_sha1, oid.hash);
        }
  
        if (get_detached_from)
                wt_status_get_detached_from(state);
  }
  
 -static void wt_status_print_state(struct wt_status *s,
 -                                struct wt_status_state *state)
 +static void wt_longstatus_print_state(struct wt_status *s,
 +                                    struct wt_status_state *state)
  {
        const char *state_color = color(WT_STATUS_HEADER, s);
        if (state->merge_in_progress)
                show_bisect_in_progress(s, state, state_color);
  }
  
 -void wt_status_print(struct wt_status *s)
 +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);
                status_printf_more(s, branch_status_color, "%s", on_what);
                status_printf_more(s, branch_color, "%s\n", branch_name);
                if (!s->is_initial)
 -                      wt_status_print_tracking(s);
 +                      wt_longstatus_print_tracking(s);
        }
  
 -      wt_status_print_state(s, &state);
 +      wt_longstatus_print_state(s, &state);
        free(state.branch);
        free(state.onto);
        free(state.detached_from);
                status_printf_ln(s, color(WT_STATUS_HEADER, s), "%s", "");
        }
  
 -      wt_status_print_updated(s);
 -      wt_status_print_unmerged(s);
 -      wt_status_print_changed(s);
 +      wt_longstatus_print_updated(s);
 +      wt_longstatus_print_unmerged(s);
 +      wt_longstatus_print_changed(s);
        if (s->submodule_summary &&
            (!s->ignore_submodule_arg ||
             strcmp(s->ignore_submodule_arg, "all"))) {
 -              wt_status_print_submodule_summary(s, 0);  /* staged */
 -              wt_status_print_submodule_summary(s, 1);  /* unstaged */
 +              wt_longstatus_print_submodule_summary(s, 0);  /* staged */
 +              wt_longstatus_print_submodule_summary(s, 1);  /* unstaged */
        }
        if (s->show_untracked_files) {
 -              wt_status_print_other(s, &s->untracked, _("Untracked files"), "add");
 +              wt_longstatus_print_other(s, &s->untracked, _("Untracked files"), "add");
                if (s->show_ignored_files)
 -                      wt_status_print_other(s, &s->ignored, _("Ignored files"), "add -f");
 +                      wt_longstatus_print_other(s, &s->ignored, _("Ignored files"), "add -f");
                if (advice_status_u_option && 2000 < s->untracked_in_ms) {
                        status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                        ? _(" (use -u option to show untracked files)") : "");
  
        if (s->verbose)
 -              wt_status_print_verbose(s);
 +              wt_longstatus_print_verbose(s);
        if (!s->commitable) {
                if (s->amend)
                        status_printf_ln(s, GIT_COLOR_NORMAL, _("No changes"));
@@@ -1730,12 -1661,14 +1730,14 @@@ static void wt_shortstatus_print_tracki
                return;
        branch_name = s->branch;
  
+ #define LABEL(string) (s->no_gettext ? (string) : _(string))
        if (s->is_initial)
-               color_fprintf(s->fp, header_color, _("Initial commit on "));
+               color_fprintf(s->fp, header_color, LABEL(N_("Initial commit on ")));
  
        if (!strcmp(s->branch, "HEAD")) {
                color_fprintf(s->fp, color(WT_STATUS_NOBRANCH, s), "%s",
-                             _("HEAD (no branch)"));
+                             LABEL(N_("HEAD (no branch)")));
                goto conclude;
        }
  
        if (!upstream_is_gone && !num_ours && !num_theirs)
                goto conclude;
  
- #define LABEL(string) (s->no_gettext ? (string) : _(string))
        color_fprintf(s->fp, header_color, " [");
        if (upstream_is_gone) {
                color_fprintf(s->fp, header_color, LABEL(N_("gone")));
        fputc(s->null_termination ? '\0' : '\n', s->fp);
  }
  
 -void wt_shortstatus_print(struct wt_status *s)
 +static void wt_shortstatus_print(struct wt_status *s)
  {
        int i;
  
        }
  }
  
 -void wt_porcelain_print(struct wt_status *s)
 +static void wt_porcelain_print(struct wt_status *s)
  {
        s->use_color = 0;
        s->relative_paths = 0;
        s->no_gettext = 1;
        wt_shortstatus_print(s);
  }
 +
 +/*
 + * Print branch information for porcelain v2 output.  These lines
 + * are printed when the '--branch' parameter is given.
 + *
 + *    # branch.oid <commit><eol>
 + *    # branch.head <head><eol>
 + *   [# branch.upstream <upstream><eol>
 + *   [# branch.ab +<ahead> -<behind><eol>]]
 + *
 + *      <commit> ::= the current commit hash or the the literal
 + *                   "(initial)" to indicate an initialized repo
 + *                   with no commits.
 + *
 + *        <head> ::= <branch_name> the current branch name or
 + *                   "(detached)" literal when detached head or
 + *                   "(unknown)" when something is wrong.
 + *
 + *    <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.
 + *
 + *
 + * The end-of-line is defined by the -z flag.
 + *
 + *                 <eol> ::= NUL when -z,
 + *                           LF when NOT -z.
 + *
 + */
 +static void wt_porcelain_v2_print_tracking(struct wt_status *s)
 +{
 +      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 (!s->branch)
 +              fprintf(s->fp, "# branch.head %s%c", "(unknown)", eol);
 +      else {
 +              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;
 +                      else
 +                              branch_name = "";
 +              } else {
 +                      branch_name = NULL;
 +                      skip_prefix(s->branch, "refs/heads/", &branch_name);
 +
 +                      fprintf(s->fp, "# branch.head %s%c", branch_name, eol);
 +              }
 +
 +              /* 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);
 +              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);
 +              }
 +      }
 +
 +      free(state.branch);
 +      free(state.onto);
 +      free(state.detached_from);
 +}
 +
 +/*
 + * Convert various submodule status values into a
 + * fixed-length string of characters in the buffer provided.
 + */
 +static void wt_porcelain_v2_submodule_state(
 +      struct wt_status_change_data *d,
 +      char sub[5])
 +{
 +      if (S_ISGITLINK(d->mode_head) ||
 +              S_ISGITLINK(d->mode_index) ||
 +              S_ISGITLINK(d->mode_worktree)) {
 +              sub[0] = 'S';
 +              sub[1] = d->new_submodule_commits ? 'C' : '.';
 +              sub[2] = (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED) ? 'M' : '.';
 +              sub[3] = (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) ? 'U' : '.';
 +      } else {
 +              sub[0] = 'N';
 +              sub[1] = '.';
 +              sub[2] = '.';
 +              sub[3] = '.';
 +      }
 +      sub[4] = 0;
 +}
 +
 +/*
 + * 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)
 +{
 +      struct wt_status_change_data *d = it->util;
 +
 +      if (!d->index_status) {
 +              /*
 +               * This entry is unchanged in the index (relative to the head).
 +               * Therefore, the collect_updated_cb was never called for this
 +               * entry (during the head-vs-index scan) and so the head column
 +               * fields were never set.
 +               *
 +               * We must have data for the index column (from the
 +               * index-vs-worktree scan (otherwise, this entry should not be
 +               * in the list of changes)).
 +               *
 +               * Copy index column fields to the head column, so that our
 +               * output looks complete.
 +               */
 +              assert(d->mode_head == 0);
 +              d->mode_head = d->mode_index;
 +              oidcpy(&d->oid_head, &d->oid_index);
 +      }
 +
 +      if (!d->worktree_status) {
 +              /*
 +               * This entry is unchanged in the worktree (relative to the index).
 +               * Therefore, the collect_changed_cb was never called for this entry
 +               * (during the index-vs-worktree scan) and so the worktree column
 +               * fields were never set.
 +               *
 +               * We must have data for the index column (from the head-vs-index
 +               * scan).
 +               *
 +               * Copy the index column fields to the worktree column so that
 +               * our output looks complete.
 +               *
 +               * Note that we only have a mode field in the worktree column
 +               * because the scan code tries really hard to not have to compute it.
 +               */
 +              assert(d->mode_worktree == 0);
 +              d->mode_worktree = d->mode_index;
 +      }
 +}
 +
 +/*
 + * Print porcelain v2 info for tracked entries with changes.
 + */
 +static void wt_porcelain_v2_print_changed_entry(
 +      struct string_list_item *it,
 +      struct wt_status *s)
 +{
 +      struct wt_status_change_data *d = it->util;
 +      struct strbuf buf_index = STRBUF_INIT;
 +      struct strbuf buf_head = STRBUF_INIT;
 +      const char *path_index = NULL;
 +      const char *path_head = NULL;
 +      char key[3];
 +      char submodule_token[5];
 +      char sep_char, eol_char;
 +
 +      wt_porcelain_v2_fix_up_changed(it, s);
 +      wt_porcelain_v2_submodule_state(d, submodule_token);
 +
 +      key[0] = d->index_status ? d->index_status : '.';
 +      key[1] = d->worktree_status ? d->worktree_status : '.';
 +      key[2] = 0;
 +
 +      if (s->null_termination) {
 +              /*
 +               * In -z mode, we DO NOT C-quote pathnames.  Current path is ALWAYS first.
 +               * A single NUL character separates them.
 +               */
 +              sep_char = '\0';
 +              eol_char = '\0';
 +              path_index = it->string;
 +              path_head = d->head_path;
 +      } else {
 +              /*
 +               * Path(s) are C-quoted if necessary. Current path is ALWAYS first.
 +               * The source path is only present when necessary.
 +               * A single TAB separates them (because paths can contain spaces
 +               * which are not escaped and C-quoting does escape TAB characters).
 +               */
 +              sep_char = '\t';
 +              eol_char = '\n';
 +              path_index = quote_path(it->string, s->prefix, &buf_index);
 +              if (d->head_path)
 +                      path_head = quote_path(d->head_path, s->prefix, &buf_head);
 +      }
 +
 +      if (path_head)
 +              fprintf(s->fp, "2 %s %s %06o %06o %06o %s %s %c%d %s%c%s%c",
 +                              key, submodule_token,
 +                              d->mode_head, d->mode_index, d->mode_worktree,
 +                              oid_to_hex(&d->oid_head), oid_to_hex(&d->oid_index),
 +                              key[0], d->score,
 +                              path_index, sep_char, path_head, eol_char);
 +      else
 +              fprintf(s->fp, "1 %s %s %06o %06o %06o %s %s %s%c",
 +                              key, submodule_token,
 +                              d->mode_head, d->mode_index, d->mode_worktree,
 +                              oid_to_hex(&d->oid_head), oid_to_hex(&d->oid_index),
 +                              path_index, eol_char);
 +
 +      strbuf_release(&buf_index);
 +      strbuf_release(&buf_head);
 +}
 +
 +/*
 + * Print porcelain v2 status info for unmerged entries.
 + */
 +static void wt_porcelain_v2_print_unmerged_entry(
 +      struct string_list_item *it,
 +      struct wt_status *s)
 +{
 +      struct wt_status_change_data *d = it->util;
 +      const struct cache_entry *ce;
 +      struct strbuf buf_index = STRBUF_INIT;
 +      const char *path_index = NULL;
 +      int pos, stage, sum;
 +      struct {
 +              int mode;
 +              struct object_id oid;
 +      } stages[3];
 +      char *key;
 +      char submodule_token[5];
 +      char unmerged_prefix = 'u';
 +      char eol_char = s->null_termination ? '\0' : '\n';
 +
 +      wt_porcelain_v2_submodule_state(d, submodule_token);
 +
 +      switch (d->stagemask) {
 +      case 1: key = "DD"; break; /* both deleted */
 +      case 2: key = "AU"; break; /* added by us */
 +      case 3: key = "UD"; break; /* deleted by them */
 +      case 4: key = "UA"; break; /* added by them */
 +      case 5: key = "DU"; break; /* deleted by us */
 +      case 6: key = "AA"; break; /* both added */
 +      case 7: key = "UU"; break; /* both modified */
 +      default:
 +              die("BUG: unhandled unmerged status %x", d->stagemask);
 +      }
 +
 +      /*
 +       * Disregard d.aux.porcelain_v2 data that we accumulated
 +       * for the head and index columns during the scans and
 +       * replace with the actual stage data.
 +       *
 +       * Note that this is a last-one-wins for each the individual
 +       * stage [123] columns in the event of multiple cache entries
 +       * for same stage.
 +       */
 +      memset(stages, 0, sizeof(stages));
 +      sum = 0;
 +      pos = cache_name_pos(it->string, strlen(it->string));
 +      assert(pos < 0);
 +      pos = -pos-1;
 +      while (pos < active_nr) {
 +              ce = active_cache[pos++];
 +              stage = ce_stage(ce);
 +              if (strcmp(ce->name, it->string) || !stage)
 +                      break;
 +              stages[stage - 1].mode = ce->ce_mode;
 +              oidcpy(&stages[stage - 1].oid, &ce->oid);
 +              sum |= (1 << (stage - 1));
 +      }
 +      if (sum != d->stagemask)
 +              die("BUG: observed stagemask 0x%x != expected stagemask 0x%x", sum, d->stagemask);
 +
 +      if (s->null_termination)
 +              path_index = it->string;
 +      else
 +              path_index = quote_path(it->string, s->prefix, &buf_index);
 +
 +      fprintf(s->fp, "%c %s %s %06o %06o %06o %06o %s %s %s %s%c",
 +                      unmerged_prefix, key, submodule_token,
 +                      stages[0].mode, /* stage 1 */
 +                      stages[1].mode, /* stage 2 */
 +                      stages[2].mode, /* stage 3 */
 +                      d->mode_worktree,
 +                      oid_to_hex(&stages[0].oid), /* stage 1 */
 +                      oid_to_hex(&stages[1].oid), /* stage 2 */
 +                      oid_to_hex(&stages[2].oid), /* stage 3 */
 +                      path_index,
 +                      eol_char);
 +
 +      strbuf_release(&buf_index);
 +}
 +
 +/*
 + * Print porcelain V2 status info for untracked and ignored entries.
 + */
 +static void wt_porcelain_v2_print_other(
 +      struct string_list_item *it,
 +      struct wt_status *s,
 +      char prefix)
 +{
 +      struct strbuf buf = STRBUF_INIT;
 +      const char *path;
 +      char eol_char;
 +
 +      if (s->null_termination) {
 +              path = it->string;
 +              eol_char = '\0';
 +      } else {
 +              path = quote_path(it->string, s->prefix, &buf);
 +              eol_char = '\n';
 +      }
 +
 +      fprintf(s->fp, "%c %s%c", prefix, path, eol_char);
 +
 +      strbuf_release(&buf);
 +}
 +
 +/*
 + * Print porcelain V2 status.
 + *
 + * [<v2_branch>]
 + * [<v2_changed_items>]*
 + * [<v2_unmerged_items>]*
 + * [<v2_untracked_items>]*
 + * [<v2_ignored_items>]*
 + *
 + */
 +static void wt_porcelain_v2_print(struct wt_status *s)
 +{
 +      struct wt_status_change_data *d;
 +      struct string_list_item *it;
 +      int i;
 +
 +      if (s->show_branch)
 +              wt_porcelain_v2_print_tracking(s);
 +
 +      for (i = 0; i < s->change.nr; i++) {
 +              it = &(s->change.items[i]);
 +              d = it->util;
 +              if (!d->stagemask)
 +                      wt_porcelain_v2_print_changed_entry(it, s);
 +      }
 +
 +      for (i = 0; i < s->change.nr; i++) {
 +              it = &(s->change.items[i]);
 +              d = it->util;
 +              if (d->stagemask)
 +                      wt_porcelain_v2_print_unmerged_entry(it, s);
 +      }
 +
 +      for (i = 0; i < s->untracked.nr; i++) {
 +              it = &(s->untracked.items[i]);
 +              wt_porcelain_v2_print_other(it, s, '?');
 +      }
 +
 +      for (i = 0; i < s->ignored.nr; i++) {
 +              it = &(s->ignored.items[i]);
 +              wt_porcelain_v2_print_other(it, s, '!');
 +      }
 +}
 +
 +void wt_status_print(struct wt_status *s)
 +{
 +      switch (s->status_format) {
 +      case STATUS_FORMAT_SHORT:
 +              wt_shortstatus_print(s);
 +              break;
 +      case STATUS_FORMAT_PORCELAIN:
 +              wt_porcelain_print(s);
 +              break;
 +      case STATUS_FORMAT_PORCELAIN_V2:
 +              wt_porcelain_v2_print(s);
 +              break;
 +      case STATUS_FORMAT_UNSPECIFIED:
 +              die("BUG: finalize_deferred_config() should have been called");
 +              break;
 +      case STATUS_FORMAT_NONE:
 +      case STATUS_FORMAT_LONG:
 +              wt_longstatus_print(s);
 +              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, fd;
 +
 +      fd = hold_locked_index(lock_file, 0);
 +      refresh_cache(REFRESH_QUIET);
 +      if (0 <= fd)
 +              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;
 +}