git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 4/8] status: per-file data collection for --porcelain=v2

From
Jeff Hostetler <jeffhost@microsoft.com>
Date
Jul 25, 2016, 19:25 UTC
Message-ID
<1469474750-49075-5-git-send-email-jeffhost@microsoft.com>
In-Reply-To
<1469474750-49075-1-git-send-email-jeffhost@microsoft.com>

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 need the file mode to display the correct icon for a changed item.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
---
 builtin/commit.c |   3 ++
 wt-status.c      | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 wt-status.h      |  17 +++++++++
 3 files changed, 133 insertions(+), 1 deletion(-)
diff --git a/builtin/commit.c b/builtin/commit.c
index e6bbb12..5b9efd2 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -153,6 +153,8 @@ static int opt_parse_porcelain(const struct option *opt, const char *arg, int un
 		*value = STATUS_FORMAT_PORCELAIN;
 	else if (!strcmp(arg, "v1"))
 		*value = STATUS_FORMAT_PORCELAIN;
+	else if (!strcmp(arg, "v2"))
+		*value = STATUS_FORMAT_PORCELAIN_V2;
 	else
 		die("unsupported porcelain version");
 
@@ -1104,6 +1106,7 @@ static struct status_deferred_config {
 static void finalize_deferred_config(struct wt_status *s)
 {
 	int use_deferred_config = (status_format != STATUS_FORMAT_PORCELAIN &&
+				   status_format != STATUS_FORMAT_PORCELAIN_V2 &&
 				   !s->null_termination);
 
 	if (s->null_termination) {
diff --git a/wt-status.c b/wt-status.c
index a9031e4..54aedc1 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -406,6 +406,110 @@ static void wt_longstatus_print_change_data(struct wt_status *s,
 	strbuf_release(&twobuf);
 }
 
+static void aux_updated_entry_porcelain_v2(
+	struct wt_status *s,
+	struct wt_status_change_data *d,
+	struct diff_filepair *p)
+{
+	switch (p->status) {
+	case DIFF_STATUS_ADDED:
+		/* {mode,sha1}_head are zero for an add. */
+		d->aux.porcelain_v2.mode_index = p->two->mode;
+		oidcpy(&d->aux.porcelain_v2.oid_index, &p->two->oid);
+		break;
+
+	case DIFF_STATUS_DELETED:
+		d->aux.porcelain_v2.mode_head = p->one->mode;
+		oidcpy(&d->aux.porcelain_v2.oid_head, &p->one->oid);
+		/* {mode,oid}_index are zero for a delete. */
+		break;
+
+	case DIFF_STATUS_RENAMED:
+		d->aux.porcelain_v2.rename_score = p->score * 100 / MAX_SCORE;
+	case DIFF_STATUS_COPIED:
+	case DIFF_STATUS_MODIFIED:
+	case DIFF_STATUS_TYPE_CHANGED:
+	case DIFF_STATUS_UNMERGED:
+		d->aux.porcelain_v2.mode_head = p->one->mode;
+		d->aux.porcelain_v2.mode_index = p->two->mode;
+		oidcpy(&d->aux.porcelain_v2.oid_head, &p->one->oid);
+		oidcpy(&d->aux.porcelain_v2.oid_index, &p->two->oid);
+		break;
+
+	case DIFF_STATUS_UNKNOWN:
+		die("BUG: index status unknown");
+		break;
+	}
+}
+
+/* Save aux info for a head-vs-index change. */
+static void aux_updated_entry(
+	struct wt_status *s,
+	struct wt_status_change_data *d,
+	struct diff_filepair *p)
+{
+	if (s->status_format == STATUS_FORMAT_PORCELAIN_V2)
+		aux_updated_entry_porcelain_v2(s, d, p);
+}
+
+static void aux_changed_entry_porcelain_v2(
+	struct wt_status *s,
+	struct wt_status_change_data *d,
+	const struct diff_filepair *p)
+{
+	switch (p->status) {
+	case DIFF_STATUS_ADDED:
+		die("BUG: worktree status add???");
+		break;
+
+	case DIFF_STATUS_DELETED:
+		d->aux.porcelain_v2.mode_index = p->one->mode;
+		oidcpy(&d->aux.porcelain_v2.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->aux.porcelain_v2.mode_index = p->one->mode;
+		d->aux.porcelain_v2.mode_worktree = p->two->mode;
+		oidcpy(&d->aux.porcelain_v2.oid_index, &p->one->oid);
+		break;
+
+	case DIFF_STATUS_UNKNOWN:
+		die("BUG: worktree status unknown???");
+		break;
+	}
+}
+
+/* Save aux info for an index-vs-worktree change. */
+static void aux_changed_entry(
+	struct wt_status *s,
+	struct wt_status_change_data *d,
+	struct diff_filepair *p)
+{
+	if (s->status_format == STATUS_FORMAT_PORCELAIN_V2)
+		aux_changed_entry_porcelain_v2(s, d, p);
+}
+
+static void aux_initial_entry_porcelain_v2(
+	struct wt_status *s,
+	struct wt_status_change_data *d,
+	const struct cache_entry *ce)
+{
+	d->aux.porcelain_v2.mode_index = ce->ce_mode;
+	hashcpy(d->aux.porcelain_v2.oid_index.hash, ce->sha1);
+}
+
+static void aux_initial_entry(
+	struct wt_status *s,
+	struct wt_status_change_data *d,
+	const struct cache_entry *ce)
+{
+	if (s->status_format == STATUS_FORMAT_PORCELAIN_V2)
+		aux_initial_entry_porcelain_v2(s, d, ce);
+}
+
 static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
 					 struct diff_options *options,
 					 void *data)
@@ -434,6 +538,7 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
 		if (S_ISGITLINK(p->two->mode))
 			d->new_submodule_commits = !!oidcmp(&p->one->oid,
 							    &p->two->oid);
+		aux_changed_entry(s, d, p);
 	}
 }
 
@@ -487,6 +592,8 @@ static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
 			d->stagemask = unmerged_mask(p->two->path);
 			break;
 		}
+
+		aux_updated_entry(s, d, p);
 	}
 }
 
