{"thread":{"id":"65512","subject":"[PATCH v1 0/1] rev-list: add --missing=print-only mode","startedAt":"2026-04-19T08:48:46Z","lastAt":"2026-09-03T20:46:10Z","messageCount":18,"participants":["Siddharth Asthana","Derrick Stolee","Patrick Steinhardt","Phillip Wood","Kristoffer Haugsbakk","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":1},"messages":[{"id":"541880","messageId":"20260419084840.33986-1-siddharthasthana31@gmail.com","threadId":"65512","inReplyTo":null,"subject":"[PATCH v1 0/1] rev-list: add --missing=print-only mode","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2026-04-19T08:48:39Z","receivedAt":"2026-04-19T08:48:46Z","isPatch":true,"body":"Hi,\n\nAt GitLab, Gitaly uses `rev-list --missing=print` to find missing\nobjects in partial clones. The current output mixes present and missing\nobjects together, with missing ones prefixed by '?', so Gitaly has to\npost-process the output to extract just the missing OIDs. Having a\ndedicated mode that outputs only the missing OIDs directly would\nsimplify this.\n\nThis patch adds --missing=print-only which suppresses all regular\nobject output and prints only the missing OIDs, one per line, without\nthe '?' prefix. A `missing_action_prints()` helper consolidates the\nrepeated three-way checks for MA_PRINT/MA_PRINT_INFO/MA_PRINT_ONLY.\n\nThe series is based on top of 9f223ef1c0 (Git 2.54-rc2).\n\nCI: https://gitlab.com/gitlab-org/git/-/pipelines/2463294546\n\nSiddharth Asthana (1):\n  rev-list: add --missing=print-only mode\n\n Documentation/rev-list-options.adoc |  5 +++\n builtin/rev-list.c                  | 49 ++++++++++++++++++++++-------\n t/t6022-rev-list-missing.sh         | 26 +++++++++++++++\n 3 files changed, 68 insertions(+), 12 deletions(-)\n\n\nbase-commit: 9f223ef1c026d91c7ac68cc0211bde255dda6199\n\nThanks\n- Siddharth\n\n"},{"id":"541881","messageId":"20260419084840.33986-2-siddharthasthana31@gmail.com","threadId":"65512","inReplyTo":"20260419084840.33986-1-siddharthasthana31@gmail.com","subject":"[PATCH v1 1/1] rev-list: add --missing=print-only mode","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2026-04-19T08:48:40Z","receivedAt":"2026-04-19T08:48:50Z","isPatch":true,"body":"When working with partial clones, it's common to want just the list of\nmissing objects. The current --missing=print mode does this but mixes\npresent and missing objects together, with missing ones prefixed by '?'.\nGetting only the missing OIDs requires an extra pipe:\n\n  git rev-list --objects --all --missing=print | perl -ne 'print if s/^[?]//'\n\nAdd --missing=print-only which outputs only the missing object OIDs, one\nper line, without any prefix. This makes the above one-liner unnecessary\nand the output directly usable by downstream tools.\n\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n Documentation/rev-list-options.adoc |  5 +++\n builtin/rev-list.c                  | 49 ++++++++++++++++++++++-------\n t/t6022-rev-list-missing.sh         | 26 +++++++++++++++\n 3 files changed, 68 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc\nindex 2d195a1474..5438be5975 100644\n--- a/Documentation/rev-list-options.adoc\n+++ b/Documentation/rev-list-options.adoc\n@@ -1056,6 +1056,11 @@ Unexpected missing objects will raise an error.\n The form `--missing=print` is like `allow-any`, but will also print a\n list of the missing objects.  Object IDs are prefixed with a ``?'' character.\n +\n+The form `--missing=print-only` is like `print`, but will print ONLY the\n+missing objects (not the present ones), and without the ``?'' prefix.  This\n+is useful for scripting, as a simpler alternative to\n+`--missing=print | sed -n 's/^?//p'`.\n++\n The form `--missing=print-info` is like `print`, but will also print additional\n information about the missing object inferred from its containing object. The\n information is all printed on the same line with the missing object ID in the\ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex 8f63003709..ba7e3e3919 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -104,14 +104,22 @@ static void missing_objects_map_entry_free(void *e)\n \n static struct oidmap missing_objects;\n enum missing_action {\n-\tMA_ERROR = 0,    /* fail if any missing objects are encountered */\n-\tMA_ALLOW_ANY,    /* silently allow ALL missing objects */\n-\tMA_PRINT,        /* print ALL missing objects in special section */\n-\tMA_PRINT_INFO,   /* same as MA_PRINT but also prints missing object info */\n+\tMA_ERROR = 0, /* fail if any missing objects are encountered */\n+\tMA_ALLOW_ANY, /* silently allow ALL missing objects */\n+\tMA_PRINT, /* print ALL missing objects in special section */\n+\tMA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */\n+\tMA_PRINT_ONLY, /* print ONLY missing objects, without the \"?\" prefix */\n \tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n };\n static enum missing_action arg_missing_action;\n \n+static inline int missing_action_prints(void)\n+{\n+\treturn arg_missing_action == MA_PRINT ||\n+\t       arg_missing_action == MA_PRINT_INFO ||\n+\t       arg_missing_action == MA_PRINT_ONLY;\n+}\n+\n /* display only the oid of each object encountered */\n static int arg_show_object_names = 1;\n \n@@ -156,11 +164,16 @@ static void print_missing_object(struct missing_objects_map_entry *entry,\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \n-\tif (line_term)\n+\tif (arg_missing_action == MA_PRINT_ONLY) {\n+\t\tprintf(\"%s\", oid_to_hex(&entry->entry.oid));\n+\t\tputchar(line_term);\n+\t\treturn;\n+\t} else if (line_term) {\n \t\tprintf(\"?%s\", oid_to_hex(&entry->entry.oid));\n-\telse\n+\t} else {\n \t\tprintf(\"%s%cmissing=yes\", oid_to_hex(&entry->entry.oid),\n \t\t       info_term);\n+\t}\n \n \tif (!print_missing_info) {\n \t\tputchar(line_term);\n@@ -209,6 +222,7 @@ static inline void finish_object__ma(struct object *obj, const char *name)\n \n \tcase MA_PRINT:\n \tcase MA_PRINT_INFO:\n+\tcase MA_PRINT_ONLY:\n \t\tadd_missing_object_entry(&obj->oid, name, obj->type);\n \t\treturn;\n \n@@ -246,6 +260,11 @@ static void show_commit(struct commit *commit, void *data)\n \t\treturn;\n \t}\n \n+\tif (arg_missing_action == MA_PRINT_ONLY) {\n+\t\tfinish_commit(commit);\n+\t\treturn;\n+\t}\n+\n \tif (show_disk_usage)\n \t\ttotal_disk_usage += get_object_disk_usage(&commit->object);\n \n@@ -384,6 +403,8 @@ static void show_object(struct object *obj, const char *name, void *cb_data)\n \tif (finish_object(obj, name, cb_data))\n \t\treturn;\n \tdisplay_progress(progress, ++progress_counter);\n+\tif (arg_missing_action == MA_PRINT_ONLY)\n+\t\treturn;\n \tif (show_disk_usage)\n \t\ttotal_disk_usage += get_object_disk_usage(obj);\n \tif (info->flags & REV_LIST_QUIET)\n@@ -525,6 +546,12 @@ static inline int parse_missing_action_value(const char *value)\n \t\treturn 1;\n \t}\n \n+\tif (!strcmp(value, \"print-only\")) {\n+\t\targ_missing_action = MA_PRINT_ONLY;\n+\t\tfetch_if_missing = 0;\n+\t\treturn 1;\n+\t}\n+\n \tif (!strcmp(value, \"allow-promisor\")) {\n \t\targ_missing_action = MA_ALLOW_PROMISOR;\n \t\tfetch_if_missing = 0;\n@@ -967,8 +994,7 @@ int cmd_rev_list(int argc,\n \n \tif (arg_print_omitted)\n \t\toidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);\n-\tif (arg_missing_action == MA_PRINT ||\n-\t    arg_missing_action == MA_PRINT_INFO) {\n+\tif (missing_action_prints()) {\n \t\tstruct oidset_iter iter;\n \t\tstruct object_id *oid;\n \n@@ -994,8 +1020,7 @@ int cmd_rev_list(int argc,\n \t\t\tprintf(\"~%s\\n\", oid_to_hex(oid));\n \t\toidset_clear(&omitted_objects);\n \t}\n-\tif (arg_missing_action == MA_PRINT ||\n-\t    arg_missing_action == MA_PRINT_INFO) {\n+\tif (missing_action_prints()) {\n \t\tstruct missing_objects_map_entry *entry;\n \t\tstruct oidmap_iter iter;\n \n@@ -1011,7 +1036,7 @@ int cmd_rev_list(int argc,\n \n \tstop_progress(&progress);\n \n-\tif (revs.count) {\n+\tif (revs.count && arg_missing_action != MA_PRINT_ONLY) {\n \t\tif (revs.left_right && revs.cherry_mark)\n \t\t\tprintf(\"%d\\t%d\\t%d\\n\", revs.count_left, revs.count_right, revs.count_same);\n \t\telse if (revs.left_right)\n@@ -1022,7 +1047,7 @@ int cmd_rev_list(int argc,\n \t\t\tprintf(\"%d\\n\", revs.count_left + revs.count_right);\n \t}\n \n-\tif (show_disk_usage)\n+\tif (show_disk_usage && arg_missing_action != MA_PRINT_ONLY)\n \t\tprint_disk_usage(total_disk_usage);\n \n cleanup:\ndiff --git a/t/t6022-rev-list-missing.sh b/t/t6022-rev-list-missing.sh\nindex 08e92dd002..105560ad21 100755\n--- a/t/t6022-rev-list-missing.sh\n+++ b/t/t6022-rev-list-missing.sh\n@@ -198,6 +198,32 @@ do\n \t'\n done\n \n+for obj in \"HEAD~1\" \"HEAD~1^{tree}\" \"HEAD:1.t\"\n+do\n+\ttest_expect_success \"rev-list --missing=print-only with missing $obj\" '\n+\t\toid=\"$(git rev-parse $obj)\" &&\n+\t\tpath=\".git/objects/$(test_oid_to_path $oid)\" &&\n+\n+\t\t# Capture present OIDs before hiding anything.\n+\t\tgit rev-list --objects --no-object-names HEAD ^$obj >present.raw &&\n+\n+\t\tmv \"$path\" \"$path.hidden\" &&\n+\t\ttest_when_finished \"mv $path.hidden $path\" &&\n+\n+\t\tgit rev-list --missing=print-only --objects --no-object-names \\\n+\t\t\tHEAD >actual &&\n+\n+\t\t# Only the missing OID should appear, without the \"?\" prefix.\n+\t\tgrep \"^$oid$\" actual &&\n+\n+\t\t# Present objects must NOT appear in the output.\n+\t\twhile read present_oid\n+\t\tdo\n+\t\t\t! grep \"^$present_oid$\" actual || return 1\n+\t\tdone <present.raw\n+\t'\n+done\n+\n test_expect_success \"-z nul-delimited --missing\" '\n \ttest_when_finished rm -rf repo &&\n \n-- \n2.53.0\n\n"},{"id":"541891","messageId":"4c9fee0b-99bb-4e41-9227-f09c63df9f9d@gmail.com","threadId":"65512","inReplyTo":"20260419084840.33986-2-siddharthasthana31@gmail.com","subject":"Re: [PATCH v1 1/1] rev-list: add --missing=print-only mode","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2026-04-19T22:36:36Z","receivedAt":"2026-04-19T22:36:38Z","isPatch":true,"body":"On 4/19/26 4:48 AM, Siddharth Asthana wrote:\n> When working with partial clones, it's common to want just the list of\n> missing objects. The current --missing=print mode does this but mixes\n> present and missing objects together, with missing ones prefixed by '?'.\n> Getting only the missing OIDs requires an extra pipe:\n> \n>    git rev-list --objects --all --missing=print | perl -ne 'print if s/^[?]//'\n> \n> Add --missing=print-only which outputs only the missing object OIDs, one\n> per line, without any prefix. This makes the above one-liner unnecessary\n> and the output directly usable by downstream tools.\n\nI'm a fan of this mode. It saves time dealing with the I/O.\n\n>   static struct oidmap missing_objects;\n>   enum missing_action {\n> -\tMA_ERROR = 0,    /* fail if any missing objects are encountered */\n> -\tMA_ALLOW_ANY,    /* silently allow ALL missing objects */\n> -\tMA_PRINT,        /* print ALL missing objects in special section */\n> -\tMA_PRINT_INFO,   /* same as MA_PRINT but also prints missing object info */\n> +\tMA_ERROR = 0, /* fail if any missing objects are encountered */\n> +\tMA_ALLOW_ANY, /* silently allow ALL missing objects */\n> +\tMA_PRINT, /* print ALL missing objects in special section */\n> +\tMA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */\n> +\tMA_PRINT_ONLY, /* print ONLY missing objects, without the \"?\" prefix */\n>   \tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n\nI'm not a fan of this adjustment of spacing on the comments,\nthough I do see that MA_ALLOW_PROMISOR had already broken the\npattern. MA_PRINT_ONLY would still work with the earlier\ncomment alignment, though.\n\n> -\tif (line_term)\n> +\tif (arg_missing_action == MA_PRINT_ONLY) {\n> +\t\tprintf(\"%s\", oid_to_hex(&entry->entry.oid));\n> +\t\tputchar(line_term);\n\nIs there a reason you didn't use a printf(\"%s%c\") here to\nput the oid and line_term together?\n\n> +\t\treturn;\n> +\t} else if (line_term) {\n>   \t\tprintf(\"?%s\", oid_to_hex(&entry->entry.oid));\n> -\telse\n> +\t} else {\n>   \t\tprintf(\"%s%cmissing=yes\", oid_to_hex(&entry->entry.oid),\n>   \t\t       info_term);\n> +\t}\n\n\n\n>   \tif (!print_missing_info) {\n>   \t\tputchar(line_term);\n> @@ -209,6 +222,7 @@ static inline void finish_object__ma(struct object *obj, const char *name)\n>   \n>   \tcase MA_PRINT:\n>   \tcase MA_PRINT_INFO:\n> +\tcase MA_PRINT_ONLY:\n>   \t\tadd_missing_object_entry(&obj->oid, name, obj->type);\n>   \t\treturn;\n>   \n> @@ -246,6 +260,11 @@ static void show_commit(struct commit *commit, void *data)\n>   \t\treturn;\n>   \t}\n>   \n> +\tif (arg_missing_action == MA_PRINT_ONLY) {\n> +\t\tfinish_commit(commit);\n> +\t\treturn;\n> +\t}\n> +\n>   \tif (show_disk_usage)\n>   \t\ttotal_disk_usage += get_object_disk_usage(&commit->object);\n>   \n> @@ -384,6 +403,8 @@ static void show_object(struct object *obj, const char *name, void *cb_data)\n>   \tif (finish_object(obj, name, cb_data))\n>   \t\treturn;\n>   \tdisplay_progress(progress, ++progress_counter);\n> +\tif (arg_missing_action == MA_PRINT_ONLY)\n> +\t\treturn;\n>   \tif (show_disk_usage)\n>   \t\ttotal_disk_usage += get_object_disk_usage(obj);\n>   \tif (info->flags & REV_LIST_QUIET)\n> @@ -525,6 +546,12 @@ static inline int parse_missing_action_value(const char *value)\n>   \t\treturn 1;\n>   \t}\n>   \n> +\tif (!strcmp(value, \"print-only\")) {\n> +\t\targ_missing_action = MA_PRINT_ONLY;\n> +\t\tfetch_if_missing = 0;\n> +\t\treturn 1;\n> +\t}\n> +\n>   \tif (!strcmp(value, \"allow-promisor\")) {\n>   \t\targ_missing_action = MA_ALLOW_PROMISOR;\n>   \t\tfetch_if_missing = 0;\n> @@ -967,8 +994,7 @@ int cmd_rev_list(int argc,\n>   \n>   \tif (arg_print_omitted)\n>   \t\toidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);\n> -\tif (arg_missing_action == MA_PRINT ||\n> -\t    arg_missing_action == MA_PRINT_INFO) {\n> +\tif (missing_action_prints()) {\n>   \t\tstruct oidset_iter iter;\n>   \t\tstruct object_id *oid;\n>   \n> @@ -994,8 +1020,7 @@ int cmd_rev_list(int argc,\n>   \t\t\tprintf(\"~%s\\n\", oid_to_hex(oid));\n>   \t\toidset_clear(&omitted_objects);\n>   \t}\n> -\tif (arg_missing_action == MA_PRINT ||\n> -\t    arg_missing_action == MA_PRINT_INFO) {\n> +\tif (missing_action_prints()) {\n>   \t\tstruct missing_objects_map_entry *entry;\n>   \t\tstruct oidmap_iter iter;\n>   \n> @@ -1011,7 +1036,7 @@ int cmd_rev_list(int argc,\n>   \n>   \tstop_progress(&progress);\n>   \n> -\tif (revs.count) {\n> +\tif (revs.count && arg_missing_action != MA_PRINT_ONLY) {\n>   \t\tif (revs.left_right && revs.cherry_mark)\n>   \t\t\tprintf(\"%d\\t%d\\t%d\\n\", revs.count_left, revs.count_right, revs.count_same);\n>   \t\telse if (revs.left_right)\n> @@ -1022,7 +1047,7 @@ int cmd_rev_list(int argc,\n>   \t\t\tprintf(\"%d\\n\", revs.count_left + revs.count_right);\n>   \t}\n>   \n> -\tif (show_disk_usage)\n> +\tif (show_disk_usage && arg_missing_action != MA_PRINT_ONLY)\n>   \t\tprint_disk_usage(total_disk_usage);\n\nI'm a little worried about all of these checks that need\nspecial-casing. These seem like options that are enabled\nby other options and could easily be grouped with the\nprint-only setting.\n\nIf there is something wrong here where these need to be\ndisabled, then we should update the documentation to say\nhow this interacts with those options. And perhaps some\nwarnings to say \"these options are not compatible\".\n\nOn that note: this patch is missing a document update.\n\nThanks,\n-Stolee\n\n\n"},{"id":"541925","messageId":"aeXZOAtILSr638LG@pks.im","threadId":"65512","inReplyTo":"20260419084840.33986-2-siddharthasthana31@gmail.com","subject":"Re: [PATCH v1 1/1] rev-list: add --missing=print-only mode","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-04-20T07:43:52Z","receivedAt":"2026-04-20T07:43:59Z","isPatch":true,"body":"On Sun, Apr 19, 2026 at 02:18:40PM +0530, Siddharth Asthana wrote:\n> When working with partial clones, it's common to want just the list of\n> missing objects. The current --missing=print mode does this but mixes\n> present and missing objects together, with missing ones prefixed by '?'.\n> Getting only the missing OIDs requires an extra pipe:\n> \n>   git rev-list --objects --all --missing=print | perl -ne 'print if s/^[?]//'\n> \n> Add --missing=print-only which outputs only the missing object OIDs, one\n> per line, without any prefix. This makes the above one-liner unnecessary\n> and the output directly usable by downstream tools.\n\nNaming is a bit tough, as \"print-only\" sounds as if we're only printing\nthem without doing anything else, but it doesn't quite convey the\nrelation to non-missing objects. I don't really have a better suggestion\nthough -- \"print-exclusively\" may convey the meaning a tiny bit better,\nbut still suffers kind of the same issue.\n\n> diff --git a/builtin/rev-list.c b/builtin/rev-list.c\n> index 8f63003709..ba7e3e3919 100644\n> --- a/builtin/rev-list.c\n> +++ b/builtin/rev-list.c\n> @@ -104,14 +104,22 @@ static void missing_objects_map_entry_free(void *e)\n>  \n>  static struct oidmap missing_objects;\n>  enum missing_action {\n> -\tMA_ERROR = 0,    /* fail if any missing objects are encountered */\n> -\tMA_ALLOW_ANY,    /* silently allow ALL missing objects */\n> -\tMA_PRINT,        /* print ALL missing objects in special section */\n> -\tMA_PRINT_INFO,   /* same as MA_PRINT but also prints missing object info */\n> +\tMA_ERROR = 0, /* fail if any missing objects are encountered */\n> +\tMA_ALLOW_ANY, /* silently allow ALL missing objects */\n> +\tMA_PRINT, /* print ALL missing objects in special section */\n> +\tMA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */\n> +\tMA_PRINT_ONLY, /* print ONLY missing objects, without the \"?\" prefix */\n\nMakes me wonder whether we'll eventually also want to have\n`MA_PRINT_INFO_ONLY`.\n\n>  \tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n>  };\n>  static enum missing_action arg_missing_action;\n>  \n> +static inline int missing_action_prints(void)\n\nHow about naming this `should_print_missing_object()` instead? That\ngives the reader a bit more context.\n\n> @@ -1011,7 +1036,7 @@ int cmd_rev_list(int argc,\n>  \n>  \tstop_progress(&progress);\n>  \n> -\tif (revs.count) {\n> +\tif (revs.count && arg_missing_action != MA_PRINT_ONLY) {\n>  \t\tif (revs.left_right && revs.cherry_mark)\n>  \t\t\tprintf(\"%d\\t%d\\t%d\\n\", revs.count_left, revs.count_right, revs.count_same);\n>  \t\telse if (revs.left_right)\n\nNot a fault of your patch, but I really feel like git-rev-list(1) is\nbecoming more and more tangled. The fact that we have to add this check\nto so many different sites doesn't inspire confidence that we have\nindeed catched all of them that need this check.\n\nIt would be great if this was reworked a bit to become more obvious, but\nthat's probably outside the scope of this patch series.\n\n> diff --git a/t/t6022-rev-list-missing.sh b/t/t6022-rev-list-missing.sh\n> index 08e92dd002..105560ad21 100755\n> --- a/t/t6022-rev-list-missing.sh\n> +++ b/t/t6022-rev-list-missing.sh\n> @@ -198,6 +198,32 @@ do\n>  \t'\n>  done\n>  \n> +for obj in \"HEAD~1\" \"HEAD~1^{tree}\" \"HEAD:1.t\"\n> +do\n> +\ttest_expect_success \"rev-list --missing=print-only with missing $obj\" '\n> +\t\toid=\"$(git rev-parse $obj)\" &&\n> +\t\tpath=\".git/objects/$(test_oid_to_path $oid)\" &&\n> +\n> +\t\t# Capture present OIDs before hiding anything.\n> +\t\tgit rev-list --objects --no-object-names HEAD ^$obj >present.raw &&\n> +\n> +\t\tmv \"$path\" \"$path.hidden\" &&\n> +\t\ttest_when_finished \"mv $path.hidden $path\" &&\n> +\n> +\t\tgit rev-list --missing=print-only --objects --no-object-names \\\n> +\t\t\tHEAD >actual &&\n> +\n> +\t\t# Only the missing OID should appear, without the \"?\" prefix.\n> +\t\tgrep \"^$oid$\" actual &&\n> +\n> +\t\t# Present objects must NOT appear in the output.\n> +\t\twhile read present_oid\n> +\t\tdo\n> +\t\t\t! grep \"^$present_oid$\" actual || return 1\n> +\t\tdone <present.raw\n\nHow many present object IDs do we have? I'm a bit worried that we now\nexecute grep(1) hundreds of times. Can we maybe do some tricks with\ncomm(1) instead?\n\nThanks!\n\nPatrick\n"},{"id":"541947","messageId":"491a27af-3ea4-4978-9d51-9c540ad31589@gmail.com","threadId":"65512","inReplyTo":"aeXZOAtILSr638LG@pks.im","subject":"Re: [PATCH v1 1/1] rev-list: add --missing=print-only mode","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-04-20T08:57:02Z","receivedAt":"2026-04-20T08:57:10Z","isPatch":true,"body":"On 20/04/2026 08:43, Patrick Steinhardt wrote:\n> On Sun, Apr 19, 2026 at 02:18:40PM +0530, Siddharth Asthana wrote:\n> \n>>   static struct oidmap missing_objects;\n>>   enum missing_action {\n>> -\tMA_ERROR = 0,    /* fail if any missing objects are encountered */\n>> -\tMA_ALLOW_ANY,    /* silently allow ALL missing objects */\n>> -\tMA_PRINT,        /* print ALL missing objects in special section */\n>> -\tMA_PRINT_INFO,   /* same as MA_PRINT but also prints missing object info */\n>> +\tMA_ERROR = 0, /* fail if any missing objects are encountered */\n>> +\tMA_ALLOW_ANY, /* silently allow ALL missing objects */\n>> +\tMA_PRINT, /* print ALL missing objects in special section */\n>> +\tMA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */\n>> +\tMA_PRINT_ONLY, /* print ONLY missing objects, without the \"?\" prefix */\n> \n> Makes me wonder whether we'll eventually also want to have\n> `MA_PRINT_INFO_ONLY`.\n\nPerhaps we'd be better to add a \"--missing-only\" option that limits the \noutput to missing objects? That would avoid the problem of \n\"--missing=print-only\" not really explaining what it does as well.\n\n>> +for obj in \"HEAD~1\" \"HEAD~1^{tree}\" \"HEAD:1.t\"\n>> +do\n>> +\ttest_expect_success \"rev-list --missing=print-only with missing $obj\" '\n>> +\t\toid=\"$(git rev-parse $obj)\" &&\n>> +\t\tpath=\".git/objects/$(test_oid_to_path $oid)\" &&\n>> +\n>> +\t\t# Capture present OIDs before hiding anything.\n>> +\t\tgit rev-list --objects --no-object-names HEAD ^$obj >present.raw &&\n>> +\n>> +\t\tmv \"$path\" \"$path.hidden\" &&\n>> +\t\ttest_when_finished \"mv $path.hidden $path\" &&\n>> +\n>> +\t\tgit rev-list --missing=print-only --objects --no-object-names \\\n>> +\t\t\tHEAD >actual &&\n>> +\n>> +\t\t# Only the missing OID should appear, without the \"?\" prefix.\n>> +\t\tgrep \"^$oid$\" actual &&\n>> +\n>> +\t\t# Present objects must NOT appear in the output.\n>> +\t\twhile read present_oid\n>> +\t\tdo\n>> +\t\t\t! grep \"^$present_oid$\" actual || return 1\n>> +\t\tdone <present.raw\n> \n> How many present object IDs do we have? I'm a bit worried that we now\n> execute grep(1) hundreds of times. Can we maybe do some tricks with\n> comm(1) instead?\n\nIf we want to verify that it only prints a single oid then\n\n\techo $oid >expect &&\n\ttest_cmp expect actual\n\nwould be much simpler more helpful if the test fails\n\nThanks\n\nPhil\n"},{"id":"541951","messageId":"aeX3_nKaCaXOdSE6@pks.im","threadId":"65512","inReplyTo":"491a27af-3ea4-4978-9d51-9c540ad31589@gmail.com","subject":"Re: [PATCH v1 1/1] rev-list: add --missing=print-only mode","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-04-20T09:55:10Z","receivedAt":"2026-04-20T09:55:19Z","isPatch":true,"body":"On Mon, Apr 20, 2026 at 09:57:02AM +0100, Phillip Wood wrote:\n> On 20/04/2026 08:43, Patrick Steinhardt wrote:\n> > On Sun, Apr 19, 2026 at 02:18:40PM +0530, Siddharth Asthana wrote:\n> > \n> > >   static struct oidmap missing_objects;\n> > >   enum missing_action {\n> > > -\tMA_ERROR = 0,    /* fail if any missing objects are encountered */\n> > > -\tMA_ALLOW_ANY,    /* silently allow ALL missing objects */\n> > > -\tMA_PRINT,        /* print ALL missing objects in special section */\n> > > -\tMA_PRINT_INFO,   /* same as MA_PRINT but also prints missing object info */\n> > > +\tMA_ERROR = 0, /* fail if any missing objects are encountered */\n> > > +\tMA_ALLOW_ANY, /* silently allow ALL missing objects */\n> > > +\tMA_PRINT, /* print ALL missing objects in special section */\n> > > +\tMA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */\n> > > +\tMA_PRINT_ONLY, /* print ONLY missing objects, without the \"?\" prefix */\n> > \n> > Makes me wonder whether we'll eventually also want to have\n> > `MA_PRINT_INFO_ONLY`.\n> \n> Perhaps we'd be better to add a \"--missing-only\" option that limits the\n> output to missing objects? That would avoid the problem of\n> \"--missing=print-only\" not really explaining what it does as well.\n\nYes, I had the same thought.\n\nPatrick\n"},{"id":"541962","messageId":"9e2ca91d-9091-4d4d-9427-ec8a23ee8909@gmail.com","threadId":"65512","inReplyTo":"4c9fee0b-99bb-4e41-9227-f09c63df9f9d@gmail.com","subject":"Re: [PATCH v1 1/1] rev-list: add --missing=print-only mode","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2026-04-20T10:24:34Z","receivedAt":"2026-04-20T10:24:42Z","isPatch":true,"body":"\n\nOn 20/04/26 04:06, Derrick Stolee wrote:\n> On 4/19/26 4:48 AM, Siddharth Asthana wrote:\n>> When working with partial clones, it's common to want just the list of\n>> missing objects. The current --missing=print mode does this but mixes\n>> present and missing objects together, with missing ones prefixed by '?'.\n>> Getting only the missing OIDs requires an extra pipe:\n>>\n>>    git rev-list --objects --all --missing=print | perl -ne 'print if \n>> s/^[?]//'\n>>\n>> Add --missing=print-only which outputs only the missing object OIDs, one\n>> per line, without any prefix. This makes the above one-liner unnecessary\n>> and the output directly usable by downstream tools.\n> \n> I'm a fan of this mode. It saves time dealing with the I/O.\n\n\nThanks!\n\n\n> \n>>   static struct oidmap missing_objects;\n>>   enum missing_action {\n>> -    MA_ERROR = 0,    /* fail if any missing objects are encountered */\n>> -    MA_ALLOW_ANY,    /* silently allow ALL missing objects */\n>> -    MA_PRINT,        /* print ALL missing objects in special section */\n>> -    MA_PRINT_INFO,   /* same as MA_PRINT but also prints missing \n>> object info */\n>> +    MA_ERROR = 0, /* fail if any missing objects are encountered */\n>> +    MA_ALLOW_ANY, /* silently allow ALL missing objects */\n>> +    MA_PRINT, /* print ALL missing objects in special section */\n>> +    MA_PRINT_INFO, /* same as MA_PRINT but also prints missing object \n>> info */\n>> +    MA_PRINT_ONLY, /* print ONLY missing objects, without the \"?\" \n>> prefix */\n>>       MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR \n>> objects */\n> \n> I'm not a fan of this adjustment of spacing on the comments,\n\n\nYou are right, unnecessary churn - will restore!\n\n\n> though I do see that MA_ALLOW_PROMISOR had already broken the\n> pattern. MA_PRINT_ONLY would still work with the earlier\n> comment alignment, though.\n> \n>> -    if (line_term)\n>> +    if (arg_missing_action == MA_PRINT_ONLY) {\n>> +        printf(\"%s\", oid_to_hex(&entry->entry.oid));\n>> +        putchar(line_term);\n> \n> Is there a reason you didn't use a printf(\"%s%c\") here to\n> put the oid and line_term together?\n\n\nI just followed the existing pattern in the same function where every \nother path uses a separate putchar(line_term). Happy to combine if you \nprefer.\n\n\n> \n>> +        return;\n>> +    } else if (line_term) {\n>>           printf(\"?%s\", oid_to_hex(&entry->entry.oid));\n>> -    else\n>> +    } else {\n>>           printf(\"%s%cmissing=yes\", oid_to_hex(&entry->entry.oid),\n>>                  info_term);\n>> +    }\n> \n> \n> \n>>       if (!print_missing_info) {\n>>           putchar(line_term);\n>> @@ -209,6 +222,7 @@ static inline void finish_object__ma(struct object \n>> *obj, const char *name)\n>>       case MA_PRINT:\n>>       case MA_PRINT_INFO:\n>> +    case MA_PRINT_ONLY:\n>>           add_missing_object_entry(&obj->oid, name, obj->type);\n>>           return;\n>> @@ -246,6 +260,11 @@ static void show_commit(struct commit *commit, \n>> void *data)\n>>           return;\n>>       }\n>> +    if (arg_missing_action == MA_PRINT_ONLY) {\n>> +        finish_commit(commit);\n>> +        return;\n>> +    }\n>> +\n>>       if (show_disk_usage)\n>>           total_disk_usage += get_object_disk_usage(&commit->object);\n>> @@ -384,6 +403,8 @@ static void show_object(struct object *obj, const \n>> char *name, void *cb_data)\n>>       if (finish_object(obj, name, cb_data))\n>>           return;\n>>       display_progress(progress, ++progress_counter);\n>> +    if (arg_missing_action == MA_PRINT_ONLY)\n>> +        return;\n>>       if (show_disk_usage)\n>>           total_disk_usage += get_object_disk_usage(obj);\n>>       if (info->flags & REV_LIST_QUIET)\n>> @@ -525,6 +546,12 @@ static inline int \n>> parse_missing_action_value(const char *value)\n>>           return 1;\n>>       }\n>> +    if (!strcmp(value, \"print-only\")) {\n>> +        arg_missing_action = MA_PRINT_ONLY;\n>> +        fetch_if_missing = 0;\n>> +        return 1;\n>> +    }\n>> +\n>>       if (!strcmp(value, \"allow-promisor\")) {\n>>           arg_missing_action = MA_ALLOW_PROMISOR;\n>>           fetch_if_missing = 0;\n>> @@ -967,8 +994,7 @@ int cmd_rev_list(int argc,\n>>       if (arg_print_omitted)\n>>           oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);\n>> -    if (arg_missing_action == MA_PRINT ||\n>> -        arg_missing_action == MA_PRINT_INFO) {\n>> +    if (missing_action_prints()) {\n>>           struct oidset_iter iter;\n>>           struct object_id *oid;\n>> @@ -994,8 +1020,7 @@ int cmd_rev_list(int argc,\n>>               printf(\"~%s\\n\", oid_to_hex(oid));\n>>           oidset_clear(&omitted_objects);\n>>       }\n>> -    if (arg_missing_action == MA_PRINT ||\n>> -        arg_missing_action == MA_PRINT_INFO) {\n>> +    if (missing_action_prints()) {\n>>           struct missing_objects_map_entry *entry;\n>>           struct oidmap_iter iter;\n>> @@ -1011,7 +1036,7 @@ int cmd_rev_list(int argc,\n>>       stop_progress(&progress);\n>> -    if (revs.count) {\n>> +    if (revs.count && arg_missing_action != MA_PRINT_ONLY) {\n>>           if (revs.left_right && revs.cherry_mark)\n>>               printf(\"%d\\t%d\\t%d\\n\", revs.count_left, \n>> revs.count_right, revs.count_same);\n>>           else if (revs.left_right)\n>> @@ -1022,7 +1047,7 @@ int cmd_rev_list(int argc,\n>>               printf(\"%d\\n\", revs.count_left + revs.count_right);\n>>       }\n>> -    if (show_disk_usage)\n>> +    if (show_disk_usage && arg_missing_action != MA_PRINT_ONLY)\n>>           print_disk_usage(total_disk_usage);\n> \n> I'm a little worried about all of these checks that need\n> special-casing. These seem like options that are enabled\n\n\nPhillip suggested making this a separate --missing-only flag that \ncomposes with existing --missing= modes - I think that's a better \ndesign. will work v2 around it.\n\n\n> by other options and could easily be grouped with the\n> print-only setting.\n> \n> If there is something wrong here where these need to be\n> disabled, then we should update the documentation to say\n\n\nAgreed - I will make --count and --disk-usage incompatible with \n--missing-only and die() with a clear message instead of silently \nsuppressing them.\n\n\n\n> how this interacts with those options. And perhaps some\n> warnings to say \"these options are not compatible\".\n> \n> On that note: this patch is missing a document update.\n\n\nThere is a doc update in rev-list-options.doc, but it doesn't  cover \ninteractions with --count/--disk-usage. Will fix in v2.\n\n\n> \n> Thanks,\n> -Stolee\n> \n> \n\n\n\n\nThanks,\nAsthana\n"},{"id":"541965","messageId":"3bb52232-ebe4-4c50-a674-943a175e983d@gmail.com","threadId":"65512","inReplyTo":"aeXZOAtILSr638LG@pks.im","subject":"Re: [PATCH v1 1/1] rev-list: add --missing=print-only mode","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2026-04-20T10:33:36Z","receivedAt":"2026-04-20T10:33:44Z","isPatch":true,"body":"\n\nOn 20/04/26 13:13, Patrick Steinhardt wrote:\n> On Sun, Apr 19, 2026 at 02:18:40PM +0530, Siddharth Asthana wrote:\n>> When working with partial clones, it's common to want just the list of\n>> missing objects. The current --missing=print mode does this but mixes\n>> present and missing objects together, with missing ones prefixed by '?'.\n>> Getting only the missing OIDs requires an extra pipe:\n>>\n>>    git rev-list --objects --all --missing=print | perl -ne 'print if s/^[?]//'\n>>\n>> Add --missing=print-only which outputs only the missing object OIDs, one\n>> per line, without any prefix. This makes the above one-liner unnecessary\n>> and the output directly usable by downstream tools.\n> \n> Naming is a bit tough, as \"print-only\" sounds as if we're only printing\n> them without doing anything else, but it doesn't quite convey the\n\n\nThe name came from Christian's original suggesttion in the issue [1], \nbut agreed it's ambiguous. Phillip's --missing-only approach solve this.\n\n[1] https://gitlab.com/gitlab-org/git/-/work_items/80#note_464005298\n\n\n> relation to non-missing objects. I don't really have a better suggestion\n> though -- \"print-exclusively\" may convey the meaning a tiny bit better,\n> but still suffers kind of the same issue.\n> \n>> diff --git a/builtin/rev-list.c b/builtin/rev-list.c\n>> index 8f63003709..ba7e3e3919 100644\n>> --- a/builtin/rev-list.c\n>> +++ b/builtin/rev-list.c\n>> @@ -104,14 +104,22 @@ static void missing_objects_map_entry_free(void *e)\n>>   \n>>   static struct oidmap missing_objects;\n>>   enum missing_action {\n>> -\tMA_ERROR = 0,    /* fail if any missing objects are encountered */\n>> -\tMA_ALLOW_ANY,    /* silently allow ALL missing objects */\n>> -\tMA_PRINT,        /* print ALL missing objects in special section */\n>> -\tMA_PRINT_INFO,   /* same as MA_PRINT but also prints missing object info */\n>> +\tMA_ERROR = 0, /* fail if any missing objects are encountered */\n>> +\tMA_ALLOW_ANY, /* silently allow ALL missing objects */\n>> +\tMA_PRINT, /* print ALL missing objects in special section */\n>> +\tMA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */\n>> +\tMA_PRINT_ONLY, /* print ONLY missing objects, without the \"?\" prefix */\n> \n> Makes me wonder whether we'll eventually also want to have\n> `MA_PRINT_INFO_ONLY`.\n\n\n\nRight - that's the strongest argument for --missing-only as a separate \nflag. Gets us that for free.\n\n\n> \n>>   \tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n>>   };\n>>   static enum missing_action arg_missing_action;\n>>   \n>> +static inline int missing_action_prints(void)\n> \n> How about naming this `should_print_missing_object()` instead? That\n> gives the reader a bit more context.\n\n\nThe function is a predicate on the mode, not on a specific object, so \nthat name would be slightly misleading. But with --missing-only this \nhelper might change shape anyway. WDYT?\n\n\n\n> \n>> @@ -1011,7 +1036,7 @@ int cmd_rev_list(int argc,\n>>   \n>>   \tstop_progress(&progress);\n>>   \n>> -\tif (revs.count) {\n>> +\tif (revs.count && arg_missing_action != MA_PRINT_ONLY) {\n>>   \t\tif (revs.left_right && revs.cherry_mark)\n>>   \t\t\tprintf(\"%d\\t%d\\t%d\\n\", revs.count_left, revs.count_right, revs.count_same);\n>>   \t\telse if (revs.left_right)\n> \n> Not a fault of your patch, but I really feel like git-rev-list(1) is\n> becoming more and more tangled. The fact that we have to add this check\n> to so many different sites doesn't inspire confidence that we have\n> indeed catched all of them that need this check.\n> \n> It would be great if this was reworked a bit to become more obvious, but\n> that's probably outside the scope of this patch series.\n> \n>> diff --git a/t/t6022-rev-list-missing.sh b/t/t6022-rev-list-missing.sh\n>> index 08e92dd002..105560ad21 100755\n>> --- a/t/t6022-rev-list-missing.sh\n>> +++ b/t/t6022-rev-list-missing.sh\n>> @@ -198,6 +198,32 @@ do\n>>   \t'\n>>   done\n>>   \n>> +for obj in \"HEAD~1\" \"HEAD~1^{tree}\" \"HEAD:1.t\"\n>> +do\n>> +\ttest_expect_success \"rev-list --missing=print-only with missing $obj\" '\n>> +\t\toid=\"$(git rev-parse $obj)\" &&\n>> +\t\tpath=\".git/objects/$(test_oid_to_path $oid)\" &&\n>> +\n>> +\t\t# Capture present OIDs before hiding anything.\n>> +\t\tgit rev-list --objects --no-object-names HEAD ^$obj >present.raw &&\n>> +\n>> +\t\tmv \"$path\" \"$path.hidden\" &&\n>> +\t\ttest_when_finished \"mv $path.hidden $path\" &&\n>> +\n>> +\t\tgit rev-list --missing=print-only --objects --no-object-names \\\n>> +\t\t\tHEAD >actual &&\n>> +\n>> +\t\t# Only the missing OID should appear, without the \"?\" prefix.\n>> +\t\tgrep \"^$oid$\" actual &&\n>> +\n>> +\t\t# Present objects must NOT appear in the output.\n>> +\t\twhile read present_oid\n>> +\t\tdo\n>> +\t\t\t! grep \"^$present_oid$\" actual || return 1\n>> +\t\tdone <present.raw\n> \n> How many present object IDs do we have? I'm a bit worried that we now\n> execute grep(1) hundreds of times. Can we maybe do some tricks with\n> comm(1) instead?\n\n\nPhillip's test_cmp approach is simpler, since we hide one object, the \noutput should be exactly that OID. Will use that.\n\n\nThanks,\nAsthana\n\n\n> \n> Thanks!\n> \n> Patrick\n\n"},{"id":"541966","messageId":"3363a365-9529-44e5-bc4e-ba19bf97ed97@gmail.com","threadId":"65512","inReplyTo":"491a27af-3ea4-4978-9d51-9c540ad31589@gmail.com","subject":"Re: [PATCH v1 1/1] rev-list: add --missing=print-only mode","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2026-04-20T10:37:27Z","receivedAt":"2026-04-20T10:37:35Z","isPatch":true,"body":"\n\nOn 20/04/26 14:27, Phillip Wood wrote:\n> On 20/04/2026 08:43, Patrick Steinhardt wrote:\n>> On Sun, Apr 19, 2026 at 02:18:40PM +0530, Siddharth Asthana wrote:\n>>\n>>>   static struct oidmap missing_objects;\n>>>   enum missing_action {\n>>> -    MA_ERROR = 0,    /* fail if any missing objects are encountered */\n>>> -    MA_ALLOW_ANY,    /* silently allow ALL missing objects */\n>>> -    MA_PRINT,        /* print ALL missing objects in special section */\n>>> -    MA_PRINT_INFO,   /* same as MA_PRINT but also prints missing \n>>> object info */\n>>> +    MA_ERROR = 0, /* fail if any missing objects are encountered */\n>>> +    MA_ALLOW_ANY, /* silently allow ALL missing objects */\n>>> +    MA_PRINT, /* print ALL missing objects in special section */\n>>> +    MA_PRINT_INFO, /* same as MA_PRINT but also prints missing \n>>> object info */\n>>> +    MA_PRINT_ONLY, /* print ONLY missing objects, without the \"?\" \n>>> prefix */\n>>\n>> Makes me wonder whether we'll eventually also want to have\n>> `MA_PRINT_INFO_ONLY`.\n> \n> Perhaps we'd be better to add a \"--missing-only\" option that limits the \n> output to missing objects? That would avoid the problem of \"-- \n\n\nMake sense, its orthogonal to --missing= and handles print-info-only for \nfree.\n\nQuestion though: should --missing-only without --missing=print (or \nprint-info) be an errro? I am leaning towards requiring it explicitly so \nthe behavior is always obvious.\n\nWill rework v2 around this.\n\n\n> missing=print-only\" not really explaining what it does as well.\n> \n>>> +for obj in \"HEAD~1\" \"HEAD~1^{tree}\" \"HEAD:1.t\"\n>>> +do\n>>> +    test_expect_success \"rev-list --missing=print-only with missing \n>>> $obj\" '\n>>> +        oid=\"$(git rev-parse $obj)\" &&\n>>> +        path=\".git/objects/$(test_oid_to_path $oid)\" &&\n>>> +\n>>> +        # Capture present OIDs before hiding anything.\n>>> +        git rev-list --objects --no-object-names HEAD ^$obj \n>>> >present.raw &&\n>>> +\n>>> +        mv \"$path\" \"$path.hidden\" &&\n>>> +        test_when_finished \"mv $path.hidden $path\" &&\n>>> +\n>>> +        git rev-list --missing=print-only --objects --no-object-names \\\n>>> +            HEAD >actual &&\n>>> +\n>>> +        # Only the missing OID should appear, without the \"?\" prefix.\n>>> +        grep \"^$oid$\" actual &&\n>>> +\n>>> +        # Present objects must NOT appear in the output.\n>>> +        while read present_oid\n>>> +        do\n>>> +            ! grep \"^$present_oid$\" actual || return 1\n>>> +        done <present.raw\n>>\n>> How many present object IDs do we have? I'm a bit worried that we now\n>> execute grep(1) hundreds of times. Can we maybe do some tricks with\n>> comm(1) instead?\n> \n> If we want to verify that it only prints a single oid then\n> \n>      echo $oid >expect &&\n>      test_cmp expect actual\n> \n> would be much simpler more helpful if the test fails\n\n\nyeah much cleaner, will use it. Thanks\n\n\n\n> \n> Thanks\n> \n> Phil\n\n\nThanks,\nAsthana\n"},{"id":"541967","messageId":"5bf346c1-0577-4b9b-8713-6053c97c6121@app.fastmail.com","threadId":"65512","inReplyTo":"491a27af-3ea4-4978-9d51-9c540ad31589@gmail.com","subject":"Re: [PATCH v1 1/1] rev-list: add --missing=print-only mode","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2026-04-20T11:00:53Z","receivedAt":"2026-04-20T11:01:56Z","isPatch":true,"body":"On Mon, Apr 20, 2026, at 10:57, Phillip Wood wrote:\n> On 20/04/2026 08:43, Patrick Steinhardt wrote:\n>> On Sun, Apr 19, 2026 at 02:18:40PM +0530, Siddharth Asthana wrote:\n>>\n>>>   static struct oidmap missing_objects;\n>>>   enum missing_action {\n>>> -\tMA_ERROR = 0,    /* fail if any missing objects are encountered */\n>>> -\tMA_ALLOW_ANY,    /* silently allow ALL missing objects */\n>>> -\tMA_PRINT,        /* print ALL missing objects in special section */\n>>> -\tMA_PRINT_INFO,   /* same as MA_PRINT but also prints missing object info */\n>>> +\tMA_ERROR = 0, /* fail if any missing objects are encountered */\n>>> +\tMA_ALLOW_ANY, /* silently allow ALL missing objects */\n>>> +\tMA_PRINT, /* print ALL missing objects in special section */\n>>> +\tMA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */\n>>> +\tMA_PRINT_ONLY, /* print ONLY missing objects, without the \"?\" prefix */\n>>\n>> Makes me wonder whether we'll eventually also want to have\n>> `MA_PRINT_INFO_ONLY`.\n>\n> Perhaps we'd be better to add a \"--missing-only\" option that limits the\n> output to missing objects? That would avoid the problem of\n> \"--missing=print-only\" not really explaining what it does as well.\n\nThe original `--missing` says what to do about missing objects. I find\n`--missing=print-only` to be surprising:\n\n• Do print missing\n• But also do not print present objects\n\nWhy would a `--missing` option dictate what to do about objects that are\npresent (hide them)? That looks tacked-on.\n\n`--missing-only` is better but has the same problem, IMO, of dictating\nhow present objects should be treated.\n\nFrom the cover letter:\n\nCV> At GitLab, Gitaly uses `rev-list --missing=print` to find missing\nCV> objects in partial clones. The current output mixes present and missing\nCV> objects together, with missing ones prefixed by '?', so Gitaly has to\nCV> post-process the output to extract just the missing OIDs. Having a\nCV> dedicated mode that outputs only the missing OIDs directly would\nCV> simplify this.\n\nThis makes me think that I want:\n\n1. I do want missing objects\n2. I do not want present objects\n\nWhich makes me think that something like `--present=no-print` makes\nmore sense.\n\nJust speaking as a user and not looking at the code.\n\n>[snip]\n"},{"id":"541971","messageId":"8a3e3a38-3f8e-4363-9e45-b5610c3efbc5@gmail.com","threadId":"65512","inReplyTo":"9e2ca91d-9091-4d4d-9427-ec8a23ee8909@gmail.com","subject":"Re: [PATCH v1 1/1] rev-list: add --missing=print-only mode","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2026-04-20T11:44:44Z","receivedAt":"2026-04-20T11:44:46Z","isPatch":true,"body":"On 4/20/2026 6:24 AM, Siddharth Asthana wrote:\n> On 20/04/26 04:06, Derrick Stolee wrote:\n>> On 4/19/26 4:48 AM, Siddharth Asthana wrote:\n\n>>> -    if (line_term)\n>>> +    if (arg_missing_action == MA_PRINT_ONLY) {\n>>> +        printf(\"%s\", oid_to_hex(&entry->entry.oid));\n>>> +        putchar(line_term);\n>>\n>> Is there a reason you didn't use a printf(\"%s%c\") here to\n>> put the oid and line_term together?\n> \n> \n> I just followed the existing pattern in the same function where every other path uses a separate putchar(line_term). Happy to combine if you prefer.\n\n>>> +    } else {\n>>>           printf(\"%s%cmissing=yes\", oid_to_hex(&entry->entry.oid),\n>>>                  info_term);\n\nI was just looking at this line in the patch context as\ncomparison, but if there are other patterns that prefer\n\"printf(); putc();\" then that's enough for me.\n\n>>> -    if (show_disk_usage)\n>>> +    if (show_disk_usage && arg_missing_action != MA_PRINT_ONLY)\n>>>           print_disk_usage(total_disk_usage);\n>>\n>> I'm a little worried about all of these checks that need\n>> special-casing. These seem like options that are enabled\n> \n> Phillip suggested making this a separate --missing-only flag that composes with existing --missing= modes - I think that's a better design. will work v2 around it.\n\nThat's a good idea. '--missing=' formats the output while\nyour mode _filters_ the output. They are different things\nand worth different options.\n\n>> how this interacts with those options. And perhaps some\n>> warnings to say \"these options are not compatible\".\n>>\n>> On that note: this patch is missing a document update.\n> \n> \n> There is a doc update in rev-list-options.doc, but it doesn't  cover interactions with --count/--disk-usage. Will fix in v2.\n\nYou're right. I thought I had looked for it in the patch\nbut missed it somehow.\n\nThanks,\n-Stolee\n\n"},{"id":"551696","messageId":"20260901185100.33948-1-siddharthasthana31@gmail.com","threadId":"65512","inReplyTo":"20260419084840.33986-1-siddharthasthana31@gmail.com","subject":"[PATCH v2 0/1] rev-list: add --missing-only option to filter output","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2026-09-01T18:50:59Z","receivedAt":"2026-09-01T18:51:07Z","isPatch":true,"body":"Hi,\n\nAt GitLab, Gitaly uses rev-list --missing=print on partial clones to\nfind missing objects. The output mixes present and missing objects and\nprefixes missing ones with '?', so we post-process it. --missing-only\navoids that.\n\nv1 added --missing=print-only as a --missing= mode. Review preferred a\nseparate filter flag, so v2 adds --missing-only next to --missing=print\nor --missing=print-info.\n\nBased on 1630431f32 (The 21st batch, 2026-08-31).\n\nChanges from v1 include:\n1. Separate --missing-only flag instead of print-only mode\n   (Phillip, Patrick, Stolee).\n2. Require --missing=print or --missing=print-info.\n3. Die on --count / --disk-usage (Stolee).\n4. No enum comment spacing churn.\n5. print-info still prints path=/type=; only '?' is dropped.\n6. test_cmp-based tests (Phillip).\n7. Link to v1:\n   https://lore.kernel.org/git/20260419084840.33986-1-siddharthasthana31@gmail.com/\n\nThanks,\nSiddharth\n\n---\nSiddharth Asthana (1):\n  rev-list: add --missing-only option to filter output\n\n Documentation/rev-list-options.adoc | 13 ++++++++\n builtin/rev-list.c                  | 42 ++++++++++++++++++++++---\n t/t6022-rev-list-missing.sh         | 49 +++++++++++++++++++++++++++++\n 3 files changed, 99 insertions(+), 5 deletions(-)\n\nRange-diff versus v1:\n\n1:  7e8f1ad997 ! 1:  3c89e6bc38 rev-list: add --missing=print-only mode\n    @@ Metadata\n     Author: Siddharth Asthana <siddharthasthana31@gmail.com>\n     \n      ## Commit message ##\n    -    rev-list: add --missing=print-only mode\n    +    rev-list: add --missing-only option to filter output\n     \n    -    When working with partial clones, it's common to want just the list of\n    -    missing objects. The current --missing=print mode does this but mixes\n    -    present and missing objects together, with missing ones prefixed by '?'.\n    -    Getting only the missing OIDs requires an extra pipe:\n    +    When working with partial clones, callers often need only the missing\n    +    object IDs. Today that means post-processing --missing=print to drop\n    +    present objects and strip the leading '?':\n     \n           git rev-list --objects --all --missing=print | perl -ne 'print if s/^[?]//'\n     \n    -    Add --missing=print-only which outputs only the missing object OIDs, one\n    -    per line, without any prefix. This makes the above one-liner unnecessary\n    -    and the output directly usable by downstream tools.\n    +    Add --missing-only. Use it with --missing=print or --missing=print-info\n    +    to print only missing objects. --missing= still picks the format;\n    +    --missing-only only filters. The leading '?' is omitted. With\n    +    print-info, path= and type= are still shown.\n    +\n    +    Require --missing=print or --missing=print-info. Reject --count and\n    +    --disk-usage.\n     \n         Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n     \n      ## Documentation/rev-list-options.adoc ##\n    -@@ Documentation/rev-list-options.adoc: Unexpected missing objects will raise an error.\n    - The form `--missing=print` is like `allow-any`, but will also print a\n    - list of the missing objects.  Object IDs are prefixed with a ``?'' character.\n    - +\n    -+The form `--missing=print-only` is like `print`, but will print ONLY the\n    -+missing objects (not the present ones), and without the ``?'' prefix.  This\n    -+is useful for scripting, as a simpler alternative to\n    -+`--missing=print | sed -n 's/^?//p'`.\n    +@@ Documentation/rev-list-options.adoc: If some tips passed to the traversal are missing, they will be\n    + considered as missing too, and the traversal will ignore them. In case\n    + we cannot get their Object ID though, an error will be raised.\n    + \n    ++`--missing-only`::\n    ++\tWhen used together with `--missing=print` or `--missing=print-info`,\n    ++\tsuppress all output for present objects and print only the missing\n    ++\tones.  The selected `--missing=` format is preserved (so\n    ++\t`--missing=print-info` still emits `path=` / `type=` fields), but the\n    ++\tleading ``?'' prefix used by the non-`-z` forms is omitted.  This is\n    ++\tuseful for scripting, as a simpler and faster alternative to\n    ++\tpost-processing the output of `--missing=print`.\n     ++\n    - The form `--missing=print-info` is like `print`, but will also print additional\n    - information about the missing object inferred from its containing object. The\n    - information is all printed on the same line with the missing object ID in the\n    ++This option is incompatible with `--count` and `--disk-usage`.\n    ++It is an error to use `--missing-only` without `--missing=print` or\n    ++`--missing=print-info`.\n    ++\n    + `--exclude-promisor-objects`::\n    + \t(For internal use only.)  Prefilter object traversal at\n    + \tpromisor boundary.  This is used with partial clone.  This is\n     \n      ## builtin/rev-list.c ##\n    -@@ builtin/rev-list.c: static void missing_objects_map_entry_free(void *e)\n    - \n    - static struct oidmap missing_objects;\n    - enum missing_action {\n    --\tMA_ERROR = 0,    /* fail if any missing objects are encountered */\n    --\tMA_ALLOW_ANY,    /* silently allow ALL missing objects */\n    --\tMA_PRINT,        /* print ALL missing objects in special section */\n    --\tMA_PRINT_INFO,   /* same as MA_PRINT but also prints missing object info */\n    -+\tMA_ERROR = 0, /* fail if any missing objects are encountered */\n    -+\tMA_ALLOW_ANY, /* silently allow ALL missing objects */\n    -+\tMA_PRINT, /* print ALL missing objects in special section */\n    -+\tMA_PRINT_INFO, /* same as MA_PRINT but also prints missing object info */\n    -+\tMA_PRINT_ONLY, /* print ONLY missing objects, without the \"?\" prefix */\n    +@@ builtin/rev-list.c: enum missing_action {\n      \tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n      };\n      static enum missing_action arg_missing_action;\n    - \n    -+static inline int missing_action_prints(void)\n    ++static int arg_missing_only;\n    ++\n    ++static inline int should_collect_missing(void)\n     +{\n     +\treturn arg_missing_action == MA_PRINT ||\n    -+\t       arg_missing_action == MA_PRINT_INFO ||\n    -+\t       arg_missing_action == MA_PRINT_ONLY;\n    ++\t       arg_missing_action == MA_PRINT_INFO;\n     +}\n    -+\n    + \n      /* display only the oid of each object encountered */\n      static int arg_show_object_names = 1;\n    - \n     @@ builtin/rev-list.c: static void print_missing_object(struct missing_objects_map_entry *entry,\n      {\n      \tstruct strbuf sb = STRBUF_INIT;\n      \n     -\tif (line_term)\n    -+\tif (arg_missing_action == MA_PRINT_ONLY) {\n    ++\t/*\n    ++\t * --missing-only filters present objects out of the walk output.\n    ++\t * It still uses the selected --missing= format for missing ones,\n    ++\t * except the human \"?\" prefix is omitted (script-friendly OIDs).\n    ++\t */\n    ++\tif (arg_missing_only && line_term)\n     +\t\tprintf(\"%s\", oid_to_hex(&entry->entry.oid));\n    -+\t\tputchar(line_term);\n    -+\t\treturn;\n    -+\t} else if (line_term) {\n    ++\telse if (line_term)\n      \t\tprintf(\"?%s\", oid_to_hex(&entry->entry.oid));\n    --\telse\n    -+\t} else {\n    + \telse\n      \t\tprintf(\"%s%cmissing=yes\", oid_to_hex(&entry->entry.oid),\n    - \t\t       info_term);\n    -+\t}\n    - \n    - \tif (!print_missing_info) {\n    - \t\tputchar(line_term);\n    -@@ builtin/rev-list.c: static inline void finish_object__ma(struct object *obj, const char *name)\n    - \n    - \tcase MA_PRINT:\n    - \tcase MA_PRINT_INFO:\n    -+\tcase MA_PRINT_ONLY:\n    - \t\tadd_missing_object_entry(&obj->oid, name, obj->type);\n    - \t\treturn;\n    - \n     @@ builtin/rev-list.c: static void show_commit(struct commit *commit, void *data)\n      \t\treturn;\n      \t}\n      \n    -+\tif (arg_missing_action == MA_PRINT_ONLY) {\n    ++\tif (arg_missing_only) {\n     +\t\tfinish_commit(commit);\n     +\t\treturn;\n     +\t}\n    @@ builtin/rev-list.c: static void show_object(struct object *obj, const char *name\n      \tif (finish_object(obj, name, cb_data))\n      \t\treturn;\n      \tdisplay_progress(progress, ++progress_counter);\n    -+\tif (arg_missing_action == MA_PRINT_ONLY)\n    ++\tif (arg_missing_only)\n     +\t\treturn;\n      \tif (show_disk_usage)\n      \t\ttotal_disk_usage += get_object_disk_usage(obj);\n      \tif (info->flags & REV_LIST_QUIET)\n    -@@ builtin/rev-list.c: static inline int parse_missing_action_value(const char *value)\n    - \t\treturn 1;\n    +@@ builtin/rev-list.c: int cmd_rev_list(int argc,\n    + \t\t\trevs.exclude_promisor_objects = 1;\n    + \t\t} else if (skip_prefix(arg, \"--missing=\", &arg)) {\n    + \t\t\tparse_missing_action_value(arg);\n    ++\t\t} else if (!strcmp(arg, \"--missing-only\")) {\n    ++\t\t\targ_missing_only = 1;\n    + \t\t} else if (!strcmp(arg, \"-z\")) {\n    + \t\t\tline_term = '\\0';\n    + \t\t\tinfo_term = '\\0';\n    + \t\t}\n      \t}\n      \n    -+\tif (!strcmp(value, \"print-only\")) {\n    -+\t\targ_missing_action = MA_PRINT_ONLY;\n    -+\t\tfetch_if_missing = 0;\n    -+\t\treturn 1;\n    -+\t}\n    ++\tif (arg_missing_only && !should_collect_missing())\n    ++\t\tdie(_(\"--missing-only requires --missing=print or --missing=print-info\"));\n    ++\n    + \tdie_for_incompatible_opt2(revs.exclude_promisor_objects,\n    + \t\t\t\t  \"--exclude_promisor_objects\",\n    + \t\t\t\t  arg_missing_action, \"--missing\");\n    +@@ builtin/rev-list.c: int cmd_rev_list(int argc,\n    + \t\t\tcontinue;\n    + \t\t}\n    + \n    ++\t\tif (!strcmp(arg, \"--missing-only\"))\n    ++\t\t\tcontinue;\n    ++\n    + \t\tusage(rev_list_usage);\n    + \n    + \t}\n    +@@ builtin/rev-list.c: int cmd_rev_list(int argc,\n    + \t    (revs.left_right || revs.cherry_mark))\n    + \t\tdie(_(\"marked counting and '%s' cannot be used together\"), \"--objects\");\n    + \n    ++\tdie_for_incompatible_opt2(arg_missing_only, \"--missing-only\",\n    ++\t\t\t\t  revs.count, \"--count\");\n    ++\tdie_for_incompatible_opt2(arg_missing_only, \"--missing-only\",\n    ++\t\t\t\t  show_disk_usage, \"--disk-usage\");\n     +\n    - \tif (!strcmp(value, \"allow-promisor\")) {\n    - \t\targ_missing_action = MA_ALLOW_PROMISOR;\n    - \t\tfetch_if_missing = 0;\n    + \tsave_commit_buffer = (revs.verbose_header ||\n    + \t\t\t      revs.grep_filter.pattern_list ||\n    + \t\t\t      revs.grep_filter.header_list);\n     @@ builtin/rev-list.c: int cmd_rev_list(int argc,\n      \n      \tif (arg_print_omitted)\n      \t\toidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);\n     -\tif (arg_missing_action == MA_PRINT ||\n     -\t    arg_missing_action == MA_PRINT_INFO) {\n    -+\tif (missing_action_prints()) {\n    ++\tif (should_collect_missing()) {\n      \t\tstruct oidset_iter iter;\n      \t\tstruct object_id *oid;\n      \n    @@ builtin/rev-list.c: int cmd_rev_list(int argc,\n      \t}\n     -\tif (arg_missing_action == MA_PRINT ||\n     -\t    arg_missing_action == MA_PRINT_INFO) {\n    -+\tif (missing_action_prints()) {\n    ++\tif (should_collect_missing()) {\n      \t\tstruct missing_objects_map_entry *entry;\n      \t\tstruct oidmap_iter iter;\n      \n    -@@ builtin/rev-list.c: int cmd_rev_list(int argc,\n    - \n    - \tstop_progress(&progress);\n    - \n    --\tif (revs.count) {\n    -+\tif (revs.count && arg_missing_action != MA_PRINT_ONLY) {\n    - \t\tif (revs.left_right && revs.cherry_mark)\n    - \t\t\tprintf(\"%d\\t%d\\t%d\\n\", revs.count_left, revs.count_right, revs.count_same);\n    - \t\telse if (revs.left_right)\n    -@@ builtin/rev-list.c: int cmd_rev_list(int argc,\n    - \t\t\tprintf(\"%d\\n\", revs.count_left + revs.count_right);\n    - \t}\n    - \n    --\tif (show_disk_usage)\n    -+\tif (show_disk_usage && arg_missing_action != MA_PRINT_ONLY)\n    - \t\tprint_disk_usage(total_disk_usage);\n    - \n    - cleanup:\n     \n      ## t/t6022-rev-list-missing.sh ##\n     @@ t/t6022-rev-list-missing.sh: do\n    @@ t/t6022-rev-list-missing.sh: do\n      \n     +for obj in \"HEAD~1\" \"HEAD~1^{tree}\" \"HEAD:1.t\"\n     +do\n    -+\ttest_expect_success \"rev-list --missing=print-only with missing $obj\" '\n    ++\ttest_expect_success \"rev-list --missing-only with missing $obj\" '\n     +\t\toid=\"$(git rev-parse $obj)\" &&\n     +\t\tpath=\".git/objects/$(test_oid_to_path $oid)\" &&\n     +\n    -+\t\t# Capture present OIDs before hiding anything.\n    -+\t\tgit rev-list --objects --no-object-names HEAD ^$obj >present.raw &&\n    -+\n     +\t\tmv \"$path\" \"$path.hidden\" &&\n     +\t\ttest_when_finished \"mv $path.hidden $path\" &&\n     +\n    -+\t\tgit rev-list --missing=print-only --objects --no-object-names \\\n    -+\t\t\tHEAD >actual &&\n    -+\n    -+\t\t# Only the missing OID should appear, without the \"?\" prefix.\n    -+\t\tgrep \"^$oid$\" actual &&\n    ++\t\tgit rev-list --missing=print --missing-only --objects \\\n    ++\t\t\t--no-object-names HEAD >actual &&\n     +\n    -+\t\t# Present objects must NOT appear in the output.\n    -+\t\twhile read present_oid\n    -+\t\tdo\n    -+\t\t\t! grep \"^$present_oid$\" actual || return 1\n    -+\t\tdone <present.raw\n    ++\t\techo $oid >expect &&\n    ++\t\ttest_cmp expect actual\n     +\t'\n     +done\n    ++\n    ++test_expect_success \"--missing-only requires --missing=print or --missing=print-info\" '\n    ++\ttest_must_fail git rev-list --missing-only --objects HEAD 2>err &&\n    ++\ttest_grep \"requires --missing=print\" err\n    ++'\n    ++\n    ++test_expect_success \"--missing-only is incompatible with --count\" '\n    ++\ttest_must_fail git rev-list --missing=print --missing-only \\\n    ++\t\t--count --objects HEAD 2>err &&\n    ++\ttest_grep \"cannot be used together\" err\n    ++'\n    ++\n    ++test_expect_success \"--missing-only is incompatible with --disk-usage\" '\n    ++\ttest_must_fail git rev-list --missing=print --missing-only \\\n    ++\t\t--disk-usage --objects HEAD 2>err &&\n    ++\ttest_grep \"cannot be used together\" err\n    ++'\n    ++\n    ++test_expect_success \"--missing-only works with --missing=print-info\" '\n    ++\toid=\"$(git rev-parse HEAD:1.t)\" &&\n    ++\tpath=\".git/objects/$(test_oid_to_path $oid)\" &&\n    ++\n    ++\tmv \"$path\" \"$path.hidden\" &&\n    ++\ttest_when_finished \"mv $path.hidden $path\" &&\n    ++\n    ++\tgit rev-list --missing=print-info --missing-only --objects \\\n    ++\t\t--no-object-names HEAD >actual &&\n    ++\n    ++\t# Filter keeps print-info fields; only the \"?\" prefix is dropped.\n    ++\techo \"$oid path=1.t type=blob\" >expect &&\n    ++\ttest_cmp expect actual\n    ++'\n     +\n      test_expect_success \"-z nul-delimited --missing\" '\n      \ttest_when_finished rm -rf repo &&\n\nbase-commit: 1630431f326e15fcde608827b5ff38422528eb59\n"},{"id":"551697","messageId":"20260901185100.33948-2-siddharthasthana31@gmail.com","threadId":"65512","inReplyTo":"20260901185100.33948-1-siddharthasthana31@gmail.com","subject":"[PATCH v2 1/1] rev-list: add --missing-only option to filter output","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2026-09-01T18:51:00Z","receivedAt":"2026-09-01T18:51:15Z","isPatch":true,"body":"When working with partial clones, callers often need only the missing\nobject IDs. Today that means post-processing --missing=print to drop\npresent objects and strip the leading '?':\n\n  git rev-list --objects --all --missing=print | perl -ne 'print if s/^[?]//'\n\nAdd --missing-only. Use it with --missing=print or --missing=print-info\nto print only missing objects. --missing= still picks the format;\n--missing-only only filters. The leading '?' is omitted. With\nprint-info, path= and type= are still shown.\n\nRequire --missing=print or --missing=print-info. Reject --count and\n--disk-usage.\n\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\nChanges from v1 include:\n1. Replace --missing=print-only mode with a separate --missing-only flag\n   (Phillip, Patrick, Stolee).\n2. Require --missing=print or --missing=print-info.\n3. Die when combined with --count or --disk-usage (Stolee).\n4. Keep enum comment alignment (no spacing churn).\n5. Keep print-info path=/type=; only drop '?'.\n6. Simpler tests with test_cmp (Phillip).\n\n Documentation/rev-list-options.adoc | 13 ++++++++\n builtin/rev-list.c                  | 42 ++++++++++++++++++++++---\n t/t6022-rev-list-missing.sh         | 49 +++++++++++++++++++++++++++++\n 3 files changed, 99 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc\nindex fd831f0ec6..bd9f345690 100644\n--- a/Documentation/rev-list-options.adoc\n+++ b/Documentation/rev-list-options.adoc\n@@ -1083,6 +1083,19 @@ If some tips passed to the traversal are missing, they will be\n considered as missing too, and the traversal will ignore them. In case\n we cannot get their Object ID though, an error will be raised.\n \n+`--missing-only`::\n+\tWhen used together with `--missing=print` or `--missing=print-info`,\n+\tsuppress all output for present objects and print only the missing\n+\tones.  The selected `--missing=` format is preserved (so\n+\t`--missing=print-info` still emits `path=` / `type=` fields), but the\n+\tleading ``?'' prefix used by the non-`-z` forms is omitted.  This is\n+\tuseful for scripting, as a simpler and faster alternative to\n+\tpost-processing the output of `--missing=print`.\n++\n+This option is incompatible with `--count` and `--disk-usage`.\n+It is an error to use `--missing-only` without `--missing=print` or\n+`--missing=print-info`.\n+\n `--exclude-promisor-objects`::\n \t(For internal use only.)  Prefilter object traversal at\n \tpromisor boundary.  This is used with partial clone.  This is\ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex 02818b81c6..09c6d27220 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -111,6 +111,13 @@ enum missing_action {\n \tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n };\n static enum missing_action arg_missing_action;\n+static int arg_missing_only;\n+\n+static inline int should_collect_missing(void)\n+{\n+\treturn arg_missing_action == MA_PRINT ||\n+\t       arg_missing_action == MA_PRINT_INFO;\n+}\n \n /* display only the oid of each object encountered */\n static int arg_show_object_names = 1;\n@@ -156,7 +163,14 @@ static void print_missing_object(struct missing_objects_map_entry *entry,\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \n-\tif (line_term)\n+\t/*\n+\t * --missing-only filters present objects out of the walk output.\n+\t * It still uses the selected --missing= format for missing ones,\n+\t * except the human \"?\" prefix is omitted (script-friendly OIDs).\n+\t */\n+\tif (arg_missing_only && line_term)\n+\t\tprintf(\"%s\", oid_to_hex(&entry->entry.oid));\n+\telse if (line_term)\n \t\tprintf(\"?%s\", oid_to_hex(&entry->entry.oid));\n \telse\n \t\tprintf(\"%s%cmissing=yes\", oid_to_hex(&entry->entry.oid),\n@@ -246,6 +260,11 @@ static void show_commit(struct commit *commit, void *data)\n \t\treturn;\n \t}\n \n+\tif (arg_missing_only) {\n+\t\tfinish_commit(commit);\n+\t\treturn;\n+\t}\n+\n \tif (show_disk_usage)\n \t\ttotal_disk_usage += get_object_disk_usage(&commit->object);\n \n@@ -384,6 +403,8 @@ static void show_object(struct object *obj, const char *name, void *cb_data)\n \tif (finish_object(obj, name, cb_data))\n \t\treturn;\n \tdisplay_progress(progress, ++progress_counter);\n+\tif (arg_missing_only)\n+\t\treturn;\n \tif (show_disk_usage)\n \t\ttotal_disk_usage += get_object_disk_usage(obj);\n \tif (info->flags & REV_LIST_QUIET)\n@@ -749,12 +770,17 @@ int cmd_rev_list(int argc,\n \t\t\trevs.exclude_promisor_objects = 1;\n \t\t} else if (skip_prefix(arg, \"--missing=\", &arg)) {\n \t\t\tparse_missing_action_value(arg);\n+\t\t} else if (!strcmp(arg, \"--missing-only\")) {\n+\t\t\targ_missing_only = 1;\n \t\t} else if (!strcmp(arg, \"-z\")) {\n \t\t\tline_term = '\\0';\n \t\t\tinfo_term = '\\0';\n \t\t}\n \t}\n \n+\tif (arg_missing_only && !should_collect_missing())\n+\t\tdie(_(\"--missing-only requires --missing=print or --missing=print-info\"));\n+\n \tdie_for_incompatible_opt2(revs.exclude_promisor_objects,\n \t\t\t\t  \"--exclude_promisor_objects\",\n \t\t\t\t  arg_missing_action, \"--missing\");\n@@ -864,6 +890,9 @@ int cmd_rev_list(int argc,\n \t\t\tcontinue;\n \t\t}\n \n+\t\tif (!strcmp(arg, \"--missing-only\"))\n+\t\t\tcontinue;\n+\n \t\tusage(rev_list_usage);\n \n \t}\n@@ -910,6 +939,11 @@ int cmd_rev_list(int argc,\n \t    (revs.left_right || revs.cherry_mark))\n \t\tdie(_(\"marked counting and '%s' cannot be used together\"), \"--objects\");\n \n+\tdie_for_incompatible_opt2(arg_missing_only, \"--missing-only\",\n+\t\t\t\t  revs.count, \"--count\");\n+\tdie_for_incompatible_opt2(arg_missing_only, \"--missing-only\",\n+\t\t\t\t  show_disk_usage, \"--disk-usage\");\n+\n \tsave_commit_buffer = (revs.verbose_header ||\n \t\t\t      revs.grep_filter.pattern_list ||\n \t\t\t      revs.grep_filter.header_list);\n@@ -967,8 +1001,7 @@ int cmd_rev_list(int argc,\n \n \tif (arg_print_omitted)\n \t\toidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);\n-\tif (arg_missing_action == MA_PRINT ||\n-\t    arg_missing_action == MA_PRINT_INFO) {\n+\tif (should_collect_missing()) {\n \t\tstruct oidset_iter iter;\n \t\tstruct object_id *oid;\n \n@@ -994,8 +1027,7 @@ int cmd_rev_list(int argc,\n \t\t\tprintf(\"~%s\\n\", oid_to_hex(oid));\n \t\toidset_clear(&omitted_objects);\n \t}\n-\tif (arg_missing_action == MA_PRINT ||\n-\t    arg_missing_action == MA_PRINT_INFO) {\n+\tif (should_collect_missing()) {\n \t\tstruct missing_objects_map_entry *entry;\n \t\tstruct oidmap_iter iter;\n \ndiff --git a/t/t6022-rev-list-missing.sh b/t/t6022-rev-list-missing.sh\nindex 1e472a45af..1bd2c3bc4f 100755\n--- a/t/t6022-rev-list-missing.sh\n+++ b/t/t6022-rev-list-missing.sh\n@@ -198,6 +198,55 @@ do\n \t'\n done\n \n+for obj in \"HEAD~1\" \"HEAD~1^{tree}\" \"HEAD:1.t\"\n+do\n+\ttest_expect_success \"rev-list --missing-only with missing $obj\" '\n+\t\toid=\"$(git rev-parse $obj)\" &&\n+\t\tpath=\".git/objects/$(test_oid_to_path $oid)\" &&\n+\n+\t\tmv \"$path\" \"$path.hidden\" &&\n+\t\ttest_when_finished \"mv $path.hidden $path\" &&\n+\n+\t\tgit rev-list --missing=print --missing-only --objects \\\n+\t\t\t--no-object-names HEAD >actual &&\n+\n+\t\techo $oid >expect &&\n+\t\ttest_cmp expect actual\n+\t'\n+done\n+\n+test_expect_success \"--missing-only requires --missing=print or --missing=print-info\" '\n+\ttest_must_fail git rev-list --missing-only --objects HEAD 2>err &&\n+\ttest_grep \"requires --missing=print\" err\n+'\n+\n+test_expect_success \"--missing-only is incompatible with --count\" '\n+\ttest_must_fail git rev-list --missing=print --missing-only \\\n+\t\t--count --objects HEAD 2>err &&\n+\ttest_grep \"cannot be used together\" err\n+'\n+\n+test_expect_success \"--missing-only is incompatible with --disk-usage\" '\n+\ttest_must_fail git rev-list --missing=print --missing-only \\\n+\t\t--disk-usage --objects HEAD 2>err &&\n+\ttest_grep \"cannot be used together\" err\n+'\n+\n+test_expect_success \"--missing-only works with --missing=print-info\" '\n+\toid=\"$(git rev-parse HEAD:1.t)\" &&\n+\tpath=\".git/objects/$(test_oid_to_path $oid)\" &&\n+\n+\tmv \"$path\" \"$path.hidden\" &&\n+\ttest_when_finished \"mv $path.hidden $path\" &&\n+\n+\tgit rev-list --missing=print-info --missing-only --objects \\\n+\t\t--no-object-names HEAD >actual &&\n+\n+\t# Filter keeps print-info fields; only the \"?\" prefix is dropped.\n+\techo \"$oid path=1.t type=blob\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \"-z nul-delimited --missing\" '\n \ttest_when_finished rm -rf repo &&\n \n\nbase-commit: 1630431f326e15fcde608827b5ff38422528eb59\n-- \n2.54.0\n\n"},{"id":"551698","messageId":"xmqq1pbcsq1h.fsf@gitster.g","threadId":"65512","inReplyTo":"20260901185100.33948-1-siddharthasthana31@gmail.com","subject":"Re: [PATCH v2 0/1] rev-list: add --missing-only option to filter output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-01T19:57:30Z","receivedAt":"2026-09-01T19:57:33Z","isPatch":true,"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> At GitLab, Gitaly uses rev-list --missing=print on partial clones to\n> find missing objects. The output mixes present and missing objects and\n> prefixes missing ones with '?', so we post-process it. --missing-only\n> avoids that.\n\nNot an objection to the feature (as it can already be done with\npost-processing), but stepping back a bit, how is this list of\nmissing objects used?\n\nYou know what objects you currently have.  They refer to other\nobjects, some of which you may lack.  You can get a list of them,\nand then what?  After fetching them from 'origin', you will have\na new set of missing objects (e.g., after fetching a missing\ncommit, its parents become known and missing; after fetching a\nmissing tree, the blobs and trees contained in it become known\nand missing).\n\nFetching missing objects a batch at a time sounds like too much\nback-and-forth to peel the onion, if the process using\n'--missing-only' is trying to find out what it wants to fetch,\nand would be a rather inefficient way to backfill a shallow\nclone.  So I wonder how this fits into the larger picture.\n\nThanks.\n"},{"id":"551701","messageId":"29b5003e-48b3-490b-a4ec-c57088acc441@gmail.com","threadId":"65512","inReplyTo":"xmqq1pbcsq1h.fsf@gitster.g","subject":"Re: [PATCH v2 0/1] rev-list: add --missing-only option to filter output","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2026-09-01T20:27:51Z","receivedAt":"2026-09-01T20:27:57Z","isPatch":true,"body":"\n\nOn 02/09/26 01:27, Junio C Hamano wrote:\n> Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n> \n>> At GitLab, Gitaly uses rev-list --missing=print on partial clones to\n>> find missing objects. The output mixes present and missing objects and\n>> prefixes missing ones with '?', so we post-process it. --missing-only\n>> avoids that.\n> \n> Not an objection to the feature (as it can already be done with\n> post-processing), but stepping back a bit, how is this list of\n> missing objects used?\n\nThanks for asking\n\n> \n> You know what objects you currently have.  They refer to other\n> objects, some of which you may lack.  You can get a list of them,\n> and then what?  After fetching them from 'origin', you will have\n> a new set of missing objects (e.g., after fetching a missing\n> commit, its parents become known and missing; after fetching a\n> missing tree, the blobs and trees contained in it become known\n> and missing).\n> \n> Fetching missing objects a batch at a time sounds like too much\n> back-and-forth to peel the onion, if the process using\n> '--missing-only' is trying to find out what it wants to fetch,\n> and would be a rather inefficient way to backfill a shallow\n> clone.  So I wonder how this fits into the larger picture.\n\nAgreed, we are not using it that way, and I would not want people to use \nit as a multi-round fetch loop either.\n\nIn Gitaly the main caller is transaction packing. When we commit a \ntransaction we walk only the quarantine (plus the new ref tips) with\nsomething like:\n\n\tgit rev-list --objects --missing=print --stdin\n\n- Objects that exist in the quarantine get packed and logged with the \ntransaction.\n\n- Objects that show up as missing (the '?' lines) are recorded as the \ntransaction's dependencies. At apply time we check those OIDs already \nexit in the main repo and abort if they do not. We do not fetch them; \nthey are expected to already be outside the quarantine.\n\nSo the missing list is a one-shot dependency set from a single walk, not \niterative discovery / onion peeling. Today we parse the mixed output and \nstrip the leading '?'. --missing-only is only so that path (and the old \n\"count missing\" demo) can get bare OIDs without post-processing.\n\nHappy to clarify this in the commit message / docs in a v3 if useful.\n\nThanks,\nSiddharth\n\n\n> \n> Thanks.\n\n"},{"id":"551810","messageId":"xmqq5x0ngxas.fsf@gitster.g","threadId":"65512","inReplyTo":"29b5003e-48b3-490b-a4ec-c57088acc441@gmail.com","subject":"Re: [PATCH v2 0/1] rev-list: add --missing-only option to filter output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-02T21:26:03Z","receivedAt":"2026-09-02T21:26:08Z","isPatch":true,"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n>> ...  So I wonder how this fits into the larger picture.\n>\n> Happy to clarify this in the commit message / docs in a v3 if useful.\n\nYeah, strengthing the description of the motivation in the proposed\nlog message is always a good way to sell your ware ;-).\n\n"},{"id":"551910","messageId":"20260903204551.65592-1-siddharthasthana31@gmail.com","threadId":"65512","inReplyTo":"20260901185100.33948-1-siddharthasthana31@gmail.com","subject":"[PATCH v3 0/1] rev-list: add --missing-only option to filter output","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2026-09-03T20:45:50Z","receivedAt":"2026-09-03T20:46:02Z","isPatch":true,"body":"Hi,\n\nv2 added --missing-only as a filter next to --missing=print /\n--missing=print-info. Junio asked how the missing list is used, so\nthis v3 only updates the log message.\n\nIt is a one-shot walk. Gitaly uses --missing=print when packing a\nquarantine and treats '?' lines as objects that must already be in\nthe main repo. Tests do the same (is this blob still missing).\n--missing-only is that list without the prefix, not a fetch loop.\n\nBased on 1630431f32 (The 21st batch, 2026-08-31).\n\nChanges from v2:\n- Stronger motivation in the commit message (Junio).\n- Link to v2:\n  https://lore.kernel.org/git/20260901185100.33948-1-siddharthasthana31@gmail.com/\n\nThanks,\nSiddharth\n\n---\nSiddharth Asthana (1):\n  rev-list: add --missing-only option to filter output\n\n Documentation/rev-list-options.adoc | 13 ++++++++\n builtin/rev-list.c                  | 42 ++++++++++++++++++++++---\n t/t6022-rev-list-missing.sh         | 49 +++++++++++++++++++++++++++++\n 3 files changed, 99 insertions(+), 5 deletions(-)\n\nRange-diff versus v2:\n\n1:  3c89e6bc38 ! 1:  c751ff41a4 rev-list: add --missing-only option to filter output\n    @@ Commit message\n     \n           git rev-list --objects --all --missing=print | perl -ne 'print if s/^[?]//'\n     \n    +    This is for a one-shot walk, not a fetch loop. Callers already have\n    +    --missing=print and strip the leading '?'. Gitaly does that when packing\n    +    a quarantine: '?' lines are objects that must already exist in the main\n    +    repo. Tests do the same (is this blob still missing). --missing-only is\n    +    just that list without the prefix.\n    +\n         Add --missing-only. Use it with --missing=print or --missing=print-info\n         to print only missing objects. --missing= still picks the format;\n         --missing-only only filters. The leading '?' is omitted. With\n\nbase-commit: 1630431f326e15fcde608827b5ff38422528eb59\n"},{"id":"551911","messageId":"20260903204551.65592-2-siddharthasthana31@gmail.com","threadId":"65512","inReplyTo":"20260903204551.65592-1-siddharthasthana31@gmail.com","subject":"[PATCH v3 1/1] rev-list: add --missing-only option to filter output","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2026-09-03T20:45:51Z","receivedAt":"2026-09-03T20:46:10Z","isPatch":true,"body":"When working with partial clones, callers often need only the missing\nobject IDs. Today that means post-processing --missing=print to drop\npresent objects and strip the leading '?':\n\n  git rev-list --objects --all --missing=print | perl -ne 'print if s/^[?]//'\n\nThis is for a one-shot walk, not a fetch loop. Callers already have\n--missing=print and strip the leading '?'. Gitaly does that when packing\na quarantine: '?' lines are objects that must already exist in the main\nrepo. Tests do the same (is this blob still missing). --missing-only is\njust that list without the prefix.\n\nAdd --missing-only. Use it with --missing=print or --missing=print-info\nto print only missing objects. --missing= still picks the format;\n--missing-only only filters. The leading '?' is omitted. With\nprint-info, path= and type= are still shown.\n\nRequire --missing=print or --missing=print-info. Reject --count and\n--disk-usage.\n\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\nChanges from v2:\n- Strengthen the motivation in the log message (Junio).\n  This is a one-shot walk (Gitaly quarantine deps, tests),\n  not a multi-round fetch loop.\n\n Documentation/rev-list-options.adoc | 13 ++++++++\n builtin/rev-list.c                  | 42 ++++++++++++++++++++++---\n t/t6022-rev-list-missing.sh         | 49 +++++++++++++++++++++++++++++\n 3 files changed, 99 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc\nindex fd831f0ec6..bd9f345690 100644\n--- a/Documentation/rev-list-options.adoc\n+++ b/Documentation/rev-list-options.adoc\n@@ -1083,6 +1083,19 @@ If some tips passed to the traversal are missing, they will be\n considered as missing too, and the traversal will ignore them. In case\n we cannot get their Object ID though, an error will be raised.\n \n+`--missing-only`::\n+\tWhen used together with `--missing=print` or `--missing=print-info`,\n+\tsuppress all output for present objects and print only the missing\n+\tones.  The selected `--missing=` format is preserved (so\n+\t`--missing=print-info` still emits `path=` / `type=` fields), but the\n+\tleading ``?'' prefix used by the non-`-z` forms is omitted.  This is\n+\tuseful for scripting, as a simpler and faster alternative to\n+\tpost-processing the output of `--missing=print`.\n++\n+This option is incompatible with `--count` and `--disk-usage`.\n+It is an error to use `--missing-only` without `--missing=print` or\n+`--missing=print-info`.\n+\n `--exclude-promisor-objects`::\n \t(For internal use only.)  Prefilter object traversal at\n \tpromisor boundary.  This is used with partial clone.  This is\ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex 02818b81c6..09c6d27220 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -111,6 +111,13 @@ enum missing_action {\n \tMA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */\n };\n static enum missing_action arg_missing_action;\n+static int arg_missing_only;\n+\n+static inline int should_collect_missing(void)\n+{\n+\treturn arg_missing_action == MA_PRINT ||\n+\t       arg_missing_action == MA_PRINT_INFO;\n+}\n \n /* display only the oid of each object encountered */\n static int arg_show_object_names = 1;\n@@ -156,7 +163,14 @@ static void print_missing_object(struct missing_objects_map_entry *entry,\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \n-\tif (line_term)\n+\t/*\n+\t * --missing-only filters present objects out of the walk output.\n+\t * It still uses the selected --missing= format for missing ones,\n+\t * except the human \"?\" prefix is omitted (script-friendly OIDs).\n+\t */\n+\tif (arg_missing_only && line_term)\n+\t\tprintf(\"%s\", oid_to_hex(&entry->entry.oid));\n+\telse if (line_term)\n \t\tprintf(\"?%s\", oid_to_hex(&entry->entry.oid));\n \telse\n \t\tprintf(\"%s%cmissing=yes\", oid_to_hex(&entry->entry.oid),\n@@ -246,6 +260,11 @@ static void show_commit(struct commit *commit, void *data)\n \t\treturn;\n \t}\n \n+\tif (arg_missing_only) {\n+\t\tfinish_commit(commit);\n+\t\treturn;\n+\t}\n+\n \tif (show_disk_usage)\n \t\ttotal_disk_usage += get_object_disk_usage(&commit->object);\n \n@@ -384,6 +403,8 @@ static void show_object(struct object *obj, const char *name, void *cb_data)\n \tif (finish_object(obj, name, cb_data))\n \t\treturn;\n \tdisplay_progress(progress, ++progress_counter);\n+\tif (arg_missing_only)\n+\t\treturn;\n \tif (show_disk_usage)\n \t\ttotal_disk_usage += get_object_disk_usage(obj);\n \tif (info->flags & REV_LIST_QUIET)\n@@ -749,12 +770,17 @@ int cmd_rev_list(int argc,\n \t\t\trevs.exclude_promisor_objects = 1;\n \t\t} else if (skip_prefix(arg, \"--missing=\", &arg)) {\n \t\t\tparse_missing_action_value(arg);\n+\t\t} else if (!strcmp(arg, \"--missing-only\")) {\n+\t\t\targ_missing_only = 1;\n \t\t} else if (!strcmp(arg, \"-z\")) {\n \t\t\tline_term = '\\0';\n \t\t\tinfo_term = '\\0';\n \t\t}\n \t}\n \n+\tif (arg_missing_only && !should_collect_missing())\n+\t\tdie(_(\"--missing-only requires --missing=print or --missing=print-info\"));\n+\n \tdie_for_incompatible_opt2(revs.exclude_promisor_objects,\n \t\t\t\t  \"--exclude_promisor_objects\",\n \t\t\t\t  arg_missing_action, \"--missing\");\n@@ -864,6 +890,9 @@ int cmd_rev_list(int argc,\n \t\t\tcontinue;\n \t\t}\n \n+\t\tif (!strcmp(arg, \"--missing-only\"))\n+\t\t\tcontinue;\n+\n \t\tusage(rev_list_usage);\n \n \t}\n@@ -910,6 +939,11 @@ int cmd_rev_list(int argc,\n \t    (revs.left_right || revs.cherry_mark))\n \t\tdie(_(\"marked counting and '%s' cannot be used together\"), \"--objects\");\n \n+\tdie_for_incompatible_opt2(arg_missing_only, \"--missing-only\",\n+\t\t\t\t  revs.count, \"--count\");\n+\tdie_for_incompatible_opt2(arg_missing_only, \"--missing-only\",\n+\t\t\t\t  show_disk_usage, \"--disk-usage\");\n+\n \tsave_commit_buffer = (revs.verbose_header ||\n \t\t\t      revs.grep_filter.pattern_list ||\n \t\t\t      revs.grep_filter.header_list);\n@@ -967,8 +1001,7 @@ int cmd_rev_list(int argc,\n \n \tif (arg_print_omitted)\n \t\toidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);\n-\tif (arg_missing_action == MA_PRINT ||\n-\t    arg_missing_action == MA_PRINT_INFO) {\n+\tif (should_collect_missing()) {\n \t\tstruct oidset_iter iter;\n \t\tstruct object_id *oid;\n \n@@ -994,8 +1027,7 @@ int cmd_rev_list(int argc,\n \t\t\tprintf(\"~%s\\n\", oid_to_hex(oid));\n \t\toidset_clear(&omitted_objects);\n \t}\n-\tif (arg_missing_action == MA_PRINT ||\n-\t    arg_missing_action == MA_PRINT_INFO) {\n+\tif (should_collect_missing()) {\n \t\tstruct missing_objects_map_entry *entry;\n \t\tstruct oidmap_iter iter;\n \ndiff --git a/t/t6022-rev-list-missing.sh b/t/t6022-rev-list-missing.sh\nindex 1e472a45af..1bd2c3bc4f 100755\n--- a/t/t6022-rev-list-missing.sh\n+++ b/t/t6022-rev-list-missing.sh\n@@ -198,6 +198,55 @@ do\n \t'\n done\n \n+for obj in \"HEAD~1\" \"HEAD~1^{tree}\" \"HEAD:1.t\"\n+do\n+\ttest_expect_success \"rev-list --missing-only with missing $obj\" '\n+\t\toid=\"$(git rev-parse $obj)\" &&\n+\t\tpath=\".git/objects/$(test_oid_to_path $oid)\" &&\n+\n+\t\tmv \"$path\" \"$path.hidden\" &&\n+\t\ttest_when_finished \"mv $path.hidden $path\" &&\n+\n+\t\tgit rev-list --missing=print --missing-only --objects \\\n+\t\t\t--no-object-names HEAD >actual &&\n+\n+\t\techo $oid >expect &&\n+\t\ttest_cmp expect actual\n+\t'\n+done\n+\n+test_expect_success \"--missing-only requires --missing=print or --missing=print-info\" '\n+\ttest_must_fail git rev-list --missing-only --objects HEAD 2>err &&\n+\ttest_grep \"requires --missing=print\" err\n+'\n+\n+test_expect_success \"--missing-only is incompatible with --count\" '\n+\ttest_must_fail git rev-list --missing=print --missing-only \\\n+\t\t--count --objects HEAD 2>err &&\n+\ttest_grep \"cannot be used together\" err\n+'\n+\n+test_expect_success \"--missing-only is incompatible with --disk-usage\" '\n+\ttest_must_fail git rev-list --missing=print --missing-only \\\n+\t\t--disk-usage --objects HEAD 2>err &&\n+\ttest_grep \"cannot be used together\" err\n+'\n+\n+test_expect_success \"--missing-only works with --missing=print-info\" '\n+\toid=\"$(git rev-parse HEAD:1.t)\" &&\n+\tpath=\".git/objects/$(test_oid_to_path $oid)\" &&\n+\n+\tmv \"$path\" \"$path.hidden\" &&\n+\ttest_when_finished \"mv $path.hidden $path\" &&\n+\n+\tgit rev-list --missing=print-info --missing-only --objects \\\n+\t\t--no-object-names HEAD >actual &&\n+\n+\t# Filter keeps print-info fields; only the \"?\" prefix is dropped.\n+\techo \"$oid path=1.t type=blob\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \"-z nul-delimited --missing\" '\n \ttest_when_finished rm -rf repo &&\n \n\nRange-diff:\n1:  3c89e6bc38 ! 1:  c751ff41a4 rev-list: add --missing-only option to filter output\n    @@ Commit message\n     \n           git rev-list --objects --all --missing=print | perl -ne 'print if s/^[?]//'\n     \n    +    This is for a one-shot walk, not a fetch loop. Callers already have\n    +    --missing=print and strip the leading '?'. Gitaly does that when packing\n    +    a quarantine: '?' lines are objects that must already exist in the main\n    +    repo. Tests do the same (is this blob still missing). --missing-only is\n    +    just that list without the prefix.\n    +\n         Add --missing-only. Use it with --missing=print or --missing=print-info\n         to print only missing objects. --missing= still picks the format;\n         --missing-only only filters. The leading '?' is omitted. With\n\nbase-commit: 1630431f326e15fcde608827b5ff38422528eb59\n-- \n2.54.0\n\n"}]}