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, peff@peff.net,
phillip.wood123@gmail.com,
Siddharth Asthana <siddharthasthana31@gmail.com>
Subject: [PATCH v2 0/1] rev-list: add --missing-only option to filter output
Date: Wed, 2 Sep 2026 00:20:59 +0530 [thread overview]
Message-ID: <20260901185100.33948-1-siddharthasthana31@gmail.com> (raw)
In-Reply-To: <20260419084840.33986-1-siddharthasthana31@gmail.com>
Hi,
At GitLab, Gitaly uses rev-list --missing=print on partial clones to
find missing objects. The output mixes present and missing objects and
prefixes missing ones with '?', so we post-process it. --missing-only
avoids that.
v1 added --missing=print-only as a --missing= mode. Review preferred a
separate filter flag, so v2 adds --missing-only next to --missing=print
or --missing=print-info.
Based on 1630431f32 (The 21st batch, 2026-08-31).
Changes from v1 include:
1. Separate --missing-only flag instead of print-only mode
(Phillip, Patrick, Stolee).
2. Require --missing=print or --missing=print-info.
3. Die on --count / --disk-usage (Stolee).
4. No enum comment spacing churn.
5. print-info still prints path=/type=; only '?' is dropped.
6. test_cmp-based tests (Phillip).
7. Link to v1:
https://lore.kernel.org/git/20260419084840.33986-1-siddharthasthana31@gmail.com/
Thanks,
Siddharth
---
Siddharth Asthana (1):
rev-list: add --missing-only option to filter output
Documentation/rev-list-options.adoc | 13 ++++++++
builtin/rev-list.c | 42 ++++++++++++++++++++++---
t/t6022-rev-list-missing.sh | 49 +++++++++++++++++++++++++++++
3 files changed, 99 insertions(+), 5 deletions(-)
Range-diff versus v1:
1: 7e8f1ad997 ! 1: 3c89e6bc38 rev-list: add --missing=print-only mode
@@ Metadata
Author: Siddharth Asthana <siddharthasthana31@gmail.com>
## Commit message ##
- rev-list: add --missing=print-only mode
+ rev-list: add --missing-only option to filter output
- 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:
+ When working with partial clones, callers often need only the missing
+ object IDs. Today that means post-processing --missing=print to drop
+ present objects and strip the leading '?':
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.
+ Add --missing-only. Use it with --missing=print or --missing=print-info
+ to print only missing objects. --missing= still picks the format;
+ --missing-only only filters. The leading '?' is omitted. With
+ print-info, path= and type= are still shown.
+
+ Require --missing=print or --missing=print-info. Reject --count and
+ --disk-usage.
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
## Documentation/rev-list-options.adoc ##
-@@ Documentation/rev-list-options.adoc: 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'`.
+@@ Documentation/rev-list-options.adoc: If some tips passed to the traversal are missing, they will be
+ considered as missing too, and the traversal will ignore them. In case
+ we cannot get their Object ID though, an error will be raised.
+
++`--missing-only`::
++ When used together with `--missing=print` or `--missing=print-info`,
++ suppress all output for present objects and print only the missing
++ ones. The selected `--missing=` format is preserved (so
++ `--missing=print-info` still emits `path=` / `type=` fields), but the
++ leading ``?'' prefix used by the non-`-z` forms is omitted. This is
++ useful for scripting, as a simpler and faster alternative to
++ post-processing the output of `--missing=print`.
++
- 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
++This option is incompatible with `--count` and `--disk-usage`.
++It is an error to use `--missing-only` without `--missing=print` or
++`--missing=print-info`.
++
+ `--exclude-promisor-objects`::
+ (For internal use only.) Prefilter object traversal at
+ promisor boundary. This is used with partial clone. This is
## builtin/rev-list.c ##
-@@ builtin/rev-list.c: 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 */
+@@ builtin/rev-list.c: enum missing_action {
MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
};
static enum missing_action arg_missing_action;
-
-+static inline int missing_action_prints(void)
++static int arg_missing_only;
++
++static inline int should_collect_missing(void)
+{
+ return arg_missing_action == MA_PRINT ||
-+ arg_missing_action == MA_PRINT_INFO ||
-+ arg_missing_action == MA_PRINT_ONLY;
++ arg_missing_action == MA_PRINT_INFO;
+}
-+
+
/* display only the oid of each object encountered */
static int arg_show_object_names = 1;
-
@@ builtin/rev-list.c: 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) {
++ /*
++ * --missing-only filters present objects out of the walk output.
++ * It still uses the selected --missing= format for missing ones,
++ * except the human "?" prefix is omitted (script-friendly OIDs).
++ */
++ if (arg_missing_only && line_term)
+ printf("%s", oid_to_hex(&entry->entry.oid));
-+ putchar(line_term);
-+ return;
-+ } else if (line_term) {
++ else if (line_term)
printf("?%s", oid_to_hex(&entry->entry.oid));
-- else
-+ } else {
+ else
printf("%s%cmissing=yes", oid_to_hex(&entry->entry.oid),
- info_term);
-+ }
-
- if (!print_missing_info) {
- putchar(line_term);
-@@ builtin/rev-list.c: 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;
-
@@ builtin/rev-list.c: static void show_commit(struct commit *commit, void *data)
return;
}
-+ if (arg_missing_action == MA_PRINT_ONLY) {
++ if (arg_missing_only) {
+ finish_commit(commit);
+ return;
+ }
@@ builtin/rev-list.c: static void show_object(struct object *obj, const char *name
if (finish_object(obj, name, cb_data))
return;
display_progress(progress, ++progress_counter);
-+ if (arg_missing_action == MA_PRINT_ONLY)
++ if (arg_missing_only)
+ return;
if (show_disk_usage)
total_disk_usage += get_object_disk_usage(obj);
if (info->flags & REV_LIST_QUIET)
-@@ builtin/rev-list.c: static inline int parse_missing_action_value(const char *value)
- return 1;
+@@ builtin/rev-list.c: int cmd_rev_list(int argc,
+ revs.exclude_promisor_objects = 1;
+ } else if (skip_prefix(arg, "--missing=", &arg)) {
+ parse_missing_action_value(arg);
++ } else if (!strcmp(arg, "--missing-only")) {
++ arg_missing_only = 1;
+ } else if (!strcmp(arg, "-z")) {
+ line_term = '\0';
+ info_term = '\0';
+ }
}
-+ if (!strcmp(value, "print-only")) {
-+ arg_missing_action = MA_PRINT_ONLY;
-+ fetch_if_missing = 0;
-+ return 1;
-+ }
++ if (arg_missing_only && !should_collect_missing())
++ die(_("--missing-only requires --missing=print or --missing=print-info"));
++
+ die_for_incompatible_opt2(revs.exclude_promisor_objects,
+ "--exclude_promisor_objects",
+ arg_missing_action, "--missing");
+@@ builtin/rev-list.c: int cmd_rev_list(int argc,
+ continue;
+ }
+
++ if (!strcmp(arg, "--missing-only"))
++ continue;
++
+ usage(rev_list_usage);
+
+ }
+@@ builtin/rev-list.c: int cmd_rev_list(int argc,
+ (revs.left_right || revs.cherry_mark))
+ die(_("marked counting and '%s' cannot be used together"), "--objects");
+
++ die_for_incompatible_opt2(arg_missing_only, "--missing-only",
++ revs.count, "--count");
++ die_for_incompatible_opt2(arg_missing_only, "--missing-only",
++ show_disk_usage, "--disk-usage");
+
- if (!strcmp(value, "allow-promisor")) {
- arg_missing_action = MA_ALLOW_PROMISOR;
- fetch_if_missing = 0;
+ save_commit_buffer = (revs.verbose_header ||
+ revs.grep_filter.pattern_list ||
+ revs.grep_filter.header_list);
@@ builtin/rev-list.c: 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()) {
++ if (should_collect_missing()) {
struct oidset_iter iter;
struct object_id *oid;
@@ builtin/rev-list.c: int cmd_rev_list(int argc,
}
- if (arg_missing_action == MA_PRINT ||
- arg_missing_action == MA_PRINT_INFO) {
-+ if (missing_action_prints()) {
++ if (should_collect_missing()) {
struct missing_objects_map_entry *entry;
struct oidmap_iter iter;
-@@ builtin/rev-list.c: 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)
-@@ builtin/rev-list.c: 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:
## t/t6022-rev-list-missing.sh ##
@@ t/t6022-rev-list-missing.sh: do
@@ t/t6022-rev-list-missing.sh: do
+for obj in "HEAD~1" "HEAD~1^{tree}" "HEAD:1.t"
+do
-+ test_expect_success "rev-list --missing=print-only with missing $obj" '
++ test_expect_success "rev-list --missing-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 &&
++ git rev-list --missing=print --missing-only --objects \
++ --no-object-names HEAD >actual &&
+
-+ # Present objects must NOT appear in the output.
-+ while read present_oid
-+ do
-+ ! grep "^$present_oid$" actual || return 1
-+ done <present.raw
++ echo $oid >expect &&
++ test_cmp expect actual
+ '
+done
++
++test_expect_success "--missing-only requires --missing=print or --missing=print-info" '
++ test_must_fail git rev-list --missing-only --objects HEAD 2>err &&
++ test_grep "requires --missing=print" err
++'
++
++test_expect_success "--missing-only is incompatible with --count" '
++ test_must_fail git rev-list --missing=print --missing-only \
++ --count --objects HEAD 2>err &&
++ test_grep "cannot be used together" err
++'
++
++test_expect_success "--missing-only is incompatible with --disk-usage" '
++ test_must_fail git rev-list --missing=print --missing-only \
++ --disk-usage --objects HEAD 2>err &&
++ test_grep "cannot be used together" err
++'
++
++test_expect_success "--missing-only works with --missing=print-info" '
++ oid="$(git rev-parse HEAD:1.t)" &&
++ path=".git/objects/$(test_oid_to_path $oid)" &&
++
++ mv "$path" "$path.hidden" &&
++ test_when_finished "mv $path.hidden $path" &&
++
++ git rev-list --missing=print-info --missing-only --objects \
++ --no-object-names HEAD >actual &&
++
++ # Filter keeps print-info fields; only the "?" prefix is dropped.
++ echo "$oid path=1.t type=blob" >expect &&
++ test_cmp expect actual
++'
+
test_expect_success "-z nul-delimited --missing" '
test_when_finished rm -rf repo &&
base-commit: 1630431f326e15fcde608827b5ff38422528eb59
next prev parent reply other threads:[~2026-09-01 18:51 UTC|newest]
Thread overview: 18+ 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 ` [PATCH v1 1/1] " Siddharth Asthana
2026-04-19 22:36 ` 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
2026-09-01 18:50 ` Siddharth Asthana [this message]
2026-09-01 18:51 ` [PATCH v2 1/1] rev-list: add --missing-only option to filter output Siddharth Asthana
2026-09-01 19:57 ` [PATCH v2 0/1] " Junio C Hamano
2026-09-01 20:27 ` Siddharth Asthana
2026-09-02 21:26 ` Junio C Hamano
2026-09-03 20:45 ` [PATCH v3 " Siddharth Asthana
2026-09-03 20:45 ` [PATCH v3 1/1] " 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=20260901185100.33948-1-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=peff@peff.net \
--cc=phillip.wood123@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.