Thread (18 messages) flat view 18 messages, 6 authors, 19d ago
COLD19d

Revision v2 of 2 in this series.

Revisions (2)
  1. v2 current
  2. v3 [diff vs current]

[PATCH v2 0/1] rev-list: add --missing-only option to filter output

From: Siddharth Asthana <hidden>
Date: 2026-09-01 18:51:07

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/ (local)

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 [off-list ref]
     
      ## 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 [off-list ref]
     
      ## 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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help