Git development
 help / color / mirror / Atom feed
From: Siddharth Asthana <siddharthasthana31@gmail.com>
To: git@vger.kernel.org
Cc: chriscool@tuxfamily.org, toon@iotcl.com, ps@pks.im,
	karthik.188@gmail.com, justin@parity.io,
	Siddharth Asthana <siddharthasthana31@gmail.com>
Subject: [PATCH v1 1/1] rev-list: add --missing=print-only mode
Date: Sun, 19 Apr 2026 14:18:40 +0530	[thread overview]
Message-ID: <20260419084840.33986-2-siddharthasthana31@gmail.com> (raw)
In-Reply-To: <20260419084840.33986-1-siddharthasthana31@gmail.com>

When working with partial clones, it's common to want just the list of
missing objects. The current --missing=print mode does this but mixes
present and missing objects together, with missing ones prefixed by '?'.
Getting only the missing OIDs requires an extra pipe:

  git rev-list --objects --all --missing=print | perl -ne 'print if s/^[?]//'

Add --missing=print-only which outputs only the missing object OIDs, one
per line, without any prefix. This makes the above one-liner unnecessary
and the output directly usable by downstream tools.

Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
---
 Documentation/rev-list-options.adoc |  5 +++
 builtin/rev-list.c                  | 49 ++++++++++++++++++++++-------
 t/t6022-rev-list-missing.sh         | 26 +++++++++++++++
 3 files changed, 68 insertions(+), 12 deletions(-)

diff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc
index 2d195a1474..5438be5975 100644
--- a/Documentation/rev-list-options.adoc
+++ b/Documentation/rev-list-options.adoc
@@ -1056,6 +1056,11 @@ Unexpected missing objects will raise an error.
 The form `--missing=print` is like `allow-any`, but will also print a
 list of the missing objects.  Object IDs are prefixed with a ``?'' character.
 +
+The form `--missing=print-only` is like `print`, but will print ONLY the
+missing objects (not the present ones), and without the ``?'' prefix.  This
+is useful for scripting, as a simpler alternative to
+`--missing=print | sed -n 's/^?//p'`.
++
 The form `--missing=print-info` is like `print`, but will also print additional
 information about the missing object inferred from its containing object. The
 information is all printed on the same line with the missing object ID in the
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 8f63003709..ba7e3e3919 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -104,14 +104,22 @@ static void missing_objects_map_entry_free(void *e)
 
 static struct oidmap missing_objects;
 enum missing_action {
-	MA_ERROR = 0,    /* fail if any missing objects are encountered */
-	MA_ALLOW_ANY,    /* silently allow ALL missing objects */
-	MA_PRINT,        /* print ALL missing objects in special section */
-	MA_PRINT_INFO,   /* same as MA_PRINT but also prints missing object info */
+	MA_ERROR = 0, /* fail if any missing objects are encountered */
+	MA_ALLOW_ANY, /* silently allow ALL missing objects */
+	MA_PRINT, /* print ALL missing objects in special section */
+	MA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */
+	MA_PRINT_ONLY, /* print ONLY missing objects, without the "?" prefix */
 	MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
 };
 static enum missing_action arg_missing_action;
 
+static inline int missing_action_prints(void)
+{
+	return arg_missing_action == MA_PRINT ||
+	       arg_missing_action == MA_PRINT_INFO ||
+	       arg_missing_action == MA_PRINT_ONLY;
+}
+
 /* display only the oid of each object encountered */
 static int arg_show_object_names = 1;
 