@@ -566,8 +673,10 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
 			d->index_status = DIFF_STATUS_UNMERGED;
 			d->stagemask |= (1 << (ce_stage(ce) - 1));
 		}
-		else
+		else {
 			d->index_status = DIFF_STATUS_ADDED;
+			aux_initial_entry(s, d, ce);
+		}
 	}
 }
 
@@ -1764,6 +1873,9 @@ void wt_status_print(struct wt_status *s)
 	case STATUS_FORMAT_PORCELAIN:
 		wt_porcelain_print(s);
 		break;
+	case STATUS_FORMAT_PORCELAIN_V2:
+		/* TODO */
+		break;
 	case STATUS_FORMAT_UNSPECIFIED:
 		die("BUG: finalize_deferred_config() should have been called");
 		break;
diff --git a/wt-status.h b/wt-status.h
index a859a12..f2cb65d 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -34,6 +34,21 @@ enum commit_whence {
 	FROM_CHERRY_PICK /* commit came from cherry-pick */
 };
 
+/*
+ * Additional per-file info which may vary based
+ * upon the chosen format.
+ */
+struct wt_status_aux_change_data {
+	struct {
+		int rename_score;
+		int mode_head;
+		int mode_index;
+		int mode_worktree;
+		struct object_id oid_head;
+		struct object_id oid_index;
+	} porcelain_v2;
+};
+
 struct wt_status_change_data {
 	int worktree_status;
 	int index_status;
@@ -41,6 +56,7 @@ struct wt_status_change_data {
 	char *head_path;
 	unsigned dirty_submodule       : 2;
 	unsigned new_submodule_commits : 1;
+	struct wt_status_aux_change_data aux;
 };
 
  enum wt_status_format {
@@ -48,6 +64,7 @@ struct wt_status_change_data {
 	STATUS_FORMAT_LONG,
 	STATUS_FORMAT_SHORT,
 	STATUS_FORMAT_PORCELAIN,
+	STATUS_FORMAT_PORCELAIN_V2,
 
 	STATUS_FORMAT_UNSPECIFIED
  };
-- 
2.8.0.rc4.17.gac42084.dirty
Previous: Junio C HamanoNext: Junio C Hamano
Message 18 of 20 in “status: V2 porcelain status”
  1. 0/8 status: V2 porcelain statusJeff Hostetler, Jul 25, 2016
  2. 1/8 status: rename long-format print routinesJeff Hostetler, Jul 25, 2016
  3. 2/8 status: cleanup API to wt_status_printJeff Hostetler, Jul 25, 2016
  4. Junio C HamanoJul 25, 2016
  5. 3/8 status: support --porcelain[=<version>]Jeff Hostetler, Jul 25, 2016
  6. Jakub NarębskiJul 25, 2016
  7. 5/8 status: print per-file porcelain v2 status dataJeff Hostetler, Jul 25, 2016
  8. Junio C HamanoJul 25, 2016
  9. Jeff HostetlerJul 26, 2016
  10. 7/8 status: update git-status.txt for --porcelain=v2Jeff Hostetler, Jul 25, 2016
  11. Jakub NarębskiJul 25, 2016
  12. Johannes SchindelinJul 26, 2016
  13. Jeff HostetlerJul 26, 2016
  14. 8/8 status: tests for --porcelain=v2Jeff Hostetler, Jul 25, 2016
  15. Johannes SchindelinJul 26, 2016
  16. 6/8 status: print branch info with --porcelain=v2 --branchJeff Hostetler, Jul 25, 2016
  17. Junio C HamanoJul 25, 2016
  18. 4/8 status: per-file data collection for --porcelain=v2Jeff Hostetler, Jul 25, 2016
  19. Junio C HamanoJul 25, 2016
  20. Jeff HostetlerJul 26, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.