status: collect per-file data for --porcelain=v2

Collect extra per-file data for porcelain V2 format. The output of `git status --porcelain` leaves out many details about the current status that clients might like to have. This can force them to be less efficient as they may need to launch secondary commands (and try to match the logic within git) to accumulate this extra information. For example, a GUI IDE might want the file mode to display the correct icon for a changed item (without having to stat it afterwards). Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff Hostetler committed Aug 11, 2016 at 10:45 UTC 1ecdecce621009a4d039d061d514056501d0ed8f
3 files changed +69 -2
builtin/commit.c
+3
@@ -153,6 +153,8 @@ static int opt_parse_porcelain(const struct option *opt, const char *arg, int un
153 *value = STATUS_FORMAT_PORCELAIN;
154 else if (!strcmp(arg, "v1") || !strcmp(arg, "1"))
155 *value = STATUS_FORMAT_PORCELAIN;
156 + else if (!strcmp(arg, "v2") || !strcmp(arg, "2"))
157 + *value = STATUS_FORMAT_PORCELAIN_V2;
158 else
159 die("unsupported porcelain version '%s'", arg);
160
@@ -1104,6 +1106,7 @@ static struct status_deferred_config {
1106 static void finalize_deferred_config(struct wt_status *s)
1107 {
1108 int use_deferred_config = (status_format != STATUS_FORMAT_PORCELAIN &&
1109 + status_format != STATUS_FORMAT_PORCELAIN_V2 &&
1110 !s->null_termination);
1111
1112 if (s->null_termination) {
wt-status.c
+62 -2
@@ -434,6 +434,31 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
434 if (S_ISGITLINK(p->two->mode))
435 d->new_submodule_commits = !!oidcmp(&p->one->oid,
436 &p->two->oid);
437 +
438 + switch (p->status) {
439 + case DIFF_STATUS_ADDED:
440 + die("BUG: worktree status add???");
441 + break;
442 +
443 + case DIFF_STATUS_DELETED:
444 + d->mode_index = p->one->mode;
445 + oidcpy(&d->oid_index, &p->one->oid);
446 + /* mode_worktree is zero for a delete. */
447 + break;
448 +
449 + case DIFF_STATUS_MODIFIED:
450 + case DIFF_STATUS_TYPE_CHANGED:
451 + case DIFF_STATUS_UNMERGED:
452 + d->mode_index = p->one->mode;
453 + d->mode_worktree = p->two->mode;
454 + oidcpy(&d->oid_index, &p->one->oid);
455 + break;
456 +
457 + case DIFF_STATUS_UNKNOWN:
458 + die("BUG: worktree status unknown???");
459 + break;
460 + }
461 +
462 }
463 }
464
@@ -479,12 +504,36 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
504 if (!d->index_status)
505 d->index_status = p->status;
506 switch (p->status) {
507 + case DIFF_STATUS_ADDED:
508 + /* Leave {mode,oid}_head zero for an add. */
509 + d->mode_index = p->two->mode;
510 + oidcpy(&d->oid_index, &p->two->oid);
511 + break;
512 + case DIFF_STATUS_DELETED:
513 + d->mode_head = p->one->mode;
514 + oidcpy(&d->oid_head, &p->one->oid);
515 + /* Leave {mode,oid}_index zero for a delete. */
516 + break;
517 +
518 case DIFF_STATUS_COPIED:
519 case DIFF_STATUS_RENAMED:
520 d->head_path = xstrdup(p->one->path);
521 + d->score = p->score * 100 / MAX_SCORE;
522 + /* fallthru */
523 + case DIFF_STATUS_MODIFIED:
524 + case DIFF_STATUS_TYPE_CHANGED:
525 + d->mode_head = p->one->mode;
526 + d->mode_index = p->two->mode;
527 + oidcpy(&d->oid_head, &p->one->oid);
528 + oidcpy(&d->oid_index, &p->two->oid);
529 break;
530 case DIFF_STATUS_UNMERGED:
531 d->stagemask = unmerged_mask(p->two->path);
532 + /*
533 + * Don't bother setting {mode,oid}_{head,index} since the print
534 + * code will output the stage values directly and not use the
535 + * values in these fields.
536 + */
537 break;
538 }
539 }
@@ -565,9 +614,17 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
614 if (ce_stage(ce)) {
615 d->index_status = DIFF_STATUS_UNMERGED;
616 d->stagemask |= (1 << (ce_stage(ce) - 1));
568 - }
569 - else
617 + /*
618 + * Don't bother setting {mode,oid}_{head,index} since the print
619 + * code will output the stage values directly and not use the
620 + * values in these fields.
621 + */
622 + } else {
623 d->index_status = DIFF_STATUS_ADDED;
624 + /* Leave {mode,oid}_head zero for adds. */
625 + d->mode_index = ce->ce_mode;
626 + hashcpy(d->oid_index.hash, ce->sha1);
627 + }
628 }
629 }
630
@@ -1764,6 +1821,9 @@ void wt_status_print(struct wt_status *s)
1821 case STATUS_FORMAT_PORCELAIN:
1822 wt_porcelain_print(s);
1823 break;
1824 + case STATUS_FORMAT_PORCELAIN_V2:
1825 + /* TODO */
1826 + break;
1827 case STATUS_FORMAT_UNSPECIFIED:
1828 die("BUG: finalize_deferred_config() should have been called");
1829 break;
wt-status.h
+4
@@ -38,6 +38,9 @@ struct wt_status_change_data {
38 int worktree_status;
39 int index_status;
40 int stagemask;
41 + int score;
42 + int mode_head, mode_index, mode_worktree;
43 + struct object_id oid_head, oid_index;
44 char *head_path;
45 unsigned dirty_submodule : 2;
46 unsigned new_submodule_commits : 1;
@@ -48,6 +51,7 @@ enum wt_status_format {
51 STATUS_FORMAT_LONG,
52 STATUS_FORMAT_SHORT,
53 STATUS_FORMAT_PORCELAIN,
54 + STATUS_FORMAT_PORCELAIN_V2,
55
56 STATUS_FORMAT_UNSPECIFIED
57 };