@@ -156,11 +164,16 @@ static void print_missing_object(struct missing_objects_map_entry *entry,
 {
 	struct strbuf sb = STRBUF_INIT;
 
-	if (line_term)
+	if (arg_missing_action == MA_PRINT_ONLY) {
+		printf("%s", oid_to_hex(&entry->entry.oid));
+		putchar(line_term);
+		return;
+	} else if (line_term) {
 		printf("?%s", oid_to_hex(&entry->entry.oid));
-	else
+	} else {
 		printf("%s%cmissing=yes", oid_to_hex(&entry->entry.oid),
 		       info_term);
+	}
 
 	if (!print_missing_info) {
 		putchar(line_term);
@@ -209,6 +222,7 @@ static inline void finish_object__ma(struct object *obj, const char *name)
 
 	case MA_PRINT:
 	case MA_PRINT_INFO:
+	case MA_PRINT_ONLY:
 		add_missing_object_entry(&obj->oid, name, obj->type);
 		return;
 
@@ -246,6 +260,11 @@ static void show_commit(struct commit *commit, void *data)
 		return;
 	}
 
+	if (arg_missing_action == MA_PRINT_ONLY) {
+		finish_commit(commit);
+		return;
+	}
+
 	if (show_disk_usage)
 		total_disk_usage += get_object_disk_usage(&commit->object);
 
@@ -384,6 +403,8 @@ static void show_object(struct object *obj, const char *name, void *cb_data)
 	if (finish_object(obj, name, cb_data))
 		return;
 	display_progress(progress, ++progress_counter);
+	if (arg_missing_action == MA_PRINT_ONLY)
+		return;
 	if (show_disk_usage)
 		total_disk_usage += get_object_disk_usage(obj);
 	if (info->flags & REV_LIST_QUIET)
@@ -525,6 +546,12 @@ static inline int parse_missing_action_value(const char *value)
 		return 1;
 	}
 
+	if (!strcmp(value, "print-only")) {
+		arg_missing_action = MA_PRINT_ONLY;
+		fetch_if_missing = 0;
+		return 1;
+	}
+
 	if (!strcmp(value, "allow-promisor")) {
 		arg_missing_action = MA_ALLOW_PROMISOR;
 		fetch_if_missing = 0;
@@ -967,8 +994,7 @@ int cmd_rev_list(int argc,
 
 	if (arg_print_omitted)
 		oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
-	if (arg_missing_action == MA_PRINT ||
-	    arg_missing_action == MA_PRINT_INFO) {
+	if (missing_action_prints()) {
 		struct oidset_iter iter;
 		struct object_id *oid;
 
@@ -994,8 +1020,7 @@ int cmd_rev_list(int argc,
 			printf("~%s\n", oid_to_hex(oid));
 		oidset_clear(&omitted_objects);
 	}
-	if (arg_missing_action == MA_PRINT ||
-	    arg_missing_action == MA_PRINT_INFO) {
+	if (missing_action_prints()) {
 		struct missing_objects_map_entry *entry;
 		struct oidmap_iter iter;
 
@@ -1011,7 +1036,7 @@ int cmd_rev_list(int argc,
 
 	stop_progress(&progress);
 
-	if (revs.count) {
+	if (revs.count && arg_missing_action != MA_PRINT_ONLY) {
 		if (revs.left_right && revs.cherry_mark)
 			printf("%d\t%d\t%d\n", revs.count_left, revs.count_right, revs.count_same);
 		else if (revs.left_right)
@@ -1022,7 +1047,7 @@ int cmd_rev_list(int argc,
 			printf("%d\n", revs.count_left + revs.count_right);
 	}
 
-	if (show_disk_usage)
+	if (show_disk_usage && arg_missing_action != MA_PRINT_ONLY)
 		print_disk_usage(total_disk_usage);
 
 cleanup:
diff --git a/t/t6022-rev-list-missing.sh b/t/t6022-rev-list-missing.sh
index 08e92dd002..105560ad21 100755
--- a/t/t6022-rev-list-missing.sh
+++ b/t/t6022-rev-list-missing.sh
@@ -198,6 +198,32 @@ do
 	'
 done
 
+for obj in "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"
+do
+	test_expect_success "rev-list --missing=print-only with missing $obj" '
+		oid="$(git rev-parse $obj)" &&
+		path=".git/objects/$(test_oid_to_path $oid)" &&
+
+		# Capture present OIDs before hiding anything.
+		git rev-list --objects --no-object-names HEAD ^$obj >present.raw &&
+
+		mv "$path" "$path.hidden" &&
+		test_when_finished "mv $path.hidden $path" &&
+
+		git rev-list --missing=print-only --objects --no-object-names \
+			HEAD >actual &&
+
+		# Only the missing OID should appear, without the "?" prefix.
+		grep "^$oid$" actual &&
+
+		# Present objects must NOT appear in the output.
+		while read present_oid
+		do
+			! grep "^$present_oid$" actual || return 1
+		done <present.raw
+	'
+done
+
 test_expect_success "-z nul-delimited --missing" '
 	test_when_finished rm -rf repo &&
 
-- 
2.53.0


  reply	other threads:[~2026-04-19  8:48 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-19  8:48 [PATCH v1 0/1] rev-list: add --missing=print-only mode Siddharth Asthana
2026-04-19  8:48 ` Siddharth Asthana [this message]
2026-04-19 22:36   ` [PATCH v1 1/1] " Derrick Stolee
2026-04-20 10:24     ` Siddharth Asthana
2026-04-20 11:44       ` Derrick Stolee
2026-04-20  7:43   ` Patrick Steinhardt
2026-04-20  8:57     ` Phillip Wood
2026-04-20  9:55       ` Patrick Steinhardt
2026-04-20 10:37       ` Siddharth Asthana
2026-04-20 11:00       ` Kristoffer Haugsbakk
2026-04-20 10:33     ` Siddharth Asthana

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260419084840.33986-2-siddharthasthana31@gmail.com \
    --to=siddharthasthana31@gmail.com \
    --cc=chriscool@tuxfamily.org \
    --cc=git@vger.kernel.org \
    --cc=justin@parity.io \
    --cc=karthik.188@gmail.com \
    --cc=ps@pks.im \
    --cc=toon@iotcl.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox