{"thread":{"id":"66230","subject":"[PATCH] builtin: replace the_repository parameter in is_bare_repository()","startedAt":"2026-08-27T18:29:13Z","lastAt":"2026-09-03T09:21:29Z","messageCount":47,"participants":["Hardik Kumar","Junio C Hamano","Ben Knoble","D. Ben Knoble","Karthik Nayak"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"551386","messageId":"20260827-env-is_bare_repo-v1-1-aa99600dc213@gmail.com","threadId":"66230","inReplyTo":null,"subject":"[PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"Hardik Kumar","fromEmail":"hardikxk@gmail.com","sentAt":"2026-08-27T18:29:00Z","receivedAt":"2026-08-27T18:29:13Z","isPatch":true,"body":"Many functions receive a `struct repository *repo` parameter but do not\nuse it (marked UNUSED) and instead pass the global `the_repository`\nparameter to the `is_bare_repository()` function.\n\nReplace the argument passed to `is_bare_repository()` from the global\n`the_repository` parameter to take the unused repository parameter so\nthat we no longer depend on `the_repository`. Patch covers the sites\nthat were not updated previously.\n\nThe patch leaves some instances of this case that would require\nadditional changes rather than simply replacing the arguments passed to\nthe function call.\n\n- Only update sites that do not introduce any functional changes.\n- `UNUSED` is dropped from `*repo` parameter to match the changes.\n\nSigned-off-by: Hardik Kumar <hardikxk@gmail.com>\n---\n builtin/blame.c | 4 ++--\n builtin/gc.c    | 4 ++--\n builtin/repo.c  | 4 ++--\n builtin/reset.c | 4 ++--\n transport.c     | 4 ++--\n 5 files changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 48d5251c6d..dbf4b4ffc7 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -957,7 +957,7 @@ static void build_ignorelist(struct blame_scoreboard *sb,\n int cmd_blame(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo UNUSED)\n+\t      struct repository *repo)\n {\n \tstruct rev_info revs;\n \tchar *path = NULL;\n@@ -1187,7 +1187,7 @@ int cmd_blame(int argc,\n \n \trevs.disable_stdin = 1;\n \tsetup_revisions(argc, argv, &revs, NULL);\n-\tif (!revs.pending.nr && is_bare_repository(the_repository)) {\n+\tif (!revs.pending.nr && is_bare_repository(repo)) {\n \t\tstruct commit *head_commit;\n \t\tstruct object_id head_oid;\n \ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex de2f9e7fed..8e82cce86b 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -582,7 +582,7 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,\n int cmd_gc(int argc,\n \t   const char **argv,\n \t   const char *prefix,\n-\t   struct repository *repo UNUSED)\n+\t   struct repository *repo)\n {\n \tint aggressive = 0;\n \tint force = 0;\n@@ -637,7 +637,7 @@ int cmd_gc(int argc,\n \t\tdie(_(\"failed to parse gc.logExpiry value %s\"), cfg.gc_log_expire);\n \n \tif (cfg.pack_refs < 0)\n-\t\tcfg.pack_refs = !is_bare_repository(the_repository);\n+\t\tcfg.pack_refs = !is_bare_repository(repo);\n \n \targc = parse_options(argc, argv, prefix, builtin_gc_options,\n \t\t\t     builtin_gc_usage, 0);\ndiff --git a/builtin/repo.c b/builtin/repo.c\nindex 84e012f83f..0bf3c0a475 100644\n--- a/builtin/repo.c\n+++ b/builtin/repo.c\n@@ -58,9 +58,9 @@ struct repo_info_field {\n \tget_value_fn *get_value;\n };\n \n-static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)\n+static int get_layout_bare(struct repository *repo, struct strbuf *buf)\n {\n-\tstrbuf_addstr(buf, is_bare_repository(the_repository) ? \"true\" : \"false\");\n+\tstrbuf_addstr(buf, is_bare_repository(repo) ? \"true\" : \"false\");\n \treturn 0;\n }\n \ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 78e69bd84b..e029b7e99a 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -336,7 +336,7 @@ static int git_reset_config(const char *var, const char *value,\n int cmd_reset(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo UNUSED)\n+\t      struct repository *repo)\n {\n \tint reset_type = NONE, update_ref_status = 0, quiet = 0;\n \tint no_refresh = 0;\n@@ -470,7 +470,7 @@ int cmd_reset(int argc,\n \tif (reset_type != SOFT && (reset_type != MIXED || repo_get_work_tree(the_repository)))\n \t\tsetup_work_tree(the_repository);\n \n-\tif (reset_type == MIXED && is_bare_repository(the_repository))\n+\tif (reset_type == MIXED && is_bare_repository(repo))\n \t\tdie(_(\"%s reset is not allowed in a bare repository\"),\n \t\t    _(reset_type_names[reset_type]));\n \ndiff --git a/transport.c b/transport.c\nindex 25e2c14a7b..82eea3024b 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -1528,7 +1528,7 @@ int transport_push(struct repository *r,\n \n \tif ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |\n \t\t      TRANSPORT_RECURSE_SUBMODULES_ONLY)) &&\n-\t    !is_bare_repository(the_repository)) {\n+\t    !is_bare_repository(r)) {\n \t\tstruct ref *ref = remote_refs;\n \t\tstruct oid_array commits = OID_ARRAY_INIT;\n \n@@ -1555,7 +1555,7 @@ int transport_push(struct repository *r,\n \tif (((flags & TRANSPORT_RECURSE_SUBMODULES_CHECK) ||\n \t     ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |\n \t\t\tTRANSPORT_RECURSE_SUBMODULES_ONLY)) &&\n-\t      !pretend)) && !is_bare_repository(the_repository)) {\n+\t      !pretend)) && !is_bare_repository(r)) {\n \t\tstruct ref *ref = remote_refs;\n \t\tstruct string_list needs_pushing = STRING_LIST_INIT_DUP;\n \t\tstruct oid_array commits = OID_ARRAY_INIT;\n\n---\nbase-commit: f78ce2f7b6df702f93d40b85d6bda92a3f65da79\nchange-id: 20260827-env-is_bare_repo-564917c2d3ab\n\n"},{"id":"551387","messageId":"xmqqo6en8jof.fsf@gitster.g","threadId":"66230","inReplyTo":"20260827-env-is_bare_repo-v1-1-aa99600dc213@gmail.com","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-27T19:09:20Z","receivedAt":"2026-08-27T19:09:23Z","isPatch":true,"body":"Hardik Kumar <hardikxk@gmail.com> writes:\n\n> The patch leaves some instances of this case that would require\n> additional changes rather than simply replacing the arguments passed to\n> the function call.\n>\n> - Only update sites that do not introduce any functional changes.\n\nHow did you make sure that the places touched by this patch do not?\n\nHow do you deal with repo==NULL case in these code paths?\n\n> - `UNUSED` is dropped from `*repo` parameter to match the changes.\n>\n> Signed-off-by: Hardik Kumar <hardikxk@gmail.com>\n> ---\n>  builtin/blame.c | 4 ++--\n>  builtin/gc.c    | 4 ++--\n>  builtin/repo.c  | 4 ++--\n>  builtin/reset.c | 4 ++--\n>  transport.c     | 4 ++--\n>  5 files changed, 10 insertions(+), 10 deletions(-)\n>\n> diff --git a/builtin/blame.c b/builtin/blame.c\n> index 48d5251c6d..dbf4b4ffc7 100644\n> --- a/builtin/blame.c\n> +++ b/builtin/blame.c\n> @@ -957,7 +957,7 @@ static void build_ignorelist(struct blame_scoreboard *sb,\n>  int cmd_blame(int argc,\n>  \t      const char **argv,\n>  \t      const char *prefix,\n> -\t      struct repository *repo UNUSED)\n> +\t      struct repository *repo)\n>  {\n>  \tstruct rev_info revs;\n>  \tchar *path = NULL;\n> @@ -1187,7 +1187,7 @@ int cmd_blame(int argc,\n>  \n>  \trevs.disable_stdin = 1;\n>  \tsetup_revisions(argc, argv, &revs, NULL);\n> -\tif (!revs.pending.nr && is_bare_repository(the_repository)) {\n> +\tif (!revs.pending.nr && is_bare_repository(repo)) {\n>  \t\tstruct commit *head_commit;\n>  \t\tstruct object_id head_oid;\n>  \n> diff --git a/builtin/gc.c b/builtin/gc.c\n> index de2f9e7fed..8e82cce86b 100644\n> --- a/builtin/gc.c\n> +++ b/builtin/gc.c\n> @@ -582,7 +582,7 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,\n>  int cmd_gc(int argc,\n>  \t   const char **argv,\n>  \t   const char *prefix,\n> -\t   struct repository *repo UNUSED)\n> +\t   struct repository *repo)\n>  {\n>  \tint aggressive = 0;\n>  \tint force = 0;\n> @@ -637,7 +637,7 @@ int cmd_gc(int argc,\n>  \t\tdie(_(\"failed to parse gc.logExpiry value %s\"), cfg.gc_log_expire);\n>  \n>  \tif (cfg.pack_refs < 0)\n> -\t\tcfg.pack_refs = !is_bare_repository(the_repository);\n> +\t\tcfg.pack_refs = !is_bare_repository(repo);\n>  \n>  \targc = parse_options(argc, argv, prefix, builtin_gc_options,\n>  \t\t\t     builtin_gc_usage, 0);\n> diff --git a/builtin/repo.c b/builtin/repo.c\n> index 84e012f83f..0bf3c0a475 100644\n> --- a/builtin/repo.c\n> +++ b/builtin/repo.c\n> @@ -58,9 +58,9 @@ struct repo_info_field {\n>  \tget_value_fn *get_value;\n>  };\n>  \n> -static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)\n> +static int get_layout_bare(struct repository *repo, struct strbuf *buf)\n>  {\n> -\tstrbuf_addstr(buf, is_bare_repository(the_repository) ? \"true\" : \"false\");\n> +\tstrbuf_addstr(buf, is_bare_repository(repo) ? \"true\" : \"false\");\n>  \treturn 0;\n>  }\n>  \n> diff --git a/builtin/reset.c b/builtin/reset.c\n> index 78e69bd84b..e029b7e99a 100644\n> --- a/builtin/reset.c\n> +++ b/builtin/reset.c\n> @@ -336,7 +336,7 @@ static int git_reset_config(const char *var, const char *value,\n>  int cmd_reset(int argc,\n>  \t      const char **argv,\n>  \t      const char *prefix,\n> -\t      struct repository *repo UNUSED)\n> +\t      struct repository *repo)\n>  {\n>  \tint reset_type = NONE, update_ref_status = 0, quiet = 0;\n>  \tint no_refresh = 0;\n> @@ -470,7 +470,7 @@ int cmd_reset(int argc,\n>  \tif (reset_type != SOFT && (reset_type != MIXED || repo_get_work_tree(the_repository)))\n>  \t\tsetup_work_tree(the_repository);\n>  \n> -\tif (reset_type == MIXED && is_bare_repository(the_repository))\n> +\tif (reset_type == MIXED && is_bare_repository(repo))\n>  \t\tdie(_(\"%s reset is not allowed in a bare repository\"),\n>  \t\t    _(reset_type_names[reset_type]));\n>  \n> diff --git a/transport.c b/transport.c\n> index 25e2c14a7b..82eea3024b 100644\n> --- a/transport.c\n> +++ b/transport.c\n> @@ -1528,7 +1528,7 @@ int transport_push(struct repository *r,\n>  \n>  \tif ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |\n>  \t\t      TRANSPORT_RECURSE_SUBMODULES_ONLY)) &&\n> -\t    !is_bare_repository(the_repository)) {\n> +\t    !is_bare_repository(r)) {\n>  \t\tstruct ref *ref = remote_refs;\n>  \t\tstruct oid_array commits = OID_ARRAY_INIT;\n>  \n> @@ -1555,7 +1555,7 @@ int transport_push(struct repository *r,\n>  \tif (((flags & TRANSPORT_RECURSE_SUBMODULES_CHECK) ||\n>  \t     ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |\n>  \t\t\tTRANSPORT_RECURSE_SUBMODULES_ONLY)) &&\n> -\t      !pretend)) && !is_bare_repository(the_repository)) {\n> +\t      !pretend)) && !is_bare_repository(r)) {\n>  \t\tstruct ref *ref = remote_refs;\n>  \t\tstruct string_list needs_pushing = STRING_LIST_INIT_DUP;\n>  \t\tstruct oid_array commits = OID_ARRAY_INIT;\n>\n> ---\n> base-commit: f78ce2f7b6df702f93d40b85d6bda92a3f65da79\n> change-id: 20260827-env-is_bare_repo-564917c2d3ab\n"},{"id":"551388","messageId":"xmqqh5kf8hqc.fsf@gitster.g","threadId":"66230","inReplyTo":"xmqqo6en8jof.fsf@gitster.g","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-27T19:51:23Z","receivedAt":"2026-08-27T19:51:28Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> - Only update sites that do not introduce any functional changes.\n>\n> How did you make sure that the places touched by this patch do not?\n>\n> How do you deal with repo==NULL case in these code paths?\n\nI guess this was a bit too short, so let me explain in a bit more\ndetail.\n\n>> diff --git a/builtin/blame.c b/builtin/blame.c\n>> index 48d5251c6d..dbf4b4ffc7 100644\n>> --- a/builtin/blame.c\n>> +++ b/builtin/blame.c\n>> @@ -957,7 +957,7 @@ static void build_ignorelist(struct blame_scoreboard *sb,\n>>  int cmd_blame(int argc,\n>>  \t      const char **argv,\n>>  \t      const char *prefix,\n>> -\t      struct repository *repo UNUSED)\n>> +\t      struct repository *repo)\n>>  {\n>>  \tstruct rev_info revs;\n>>  \tchar *path = NULL;\n>> @@ -1187,7 +1187,7 @@ int cmd_blame(int argc,\n>>  \n>>  \trevs.disable_stdin = 1;\n>>  \tsetup_revisions(argc, argv, &revs, NULL);\n>> -\tif (!revs.pending.nr && is_bare_repository(the_repository)) {\n>> +\tif (!revs.pending.nr && is_bare_repository(repo)) {\n>>  \t\tstruct commit *head_commit;\n>>  \t\tstruct object_id head_oid;\n\nThere are a handful of uses of the_repository before the execution\nreaches here.  But you left them unmodified.\n\nThe original code used to consistently used the_repository.  Here\nyou changed it to use \"repo\".  In practice, they are most likely the\nsame when \"repo\" is not NULL, so in that sense, this may not be\nbreaking anything, but you must ask yourself what the point is,\nunless you convert all uses of the_repository with \"repo\".  It does\nnot help libification effort at all.\n\nIn general, builtin/foo.c::cmd_foo() are concrete programs that work\non specific repository (i.e., the_repository), and there is not much\nreason to rewrite the use of the_repository to use \"repo\" given by\nthe caller which is git potty.  You'd also need to deal with the\ncase where \"repo\" is NULL (hint: \"cd / && git foo -h\").\n\nThey are quite different from other parts of the system, things\noutside builtin/, many of which are general utility/helper routines,\nmany of which should be designed to work with given repository.\n"},{"id":"551389","messageId":"DKZZOTND7RNF.16J4VLMEKOMLM@gmail.com","threadId":"66230","inReplyTo":"xmqqo6en8jof.fsf@gitster.g","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"Hardik Kumar","fromEmail":"hardikxk@gmail.com","sentAt":"2026-08-27T19:56:41Z","receivedAt":"2026-08-27T19:56:47Z","isPatch":true,"body":"On Fri Aug 28, 2026 at 12:39 AM IST, Junio C Hamano wrote:\n\n>> The patch leaves some instances of this case that would require\n>> additional changes rather than simply replacing the arguments passed to\n>> the function call.\n>>\n>> - Only update sites that do not introduce any functional changes.\n>\n> How did you make sure that the places touched by this patch do not?\n>\n> How do you deal with repo==NULL case in these code paths?\n\nI verified by running the entire test suite which passed fine. In\naddition to that the methods in `repository.c` should already handle\nsuch a case if the `repo` were to ever be NULL or not initialized as the\nsame pointer is what is passed to all callers.\n\nAlso the repo should always be NOT NULL and then git just throws an\nerror about the inexistence of it.\n\n"},{"id":"551390","messageId":"DKZZYSTLY6TX.2TDQEBBOG5IAV@gmail.com","threadId":"66230","inReplyTo":"xmqqh5kf8hqc.fsf@gitster.g","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"Hardik Kumar","fromEmail":"hardikxk@gmail.com","sentAt":"2026-08-27T20:09:43Z","receivedAt":"2026-08-27T20:09:49Z","isPatch":true,"body":"On Fri Aug 28, 2026 at 1:21 AM IST, Junio C Hamano wrote:\n\n> I guess this was a bit too short, so let me explain in a bit more\n> detail.\n>\n>>> diff --git a/builtin/blame.c b/builtin/blame.c\n>>> index 48d5251c6d..dbf4b4ffc7 100644\n>>> --- a/builtin/blame.c\n>>> +++ b/builtin/blame.c\n>>> @@ -957,7 +957,7 @@ static void build_ignorelist(struct blame_scoreboard *sb,\n>>>  int cmd_blame(int argc,\n>>>  \t      const char **argv,\n>>>  \t      const char *prefix,\n>>> -\t      struct repository *repo UNUSED)\n>>> +\t      struct repository *repo)\n>>>  {\n>>>  \tstruct rev_info revs;\n>>>  \tchar *path = NULL;\n>>> @@ -1187,7 +1187,7 @@ int cmd_blame(int argc,\n>>>  \n>>>  \trevs.disable_stdin = 1;\n>>>  \tsetup_revisions(argc, argv, &revs, NULL);\n>>> -\tif (!revs.pending.nr && is_bare_repository(the_repository)) {\n>>> +\tif (!revs.pending.nr && is_bare_repository(repo)) {\n>>>  \t\tstruct commit *head_commit;\n>>>  \t\tstruct object_id head_oid;\n>\n> There are a handful of uses of the_repository before the execution\n> reaches here.  But you left them unmodified.\n>\n> The original code used to consistently used the_repository.  Here\n> you changed it to use \"repo\".  In practice, they are most likely the\n> same when \"repo\" is not NULL, so in that sense, this may not be\n> breaking anything, but you must ask yourself what the point is,\n> unless you convert all uses of the_repository with \"repo\".  It does\n> not help libification effort at all.\n\nMy main goal here was to start small with by removing the dependence\nfrom `the_repository`. The other instances are obivous left out which\nmakes the patch seem inconsistent but I suppose those functions are the\nones that require execution before the flow ever checks for the value of\n`repo` and so they rely on the global one instead.\n\n> In general, builtin/foo.c::cmd_foo() are concrete programs that work\n> on specific repository (i.e., the_repository), and there is not much\n> reason to rewrite the use of the_repository to use \"repo\" given by\n> the caller which is git potty.  You'd also need to deal with the\n> case where \"repo\" is NULL (hint: \"cd / && git foo -h\").\n\nRight, but would safety check be required for single instance or better\nto find and work on only the specific ones which could lead to an\nexception.\n\n>\n> They are quite different from other parts of the system, things\n> outside builtin/, many of which are general utility/helper routines,\n> many of which should be designed to work with given repository.\n\n\n"},{"id":"551391","messageId":"xmqq7blb8g04.fsf@gitster.g","threadId":"66230","inReplyTo":"DKZZYSTLY6TX.2TDQEBBOG5IAV@gmail.com","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-27T20:28:43Z","receivedAt":"2026-08-27T20:28:46Z","isPatch":true,"body":"\"Hardik Kumar\" <hardikxk@gmail.com> writes:\n\n>> In general, builtin/foo.c::cmd_foo() are concrete programs that work\n>> on specific repository (i.e., the_repository), and there is not much\n>> reason to rewrite the use of the_repository to use \"repo\" given by\n>> the caller which is git potty.  You'd also need to deal with the\n>> case where \"repo\" is NULL (hint: \"cd / && git foo -h\").\n>\n> Right, but would safety check be required for single instance or better\n> to find and work on only the specific ones which could lead to an\n> exception.\n\nI do not quite get what you mean.  In a single function you use\nthe_repository and repo interchangeably, relying on repo, when it is\nnot NULL), being the same as the_repository for correctness.  If\nthey ever refer to different things, then your updated code is less\nconsistent than the original, which would not be an improvement.\n\nI actually think a good medium size project is to fix the last\nparameter given to cmd_foo() built-in command implementations that\nis a pointer to \"struct repository\".  It was a misguided design.\n\nThis pointer is either NULL or the_repository; it never takes any\nother value.  It is misleading and invites confusion that these\nfunctions can take arbitrary repository instance.  It also invites\npeople to replace all references in cmd_foo() to \"the_repository\"\nwith \"repo\", which may lead to an error.  Depending on where\nparse_options() call appears in the cmd_foo(), \"cd / && git foo -h\"\nwill cause segfaults with such a change.\n\nIf we change the function signature of cmd_foo() to receive a \"bool\"\nthat says \"true\" if the command was run inside a repository and\n\"false\" otherwise, cmd_foo() can still tell if the command was run\noutside a repository, and programmers will not be misled to use\nanything other than \"the_repository\" as the repository to work on.\n\nThe utility functions builtin/foo.c borrows from outside builtin/\ndirectory are being \"libified\" to reduce the hardcoded dependence on\nthe_repository, and cmd_foo() can call these functions with\nthe_repository as a parameter.  But we have no reason to waste our\ntime updating (and also reviewing patches that make such updates)\nthe built-in implementations themselves to take a pointer to an\narbitrary repository.\n"},{"id":"551392","messageId":"F276C11F-1904-496E-AA77-953724362C9A@gmail.com","threadId":"66230","inReplyTo":"xmqq7blb8g04.fsf@gitster.g","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-27T21:12:19Z","receivedAt":"2026-08-27T21:12:31Z","isPatch":true,"body":"\n> Le 27 août 2026 à 16:30, Junio C Hamano <gitster@pobox.com> a écrit :\n> \n> ﻿\"Hardik Kumar\" <hardikxk@gmail.com> writes:\n> \n>>> In general, builtin/foo.c::cmd_foo() are concrete programs that work\n>>> on specific repository (i.e., the_repository), and there is not much\n>>> reason to rewrite the use of the_repository to use \"repo\" given by\n>>> the caller which is git potty.  You'd also need to deal with the\n>>> case where \"repo\" is NULL (hint: \"cd / && git foo -h\").\n\n[snip]\n\n> The utility functions builtin/foo.c borrows from outside builtin/\n> directory are being \"libified\" to reduce the hardcoded dependence on\n> the_repository, and cmd_foo() can call these functions with\n> the_repository as a parameter.  But we have no reason to waste our\n> time updating (and also reviewing patches that make such updates)\n> the built-in implementations themselves to take a pointer to an\n> arbitrary repository.\n\nHm. What if a program wants to do « exactly what ‘git switch’ does » sans shelling out? It’d be a maintenance burden to answer « open code it using helpers in libgit and the builtin sources », at least as presented. Many builtin sources seem (at least to me) quite complex! And it’s not immediately obvious how I could recreate the intended effects of, say, « switch branches » with just one or 2 libgit calls. (Maybe that’s just me.)\n\nIn other words, the stance « it’s not worth it to libify builtins » only makes sense if we also say « we don’t explicitly support precisely replicating builtin behavior via libgit ».\n\nWhich is fine! I’m probably just not aware if there was discussion/consensus on that somewhere. Pointers welcome :)\n\n(I for one think it would be nice to have the ability to call a builtin directly through libgit, or at least think through what organization of code would be necessary to make it feasible to say « to do builtin X, you need only call these 5 lib functions in sequence with your choice of arguments »—since perhaps parseopt’ing isn’t so relevant at that level—but I lack a concrete use case at the moment.)"},{"id":"551393","messageId":"xmqqmru76ybk.fsf_-_@gitster.g","threadId":"66230","inReplyTo":"xmqq7blb8g04.fsf@gitster.g","subject":"[PATCH] do not pass \"repo\" to builtin commmand implementations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-27T21:35:59Z","receivedAt":"2026-08-27T21:36:02Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> I actually think a good medium size project is to fix the last\n> parameter given to cmd_foo() built-in command implementations that\n> is a pointer to \"struct repository\".  It was a misguided design.\n\nSuch a patch would look like this.  I am sending it out mostly for\nillustration, but it applies cleanly to today's 'master' and the\nresult passes the test suite.\n\nAs it affects everything inside builtin/, it may be tricky to find\nthe time when it is appropriate to apply a patch like this one, but\nin not so longer term it would be worth doing to avoid wasted work.\n\nOpinions?\n\n----- >8 -----\n\nEarlier, commit 9b1cb5070f (builtin: add a repository parameter for\nbuiltin functions, 2024-09-13) added a 'repo' parameter to built-in\ncommand implementations, but this was largely a misguided design.\n\nWe claimed that this would help reduce direct use of 'the_repository'\nand aid the libification effort.  However, it does not.  These\nbuilt-in implementations are not intended to be reusable library\nroutines to begin with.\n\nFurthermore, when the 'repo' parameter given to them is non-NULL, it\nis always 'the_repository'.  To safely use the passed-in 'repo'\ninstead of 'the_repository', an implementation must handle the case\nwhere 'repo' is NULL (which happens when running outside a\nrepository) and rely on fallback logic such as defaulting back to\n'the_repository'.\n\nQuite honestly, it is wasteful makework.\n\nReplace the 'repo' parameter given to cmd_foo() in builtin/ with a\nboolean 'has_repo' flag.  This ensures that these builtin\nimplementations can still tell when they are invoked outside a\nrepository, and also ensures that developers do not waste time\nmodifying '.c' files under builtin/ to reduce uses of\n'the_repository'.  That effort is better spent libifying code\noutside the builtin/ directory where it truly matters.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/MyFirstContribution.adoc |   8 +-\n Documentation/MyFirstObjectWalk.adoc   |  16 +-\n builtin.h                              | 292 ++++++++++++++++-----------------\n builtin/add.c                          |  47 +++---\n builtin/am.c                           |   2 +-\n builtin/annotate.c                     |   4 +-\n builtin/apply.c                        |   8 +-\n builtin/archive.c                      |   5 +-\n builtin/backfill.c                     |   8 +-\n builtin/bisect.c                       |   4 +-\n builtin/blame.c                        |   2 +-\n builtin/branch.c                       |   2 +-\n builtin/bugreport.c                    |   2 +-\n builtin/bundle.c                       |   4 +-\n builtin/cat-file.c                     |   2 +-\n builtin/check-attr.c                   |   2 +-\n builtin/check-ignore.c                 |   2 +-\n builtin/check-mailmap.c                |   2 +-\n builtin/check-ref-format.c             |   2 +-\n builtin/checkout--worker.c             |   2 +-\n builtin/checkout-index.c               |  29 ++--\n builtin/checkout.c                     |   6 +-\n builtin/clean.c                        |   2 +-\n builtin/clone.c                        |   2 +-\n builtin/column.c                       |   2 +-\n builtin/commit-graph.c                 |   4 +-\n builtin/commit-tree.c                  |   2 +-\n builtin/commit.c                       |   4 +-\n builtin/config.c                       |   4 +-\n builtin/count-objects.c                |   2 +-\n builtin/credential-cache--daemon.c     |   4 +-\n builtin/credential-cache.c             |   4 +-\n builtin/credential-store.c             |   2 +-\n builtin/credential.c                   |   2 +-\n builtin/describe.c                     |   2 +-\n builtin/diagnose.c                     |   2 +-\n builtin/diff-files.c                   |   2 +-\n builtin/diff-index.c                   |   2 +-\n builtin/diff-pairs.c                   |  11 +-\n builtin/diff-tree.c                    |   2 +-\n builtin/diff.c                         |   2 +-\n builtin/difftool.c                     |  13 +-\n builtin/fast-export.c                  |   2 +-\n builtin/fast-import.c                  |   4 +-\n builtin/fetch-pack.c                   |   2 +-\n builtin/fetch.c                        |   2 +-\n builtin/fmt-merge-msg.c                |   5 +-\n builtin/for-each-ref.c                 |   5 +-\n builtin/for-each-repo.c                |   2 +-\n builtin/fsck.c                         |  61 +++----\n builtin/fsmonitor--daemon.c            |   4 +-\n builtin/gc.c                           |   6 +-\n builtin/get-tar-commit-id.c            |   2 +-\n builtin/grep.c                         |   2 +-\n builtin/hash-object.c                  |   2 +-\n builtin/help.c                         |   2 +-\n builtin/history.c                      |   4 +-\n builtin/hook.c                         |   4 +-\n builtin/index-pack.c                   |   2 +-\n builtin/init-db.c                      |   2 +-\n builtin/interpret-trailers.c           |   2 +-\n builtin/last-modified.c                |   7 +-\n builtin/log.c                          |  12 +-\n builtin/ls-files.c                     |  23 +--\n builtin/ls-remote.c                    |   2 +-\n builtin/ls-tree.c                      |   2 +-\n builtin/mailinfo.c                     |   2 +-\n builtin/mailsplit.c                    |   2 +-\n builtin/merge-base.c                   |   2 +-\n builtin/merge-file.c                   |   6 +-\n builtin/merge-index.c                  |   2 +-\n builtin/merge-ours.c                   |  13 +-\n builtin/merge-recursive.c              |   2 +-\n builtin/merge-tree.c                   |   2 +-\n builtin/merge.c                        |   2 +-\n builtin/mktag.c                        |   4 +-\n builtin/mktree.c                       |   7 +-\n builtin/multi-pack-index.c             |   4 +-\n builtin/mv.c                           |   2 +-\n builtin/name-rev.c                     |   4 +-\n builtin/notes.c                        |   4 +-\n builtin/pack-objects.c                 |   2 +-\n builtin/pack-redundant.c               |   2 +-\n builtin/pack-refs.c                    |   5 +-\n builtin/patch-id.c                     |   2 +-\n builtin/prune-packed.c                 |   2 +-\n builtin/prune.c                        |  19 ++-\n builtin/pull.c                         |   2 +-\n builtin/push.c                         |   2 +-\n builtin/range-diff.c                   |   2 +-\n builtin/read-tree.c                    |   2 +-\n builtin/rebase.c                       |   2 +-\n builtin/receive-pack.c                 |   2 +-\n builtin/reflog.c                       |   6 +-\n builtin/refs.c                         |   5 +-\n builtin/remote-ext.c                   |   2 +-\n builtin/remote-fd.c                    |   2 +-\n builtin/remote.c                       |   4 +-\n builtin/repack.c                       |  49 +++---\n builtin/replace.c                      |   2 +-\n builtin/replay.c                       |  11 +-\n builtin/repo.c                         |   4 +-\n builtin/rerere.c                       |   2 +-\n builtin/reset.c                        |   2 +-\n builtin/rev-list.c                     |   2 +-\n builtin/rev-parse.c                    |   2 +-\n builtin/revert.c                       |   8 +-\n builtin/rm.c                           |   2 +-\n builtin/send-pack.c                    |   9 +-\n builtin/shortlog.c                     |   2 +-\n builtin/show-branch.c                  |   2 +-\n builtin/show-index.c                   |   2 +-\n builtin/show-ref.c                     |   6 +-\n builtin/sparse-checkout.c              |   8 +-\n builtin/stash.c                        |   6 +-\n builtin/stripspace.c                   |   2 +-\n builtin/submodule--helper.c            |   4 +-\n builtin/symbolic-ref.c                 |   2 +-\n builtin/tag.c                          |   2 +-\n builtin/unpack-file.c                  |   2 +-\n builtin/unpack-objects.c               |   4 +-\n builtin/update-index.c                 |   2 +-\n builtin/update-ref.c                   |   2 +-\n builtin/update-server-info.c           |   7 +-\n builtin/upload-archive.c               |   8 +-\n builtin/upload-pack.c                  |   2 +-\n builtin/url-parse.c                    |   2 +-\n builtin/var.c                          |   2 +-\n builtin/verify-commit.c                |   7 +-\n builtin/verify-pack.c                  |   2 +-\n builtin/verify-tag.c                   |   9 +-\n builtin/worktree.c                     |   4 +-\n builtin/write-tree.c                   |   2 +-\n git.c                                  |   4 +-\n help.c                                 |   2 +-\n 135 files changed, 507 insertions(+), 486 deletions(-)\n\ndiff --git c/Documentation/MyFirstContribution.adoc w/Documentation/MyFirstContribution.adoc\nindex 34bfa2e3a9..8dfcfd0b93 100644\n--- c/Documentation/MyFirstContribution.adoc\n+++ w/Documentation/MyFirstContribution.adoc\n@@ -152,7 +152,7 @@ point for your command in a function matching the style and signature:\n \n ----\n int cmd_psuh(int argc UNUSED, const char **argv UNUSED,\n-\t     const char *prefix UNUSED, struct repository *repo UNUSED)\n+\t     const char *prefix UNUSED, bool has_repo UNUSED)\n ----\n \n A few things to note:\n@@ -160,7 +160,7 @@ A few things to note:\n * A subcommand implementation takes its command line arguments\n   in `int argc` + `const char **argv`, like `main()` would.\n \n-* It also takes two extra parameters, `prefix` and `repo`. What\n+* It also takes two extra parameters, `prefix` and `has_repo`. What\n   they mean will not be discussed until much later.\n \n * Because this first example will not use any of the parameters,\n@@ -175,7 +175,7 @@ declaration for `cmd_pull`, and add a new line for `psuh` immediately before it,\n in order to keep the declarations alphabetically sorted:\n \n ----\n-int cmd_psuh(int argc, const char **argv, const char *prefix, struct repository *repo);\n+int cmd_psuh(int argc, const char **argv, const char *prefix, bool has_repo);\n ----\n \n Be sure to `#include \"builtin.h\"` in your `psuh.c`. You'll also need to\n@@ -192,7 +192,7 @@ should also do so when writing your user-facing commands in the future.\n \n ----\n int cmd_psuh(int argc UNUSED, const char **argv UNUSED,\n-\t     const char *prefix UNUSED, struct repository *repo UNUSED)\n+\t     const char *prefix UNUSED, bool has_repo UNUSED)\n {\n \tprintf(_(\"Pony saying hello goes here.\\n\"));\n \treturn 0;\ndiff --git c/Documentation/MyFirstObjectWalk.adoc w/Documentation/MyFirstObjectWalk.adoc\nindex 413a9fdb05..8e40c685b8 100644\n--- c/Documentation/MyFirstObjectWalk.adoc\n+++ w/Documentation/MyFirstObjectWalk.adoc\n@@ -43,7 +43,7 @@ Open up a new file `builtin/walken.c` and set up the command handler:\n #include \"builtin.h\"\n #include \"trace.h\"\n \n-int cmd_walken(int argc, const char **argv, const char *prefix, struct repository *repo)\n+int cmd_walken(int argc, const char **argv, const char *prefix, bool has_repo UNUSED)\n {\n \ttrace_printf(_(\"cmd_walken incoming...\\n\"));\n \treturn 0;\n@@ -67,7 +67,7 @@ We'll need to include the `parse-options.h` header.\n \n ...\n \n-int cmd_walken(int argc, const char **argv, const char *prefix)\n+int cmd_walken(int argc, const char **argv, const char *prefix, bool has_repo UNUSED)\n {\n \tconst char * const walken_usage[] = {\n \t\tN_(\"git walken\"),\n@@ -86,7 +86,7 @@ int cmd_walken(int argc, const char **argv, const char *prefix)\n Also add the relevant line in `builtin.h` near `cmd_version()`:\n \n ----\n-int cmd_walken(int argc, const char **argv, const char *prefix, struct repository *repo);\n+int cmd_walken(int argc, const char **argv, const char *prefix, bool has_repo);\n ----\n \n Include the command in `git.c` in `commands[]` near the entry for `version`,\n@@ -237,11 +237,11 @@ static int git_walken_config(const char *var, const char *value,\n Make sure to invoke `repo_config()` with it in your `cmd_walken()`:\n \n ----\n-int cmd_walken(int argc, const char **argv, const char *prefix, struct repository *repo)\n+int cmd_walken(int argc, const char **argv, const char *prefix, bool has_repo UNUSED)\n {\n \t...\n \n-\trepo_config(repo, git_walken_config, NULL);\n+\trepo_config(the_repository, git_walken_config, NULL);\n \n \t...\n }\n@@ -263,14 +263,14 @@ We'll also need to include the `revision.h` header:\n \n ...\n \n-int cmd_walken(int argc, const char **argv, const char *prefix, struct repository *repo)\n+int cmd_walken(int argc, const char **argv, const char *prefix, bool has_repo UNUSED)\n {\n \t/* This can go wherever you like in your declarations.*/\n \tstruct rev_info rev;\n \t...\n \n \t/* This should go after the repo_config() call. */\n-\trepo_init_revisions(repo, &rev, prefix);\n+\trepo_init_revisions(the_repository, &rev, prefix);\n \n \t...\n }\n@@ -318,7 +318,7 @@ Then let's invoke `final_rev_info_setup()` after the call to\n `repo_init_revisions()`:\n \n ----\n-int cmd_walken(int argc, const char **argv, const char *prefix, struct repository *repo)\n+int cmd_walken(int argc, const char **argv, const char *prefix, bool has_repo UNUSED)\n {\n \t...\n \ndiff --git c/builtin.h w/builtin.h\nindex 4e47a4ebd3..66d187e4cd 100644\n--- c/builtin.h\n+++ w/builtin.h\n@@ -18,7 +18,7 @@\n  *   signature:\n  *\n  *\tint cmd_foo(int argc, const char **argv,\n- *\t\t    const char *prefix, struct repository *repo);\n+ *\t\t    const char *prefix, bool has_repo);\n  *\n  * . Add the external declaration for the function to `builtin.h`.\n  *\n@@ -139,150 +139,150 @@ int is_builtin(const char *s);\n \t\tBUG(\"unexpected prefix in builtin: %s\", (prefix)); \\\n } while (0)\n \n-int cmd_add(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_am(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_annotate(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_apply(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_archive(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_backfill(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_bisect(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_blame(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_branch(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_bugreport(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_bundle(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_cat_file(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_checkout(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_checkout__worker(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_checkout_index(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_check_attr(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_check_ignore(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_check_mailmap(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_check_ref_format(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_cherry(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_cherry_pick(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_clone(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_clean(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_column(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_commit(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_commit_graph(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_commit_tree(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_config(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_count_objects(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_credential(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_credential_cache(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_credential_store(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_describe(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_diagnose(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_diff_files(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_diff_index(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_diff(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_diff_pairs(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_diff_tree(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_difftool(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_env__helper(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_fast_export(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_fast_import(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_fetch(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_fetch_pack(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_for_each_ref(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_for_each_repo(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_format_patch(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_format_rev(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_fsck(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_gc(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_grep(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_hash_object(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_help(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_history(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_hook(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_index_pack(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_init_db(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_interpret_trailers(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_last_modified(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_log_reflog(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_log(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_ls_files(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_ls_tree(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_ls_remote(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_mailinfo(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_mailsplit(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_maintenance(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_merge(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_merge_base(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_merge_index(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_merge_ours(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_merge_file(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_merge_recursive(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_merge_tree(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_mktag(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_mktree(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_multi_pack_index(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_mv(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_name_rev(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_notes(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_pack_objects(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_pack_redundant(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_patch_id(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_prune(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_prune_packed(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_pull(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_push(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_range_diff(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_read_tree(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_rebase(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_rebase__interactive(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_receive_pack(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_reflog(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_refs(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_remote(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_repo(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_rev_list(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_rev_parse(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_revert(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_rm(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_send_pack(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_shortlog(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_show(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_show_branch(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_show_index(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_sparse_checkout(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_status(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_stash(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_stripspace(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_submodule__helper(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_switch(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_symbolic_ref(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_tag(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_unpack_file(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_unpack_objects(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_update_index(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_update_ref(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_update_server_info(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_upload_archive(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_upload_pack(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_url_parse(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_var(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_verify_commit(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_verify_tag(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_version(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_whatchanged(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_worktree(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_write_tree(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_verify_pack(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_show_ref(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_pack_refs(int argc, const char **argv, const char *prefix, struct repository *repo);\n-int cmd_replace(int argc, const char **argv, const char *prefix, struct repository *repo);\n+int cmd_add(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_am(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_annotate(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_apply(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_archive(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_backfill(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_bisect(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_blame(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_branch(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_bugreport(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_bundle(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_cat_file(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_checkout(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_checkout__worker(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_checkout_index(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_check_attr(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_check_ignore(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_check_mailmap(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_check_ref_format(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_cherry(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_cherry_pick(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_clone(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_clean(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_column(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_commit(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_commit_graph(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_commit_tree(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_config(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_count_objects(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_credential(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_credential_cache(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_credential_store(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_describe(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_diagnose(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_diff_files(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_diff_index(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_diff(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_diff_pairs(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_diff_tree(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_difftool(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_env__helper(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_fast_export(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_fast_import(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_fetch(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_fetch_pack(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_for_each_ref(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_for_each_repo(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_format_patch(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_format_rev(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_fsck(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_gc(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_grep(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_hash_object(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_help(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_history(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_hook(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_index_pack(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_init_db(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_interpret_trailers(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_last_modified(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_log_reflog(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_log(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_ls_files(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_ls_tree(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_ls_remote(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_mailinfo(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_mailsplit(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_maintenance(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_merge(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_merge_base(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_merge_index(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_merge_ours(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_merge_file(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_merge_recursive(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_merge_tree(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_mktag(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_mktree(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_multi_pack_index(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_mv(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_name_rev(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_notes(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_pack_objects(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_pack_redundant(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_patch_id(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_prune(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_prune_packed(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_pull(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_push(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_range_diff(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_read_tree(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_rebase(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_rebase__interactive(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_receive_pack(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_reflog(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_refs(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_remote(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_remote_ext(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_remote_fd(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_repack(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_replay(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_repo(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_rerere(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_reset(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_restore(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_rev_list(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_rev_parse(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_revert(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_rm(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_send_pack(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_shortlog(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_show(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_show_branch(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_show_index(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_sparse_checkout(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_status(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_stash(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_stripspace(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_submodule__helper(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_switch(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_symbolic_ref(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_tag(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_unpack_file(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_unpack_objects(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_update_index(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_update_ref(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_update_server_info(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_upload_archive(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_upload_pack(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_url_parse(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_var(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_verify_commit(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_verify_tag(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_version(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_whatchanged(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_worktree(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_write_tree(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_verify_pack(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_show_ref(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_pack_refs(int argc, const char **argv, const char *prefix, bool has_repo);\n+int cmd_replace(int argc, const char **argv, const char *prefix, bool has_repo);\n \n #endif\ndiff --git c/builtin/add.c w/builtin/add.c\nindex eab8f03cad..dc0e862347 100644\n--- c/builtin/add.c\n+++ w/builtin/add.c\n@@ -4,6 +4,7 @@\n  * Copyright (C) 2006 Linus Torvalds\n  */\n \n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"advice.h\"\n #include \"config.h\"\n@@ -455,7 +456,7 @@ static int add_resolved_files(struct repository *repo,\n int cmd_add(int argc,\n \t    const char **argv,\n \t    const char *prefix,\n-\t    struct repository *repo)\n+\t    bool has_repo UNUSED)\n {\n \tint exit_status = 0;\n \tstruct pathspec pathspec;\n@@ -468,13 +469,13 @@ int cmd_add(int argc,\n \tstruct lock_file lock_file = LOCK_INIT;\n \tstruct odb_transaction *transaction;\n \n-\trepo_config(repo, add_config, NULL);\n+\trepo_config(the_repository, add_config, NULL);\n \n \targc = parse_options(argc, argv, prefix, builtin_add_options,\n \t\t\t  builtin_add_usage, PARSE_OPT_KEEP_ARGV0);\n \n-\tprepare_repo_settings(repo);\n-\trepo->settings.command_requires_full_index = 0;\n+\tprepare_repo_settings(the_repository);\n+\tthe_repository->settings.command_requires_full_index = 0;\n \n \tif (interactive_opts.context < -1)\n \t\tdie(_(\"'%s' cannot be negative\"), \"--unified\");\n@@ -488,7 +489,7 @@ int cmd_add(int argc,\n \t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--dry-run\", \"--interactive/--patch\");\n \t\tif (pathspec_from_file)\n \t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--interactive/--patch\");\n-\t\texit(interactive_add(repo, argv + 1, prefix, patch_interactive, &interactive_opts));\n+\t\texit(interactive_add(the_repository, argv + 1, prefix, patch_interactive, &interactive_opts));\n \t} else {\n \t\tif (interactive_opts.context != -1)\n \t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--unified\", \"--interactive/--patch\");\n@@ -501,7 +502,7 @@ int cmd_add(int argc,\n \tif (edit_interactive) {\n \t\tif (pathspec_from_file)\n \t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--edit\");\n-\t\treturn(edit_patch(repo, argc, argv, prefix));\n+\t\treturn(edit_patch(the_repository, argc, argv, prefix));\n \t}\n \targc--;\n \targv++;\n@@ -528,7 +529,7 @@ int cmd_add(int argc,\n \t\t\t     (0 < addremove_explicit) ||\n \t\t\t     add_resolved);\n \n-\trepo_hold_locked_index(repo, &lock_file, LOCK_DIE_ON_ERROR);\n+\trepo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);\n \n \t/*\n \t * Check the \"pathspec '%s' did not match any files\" block\n@@ -570,11 +571,11 @@ int cmd_add(int argc,\n \t\t (!(addremove || take_worktree_changes)\n \t\t  ? ADD_CACHE_IGNORE_REMOVAL : 0));\n \n-\tif (repo_read_index_preload(repo, &pathspec, 0) < 0)\n+\tif (repo_read_index_preload(the_repository, &pathspec, 0) < 0)\n \t\tdie(_(\"index file corrupt\"));\n \n-\tdie_in_unpopulated_submodule(repo->index, prefix);\n-\tdie_path_inside_submodule(repo->index, &pathspec);\n+\tdie_in_unpopulated_submodule(the_repository->index, prefix);\n+\tdie_path_inside_submodule(the_repository->index, &pathspec);\n \n \tif (add_new_files) {\n \t\tint baselen;\n@@ -586,13 +587,13 @@ int cmd_add(int argc,\n \t\t}\n \n \t\t/* This picks up the paths that are not tracked */\n-\t\tbaselen = fill_directory(&dir, repo->index, &pathspec);\n+\t\tbaselen = fill_directory(&dir, the_repository->index, &pathspec);\n \t\tif (pathspec.nr)\n-\t\t\tseen = prune_directory(repo, &dir, &pathspec, baselen);\n+\t\t\tseen = prune_directory(the_repository, &dir, &pathspec, baselen);\n \t}\n \n \tif (refresh_only) {\n-\t\texit_status |= refresh(repo, verbose, &pathspec);\n+\t\texit_status |= refresh(the_repository, verbose, &pathspec);\n \t\tgoto finish;\n \t}\n \n@@ -603,7 +604,7 @@ int cmd_add(int argc,\n \n \t\tif (!seen)\n \t\t\tseen = find_pathspecs_matching_against_index(&pathspec,\n-\t\t\t\t\trepo->index, PS_IGNORE_SKIP_WORKTREE);\n+\t\t\t\t\tthe_repository->index, PS_IGNORE_SKIP_WORKTREE);\n \n \t\t/*\n \t\t * file_exists() assumes exact match\n@@ -639,8 +640,8 @@ int cmd_add(int argc,\n \t\t\t    !file_exists(path)) {\n \t\t\t\tif (ignore_missing) {\n \t\t\t\t\tint dtype = DT_UNKNOWN;\n-\t\t\t\t\tif (is_excluded(&dir, repo->index, path, &dtype))\n-\t\t\t\t\t\tdir_add_ignored(&dir, repo->index,\n+\t\t\t\t\tif (is_excluded(&dir, the_repository->index, path, &dtype))\n+\t\t\t\t\t\tdir_add_ignored(&dir, the_repository->index,\n \t\t\t\t\t\t\t\tpath, pathspec.items[i].len);\n \t\t\t\t} else\n \t\t\t\t\tdie(_(\"pathspec '%s' did not match any files\"),\n@@ -659,15 +660,15 @@ int cmd_add(int argc,\n \t\tstring_list_clear(&only_match_skip_worktree, 0);\n \t}\n \n-\todb_transaction_begin_or_die(repo->objects, &transaction, 0);\n+\todb_transaction_begin_or_die(the_repository->objects, &transaction, 0);\n \n \tps_matched = xcalloc(pathspec.nr, 1);\n \tif (add_resolved)\n-\t\texit_status |= add_resolved_files(repo, &pathspec, flags);\n+\t\texit_status |= add_resolved_files(the_repository, &pathspec, flags);\n \telse if (add_renormalize)\n-\t\texit_status |= renormalize_tracked_files(repo, &pathspec, flags);\n+\t\texit_status |= renormalize_tracked_files(the_repository, &pathspec, flags);\n \telse\n-\t\texit_status |= add_files_to_cache(repo, prefix,\n+\t\texit_status |= add_files_to_cache(the_repository, prefix,\n \t\t\t\t\t\t  &pathspec, ps_matched,\n \t\t\t\t\t\t  include_sparse, flags, ignored_too);\n \n@@ -676,14 +677,14 @@ int cmd_add(int argc,\n \t\texit(128);\n \n \tif (add_new_files)\n-\t\texit_status |= add_files(repo, &dir, flags);\n+\t\texit_status |= add_files(the_repository, &dir, flags);\n \n \tif (chmod_arg && pathspec.nr)\n-\t\texit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only);\n+\t\texit_status |= chmod_pathspec(the_repository, &pathspec, chmod_arg[0], show_only);\n \todb_transaction_commit(transaction);\n \n finish:\n-\tif (write_locked_index(repo->index, &lock_file,\n+\tif (write_locked_index(the_repository->index, &lock_file,\n \t\t\t       COMMIT_LOCK | SKIP_IF_UNCHANGED))\n \t\tdie(_(\"unable to write new index file\"));\n \ndiff --git c/builtin/am.c w/builtin/am.c\nindex e9623b8307..18a45c58ac 100644\n--- c/builtin/am.c\n+++ w/builtin/am.c\n@@ -2312,7 +2312,7 @@ static int parse_opt_show_current_patch(const struct option *opt, const char *ar\n int cmd_am(int argc,\n \t   const char **argv,\n \t   const char *prefix,\n-\t   struct repository *repo UNUSED)\n+\t   bool has_repo UNUSED)\n {\n \tstruct am_state state;\n \tint binary = -1;\ndiff --git c/builtin/annotate.c w/builtin/annotate.c\nindex 7f754f2309..de433f4823 100644\n--- c/builtin/annotate.c\n+++ w/builtin/annotate.c\n@@ -11,7 +11,7 @@\n int cmd_annotate(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo)\n+\t\t bool has_repo)\n {\n \tstruct strvec args = STRVEC_INIT;\n \tconst char **args_copy;\n@@ -28,7 +28,7 @@ int cmd_annotate(int argc,\n \tCALLOC_ARRAY(args_copy, args.nr + 1);\n \tCOPY_ARRAY(args_copy, args.v, args.nr);\n \n-\tret = cmd_blame(args.nr, args_copy, prefix, repo);\n+\tret = cmd_blame(args.nr, args_copy, prefix, has_repo);\n \n \tstrvec_clear(&args);\n \tfree(args_copy);\ndiff --git c/builtin/apply.c w/builtin/apply.c\nindex d642a40251..3094f4c22d 100644\n--- c/builtin/apply.c\n+++ w/builtin/apply.c\n@@ -12,7 +12,7 @@ static const char * const apply_usage[] = {\n int cmd_apply(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo)\n+\t      bool has_repo)\n {\n \tint force_apply = 0;\n \tint options = 0;\n@@ -35,9 +35,9 @@ int cmd_apply(int argc,\n \t\t\t\t   &state, &force_apply, &options,\n \t\t\t\t   apply_usage);\n \n-\tif (repo) {\n-\t\tprepare_repo_settings(repo);\n-\t\trepo->settings.command_requires_full_index = 0;\n+\tif (has_repo) {\n+\t\tprepare_repo_settings(the_repository);\n+\t\tthe_repository->settings.command_requires_full_index = 0;\n \t}\n \n \tif (check_apply_state(&state, force_apply))\ndiff --git c/builtin/archive.c w/builtin/archive.c\nindex 3c1288a123..26d7d23c80 100644\n--- c/builtin/archive.c\n+++ w/builtin/archive.c\n@@ -2,6 +2,7 @@\n  * Copyright (c) 2006 Franck Bui-Huu\n  * Copyright (c) 2006 Rene Scharfe\n  */\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"archive.h\"\n #include \"gettext.h\"\n@@ -78,7 +79,7 @@ static int run_remote_archiver(int argc, const char **argv,\n int cmd_archive(int argc,\n \t\tconst char **argv,\n \t\tconst char *prefix,\n-\t\tstruct repository *repo)\n+\t\tbool has_repo UNUSED)\n {\n \tconst char *exec = \"git-upload-archive\";\n \tchar *output = NULL;\n@@ -109,7 +110,7 @@ int cmd_archive(int argc,\n \n \tsetvbuf(stderr, NULL, _IOLBF, BUFSIZ);\n \n-\tret = write_archive(argc, argv, prefix, repo, output, 0);\n+\tret = write_archive(argc, argv, prefix, the_repository, output, 0);\n \n out:\n \tfree(output);\ndiff --git c/builtin/backfill.c w/builtin/backfill.c\nindex e71e0f4742..b584421250 100644\n--- c/builtin/backfill.c\n+++ w/builtin/backfill.c\n@@ -139,11 +139,11 @@ static int do_backfill(struct backfill_context *ctx)\n \treturn ret;\n }\n \n-int cmd_backfill(int argc, const char **argv, const char *prefix, struct repository *repo)\n+int cmd_backfill(int argc, const char **argv, const char *prefix, bool has_repo UNUSED)\n {\n \tint result;\n \tstruct backfill_context ctx = {\n-\t\t.repo = repo,\n+\t\t.repo = the_repository,\n \t\t.current_batch = OID_ARRAY_INIT,\n \t\t.min_batch_size = 50000,\n \t\t.sparse = -1,\n@@ -169,14 +169,14 @@ int cmd_backfill(int argc, const char **argv, const char *prefix, struct reposit\n \t\t\t     PARSE_OPT_KEEP_ARGV0 |\n \t\t\t     PARSE_OPT_KEEP_DASHDASH);\n \n-\trepo_init_revisions(repo, &ctx.revs, prefix);\n+\trepo_init_revisions(the_repository, &ctx.revs, prefix);\n \targc = setup_revisions(argc, argv, &ctx.revs, NULL);\n \n \tif (argc > 1)\n \t\tdie(_(\"unrecognized argument: %s\"), argv[1]);\n \treject_unsupported_rev_list_options(&ctx.revs);\n \n-\trepo_config(repo, git_default_config, NULL);\n+\trepo_config(the_repository, git_default_config, NULL);\n \n \tif (ctx.sparse < 0)\n \t\tctx.sparse = cfg->apply_sparse_checkout;\ndiff --git c/builtin/bisect.c w/builtin/bisect.c\nindex 1cfb8a794b..045e44af9a 100644\n--- c/builtin/bisect.c\n+++ w/builtin/bisect.c\n@@ -1598,7 +1598,7 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE\n int cmd_bisect(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo)\n+\t       bool has_repo UNUSED)\n {\n \tint res = 0;\n \tparse_opt_subcommand_fn *fn = NULL;\n@@ -1640,7 +1640,7 @@ int cmd_bisect(int argc,\n \t} else {\n \t\targc--;\n \t\targv++;\n-\t\tres = fn(argc, argv, prefix, repo);\n+\t\tres = fn(argc, argv, prefix, the_repository);\n \t}\n \n \tif (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {\ndiff --git c/builtin/blame.c w/builtin/blame.c\nindex 48d5251c6d..2df1dfaacf 100644\n--- c/builtin/blame.c\n+++ w/builtin/blame.c\n@@ -957,7 +957,7 @@ static void build_ignorelist(struct blame_scoreboard *sb,\n int cmd_blame(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo UNUSED)\n+\t      bool has_repo UNUSED)\n {\n \tstruct rev_info revs;\n \tchar *path = NULL;\ndiff --git c/builtin/branch.c w/builtin/branch.c\nindex a613148fc7..f4258c9e32 100644\n--- c/builtin/branch.c\n+++ w/builtin/branch.c\n@@ -969,7 +969,7 @@ static void die_if_upstream_looks_like_remote(const char *new_upstream, const ch\n int cmd_branch(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo UNUSED)\n+\t       bool has_repo UNUSED)\n {\n \t/* possible actions */\n \tint delete = 0, rename = 0, copy = 0, list = 0,\ndiff --git c/builtin/bugreport.c w/builtin/bugreport.c\nindex f78c3f2aed..d4ab2cc1a9 100644\n--- c/builtin/bugreport.c\n+++ w/builtin/bugreport.c\n@@ -93,7 +93,7 @@ static void get_header(struct strbuf *buf, const char *title)\n int cmd_bugreport(int argc,\n \t\t  const char **argv,\n \t\t  const char *prefix,\n-\t\t  struct repository *repo UNUSED)\n+\t\t  bool has_repo UNUSED)\n {\n \tstruct strbuf buffer = STRBUF_INIT;\n \tstruct strbuf report_path = STRBUF_INIT;\ndiff --git c/builtin/bundle.c w/builtin/bundle.c\nindex 1e170e9278..3df9a20b57 100644\n--- c/builtin/bundle.c\n+++ w/builtin/bundle.c\n@@ -235,7 +235,7 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix,\n int cmd_bundle(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo)\n+\t       bool has_repo UNUSED)\n {\n \tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option options[] = {\n@@ -251,5 +251,5 @@ int cmd_bundle(int argc,\n \n \tpacket_trace_identity(\"bundle\");\n \n-\treturn !!fn(argc, argv, prefix, repo);\n+\treturn !!fn(argc, argv, prefix, the_repository);\n }\ndiff --git c/builtin/cat-file.c w/builtin/cat-file.c\nindex 8870a210ec..b61364231e 100644\n--- c/builtin/cat-file.c\n+++ w/builtin/cat-file.c\n@@ -1182,7 +1182,7 @@ static int batch_option_callback(const struct option *opt,\n int cmd_cat_file(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo UNUSED)\n+\t\t bool has_repo UNUSED)\n {\n \tint opt = 0;\n \tint opt_cw = 0;\ndiff --git c/builtin/check-attr.c w/builtin/check-attr.c\nindex 217d83ea7d..44dd21b13e 100644\n--- c/builtin/check-attr.c\n+++ w/builtin/check-attr.c\n@@ -110,7 +110,7 @@ static NORETURN void error_with_usage(const char *msg)\n int cmd_check_attr(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tstruct attr_check *check;\n \tstruct object_id initialized_oid;\ndiff --git c/builtin/check-ignore.c w/builtin/check-ignore.c\nindex 644c9a414f..bd26521cc6 100644\n--- c/builtin/check-ignore.c\n+++ w/builtin/check-ignore.c\n@@ -155,7 +155,7 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)\n int cmd_check_ignore(int argc,\n \t\t     const char **argv,\n \t\t     const char *prefix,\n-\t\t     struct repository *repo UNUSED)\n+\t\t     bool has_repo UNUSED)\n {\n \tint num_ignored;\n \tstruct dir_struct dir = DIR_INIT;\ndiff --git c/builtin/check-mailmap.c w/builtin/check-mailmap.c\nindex 3f2a39cae0..b45b4c4cae 100644\n--- c/builtin/check-mailmap.c\n+++ w/builtin/check-mailmap.c\n@@ -52,7 +52,7 @@ static void check_mailmap(struct string_list *mailmap, const char *contact)\n int cmd_check_mailmap(int argc,\n \t\t      const char **argv,\n \t\t      const char *prefix,\n-\t\t      struct repository *repo UNUSED)\n+\t\t      bool has_repo UNUSED)\n {\n \tint i;\n \tstruct string_list mailmap = STRING_LIST_INIT_NODUP;\ndiff --git c/builtin/check-ref-format.c w/builtin/check-ref-format.c\nindex fd1c9c0e0c..77df939550 100644\n--- c/builtin/check-ref-format.c\n+++ w/builtin/check-ref-format.c\n@@ -56,7 +56,7 @@ static int check_ref_format_branch(const char *arg)\n int cmd_check_ref_format(int argc,\n \t\t\t const char **argv,\n \t\t\t const char *prefix,\n-\t\t\t struct repository *repo UNUSED)\n+\t\t\t bool has_repo UNUSED)\n {\n \tint i;\n \tint normalize = 0;\ndiff --git c/builtin/checkout--worker.c w/builtin/checkout--worker.c\nindex e0772b718b..6af94b0191 100644\n--- c/builtin/checkout--worker.c\n+++ w/builtin/checkout--worker.c\n@@ -120,7 +120,7 @@ static const char * const checkout_worker_usage[] = {\n int cmd_checkout__worker(int argc,\n \t\t\t const char **argv,\n \t\t\t const char *prefix,\n-\t\t\t struct repository *repo UNUSED)\n+\t\t\t bool has_repo UNUSED)\n {\n \tstruct checkout state = CHECKOUT_INIT;\n \tstruct option checkout_worker_options[] = {\ndiff --git c/builtin/checkout-index.c w/builtin/checkout-index.c\nindex 311b94ff31..ed329cbf81 100644\n--- c/builtin/checkout-index.c\n+++ w/builtin/checkout-index.c\n@@ -5,6 +5,7 @@\n  *\n  */\n \n+#define USE_THE_REPOSITORY_VARIABLE\n #define DISABLE_SIGN_COMPARE_WARNINGS\n \n #include \"builtin.h\"\n@@ -213,7 +214,7 @@ static int option_parse_stage(const struct option *opt,\n int cmd_checkout_index(int argc,\n \t\t       const char **argv,\n \t\t       const char *prefix,\n-\t\t       struct repository *repo)\n+\t\t       bool has_repo UNUSED)\n {\n \tint i;\n \tstruct lock_file lock_file = LOCK_INIT;\n@@ -253,19 +254,19 @@ int cmd_checkout_index(int argc,\n \tshow_usage_with_options_if_asked(argc, argv,\n \t\t\t\t\t builtin_checkout_index_usage,\n \t\t\t\t\t builtin_checkout_index_options);\n-\trepo_config(repo, git_default_config, NULL);\n+\trepo_config(the_repository, git_default_config, NULL);\n \tprefix_length = prefix ? strlen(prefix) : 0;\n \n-\tprepare_repo_settings(repo);\n-\trepo->settings.command_requires_full_index = 0;\n+\tprepare_repo_settings(the_repository);\n+\tthe_repository->settings.command_requires_full_index = 0;\n \n-\tif (repo_read_index(repo) < 0) {\n+\tif (repo_read_index(the_repository) < 0) {\n \t\tdie(\"invalid cache\");\n \t}\n \n \targc = parse_options(argc, argv, prefix, builtin_checkout_index_options,\n \t\t\tbuiltin_checkout_index_usage, 0);\n-\tstate.istate = repo->index;\n+\tstate.istate = the_repository->index;\n \tstate.force = force;\n \tstate.quiet = quiet;\n \tstate.not_new = not_new;\n@@ -285,8 +286,8 @@ int cmd_checkout_index(int argc,\n \t */\n \tif (index_opt && !state.base_dir_len && !to_tempfile) {\n \t\tstate.refresh_cache = 1;\n-\t\tstate.istate = repo->index;\n-\t\trepo_hold_locked_index(repo, &lock_file,\n+\t\tstate.istate = the_repository->index;\n+\t\trepo_hold_locked_index(the_repository, &lock_file,\n \t\t\t\t       LOCK_DIE_ON_ERROR);\n \t}\n \n@@ -303,8 +304,8 @@ int cmd_checkout_index(int argc,\n \t\t\tdie(\"git checkout-index: don't mix '--all' and explicit filenames\");\n \t\tif (read_from_stdin)\n \t\t\tdie(\"git checkout-index: don't mix '--stdin' and explicit filenames\");\n-\t\tp = prefix_path(repo, prefix, prefix_length, arg);\n-\t\terr |= checkout_file(repo->index, p, prefix);\n+\t\tp = prefix_path(the_repository, prefix, prefix_length, arg);\n+\t\terr |= checkout_file(the_repository->index, p, prefix);\n \t\tfree(p);\n \t}\n \n@@ -325,8 +326,8 @@ int cmd_checkout_index(int argc,\n \t\t\t\t\tdie(\"line is badly quoted\");\n \t\t\t\tstrbuf_swap(&buf, &unquoted);\n \t\t\t}\n-\t\t\tp = prefix_path(repo, prefix, prefix_length, buf.buf);\n-\t\t\terr |= checkout_file(repo->index, p, prefix);\n+\t\t\tp = prefix_path(the_repository, prefix, prefix_length, buf.buf);\n+\t\t\terr |= checkout_file(the_repository->index, p, prefix);\n \t\t\tfree(p);\n \t\t}\n \t\tstrbuf_release(&unquoted);\n@@ -334,7 +335,7 @@ int cmd_checkout_index(int argc,\n \t}\n \n \tif (all)\n-\t\terr |= checkout_all(repo->index, prefix, prefix_length);\n+\t\terr |= checkout_all(the_repository->index, prefix, prefix_length);\n \n \tif (pc_workers > 1)\n \t\terr |= run_parallel_checkout(&state, pc_workers, pc_threshold,\n@@ -344,7 +345,7 @@ int cmd_checkout_index(int argc,\n \t\treturn 1;\n \n \tif (is_lock_file_locked(&lock_file) &&\n-\t    write_locked_index(repo->index, &lock_file, COMMIT_LOCK))\n+\t    write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))\n \t\tdie(\"Unable to write new index file\");\n \treturn 0;\n }\ndiff --git c/builtin/checkout.c w/builtin/checkout.c\nindex 55e3a89a85..2a9fa4dcd3 100644\n--- c/builtin/checkout.c\n+++ w/builtin/checkout.c\n@@ -2092,7 +2092,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n int cmd_checkout(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo UNUSED)\n+\t\t bool has_repo UNUSED)\n {\n \tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n \tstruct option *options;\n@@ -2144,7 +2144,7 @@ int cmd_checkout(int argc,\n int cmd_switch(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo UNUSED)\n+\t       bool has_repo UNUSED)\n {\n \tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n \tstruct option *options = NULL;\n@@ -2183,7 +2183,7 @@ int cmd_switch(int argc,\n int cmd_restore(int argc,\n \t\tconst char **argv,\n \t\tconst char *prefix,\n-\t\tstruct repository *repo UNUSED)\n+\t\tbool has_repo UNUSED)\n {\n \tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n \tstruct option *options;\ndiff --git c/builtin/clean.c w/builtin/clean.c\nindex 1d5e7e5366..69df102fd0 100644\n--- c/builtin/clean.c\n+++ w/builtin/clean.c\n@@ -919,7 +919,7 @@ static void correct_untracked_entries(struct dir_struct *dir)\n int cmd_clean(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo UNUSED)\n+\t      bool has_repo UNUSED)\n {\n \tint i, res;\n \tint dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;\ndiff --git c/builtin/clone.c w/builtin/clone.c\nindex 5b25cca510..ea1e85e2a8 100644\n--- c/builtin/clone.c\n+++ w/builtin/clone.c\n@@ -869,7 +869,7 @@ static int path_exists(const char *path)\n int cmd_clone(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repository UNUSED)\n+\t      bool has_repo UNUSED)\n {\n \tint is_bundle = 0, is_local;\n \tint reject_shallow = 0;\ndiff --git c/builtin/column.c w/builtin/column.c\nindex 87dce3c6e5..d4262a08b0 100644\n--- c/builtin/column.c\n+++ w/builtin/column.c\n@@ -22,7 +22,7 @@ static int column_config(const char *var, const char *value,\n int cmd_column(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo UNUSED)\n+\t       bool has_repo UNUSED)\n {\n \tstruct string_list list = STRING_LIST_INIT_DUP;\n \tstruct strbuf sb = STRBUF_INIT;\ndiff --git c/builtin/commit-graph.c w/builtin/commit-graph.c\nindex d62005edc0..a350a05291 100644\n--- c/builtin/commit-graph.c\n+++ w/builtin/commit-graph.c\n@@ -341,7 +341,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,\n int cmd_commit_graph(int argc,\n \t\t     const char **argv,\n \t\t     const char *prefix,\n-\t\t     struct repository *repo)\n+\t\t     bool has_repo UNUSED)\n {\n \tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option builtin_commit_graph_options[] = {\n@@ -360,5 +360,5 @@ int cmd_commit_graph(int argc,\n \t\t\t     builtin_commit_graph_usage, 0);\n \tFREE_AND_NULL(options);\n \n-\treturn fn(argc, argv, prefix, repo);\n+\treturn fn(argc, argv, prefix, the_repository);\n }\ndiff --git c/builtin/commit-tree.c w/builtin/commit-tree.c\nindex 30535db131..cbfe4fe3a0 100644\n--- c/builtin/commit-tree.c\n+++ w/builtin/commit-tree.c\n@@ -95,7 +95,7 @@ static int parse_file_arg_callback(const struct option *opt,\n int cmd_commit_tree(int argc,\n \t\t    const char **argv,\n \t\t    const char *prefix,\n-\t\t    struct repository *repo UNUSED)\n+\t\t    bool has_repo UNUSED)\n {\n \tstatic struct strbuf buffer = STRBUF_INIT;\n \tstruct commit_list *parents = NULL;\ndiff --git c/builtin/commit.c w/builtin/commit.c\nindex 28f6174503..92317ec2fc 100644\n--- c/builtin/commit.c\n+++ w/builtin/commit.c\n@@ -1537,7 +1537,7 @@ static int git_status_config(const char *k, const char *v,\n int cmd_status(int argc,\n const char **argv,\n const char *prefix,\n-struct repository *repo UNUSED)\n+bool has_repo UNUSED)\n {\n \tstatic int no_renames = -1;\n \tstatic const char *rename_score_arg = (const char *)-1;\n@@ -1698,7 +1698,7 @@ static int git_commit_config(const char *k, const char *v,\n int cmd_commit(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo UNUSED)\n+\t       bool has_repo UNUSED)\n {\n \tstatic struct wt_status s;\n \tstatic const char *cleanup_arg = NULL;\ndiff --git c/builtin/config.c w/builtin/config.c\nindex 2554322317..b5e2fd42f1 100644\n--- c/builtin/config.c\n+++ w/builtin/config.c\n@@ -1627,7 +1627,7 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)\n int cmd_config(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo)\n+\t       bool has_repo UNUSED)\n {\n \tparse_opt_subcommand_fn *subcommand = NULL;\n \tstruct option subcommand_opts[] = {\n@@ -1654,7 +1654,7 @@ int cmd_config(int argc,\n \tif (subcommand) {\n \t\targc = parse_options(argc, argv, prefix, subcommand_opts, builtin_config_usage,\n \t\t       PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_UNKNOWN_OPT);\n-\t\treturn subcommand(argc, argv, prefix, repo);\n+\t\treturn subcommand(argc, argv, prefix, the_repository);\n \t}\n \n \treturn cmd_config_actions(argc, argv, prefix);\ndiff --git c/builtin/count-objects.c w/builtin/count-objects.c\nindex 18f6e33b6f..aabe93aaef 100644\n--- c/builtin/count-objects.c\n+++ w/builtin/count-objects.c\n@@ -97,7 +97,7 @@ static char const * const count_objects_usage[] = {\n int cmd_count_objects(int argc,\n \t\t      const char **argv,\n \t\t      const char *prefix,\n-\t\t      struct repository *repo UNUSED)\n+\t\t      bool has_repo UNUSED)\n {\n \tint human_readable = 0;\n \tstruct option opts[] = {\ndiff --git c/builtin/credential-cache--daemon.c w/builtin/credential-cache--daemon.c\nindex 65cc619bec..11bb8007b6 100644\n--- c/builtin/credential-cache--daemon.c\n+++ w/builtin/credential-cache--daemon.c\n@@ -291,7 +291,7 @@ static void init_socket_directory(const char *path)\n int cmd_credential_cache_daemon(int argc,\n \t\t\t\tconst char **argv,\n \t\t\t\tconst char *prefix,\n-\t\t\t\tstruct repository *repo UNUSED)\n+\t\t\t\tbool has_repo UNUSED)\n {\n \tstruct tempfile *socket_file;\n \tconst char *socket_path;\n@@ -337,7 +337,7 @@ int cmd_credential_cache_daemon(int argc,\n int cmd_credential_cache_daemon(int argc,\n const char **argv,\n const char *prefix,\n-struct repository *repo UNUSED)\n+bool has_repo UNUSED)\n {\n \tconst char * const usage[] = {\n \t\t\"git credential-cache--daemon [--debug] <socket-path>\",\ndiff --git c/builtin/credential-cache.c w/builtin/credential-cache.c\nindex 7f733cb756..97298070bf 100644\n--- c/builtin/credential-cache.c\n+++ w/builtin/credential-cache.c\n@@ -140,7 +140,7 @@ static void announce_capabilities(void)\n int cmd_credential_cache(int argc,\n \t\t\t const char **argv,\n \t\t\t const char *prefix,\n-\t\t\t struct repository *repo UNUSED)\n+\t\t\t bool has_repo UNUSED)\n {\n \tconst char *socket_path_arg = NULL;\n \tchar *socket_path;\n@@ -190,7 +190,7 @@ int cmd_credential_cache(int argc,\n #else\n \n int cmd_credential_cache(int argc, const char **argv, const char *prefix,\n-\t\t\t struct repository *repo UNUSED)\n+\t\t\t bool has_repo UNUSED)\n {\n \tconst char * const usage[] = {\n \t\t\"git credential-cache [options] <action>\",\ndiff --git c/builtin/credential-store.c w/builtin/credential-store.c\nindex bc1453c6b2..9ccdd7aeb6 100644\n--- c/builtin/credential-store.c\n+++ w/builtin/credential-store.c\n@@ -169,7 +169,7 @@ static void lookup_credential(const struct string_list *fns, struct credential *\n int cmd_credential_store(int argc,\n \t\t\t const char **argv,\n \t\t\t const char *prefix,\n-\t\t\t struct repository *repo UNUSED)\n+\t\t\t bool has_repo UNUSED)\n {\n \tconst char * const usage[] = {\n \t\t\"git credential-store [<options>] <action>\",\ndiff --git c/builtin/credential.c w/builtin/credential.c\nindex a295c80b36..a1024a57f6 100644\n--- c/builtin/credential.c\n+++ w/builtin/credential.c\n@@ -12,7 +12,7 @@ static const char usage_msg[] =\n int cmd_credential(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix UNUSED,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tconst char *op;\n \tstruct credential c = CREDENTIAL_INIT;\ndiff --git c/builtin/describe.c w/builtin/describe.c\nindex c0abc931a5..84983debfe 100644\n--- c/builtin/describe.c\n+++ w/builtin/describe.c\n@@ -601,7 +601,7 @@ static int option_parse_exact_match(const struct option *opt, const char *arg,\n int cmd_describe(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo UNUSED )\n+\t\t bool has_repo UNUSED)\n {\n \tstruct refs_for_each_ref_options for_each_ref_opts = {\n \t\t.flags = REFS_FOR_EACH_INCLUDE_BROKEN,\ndiff --git c/builtin/diagnose.c w/builtin/diagnose.c\nindex ec86d66389..120121cc8f 100644\n--- c/builtin/diagnose.c\n+++ w/builtin/diagnose.c\n@@ -16,7 +16,7 @@ static const char * const diagnose_usage[] = {\n int cmd_diagnose(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo UNUSED)\n+\t\t bool has_repo UNUSED)\n {\n \tstruct strbuf zip_path = STRBUF_INIT;\n \ttime_t now = time(NULL);\ndiff --git c/builtin/diff-files.c w/builtin/diff-files.c\nindex ea91347ce2..4e6a662987 100644\n--- c/builtin/diff-files.c\n+++ w/builtin/diff-files.c\n@@ -23,7 +23,7 @@ COMMON_DIFF_OPTIONS_HELP;\n int cmd_diff_files(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tstruct rev_info rev;\n \tint result;\ndiff --git c/builtin/diff-index.c w/builtin/diff-index.c\nindex 3db7cffede..9d217592d3 100644\n--- c/builtin/diff-index.c\n+++ w/builtin/diff-index.c\n@@ -19,7 +19,7 @@ COMMON_DIFF_OPTIONS_HELP;\n int cmd_diff_index(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tstruct rev_info rev;\n \tunsigned int option = 0;\ndiff --git c/builtin/diff-pairs.c w/builtin/diff-pairs.c\nindex 71c045331a..ba40e2daca 100644\n--- c/builtin/diff-pairs.c\n+++ w/builtin/diff-pairs.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"config.h\"\n #include \"diff.h\"\n@@ -28,7 +29,7 @@ static void parse_oid_or_die(const char *hex, struct object_id *oid,\n }\n \n int cmd_diff_pairs(int argc, const char **argv, const char *prefix,\n-\t\t   struct repository *repo)\n+\t\t   bool has_repo UNUSED)\n {\n \tstruct strbuf path_dst = STRBUF_INIT;\n \tstruct strbuf path = STRBUF_INIT;\n@@ -46,7 +47,7 @@ int cmd_diff_pairs(int argc, const char **argv, const char *prefix,\n \t\tOPT_END()\n \t};\n \n-\trepo_init_revisions(repo, &revs, prefix);\n+\trepo_init_revisions(the_repository, &revs, prefix);\n \n \t/*\n \t * Diff options are usually parsed implicitly as part of\n@@ -56,7 +57,7 @@ int cmd_diff_pairs(int argc, const char **argv, const char *prefix,\n \tparseopts = add_diff_options(builtin_diff_pairs_options, &revs.diffopt);\n \tshow_usage_with_options_if_asked(argc, argv, builtin_diff_pairs_usage, parseopts);\n \n-\trepo_config(repo, git_diff_basic_config, NULL);\n+\trepo_config(the_repository, git_diff_basic_config, NULL);\n \trevs.diffopt.no_free = 1;\n \trevs.disable_stdin = 1;\n \trevs.abbrev = 0;\n@@ -129,8 +130,8 @@ int cmd_diff_pairs(int argc, const char **argv, const char *prefix,\n \t\tif (S_ISDIR(mode_a) || S_ISDIR(mode_b))\n \t\t\tdie(_(\"tree objects not supported\"));\n \n-\t\tparse_oid_or_die(p, &oid_a, &p, repo->hash_algo);\n-\t\tparse_oid_or_die(p, &oid_b, &p, repo->hash_algo);\n+\t\tparse_oid_or_die(p, &oid_a, &p, the_repository->hash_algo);\n+\t\tparse_oid_or_die(p, &oid_b, &p, the_repository->hash_algo);\n \n \t\tstatus = *p++;\n \ndiff --git c/builtin/diff-tree.c w/builtin/diff-tree.c\nindex 8b8f8b54e4..4733798e5a 100644\n--- c/builtin/diff-tree.c\n+++ w/builtin/diff-tree.c\n@@ -112,7 +112,7 @@ static void diff_tree_tweak_rev(struct rev_info *rev)\n int cmd_diff_tree(int argc,\n \t\t  const char **argv,\n \t\t  const char *prefix,\n-\t\t  struct repository *repo UNUSED)\n+\t\t  bool has_repo UNUSED)\n {\n \tchar line[1000];\n \tstruct object *tree1, *tree2;\ndiff --git c/builtin/diff.c w/builtin/diff.c\nindex 18b1083e98..75c4120b74 100644\n--- c/builtin/diff.c\n+++ w/builtin/diff.c\n@@ -399,7 +399,7 @@ static void symdiff_release(struct symdiff *sdiff)\n int cmd_diff(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n-\t     struct repository *repo UNUSED)\n+\t     bool has_repo UNUSED)\n {\n \tint i;\n \tstruct rev_info rev;\ndiff --git c/builtin/difftool.c w/builtin/difftool.c\nindex bc7b2ea443..18ca0e313b 100644\n--- c/builtin/difftool.c\n+++ w/builtin/difftool.c\n@@ -12,6 +12,7 @@\n  * Copyright (C) 2016 Johannes Schindelin\n  */\n \n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n \n #include \"abspath.h\"\n@@ -717,7 +718,7 @@ static int run_file_diff(int prompt, const char *prefix,\n int cmd_difftool(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo)\n+\t\t bool has_repo UNUSED)\n {\n \tint use_gui_tool = -1, dir_diff = 0, prompt = -1, tool_help = 0, no_index = 0;\n \tstatic char *difftool_cmd = NULL, *extcmd = NULL;\n@@ -753,7 +754,7 @@ int cmd_difftool(int argc,\n \t};\n \tstruct child_process child = CHILD_PROCESS_INIT;\n \n-\trepo_config(repo, difftool_config, &dt_options);\n+\trepo_config(the_repository, difftool_config, &dt_options);\n \tdt_options.symlinks = dt_options.has_symlinks;\n \n \targc = parse_options(argc, argv, prefix, builtin_difftool_options,\n@@ -767,9 +768,9 @@ int cmd_difftool(int argc,\n \t\tdie(_(\"difftool requires worktree or --no-index\"));\n \n \tif (!no_index){\n-\t\tsetup_work_tree(repo);\n-\t\tsetenv(GIT_DIR_ENVIRONMENT, absolute_path(repo_get_git_dir(repo)), 1);\n-\t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(repo_get_work_tree(repo)), 1);\n+\t\tsetup_work_tree(the_repository);\n+\t\tsetenv(GIT_DIR_ENVIRONMENT, absolute_path(repo_get_git_dir(the_repository)), 1);\n+\t\tsetenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(repo_get_work_tree(the_repository)), 1);\n \t} else if (dir_diff)\n \t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--dir-diff\", \"--no-index\");\n \n@@ -818,6 +819,6 @@ int cmd_difftool(int argc,\n \tstrvec_pushv(&child.args, argv);\n \n \tif (dir_diff)\n-\t\treturn run_dir_diff(repo, &dt_options, extcmd, prefix, &child);\n+\t\treturn run_dir_diff(the_repository, &dt_options, extcmd, prefix, &child);\n \treturn run_file_diff(prompt, prefix, &child);\n }\ndiff --git c/builtin/fast-export.c w/builtin/fast-export.c\nindex 50278bef7a..cd7f4e90d9 100644\n--- c/builtin/fast-export.c\n+++ w/builtin/fast-export.c\n@@ -1310,7 +1310,7 @@ static int parse_opt_anonymize_map(const struct option *opt,\n int cmd_fast_export(int argc,\n \t\t    const char **argv,\n \t\t    const char *prefix,\n-\t\t    struct repository *repo UNUSED)\n+\t\t    bool has_repo UNUSED)\n {\n \tstruct rev_info revs;\n \tstruct commit *commit;\ndiff --git c/builtin/fast-import.c w/builtin/fast-import.c\nindex fbd919982c..c547bf7281 100644\n--- c/builtin/fast-import.c\n+++ w/builtin/fast-import.c\n@@ -4123,7 +4123,7 @@ static int option_parse_quiet(const struct option *opt UNUSED,\n int cmd_fast_import(int argc,\n \t\t    const char **argv,\n \t\t    const char *prefix,\n-\t\t    struct repository *repo)\n+\t\t    bool has_repo UNUSED)\n {\n \tstruct fast_import_state state;\n \n@@ -4320,7 +4320,7 @@ int cmd_fast_import(int argc,\n \t\tfprintf(stderr, \"       pools:    %10lu KiB\\n\", (unsigned long)((tree_entry_allocd + fi_mem_pool.pool_alloc) /1024));\n \t\tfprintf(stderr, \"     objects:    %10\" PRIuMAX \" KiB\\n\", (alloc_count*sizeof(struct object_entry))/1024);\n \t\tfprintf(stderr, \"---------------------------------------------------------------------\\n\");\n-\t\tpack_report(repo);\n+\t\tpack_report(the_repository);\n \t\tfprintf(stderr, \"---------------------------------------------------------------------\\n\");\n \t\tfprintf(stderr, \"\\n\");\n \t}\ndiff --git c/builtin/fetch-pack.c w/builtin/fetch-pack.c\nindex 316badd969..16fcca7777 100644\n--- c/builtin/fetch-pack.c\n+++ w/builtin/fetch-pack.c\n@@ -49,7 +49,7 @@ static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,\n int cmd_fetch_pack(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix UNUSED,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tint i, ret;\n \tstruct ref *fetched_refs = NULL, *remote_refs = NULL;\ndiff --git c/builtin/fetch.c w/builtin/fetch.c\nindex ab7db2be06..15fea4ce09 100644\n--- c/builtin/fetch.c\n+++ w/builtin/fetch.c\n@@ -2505,7 +2505,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,\n int cmd_fetch(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo UNUSED)\n+\t      bool has_repo UNUSED)\n {\n \tstruct fetch_config config = {\n \t\t.display_format = DISPLAY_FORMAT_FULL,\ndiff --git c/builtin/fmt-merge-msg.c w/builtin/fmt-merge-msg.c\nindex cf4273a52c..44db2133bc 100644\n--- c/builtin/fmt-merge-msg.c\n+++ w/builtin/fmt-merge-msg.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"config.h\"\n #include \"fmt-merge-msg.h\"\n@@ -12,7 +13,7 @@ static const char * const fmt_merge_msg_usage[] = {\n int cmd_fmt_merge_msg(int argc,\n \t\t      const char **argv,\n \t\t      const char *prefix,\n-\t\t      struct repository *repo)\n+\t\t      bool has_repo UNUSED)\n {\n \tchar *inpath = NULL;\n \tconst char *message = NULL;\n@@ -53,7 +54,7 @@ int cmd_fmt_merge_msg(int argc,\n \tint ret;\n \tstruct fmt_merge_msg_opts opts;\n \n-\trepo_config(repo, fmt_merge_msg_config, &merge_log_config);\n+\trepo_config(the_repository, fmt_merge_msg_config, &merge_log_config);\n \targc = parse_options(argc, argv, prefix, options, fmt_merge_msg_usage,\n \t\t\t     0);\n \tif (argc > 0)\ndiff --git c/builtin/for-each-ref.c w/builtin/for-each-ref.c\nindex 4a2fc421db..25c84bca6b 100644\n--- c/builtin/for-each-ref.c\n+++ w/builtin/for-each-ref.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"commit.h\"\n #include \"config.h\"\n@@ -113,12 +114,12 @@ int for_each_ref_core(int argc, const char **argv, const char *prefix, struct re\n int cmd_for_each_ref(int argc,\n \t\t     const char **argv,\n \t\t     const char *prefix,\n-\t\t     struct repository *repo)\n+\t\t     bool has_repo UNUSED)\n {\n \tstatic char const * const for_each_ref_usage[] = {\n \t\tN_(\"git for-each-ref \" COMMON_USAGE_FOR_EACH_REF),\n \t\tNULL\n \t};\n \n-\treturn for_each_ref_core(argc, argv, prefix, repo, for_each_ref_usage);\n+\treturn for_each_ref_core(argc, argv, prefix, the_repository, for_each_ref_usage);\n }\ndiff --git c/builtin/for-each-repo.c w/builtin/for-each-repo.c\nindex 927d3d92da..80b0cb0739 100644\n--- c/builtin/for-each-repo.c\n+++ w/builtin/for-each-repo.c\n@@ -33,7 +33,7 @@ static int run_command_on_repo(const char *path, const char **argv)\n int cmd_for_each_repo(int argc,\n \t\t      const char **argv,\n \t\t      const char *prefix,\n-\t\t      struct repository *repo UNUSED)\n+\t\t      bool has_repo UNUSED)\n {\n \tstatic const char *config_key = NULL;\n \tint keep_going = 0;\ndiff --git c/builtin/fsck.c w/builtin/fsck.c\nindex a6c054e45b..f3083c0e7a 100644\n--- c/builtin/fsck.c\n+++ w/builtin/fsck.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n@@ -1008,7 +1009,7 @@ static struct option fsck_opts[] = {\n int cmd_fsck(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n-\t     struct repository *repo)\n+\t     bool has_repo UNUSED)\n {\n \tstruct odb_source *source;\n \tstruct snapshot snap = {\n@@ -1026,10 +1027,10 @@ int cmd_fsck(int argc,\n \n \targc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);\n \n-\tfsck_options_init(&fsck_walk_options, repo, FSCK_OPTIONS_DEFAULT);\n+\tfsck_options_init(&fsck_walk_options, the_repository, FSCK_OPTIONS_DEFAULT);\n \tfsck_walk_options.walk = mark_object;\n \n-\tfsck_options_init(&fsck_obj_options, repo, FSCK_OPTIONS_DEFAULT);\n+\tfsck_options_init(&fsck_obj_options, the_repository, FSCK_OPTIONS_DEFAULT);\n \tfsck_obj_options.walk = mark_used;\n \tfsck_obj_options.error_func = fsck_objects_error_func;\n \tif (check_strict)\n@@ -1048,11 +1049,11 @@ int cmd_fsck(int argc,\n \tif (name_objects)\n \t\tfsck_enable_object_names(&fsck_walk_options);\n \n-\trepo_config(repo, git_fsck_config, &fsck_obj_options);\n-\tprepare_repo_settings(repo);\n+\trepo_config(the_repository, git_fsck_config, &fsck_obj_options);\n+\tprepare_repo_settings(the_repository);\n \n \tif (check_references)\n-\t\tfsck_refs(repo);\n+\t\tfsck_refs(the_repository);\n \n \t/*\n \t * Take a snapshot of the refs before walking objects to avoid looking\n@@ -1060,18 +1061,18 @@ int cmd_fsck(int argc,\n \t * objects. We can still walk over new objects that are added during the\n \t * execution of fsck but won't miss any objects that were reachable.\n \t */\n-\tsnapshot_refs(repo, &snap, argc, argv);\n+\tsnapshot_refs(the_repository, &snap, argc, argv);\n \n \t/* Ensure we get a \"fresh\" view of the odb */\n-\todb_reprepare(repo->objects);\n+\todb_reprepare(the_repository->objects);\n \n \tif (connectivity_only) {\n-\t\todb_for_each_object(repo->objects, NULL,\n-\t\t\t\t    mark_object_for_connectivity, repo, 0);\n+\t\todb_for_each_object(the_repository->objects, NULL,\n+\t\t\t\t    mark_object_for_connectivity, the_repository, 0);\n \t} else {\n-\t\todb_prepare_alternates(repo->objects);\n-\t\tfor (source = repo->objects->sources; source; source = source->next)\n-\t\t\tfsck_source(repo, source);\n+\t\todb_prepare_alternates(the_repository->objects);\n+\t\tfor (source = the_repository->objects->sources; source; source = source->next)\n+\t\t\tfsck_source(the_repository, source);\n \n \t\tif (check_full) {\n \t\t\tstruct packed_git *p;\n@@ -1079,20 +1080,20 @@ int cmd_fsck(int argc,\n \t\t\tstruct progress *progress = NULL;\n \n \t\t\tif (show_progress) {\n-\t\t\t\trepo_for_each_pack(repo, p) {\n+\t\t\t\trepo_for_each_pack(the_repository, p) {\n \t\t\t\t\tif (open_pack_index(p))\n \t\t\t\t\t\tcontinue;\n \t\t\t\t\ttotal += p->num_objects;\n \t\t\t\t}\n \n-\t\t\t\tprogress = start_progress(repo,\n+\t\t\t\tprogress = start_progress(the_repository,\n \t\t\t\t\t\t\t  _(\"Checking objects\"), total);\n \t\t\t}\n \n-\t\t\trepo_for_each_pack(repo, p) {\n+\t\t\trepo_for_each_pack(the_repository, p) {\n \t\t\t\t/* verify gives error messages itself */\n-\t\t\t\tif (verify_pack(repo,\n-\t\t\t\t\t\tp, fsck_obj_buffer, repo,\n+\t\t\t\tif (verify_pack(the_repository,\n+\t\t\t\t\t\tp, fsck_obj_buffer, the_repository,\n \t\t\t\t\t\tprogress, count))\n \t\t\t\t\terrors_found |= ERROR_PACK;\n \t\t\t\tcount += p->num_objects;\n@@ -1105,7 +1106,7 @@ int cmd_fsck(int argc,\n \t}\n \n \t/* Process the snapshotted refs and the reflogs. */\n-\tprocess_refs(repo, &snap);\n+\tprocess_refs(the_repository, &snap);\n \n \t/* If not given any explicit objects, process index files too. */\n \tif (!argc)\n@@ -1121,11 +1122,11 @@ int cmd_fsck(int argc,\n \t\tverify_index_checksum = 1;\n \t\tverify_ce_order = 1;\n \n-\t\tworktrees = get_worktrees(repo);\n+\t\tworktrees = get_worktrees(the_repository);\n \t\tfor (p = worktrees; *p; p++) {\n \t\t\tstruct worktree *wt = *p;\n \t\t\tstruct index_state istate =\n-\t\t\t\tINDEX_STATE_INIT(repo);\n+\t\t\t\tINDEX_STATE_INIT(the_repository);\n \t\t\tchar *path, *wt_gitdir;\n \n \t\t\t/*\n@@ -1146,17 +1147,17 @@ int cmd_fsck(int argc,\n \t\tfree_worktrees(worktrees);\n \t}\n \n-\terrors_found |= check_pack_rev_indexes(repo, show_progress);\n-\tif (verify_bitmap_files(repo))\n+\terrors_found |= check_pack_rev_indexes(the_repository, show_progress);\n+\tif (verify_bitmap_files(the_repository))\n \t\terrors_found |= ERROR_BITMAP;\n \n-\tcheck_connectivity(repo);\n+\tcheck_connectivity(the_repository);\n \n-\tif (repo->settings.core_commit_graph) {\n+\tif (the_repository->settings.core_commit_graph) {\n \t\tstruct child_process commit_graph_verify = CHILD_PROCESS_INIT;\n \n-\t\todb_prepare_alternates(repo->objects);\n-\t\tfor (source = repo->objects->sources; source; source = source->next) {\n+\t\todb_prepare_alternates(the_repository->objects);\n+\t\tfor (source = the_repository->objects->sources; source; source = source->next) {\n \t\t\tchild_process_init(&commit_graph_verify);\n \t\t\tcommit_graph_verify.git_cmd = 1;\n \t\t\tstrvec_pushl(&commit_graph_verify.args, \"commit-graph\",\n@@ -1170,11 +1171,11 @@ int cmd_fsck(int argc,\n \t\t}\n \t}\n \n-\tif (repo->settings.core_multi_pack_index) {\n+\tif (the_repository->settings.core_multi_pack_index) {\n \t\tstruct child_process midx_verify = CHILD_PROCESS_INIT;\n \n-\t\todb_prepare_alternates(repo->objects);\n-\t\tfor (source = repo->objects->sources; source; source = source->next) {\n+\t\todb_prepare_alternates(the_repository->objects);\n+\t\tfor (source = the_repository->objects->sources; source; source = source->next) {\n \t\t\tchild_process_init(&midx_verify);\n \t\t\tmidx_verify.git_cmd = 1;\n \t\t\tstrvec_pushl(&midx_verify.args, \"multi-pack-index\",\ndiff --git c/builtin/fsmonitor--daemon.c w/builtin/fsmonitor--daemon.c\nindex 4161dd8282..f1df9a7dd1 100644\n--- c/builtin/fsmonitor--daemon.c\n+++ w/builtin/fsmonitor--daemon.c\n@@ -1568,7 +1568,7 @@ static int try_to_start_background_daemon(void)\n int cmd_fsmonitor__daemon(int argc,\n \t\t\t  const char **argv,\n \t\t\t  const char *prefix,\n-\t\t\t  struct repository *repo UNUSED)\n+\t\t\t  bool has_repo UNUSED)\n {\n \tconst char *subcmd;\n \tenum fsmonitor_reason reason;\n@@ -1631,7 +1631,7 @@ int cmd_fsmonitor__daemon(int argc,\n }\n \n #else\n-int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED)\n+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED, bool has_repo UNUSED)\n {\n \tstruct option options[] = {\n \t\tOPT_END()\ndiff --git c/builtin/gc.c w/builtin/gc.c\nindex de2f9e7fed..611cac5eb0 100644\n--- c/builtin/gc.c\n+++ w/builtin/gc.c\n@@ -582,7 +582,7 @@ static int maintenance_task_odb(struct maintenance_run_opts *opts,\n int cmd_gc(int argc,\n \t   const char **argv,\n \t   const char *prefix,\n-\t   struct repository *repo UNUSED)\n+\t   bool has_repo UNUSED)\n {\n \tint aggressive = 0;\n \tint force = 0;\n@@ -3141,7 +3141,7 @@ static const char *const builtin_maintenance_usage[] = {\n int cmd_maintenance(int argc,\n \t\t    const char **argv,\n \t\t    const char *prefix,\n-\t\t    struct repository *repo)\n+\t\t    bool has_repo UNUSED)\n {\n \tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option builtin_maintenance_options[] = {\n@@ -3156,5 +3156,5 @@ int cmd_maintenance(int argc,\n \n \targc = parse_options(argc, argv, prefix, builtin_maintenance_options,\n \t\t\t     builtin_maintenance_usage, 0);\n-\treturn fn(argc, argv, prefix, repo);\n+\treturn fn(argc, argv, prefix, the_repository);\n }\ndiff --git c/builtin/get-tar-commit-id.c w/builtin/get-tar-commit-id.c\nindex e4cd1627b4..9471dfa5f0 100644\n--- c/builtin/get-tar-commit-id.c\n+++ w/builtin/get-tar-commit-id.c\n@@ -15,7 +15,7 @@ static const char builtin_get_tar_commit_id_usage[] =\n int cmd_get_tar_commit_id(int argc,\n \t\t\t  const char **argv,\n \t\t\t  const char *prefix,\n-\t\t\t  struct repository *repo UNUSED)\n+\t\t\t  bool has_repo UNUSED)\n {\n \tchar buffer[HEADERSIZE];\n \tstruct ustar_header *header = (struct ustar_header *)buffer;\ndiff --git c/builtin/grep.c w/builtin/grep.c\nindex d3d86abe01..2e93aa05fa 100644\n--- c/builtin/grep.c\n+++ w/builtin/grep.c\n@@ -1035,7 +1035,7 @@ static int pattern_callback(const struct option *opt, const char *arg,\n int cmd_grep(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n-\t     struct repository *repo UNUSED)\n+\t     bool has_repo UNUSED)\n {\n \tint hit = 0;\n \tint cached = 0, untracked = 0, opt_exclude = -1;\ndiff --git c/builtin/hash-object.c w/builtin/hash-object.c\nindex f306b0643f..547d635a79 100644\n--- c/builtin/hash-object.c\n+++ w/builtin/hash-object.c\n@@ -64,7 +64,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags)\n int cmd_hash_object(int argc,\n \t\t    const char **argv,\n \t\t    const char *prefix,\n-\t\t    struct repository *repo UNUSED)\n+\t\t    bool has_repo UNUSED)\n {\n \tstatic const char * const hash_object_usage[] = {\n \t\tN_(\"git hash-object [-t <type>] [-w] [--path=<file> | --no-filters]\\n\"\ndiff --git c/builtin/help.c w/builtin/help.c\nindex a140339999..37dadea7a0 100644\n--- c/builtin/help.c\n+++ w/builtin/help.c\n@@ -662,7 +662,7 @@ static void opt_mode_usage(int argc, const char *opt_mode,\n int cmd_help(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n-\t     struct repository *repo UNUSED)\n+\t     bool has_repo UNUSED)\n {\n \tint nongit;\n \tenum help_format parsed_help_format;\ndiff --git c/builtin/history.c w/builtin/history.c\nindex 000155ad9c..33590b30bf 100644\n--- c/builtin/history.c\n+++ w/builtin/history.c\n@@ -1187,7 +1187,7 @@ static int cmd_history_drop(int argc,\n int cmd_history(int argc,\n \t\tconst char **argv,\n \t\tconst char *prefix,\n-\t\tstruct repository *repo)\n+\t\tbool has_repo UNUSED)\n {\n \tconst char * const usage[] = {\n \t\tGIT_HISTORY_DROP_USAGE,\n@@ -1206,5 +1206,5 @@ int cmd_history(int argc,\n \t};\n \n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n-\treturn fn(argc, argv, prefix, repo);\n+\treturn fn(argc, argv, prefix, the_repository);\n }\ndiff --git c/builtin/hook.c w/builtin/hook.c\nindex cceeb3586e..394801ccde 100644\n--- c/builtin/hook.c\n+++ w/builtin/hook.c\n@@ -192,7 +192,7 @@ static int run(int argc, const char **argv, const char *prefix,\n int cmd_hook(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n-\t     struct repository *repo)\n+\t     bool has_repo UNUSED)\n {\n \tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option builtin_hook_options[] = {\n@@ -204,5 +204,5 @@ int cmd_hook(int argc,\n \targc = parse_options(argc, argv, NULL, builtin_hook_options,\n \t\t\t     builtin_hook_usage, 0);\n \n-\treturn fn(argc, argv, prefix, repo);\n+\treturn fn(argc, argv, prefix, the_repository);\n }\ndiff --git c/builtin/index-pack.c w/builtin/index-pack.c\nindex d1761282db..7223a6c6a0 100644\n--- c/builtin/index-pack.c\n+++ w/builtin/index-pack.c\n@@ -1886,7 +1886,7 @@ static void repack_local_links(void)\n int cmd_index_pack(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tint i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index;\n \tconst char *curr_index;\ndiff --git c/builtin/init-db.c w/builtin/init-db.c\nindex e96b1283b7..7da1ec263b 100644\n--- c/builtin/init-db.c\n+++ w/builtin/init-db.c\n@@ -72,7 +72,7 @@ static const char *const init_db_usage[] = {\n int cmd_init_db(int argc,\n \t\tconst char **argv,\n \t\tconst char *prefix,\n-\t\tstruct repository *repo UNUSED)\n+\t\tbool has_repo UNUSED)\n {\n \tchar *git_dir;\n \tconst char *real_git_dir = NULL;\ndiff --git c/builtin/interpret-trailers.c w/builtin/interpret-trailers.c\nindex e7e86e9523..7b5274d612 100644\n--- c/builtin/interpret-trailers.c\n+++ w/builtin/interpret-trailers.c\n@@ -139,7 +139,7 @@ static void interpret_trailers(const struct process_trailer_options *opts,\n int cmd_interpret_trailers(int argc,\n \t\t\t   const char **argv,\n \t\t\t   const char *prefix,\n-\t\t\t   struct repository *repo UNUSED)\n+\t\t\t   bool has_repo UNUSED)\n {\n \tstruct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;\n \tLIST_HEAD(trailers);\ndiff --git c/builtin/last-modified.c w/builtin/last-modified.c\nindex 3846244dfc..72f7e7843e 100644\n--- c/builtin/last-modified.c\n+++ w/builtin/last-modified.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"git-compat-util.h\"\n #include \"bloom.h\"\n #include \"builtin.h\"\n@@ -518,7 +519,7 @@ static int last_modified_init(struct last_modified *lm, struct repository *r,\n }\n \n int cmd_last_modified(int argc, const char **argv, const char *prefix,\n-\t\t      struct repository *repo)\n+\t\t      bool has_repo UNUSED)\n {\n \tint ret;\n \tstruct last_modified lm = { 0 };\n@@ -546,9 +547,9 @@ int cmd_last_modified(int argc, const char **argv, const char *prefix,\n \t\t\t     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |\n \t\t\t     PARSE_OPT_KEEP_DASHDASH);\n \n-\trepo_config(repo, git_default_config, NULL);\n+\trepo_config(the_repository, git_default_config, NULL);\n \n-\tret = last_modified_init(&lm, repo, prefix, argc, argv);\n+\tret = last_modified_init(&lm, the_repository, prefix, argc, argv);\n \tif (ret > 0)\n \t\tusage_with_options(last_modified_usage,\n \t\t\t\t   last_modified_options);\ndiff --git c/builtin/log.c w/builtin/log.c\nindex 350b35c556..d495a5088e 100644\n--- c/builtin/log.c\n+++ w/builtin/log.c\n@@ -526,7 +526,7 @@ static int git_log_config(const char *var, const char *value,\n int cmd_whatchanged(int argc,\n \t\t    const char **argv,\n \t\t    const char *prefix,\n-\t\t    struct repository *repo UNUSED)\n+\t\t    bool has_repo UNUSED)\n {\n \tstruct log_config cfg;\n \tstruct rev_info rev;\n@@ -661,7 +661,7 @@ static void show_setup_revisions_tweak(struct rev_info *rev)\n int cmd_show(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n-\t     struct repository *repo UNUSED)\n+\t     bool has_repo UNUSED)\n {\n \tstruct log_config cfg;\n \tstruct rev_info rev;\n@@ -780,7 +780,7 @@ int cmd_show(int argc,\n int cmd_log_reflog(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tstruct log_config cfg;\n \tstruct rev_info rev;\n@@ -825,7 +825,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev)\n int cmd_log(int argc,\n \t    const char **argv,\n \t    const char *prefix,\n-\t    struct repository *repo UNUSED)\n+\t    bool has_repo UNUSED)\n {\n \tstruct log_config cfg;\n \tstruct rev_info rev;\n@@ -1955,7 +1955,7 @@ static void infer_range_diff_ranges(struct strbuf *r1,\n int cmd_format_patch(int argc,\n \t\t     const char **argv,\n \t\t     const char *prefix,\n-\t\t     struct repository *repo UNUSED)\n+\t\t     bool has_repo UNUSED)\n {\n \tstruct format_config cfg;\n \tstruct commit *commit;\n@@ -2735,7 +2735,7 @@ static void prefetch_cherry_blobs(struct repository *repo,\n int cmd_cherry(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo UNUSED)\n+\t       bool has_repo UNUSED)\n {\n \tstruct rev_info revs;\n \tstruct patch_ids ids;\ndiff --git c/builtin/ls-files.c w/builtin/ls-files.c\nindex b044520f9e..220f2a3ec2 100644\n--- c/builtin/ls-files.c\n+++ w/builtin/ls-files.c\n@@ -6,6 +6,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n \n+#define USE_THE_REPOSITORY_VARIABLE\n #define DISABLE_SIGN_COMPARE_WARNINGS\n \n #include \"builtin.h\"\n@@ -590,7 +591,7 @@ static int option_parse_exclude_standard(const struct option *opt,\n int cmd_ls_files(int argc,\n \t\t const char **argv,\n \t\t const char *cmd_prefix,\n-\t\t struct repository *repo)\n+\t\t bool has_repo UNUSED)\n {\n \tint require_work_tree = 0, show_tag = 0, i;\n \tchar *max_prefix;\n@@ -670,15 +671,15 @@ int cmd_ls_files(int argc,\n \tshow_usage_with_options_if_asked(argc, argv,\n \t\t\t\t\t ls_files_usage, builtin_ls_files_options);\n \n-\tprepare_repo_settings(repo);\n-\trepo->settings.command_requires_full_index = 0;\n+\tprepare_repo_settings(the_repository);\n+\tthe_repository->settings.command_requires_full_index = 0;\n \n \tprefix = cmd_prefix;\n \tif (prefix)\n \t\tprefix_len = strlen(prefix);\n-\trepo_config(repo, git_default_config, NULL);\n+\trepo_config(the_repository, git_default_config, NULL);\n \n-\tif (repo_read_index(repo) < 0)\n+\tif (repo_read_index(the_repository) < 0)\n \t\tdie(\"index file corrupt\");\n \n \targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n@@ -717,8 +718,8 @@ int cmd_ls_files(int argc,\n \tif (dir.exclude_per_dir)\n \t\texc_given = 1;\n \n-\tif (require_work_tree && !is_inside_work_tree(repo))\n-\t\tsetup_work_tree(repo);\n+\tif (require_work_tree && !is_inside_work_tree(the_repository))\n+\t\tsetup_work_tree(the_repository);\n \n \tif (recurse_submodules &&\n \t    (show_deleted || show_others || show_unmerged ||\n@@ -747,7 +748,7 @@ int cmd_ls_files(int argc,\n \t\tmax_prefix = common_prefix(&pathspec);\n \tmax_prefix_len = get_common_prefix_len(max_prefix);\n \n-\tprune_index(repo->index, max_prefix, max_prefix_len);\n+\tprune_index(the_repository->index, max_prefix, max_prefix_len);\n \n \t/* Treat unmatching pathspec elements as errors */\n \tif (pathspec.nr && error_unmatch)\n@@ -771,13 +772,13 @@ int cmd_ls_files(int argc,\n \t\t */\n \t\tif (show_stage || show_unmerged)\n \t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"ls-files --with-tree\", \"-s/-u\");\n-\t\toverlay_tree_on_index(repo->index, with_tree, max_prefix);\n+\t\toverlay_tree_on_index(the_repository->index, with_tree, max_prefix);\n \t}\n \n-\tshow_files(repo, &dir);\n+\tshow_files(the_repository, &dir);\n \n \tif (show_resolve_undo)\n-\t\tshow_ru_info(repo, repo->index);\n+\t\tshow_ru_info(the_repository, the_repository->index);\n \n \tif (ps_matched && report_path_error(ps_matched, &pathspec)) {\n \t\tfprintf(stderr, \"Did you forget to 'git add'?\\n\");\ndiff --git c/builtin/ls-remote.c w/builtin/ls-remote.c\nindex fe77829557..f04e9ded50 100644\n--- c/builtin/ls-remote.c\n+++ w/builtin/ls-remote.c\n@@ -41,7 +41,7 @@ static int tail_match(const struct strvec *pattern, const char *path)\n int cmd_ls_remote(int argc,\n \t\t  const char **argv,\n \t\t  const char *prefix,\n-\t\t  struct repository *repo UNUSED)\n+\t\t  bool has_repo UNUSED)\n {\n \tconst char *dest = NULL;\n \tunsigned flags = 0;\ndiff --git c/builtin/ls-tree.c w/builtin/ls-tree.c\nindex 46edaffc2e..a75b225e9a 100644\n--- c/builtin/ls-tree.c\n+++ w/builtin/ls-tree.c\n@@ -338,7 +338,7 @@ static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {\n int cmd_ls_tree(int argc,\n \t\tconst char **argv,\n \t\tconst char *prefix,\n-\t\tstruct repository *repo UNUSED)\n+\t\tbool has_repo UNUSED)\n {\n \tstruct object_id oid;\n \tstruct tree *tree;\ndiff --git c/builtin/mailinfo.c w/builtin/mailinfo.c\nindex 8de7ba7de1..186e8a6907 100644\n--- c/builtin/mailinfo.c\n+++ w/builtin/mailinfo.c\n@@ -52,7 +52,7 @@ static int parse_opt_quoted_cr(const struct option *opt, const char *arg, int un\n int cmd_mailinfo(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo UNUSED)\n+\t\t bool has_repo UNUSED)\n {\n \tstruct metainfo_charset meta_charset;\n \tstruct mailinfo mi;\ndiff --git c/builtin/mailsplit.c w/builtin/mailsplit.c\nindex 0993418e63..177bb7f16b 100644\n--- c/builtin/mailsplit.c\n+++ w/builtin/mailsplit.c\n@@ -274,7 +274,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,\n int cmd_mailsplit(int argc,\n \t\t  const char **argv,\n \t\t  const char *prefix,\n-\t\t  struct repository *repo UNUSED)\n+\t\t  bool has_repo UNUSED)\n {\n \tint nr = 0, nr_prec = 4, num = 0;\n \tint allow_bare = 0;\ndiff --git c/builtin/merge-base.c w/builtin/merge-base.c\nindex a87011c6cd..63b74c89bc 100644\n--- c/builtin/merge-base.c\n+++ w/builtin/merge-base.c\n@@ -149,7 +149,7 @@ static int handle_fork_point(int argc, const char **argv)\n int cmd_merge_base(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tstruct commit **rev;\n \tsize_t rev_nr = 0;\ndiff --git c/builtin/merge-file.c w/builtin/merge-file.c\nindex 8fa5765239..a84246c816 100644\n--- c/builtin/merge-file.c\n+++ w/builtin/merge-file.c\n@@ -60,7 +60,7 @@ static int diff_algorithm_cb(const struct option *opt,\n int cmd_merge_file(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo)\n+\t\t   bool has_repo)\n {\n \tconst char *names[3] = { 0 };\n \tmmfile_t mmfs[3] = { 0 };\n@@ -96,7 +96,7 @@ int cmd_merge_file(int argc,\n \txmp.favor = 0;\n \n \t/* Read the configuration file */\n-\trepo_config(repo, git_xmerge_config, NULL);\n+\trepo_config(the_repository, git_xmerge_config, NULL);\n \tif (0 <= git_xmerge_style)\n \t\txmp.style = git_xmerge_style;\n \n@@ -108,7 +108,7 @@ int cmd_merge_file(int argc,\n \t\t\treturn error_errno(\"failed to redirect stderr to /dev/null\");\n \t}\n \n-\tif (!repo && object_id)\n+\tif (!has_repo && object_id)\n \t\t/* emit the correct \"not a git repo\" error in this case */\n \t\tsetup_git_directory(the_repository);\n \ndiff --git c/builtin/merge-index.c w/builtin/merge-index.c\nindex 3314fb1336..f68d28cb9c 100644\n--- c/builtin/merge-index.c\n+++ w/builtin/merge-index.c\n@@ -81,7 +81,7 @@ static const char usage_string[] =\n int cmd_merge_index(int argc,\n \t\t    const char **argv,\n \t\t    const char *prefix UNUSED,\n-\t\t    struct repository *repo UNUSED)\n+\t\t    bool has_repo UNUSED)\n {\n \tint i, force_file = 0;\n \ndiff --git c/builtin/merge-ours.c w/builtin/merge-ours.c\nindex 405b2989f7..f4447deac7 100644\n--- c/builtin/merge-ours.c\n+++ w/builtin/merge-ours.c\n@@ -8,6 +8,7 @@\n  * Pretend we resolved the heads, but declare our tree trumps everybody else.\n  */\n \n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"git-compat-util.h\"\n #include \"builtin.h\"\n #include \"config.h\"\n@@ -20,22 +21,22 @@ static const char builtin_merge_ours_usage[] =\n int cmd_merge_ours(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix UNUSED,\n-\t\t   struct repository *repo)\n+\t\t   bool has_repo UNUSED)\n {\n \tshow_usage_if_asked(argc, argv, builtin_merge_ours_usage);\n \n-\trepo_config(repo, git_default_config, NULL);\n-\tprepare_repo_settings(repo);\n-\trepo->settings.command_requires_full_index = 0;\n+\trepo_config(the_repository, git_default_config, NULL);\n+\tprepare_repo_settings(the_repository);\n+\tthe_repository->settings.command_requires_full_index = 0;\n \n \t/*\n \t * The contents of the current index becomes the tree we\n \t * commit.  The index must match HEAD, or this merge cannot go\n \t * through.\n \t */\n-\tif (repo_read_index(repo) < 0)\n+\tif (repo_read_index(the_repository) < 0)\n \t\tdie_errno(\"read_cache failed\");\n-\tif (index_differs_from(repo, \"HEAD\", NULL, 0))\n+\tif (index_differs_from(the_repository, \"HEAD\", NULL, 0))\n \t\treturn 2;\n \treturn 0;\n }\ndiff --git c/builtin/merge-recursive.c w/builtin/merge-recursive.c\nindex 17aa4db37a..76480eee1f 100644\n--- c/builtin/merge-recursive.c\n+++ w/builtin/merge-recursive.c\n@@ -24,7 +24,7 @@ static char *better_branch_name(const char *branch)\n int cmd_merge_recursive(int argc,\n \t\t\tconst char **argv,\n \t\t\tconst char *prefix UNUSED,\n-\t\t\tstruct repository *repo UNUSED)\n+\t\t\tbool has_repo UNUSED)\n {\n \tstruct object_id bases[21];\n \tunsigned bases_count = 0;\ndiff --git c/builtin/merge-tree.c w/builtin/merge-tree.c\nindex 49f41e520f..3a82f5dd3d 100644\n--- c/builtin/merge-tree.c\n+++ w/builtin/merge-tree.c\n@@ -539,7 +539,7 @@ static int real_merge(struct merge_tree_options *o,\n int cmd_merge_tree(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tstruct merge_tree_options o = { .show_messages = -1 };\n \tstruct strvec xopts = STRVEC_INIT;\ndiff --git c/builtin/merge.c w/builtin/merge.c\nindex 5b4eb23a83..084c5c427a 100644\n--- c/builtin/merge.c\n+++ w/builtin/merge.c\n@@ -1363,7 +1363,7 @@ static int merging_a_throwaway_tag(struct commit *commit)\n int cmd_merge(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo UNUSED)\n+\t      bool has_repo UNUSED)\n {\n \tstruct object_id result_tree, stash, head_oid;\n \tstruct commit *head_commit;\ndiff --git c/builtin/mktag.c w/builtin/mktag.c\nindex 37c17e6beb..3a3b246e87 100644\n--- c/builtin/mktag.c\n+++ w/builtin/mktag.c\n@@ -75,7 +75,7 @@ static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)\n int cmd_mktag(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo)\n+\t      bool has_repo UNUSED)\n {\n \tstatic struct option builtin_mktag_options[] = {\n \t\tOPT_BOOL(0, \"strict\", &option_strict,\n@@ -94,7 +94,7 @@ int cmd_mktag(int argc,\n \tif (strbuf_read(&buf, 0, 0) < 0)\n \t\tdie_errno(_(\"could not read from stdin\"));\n \n-\tfsck_options_init(&fsck_options, repo, FSCK_OPTIONS_STRICT);\n+\tfsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_STRICT);\n \tfsck_options.error_func = mktag_fsck_error_func;\n \tfsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY,\n \t\t\t\t   FSCK_WARN);\ndiff --git c/builtin/mktree.c w/builtin/mktree.c\nindex 4084e32476..cc7c8a1071 100644\n--- c/builtin/mktree.c\n+++ w/builtin/mktree.c\n@@ -3,6 +3,7 @@\n  *\n  * Copyright (c) Junio C Hamano, 2006, 2009\n  */\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n@@ -154,7 +155,7 @@ static void mktree_line(struct repository *repo, char *buf, int nul_term_line, i\n int cmd_mktree(int ac,\n \t       const char **av,\n \t       const char *prefix,\n-\t       struct repository *repo)\n+\t       bool has_repo UNUSED)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tstruct object_id oid;\n@@ -186,7 +187,7 @@ int cmd_mktree(int ac,\n \t\t\t\t\tbreak;\n \t\t\t\tdie(\"input format error: (blank line only valid in batch mode)\");\n \t\t\t}\n-\t\t\tmktree_line(repo, sb.buf, nul_term_line, allow_missing);\n+\t\t\tmktree_line(the_repository, sb.buf, nul_term_line, allow_missing);\n \t\t}\n \t\tif (is_batch_mode && got_eof && used < 1) {\n \t\t\t/*\n@@ -196,7 +197,7 @@ int cmd_mktree(int ac,\n \t\t\t */\n \t\t\t; /* skip creating an empty tree */\n \t\t} else {\n-\t\t\twrite_tree(repo, &oid);\n+\t\t\twrite_tree(the_repository, &oid);\n \t\t\tputs(oid_to_hex(&oid));\n \t\t\tfflush(stdout);\n \t\t}\ndiff --git c/builtin/multi-pack-index.c w/builtin/multi-pack-index.c\nindex 6e73c85cde..73c8b9d7d5 100644\n--- c/builtin/multi-pack-index.c\n+++ w/builtin/multi-pack-index.c\n@@ -405,7 +405,7 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv,\n int cmd_multi_pack_index(int argc,\n \t\t\t const char **argv,\n \t\t\t const char *prefix,\n-\t\t\t struct repository *repo)\n+\t\t\t bool has_repo UNUSED)\n {\n \tint res;\n \tparse_opt_subcommand_fn *fn = NULL;\n@@ -432,7 +432,7 @@ int cmd_multi_pack_index(int argc,\n \t\t\t     builtin_multi_pack_index_usage, 0);\n \tFREE_AND_NULL(options);\n \n-\tres = fn(argc, argv, prefix, repo);\n+\tres = fn(argc, argv, prefix, the_repository);\n \n \tfree(opts.object_dir);\n \treturn res;\ndiff --git c/builtin/mv.c w/builtin/mv.c\nindex 373d4aeba3..21e9bf5180 100644\n--- c/builtin/mv.c\n+++ w/builtin/mv.c\n@@ -215,7 +215,7 @@ static int pathmap_cmp(const void *cmp_data UNUSED,\n int cmd_mv(int argc,\n \t   const char **argv,\n \t   const char *prefix,\n-\t   struct repository *repo UNUSED)\n+\t   bool has_repo UNUSED)\n {\n \tint i, flags, gitmodules_modified = 0;\n \tint verbose = 0, show_only = 0, force = 0, ignore_errors = 0, ignore_sparse = 0;\ndiff --git c/builtin/name-rev.c w/builtin/name-rev.c\nindex 60cbbfb4b7..94fc8c9dcd 100644\n--- c/builtin/name-rev.c\n+++ w/builtin/name-rev.c\n@@ -636,7 +636,7 @@ static void name_rev_line(char *p, struct command *cmd)\n int cmd_name_rev(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo UNUSED)\n+\t\t bool has_repo UNUSED)\n {\n \tstruct mem_pool string_pool;\n \tstruct object_array revs = OBJECT_ARRAY_INIT;\n@@ -811,7 +811,7 @@ static char const *const format_rev_usage[] = {\n int cmd_format_rev(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tconst char *format = NULL;\n \tenum stdin_mode stdin_mode;\ndiff --git c/builtin/notes.c w/builtin/notes.c\nindex 9f1f0ec840..bc5cc6fc6d 100644\n--- c/builtin/notes.c\n+++ w/builtin/notes.c\n@@ -1127,7 +1127,7 @@ static int get_ref(int argc, const char **argv, const char *prefix,\n int cmd_notes(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo)\n+\t      bool has_repo UNUSED)\n {\n \tconst char *override_notes_ref = NULL;\n \tparse_opt_subcommand_fn *fn = NULL;\n@@ -1166,5 +1166,5 @@ int cmd_notes(int argc,\n \t\tstrbuf_release(&sb);\n \t}\n \n-\treturn !!fn(argc, argv, prefix, repo);\n+\treturn !!fn(argc, argv, prefix, the_repository);\n }\ndiff --git c/builtin/pack-objects.c w/builtin/pack-objects.c\nindex 1d9dc31454..31fb637c37 100644\n--- c/builtin/pack-objects.c\n+++ w/builtin/pack-objects.c\n@@ -5118,7 +5118,7 @@ static int parse_stdin_packs_mode(const struct option *opt, const char *arg,\n int cmd_pack_objects(int argc,\n \t\t     const char **argv,\n \t\t     const char *prefix,\n-\t\t     struct repository *repo UNUSED)\n+\t\t     bool has_repo UNUSED)\n {\n \tint use_internal_rev_list = 0;\n \tint all_progress_implied = 0;\ndiff --git c/builtin/pack-redundant.c w/builtin/pack-redundant.c\nindex 86749bb7e7..bd433f120d 100644\n--- c/builtin/pack-redundant.c\n+++ w/builtin/pack-redundant.c\n@@ -587,7 +587,7 @@ static void load_all(void)\n \t\tadd_pack(p);\n }\n \n-int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED) {\n+int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, bool has_repo UNUSED) {\n \tint i; int i_still_use_this = 0; struct pack_list *min = NULL, *red, *pl;\n \tstruct llist *ignore;\n \tstruct strbuf idx_name = STRBUF_INIT;\ndiff --git c/builtin/pack-refs.c w/builtin/pack-refs.c\nindex 3446b84cda..4bfdf48546 100644\n--- c/builtin/pack-refs.c\n+++ w/builtin/pack-refs.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"gettext.h\"\n #include \"pack-refs.h\"\n@@ -5,12 +6,12 @@\n int cmd_pack_refs(int argc,\n \t\t  const char **argv,\n \t\t  const char *prefix,\n-\t\t  struct repository *repo)\n+\t\t  bool has_repo UNUSED)\n {\n \tstatic char const * const pack_refs_usage[] = {\n \t\tN_(\"git pack-refs \" PACK_REFS_OPTS),\n \t\tNULL\n \t};\n \n-\treturn pack_refs_core(argc, argv, prefix, repo, pack_refs_usage);\n+\treturn pack_refs_core(argc, argv, prefix, the_repository, pack_refs_usage);\n }\ndiff --git c/builtin/patch-id.c w/builtin/patch-id.c\nindex 22f36ecf80..0942ceb081 100644\n--- c/builtin/patch-id.c\n+++ w/builtin/patch-id.c\n@@ -222,7 +222,7 @@ static int git_patch_id_config(const char *var, const char *value,\n int cmd_patch_id(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo UNUSED)\n+\t\t bool has_repo UNUSED)\n {\n \t/* if nothing is set, default to unstable */\n \tstruct patch_id_opts config = {0, 0};\ndiff --git c/builtin/prune-packed.c w/builtin/prune-packed.c\nindex 4d63f26b0a..d23f8640ef 100644\n--- c/builtin/prune-packed.c\n+++ w/builtin/prune-packed.c\n@@ -11,7 +11,7 @@ static const char * const prune_packed_usage[] = {\n int cmd_prune_packed(int argc,\n \t\t     const char **argv,\n \t\t     const char *prefix,\n-\t\t     struct repository *repo UNUSED)\n+\t\t     bool has_repo UNUSED)\n {\n \tint opts = isatty(2) ? PRUNE_PACKED_VERBOSE : 0;\n \tconst struct option prune_packed_options[] = {\ndiff --git c/builtin/prune.c w/builtin/prune.c\nindex 55635a891f..349c979f4f 100644\n--- c/builtin/prune.c\n+++ w/builtin/prune.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #define DISABLE_SIGN_COMPARE_WARNINGS\n \n #include \"builtin.h\"\n@@ -153,7 +154,7 @@ static void remove_temporary_files(const char *path)\n int cmd_prune(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo)\n+\t      bool has_repo UNUSED)\n {\n \tstruct rev_info revs;\n \tint exclude_promisor_objects = 0;\n@@ -175,16 +176,16 @@ int cmd_prune(int argc,\n \n \targc = parse_options(argc, argv, prefix, options, prune_usage, 0);\n \n-\trepo_init_revisions(repo, &revs, prefix);\n-\tif (repo->repository_format_precious_objects)\n+\trepo_init_revisions(the_repository, &revs, prefix);\n+\tif (the_repository->repository_format_precious_objects)\n \t\tdie(_(\"cannot prune in a precious-objects repo\"));\n \n \twhile (argc--) {\n \t\tstruct object_id oid;\n \t\tconst char *name = *argv++;\n \n-\t\tif (!repo_get_oid(repo, name, &oid)) {\n-\t\t\tstruct object *object = parse_object_or_die(repo, &oid, name);\n+\t\tif (!repo_get_oid(the_repository, name, &oid)) {\n+\t\t\tstruct object *object = parse_object_or_die(the_repository, &oid, name);\n \t\t\tadd_pending_object(&revs, object, \"\");\n \t\t}\n \t\telse\n@@ -198,16 +199,16 @@ int cmd_prune(int argc,\n \t\trevs.exclude_promisor_objects = 1;\n \t}\n \n-\tfor_each_loose_file_in_source(repo->objects->sources,\n+\tfor_each_loose_file_in_source(the_repository->objects->sources,\n \t\t\t\t      prune_object, prune_cruft, prune_subdir, &revs);\n \n \tprune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0);\n-\tremove_temporary_files(repo_get_object_directory(repo));\n-\ts = mkpathdup(\"%s/pack\", repo_get_object_directory(repo));\n+\tremove_temporary_files(repo_get_object_directory(the_repository));\n+\ts = mkpathdup(\"%s/pack\", repo_get_object_directory(the_repository));\n \tremove_temporary_files(s);\n \tfree(s);\n \n-\tif (is_repository_shallow(repo)) {\n+\tif (is_repository_shallow(the_repository)) {\n \t\tperform_reachability_traversal(&revs);\n \t\tprune_shallow(show_only ? PRUNE_SHOW_ONLY : 0);\n \t}\ndiff --git c/builtin/pull.c w/builtin/pull.c\nindex db3ee0aab3..9d4412f4a3 100644\n--- c/builtin/pull.c\n+++ w/builtin/pull.c\n@@ -856,7 +856,7 @@ static void show_advice_pull_non_ff(void)\n int cmd_pull(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n-\t     struct repository *repository UNUSED)\n+\t     bool has_repo UNUSED)\n {\n \tconst char *repo, **refspecs;\n \tstruct oid_array merge_heads = OID_ARRAY_INIT;\ndiff --git c/builtin/push.c w/builtin/push.c\nindex 2377b5af55..d6d6c63ce3 100644\n--- c/builtin/push.c\n+++ w/builtin/push.c\n@@ -691,7 +691,7 @@ static void die_if_repo_looks_like_ref(const char *repo)\n int cmd_push(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n-\t     struct repository *repository UNUSED)\n+\t     bool has_repo UNUSED)\n {\n \tint flags = 0;\n \tint tags = 0;\ndiff --git c/builtin/range-diff.c w/builtin/range-diff.c\nindex e54c0f7fe1..312a36034d 100644\n--- c/builtin/range-diff.c\n+++ w/builtin/range-diff.c\n@@ -35,7 +35,7 @@ static int parse_max_memory(const struct option *opt, const char *arg, int unset\n int cmd_range_diff(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tstruct diff_options diffopt = { NULL };\n \tstruct strvec log_arg = STRVEC_INIT;\ndiff --git c/builtin/read-tree.c w/builtin/read-tree.c\nindex 999a82ecdf..6d7b1e1315 100644\n--- c/builtin/read-tree.c\n+++ w/builtin/read-tree.c\n@@ -111,7 +111,7 @@ static int git_read_tree_config(const char *var, const char *value,\n int cmd_read_tree(int argc,\n \t\t  const char **argv,\n \t\t  const char *cmd_prefix,\n-\t\t  struct repository *repo UNUSED)\n+\t\t  bool has_repo UNUSED)\n {\n \tint i, stage = 0;\n \tstruct object_id oid;\ndiff --git c/builtin/rebase.c w/builtin/rebase.c\nindex 10a306310c..3dfe959d78 100644\n--- c/builtin/rebase.c\n+++ w/builtin/rebase.c\n@@ -1099,7 +1099,7 @@ static int check_exec_cmd(const char *cmd)\n int cmd_rebase(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo UNUSED)\n+\t       bool has_repo UNUSED)\n {\n \tstruct rebase_options options = REBASE_OPTIONS_INIT;\n \tconst char *branch_name;\ndiff --git c/builtin/receive-pack.c w/builtin/receive-pack.c\nindex 86933d8d7e..c751487867 100644\n--- c/builtin/receive-pack.c\n+++ w/builtin/receive-pack.c\n@@ -2612,7 +2612,7 @@ static int delete_only(struct command *commands)\n int cmd_receive_pack(int argc,\n \t\t     const char **argv,\n \t\t     const char *prefix,\n-\t\t     struct repository *repo UNUSED)\n+\t\t     bool has_repo UNUSED)\n {\n \tint advertise_refs = 0;\n \tstruct command *commands;\ndiff --git c/builtin/reflog.c w/builtin/reflog.c\nindex 1211c58fa4..f04e6701c2 100644\n--- c/builtin/reflog.c\n+++ w/builtin/reflog.c\n@@ -467,7 +467,7 @@ static int cmd_reflog_write(int argc, const char **argv, const char *prefix,\n int cmd_reflog(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repository)\n+\t       bool has_repo)\n {\n \tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option options[] = {\n@@ -486,7 +486,7 @@ int cmd_reflog(int argc,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |\n \t\t\t     PARSE_OPT_KEEP_UNKNOWN_OPT);\n \tif (fn)\n-\t\treturn fn(argc - 1, argv + 1, prefix, repository);\n+\t\treturn fn(argc - 1, argv + 1, prefix, the_repository);\n \telse\n-\t\treturn cmd_log_reflog(argc, argv, prefix, repository);\n+\t\treturn cmd_log_reflog(argc, argv, prefix, has_repo);\n }\ndiff --git c/builtin/refs.c w/builtin/refs.c\nindex 5cd21c25fe..9abcc6586f 100644\n--- c/builtin/refs.c\n+++ w/builtin/refs.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"config.h\"\n #include \"fsck.h\"\n@@ -377,7 +378,7 @@ static int cmd_refs_rename(int argc, const char **argv, const char *prefix,\n int cmd_refs(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n-\t     struct repository *repo)\n+\t     bool has_repo UNUSED)\n {\n \tconst char * const refs_usage[] = {\n \t\tREFS_MIGRATE_USAGE,\n@@ -406,5 +407,5 @@ int cmd_refs(int argc,\n \t};\n \n \targc = parse_options(argc, argv, prefix, opts, refs_usage, 0);\n-\treturn fn(argc, argv, prefix, repo);\n+\treturn fn(argc, argv, prefix, the_repository);\n }\ndiff --git c/builtin/remote-ext.c w/builtin/remote-ext.c\nindex bd2037f27d..d14bc8424f 100644\n--- c/builtin/remote-ext.c\n+++ w/builtin/remote-ext.c\n@@ -198,7 +198,7 @@ static int command_loop(const char *child)\n int cmd_remote_ext(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tBUG_ON_NON_EMPTY_PREFIX(prefix);\n \ndiff --git c/builtin/remote-fd.c w/builtin/remote-fd.c\nindex 39908546ba..2d1d1e9130 100644\n--- c/builtin/remote-fd.c\n+++ w/builtin/remote-fd.c\n@@ -56,7 +56,7 @@ static void command_loop(int input_fd, int output_fd)\n int cmd_remote_fd(int argc,\n \t\t  const char **argv,\n \t\t  const char *prefix,\n-\t\t  struct repository *repo UNUSED)\n+\t\t  bool has_repo UNUSED)\n {\n \tint input_fd = -1;\n \tint output_fd = -1;\ndiff --git c/builtin/remote.c w/builtin/remote.c\nindex de989ea3ba..f2c11ae3ec 100644\n--- c/builtin/remote.c\n+++ w/builtin/remote.c\n@@ -1933,7 +1933,7 @@ static int set_url(int argc, const char **argv, const char *prefix,\n int cmd_remote(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo)\n+\t       bool has_repo UNUSED)\n {\n \tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option options[] = {\n@@ -1956,7 +1956,7 @@ int cmd_remote(int argc,\n \t\t\t     PARSE_OPT_SUBCOMMAND_OPTIONAL);\n \n \tif (fn) {\n-\t\treturn !!fn(argc, argv, prefix, repo);\n+\t\treturn !!fn(argc, argv, prefix, the_repository);\n \t} else {\n \t\tif (argc) {\n \t\t\terror(_(\"unknown subcommand: `%s'\"), argv[0]);\ndiff --git c/builtin/repack.c w/builtin/repack.c\nindex c4360382c1..96f6faddc3 100644\n--- c/builtin/repack.c\n+++ w/builtin/repack.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #define DISABLE_SIGN_COMPARE_WARNINGS\n \n #include \"builtin.h\"\n@@ -158,7 +159,7 @@ static int option_parse_write_midx(const struct option *opt, const char *arg,\n int cmd_repack(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo)\n+\t       bool has_repo UNUSED)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tstruct string_list_item *item;\n@@ -272,7 +273,7 @@ int cmd_repack(int argc,\n \tconfig_ctx.midx_split_factor = DEFAULT_MIDX_SPLIT_FACTOR;\n \tconfig_ctx.midx_new_layer_threshold = DEFAULT_MIDX_NEW_LAYER_THRESHOLD;\n \n-\trepo_config(repo, repack_config, &config_ctx);\n+\trepo_config(the_repository, repack_config, &config_ctx);\n \n \targc = parse_options(argc, argv, prefix, builtin_repack_options,\n \t\t\t\tgit_repack_usage, 0);\n@@ -316,7 +317,7 @@ int cmd_repack(int argc,\n \t\t * dropped objects from, so dropping them would be permanent\n \t\t * data loss.\n \t\t */\n-\t\tif (!repo_has_promisor_remote(repo))\n+\t\tif (!repo_has_promisor_remote(the_repository))\n \t\t\tdie(_(\"--drop-filtered requires a promisor remote\"));\n \n \t\t/*\n@@ -329,10 +330,10 @@ int cmd_repack(int argc,\n \t\t * safety measure. Bare repositories have no such state, so\n \t\t * the check is skipped there.\n \t\t */\n-\t\tif (!is_bare_repository(repo)) {\n+\t\tif (!is_bare_repository(the_repository)) {\n \t\t\tstruct wt_status_state state = { 0 };\n \n-\t\t\twt_status_get_state(repo, &state, 0);\n+\t\t\twt_status_get_state(the_repository, &state, 0);\n \t\t\tif (state.merge_in_progress || state.revert_in_progress ||\n \t\t\t    state.rebase_in_progress || state.bisect_in_progress ||\n \t\t\t    state.cherry_pick_in_progress || state.am_in_progress ||\n@@ -356,7 +357,7 @@ int cmd_repack(int argc,\n \t\tif (!dry_run)\n \t\t\tdelete_redundant = 1;\n \n-\t\tret = enumerate_promisor_blobs(repo, &po_args.filter_options, &drop_oids);\n+\t\tret = enumerate_promisor_blobs(the_repository, &po_args.filter_options, &drop_oids);\n \n \t\tif (ret)\n \t\t\tgoto cleanup;\n@@ -368,11 +369,11 @@ int cmd_repack(int argc,\n \t\t * nothing. This guard just avoids that churn. Bare\n \t\t * repositories have no index, so the check is skipped there.\n \t\t */\n-\t\tif (!is_bare_repository(repo) && oidset_size(&drop_oids)) {\n-\t\t\tstruct index_state *istate = repo->index;\n+\t\tif (!is_bare_repository(the_repository) && oidset_size(&drop_oids)) {\n+\t\t\tstruct index_state *istate = the_repository->index;\n \t\t\tunsigned int i;\n \n-\t\t\tif (repo_read_index(repo) < 0)\n+\t\t\tif (repo_read_index(the_repository) < 0)\n \t\t\t\tdie(_(\"could not read the index\"));\n \n \t\t\tfor (i = 0; i < istate->cache_nr; i++) {\n@@ -394,7 +395,7 @@ int cmd_repack(int argc,\n \t\t}\n \t}\n \n-\tif (delete_redundant && repo->repository_format_precious_objects)\n+\tif (delete_redundant && the_repository->repository_format_precious_objects)\n \t\tdie(_(\"cannot delete packs in a precious-objects repo\"));\n \n \tdie_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), \"-A\",\n@@ -406,7 +407,7 @@ int cmd_repack(int argc,\n \n \tif (write_bitmaps < 0) {\n \t\tif (write_midx == REPACK_WRITE_MIDX_NONE &&\n-\t\t    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(repo)))\n+\t\t    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(the_repository)))\n \t\t\twrite_bitmaps = 0;\n \t}\n \tif (po_args.pack_kept_objects < 0)\n@@ -418,7 +419,7 @@ int cmd_repack(int argc,\n \t\tdie(_(incremental_bitmap_conflict_error));\n \n \tif (write_bitmaps && po_args.local &&\n-\t    odb_has_alternates(repo->objects)) {\n+\t    odb_has_alternates(the_repository->objects)) {\n \t\t/*\n \t\t * When asked to do a local repack, but we have\n \t\t * packfiles that are inherited from an alternate, then\n@@ -441,20 +442,20 @@ int cmd_repack(int argc,\n \t\tstruct strbuf path = STRBUF_INIT;\n \n \t\tstrbuf_addf(&path, \"%s/%s_XXXXXX\",\n-\t\t\t    repo_get_object_directory(repo),\n+\t\t\t    repo_get_object_directory(the_repository),\n \t\t\t    \"bitmap-ref-tips\");\n \n \t\trefs_snapshot = xmks_tempfile(path.buf);\n-\t\tmidx_snapshot_refs(repo, refs_snapshot);\n+\t\tmidx_snapshot_refs(the_repository, refs_snapshot);\n \n \t\tstrbuf_release(&path);\n \t}\n \n-\tpackdir = mkpathdup(\"%s/pack\", repo_get_object_directory(repo));\n+\tpackdir = mkpathdup(\"%s/pack\", repo_get_object_directory(the_repository));\n \tpacktmp_name = xstrfmt(\".tmp-%d-pack\", (int)getpid());\n \tpacktmp = mkpathdup(\"%s/%s\", packdir, packtmp_name);\n \n-\texisting.repo = repo;\n+\texisting.repo = the_repository;\n \texisting_packs_collect(&existing, &keep_pack_list);\n \n \tif (geometry.split_factor) {\n@@ -492,7 +493,7 @@ int cmd_repack(int argc,\n \t\tstrvec_push(&cmd.args, \"--reflog\");\n \t\tstrvec_push(&cmd.args, \"--indexed-objects\");\n \t}\n-\tif (repo_has_promisor_remote(repo))\n+\tif (repo_has_promisor_remote(the_repository))\n \t\tstrvec_push(&cmd.args, \"--exclude-promisor-objects\");\n \tif (write_midx == REPACK_WRITE_MIDX_NONE) {\n \t\tif (write_bitmaps > 0)\n@@ -504,7 +505,7 @@ int cmd_repack(int argc,\n \t\tstrvec_push(&cmd.args, \"--delta-islands\");\n \n \tif (pack_everything & ALL_INTO_ONE) {\n-\t\trepack_promisor_objects(repo, &po_args, &names, packtmp,\n+\t\trepack_promisor_objects(the_repository, &po_args, &names, packtmp,\n \t\t\t(drop_filtered && !dry_run) ? &drop_oids : NULL);\n \n \t\tif (existing_packs_has_non_kept(&existing) &&\n@@ -530,7 +531,7 @@ int cmd_repack(int argc,\n \t\t    !(pack_everything & PACK_CRUFT))\n \t\t\tstrvec_push(&cmd.args, \"--pack-loose-unreachable\");\n \t} else if (geometry.split_factor) {\n-\t\tpack_geometry_repack_promisors(repo, &po_args, &geometry,\n+\t\tpack_geometry_repack_promisors(the_repository, &po_args, &geometry,\n \t\t\t\t\t       &names, packtmp);\n \n \t\tif (midx_must_contain_cruft)\n@@ -593,7 +594,7 @@ int cmd_repack(int argc,\n \t\t\t.destination = packdir,\n \t\t\t.packtmp = packtmp,\n \t\t};\n-\t\tret = finish_pack_objects_cmd(repo->hash_algo, &opts, &cmd,\n+\t\tret = finish_pack_objects_cmd(the_repository->hash_algo, &opts, &cmd,\n \t\t\t\t\t      &names);\n \t\tif (ret)\n \t\t\tgoto cleanup;\n@@ -706,7 +707,7 @@ int cmd_repack(int argc,\n \n \tstring_list_sort(&names);\n \n-\todb_close(repo->objects);\n+\todb_close(the_repository->objects);\n \n \t/*\n \t * Ok we have prepared all new packfiles.\n@@ -742,7 +743,7 @@ int cmd_repack(int argc,\n \t\t\tgoto cleanup;\n \t}\n \n-\todb_reprepare(repo->objects);\n+\todb_reprepare(the_repository->objects);\n \n \tif (delete_redundant) {\n \t\tint opts = 0;\n@@ -762,12 +763,12 @@ int cmd_repack(int argc,\n \t\tif (!keep_unreachable &&\n \t\t    (!(pack_everything & LOOSEN_UNREACHABLE) ||\n \t\t     unpack_unreachable) &&\n-\t\t    is_repository_shallow(repo))\n+\t\t    is_repository_shallow(the_repository))\n \t\t\tprune_shallow(PRUNE_QUICK);\n \t}\n \n \tif (run_update_server_info)\n-\t\tupdate_server_info(repo, 0);\n+\t\tupdate_server_info(the_repository, 0);\n \n \tif (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) {\n \t\tstruct odb_source_files *files = odb_source_files_downcast(existing.source);\ndiff --git c/builtin/replace.c w/builtin/replace.c\nindex aed6b2c8de..fd4e1adaf1 100644\n--- c/builtin/replace.c\n+++ w/builtin/replace.c\n@@ -545,7 +545,7 @@ static int convert_graft_file(int force)\n int cmd_replace(int argc,\n \t\tconst char **argv,\n \t\tconst char *prefix,\n-\t\tstruct repository *repo UNUSED)\n+\t\tbool has_repo UNUSED)\n {\n \tint force = 0;\n \tint raw = 0;\ndiff --git c/builtin/replay.c w/builtin/replay.c\nindex 39e3a86f6c..3f5b9cc36b 100644\n--- c/builtin/replay.c\n+++ w/builtin/replay.c\n@@ -2,6 +2,7 @@\n  * \"git replay\" builtin command\n  */\n \n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"git-compat-util.h\"\n \n #include \"builtin.h\"\n@@ -69,7 +70,7 @@ static int handle_ref_update(enum ref_action_mode mode,\n int cmd_replay(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo)\n+\t       bool has_repo UNUSED)\n {\n \tstruct replay_revisions_options opts = { 0 };\n \tstruct replay_result result = { 0 };\n@@ -134,7 +135,7 @@ int cmd_replay(int argc,\n \t\t\t\t  !!opts.contained, \"--contained\");\n \n \t/* Parse ref action mode from command line or config */\n-\tref_mode = get_ref_action_mode(repo, ref_action);\n+\tref_mode = get_ref_action_mode(the_repository, ref_action);\n \n \t/*\n \t * Cherry-pick/rebase need oldest-first ordering so that each\n@@ -144,7 +145,7 @@ int cmd_replay(int argc,\n \t */\n \tdesired_reverse = !opts.revert;\n \n-\trepo_init_revisions(repo, &revs, prefix);\n+\trepo_init_revisions(the_repository, &revs, prefix);\n \n \t/*\n \t * Set desired values for rev walking options here. If they\n@@ -206,14 +207,14 @@ int cmd_replay(int argc,\n \t\tstrbuf_addf(&reflog_msg, \"replay --advance %s\", opts.advance);\n \t} else {\n \t\tstruct object_id oid;\n-\t\tif (repo_get_oid_committish(repo, opts.onto, &oid))\n+\t\tif (repo_get_oid_committish(the_repository, opts.onto, &oid))\n \t\t\tBUG(\"--onto commit should have been resolved beforehand already\");\n \t\tstrbuf_addf(&reflog_msg, \"replay --onto %s\", oid_to_hex(&oid));\n \t}\n \n \t/* Initialize ref transaction if using update mode */\n \tif (ref_mode == REF_ACTION_UPDATE) {\n-\t\ttransaction = ref_store_transaction_begin(get_main_ref_store(repo),\n+\t\ttransaction = ref_store_transaction_begin(get_main_ref_store(the_repository),\n \t\t\t\t\t\t\t  0, &transaction_err);\n \t\tif (!transaction) {\n \t\t\tret = error(_(\"failed to begin ref transaction: %s\"),\ndiff --git c/builtin/repo.c w/builtin/repo.c\nindex 84e012f83f..5b12501a7c 100644\n--- c/builtin/repo.c\n+++ w/builtin/repo.c\n@@ -981,7 +981,7 @@ static int cmd_repo_structure(int argc, const char **argv, const char *prefix,\n }\n \n int cmd_repo(int argc, const char **argv, const char *prefix,\n-\t     struct repository *repo)\n+\t     bool has_repo UNUSED)\n {\n \tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option options[] = {\n@@ -992,5 +992,5 @@ int cmd_repo(int argc, const char **argv, const char *prefix,\n \n \targc = parse_options(argc, argv, prefix, options, repo_usage, 0);\n \n-\treturn fn(argc, argv, prefix, repo);\n+\treturn fn(argc, argv, prefix, the_repository);\n }\ndiff --git c/builtin/rerere.c w/builtin/rerere.c\nindex a056cb791b..caa88130fc 100644\n--- c/builtin/rerere.c\n+++ w/builtin/rerere.c\n@@ -53,7 +53,7 @@ static int diff_two(const char *file1, const char *label1,\n int cmd_rerere(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo UNUSED)\n+\t       bool has_repo UNUSED)\n {\n \tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n \tint autoupdate = -1, flags = 0;\ndiff --git c/builtin/reset.c w/builtin/reset.c\nindex 78e69bd84b..80f201ed68 100644\n--- c/builtin/reset.c\n+++ w/builtin/reset.c\n@@ -336,7 +336,7 @@ static int git_reset_config(const char *var, const char *value,\n int cmd_reset(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo UNUSED)\n+\t      bool has_repo UNUSED)\n {\n \tint reset_type = NONE, update_ref_status = 0, quiet = 0;\n \tint no_refresh = 0;\ndiff --git c/builtin/rev-list.c w/builtin/rev-list.c\nindex 02818b81c6..14898a0aeb 100644\n--- c/builtin/rev-list.c\n+++ w/builtin/rev-list.c\n@@ -692,7 +692,7 @@ static void prepare_maximal_independent(struct rev_info *revs)\n int cmd_rev_list(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo UNUSED)\n+\t\t bool has_repo UNUSED)\n {\n \tstruct rev_info revs;\n \tstruct rev_list_info info;\ndiff --git c/builtin/rev-parse.c w/builtin/rev-parse.c\nindex 43693454d5..b4435981ab 100644\n--- c/builtin/rev-parse.c\n+++ w/builtin/rev-parse.c\n@@ -698,7 +698,7 @@ static void print_path(const char *path, const char *prefix,\n int cmd_rev_parse(int argc,\n \t\t  const char **argv,\n \t\t  const char *prefix,\n-\t\t  struct repository *repo UNUSED)\n+\t\t  bool has_repo UNUSED)\n {\n \tint i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;\n \tconst struct git_hash_algo *output_algo = NULL;\ndiff --git c/builtin/revert.c w/builtin/revert.c\nindex bedc40f368..42d0332847 100644\n--- c/builtin/revert.c\n+++ w/builtin/revert.c\n@@ -281,7 +281,7 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,\n int cmd_revert(int argc,\n \t       const char **argv,\n \t       const char *prefix,\n-\t       struct repository *repo UNUSED)\n+\t       bool has_repo UNUSED)\n {\n \tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\n@@ -299,9 +299,9 @@ int cmd_revert(int argc,\n }\n \n int cmd_cherry_pick(int argc,\n-const char **argv,\n-const char *prefix,\n-struct repository *repo UNUSED)\n+\t\t    const char **argv,\n+\t\t    const char *prefix,\n+\t\t    bool has_repo UNUSED)\n {\n \tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tint res;\ndiff --git c/builtin/rm.c w/builtin/rm.c\nindex 081d0bc375..9e08fb1fc2 100644\n--- c/builtin/rm.c\n+++ w/builtin/rm.c\n@@ -265,7 +265,7 @@ static struct option builtin_rm_options[] = {\n int cmd_rm(int argc,\n \t   const char **argv,\n \t   const char *prefix,\n-\t   struct repository *repo UNUSED)\n+\t   bool has_repo UNUSED)\n {\n \tstruct lock_file lock_file = LOCK_INIT;\n \tint i, ret = 0;\ndiff --git c/builtin/send-pack.c w/builtin/send-pack.c\nindex d6cdbae472..24656f911c 100644\n--- c/builtin/send-pack.c\n+++ w/builtin/send-pack.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"config.h\"\n #include \"environment.h\"\n@@ -151,7 +152,7 @@ static int send_pack_config(const char *k, const char *v,\n int cmd_send_pack(int argc,\n \t\t  const char **argv,\n \t\t  const char *prefix,\n-\t\t  struct repository *repo)\n+\t\t  bool has_repo UNUSED)\n {\n \tstruct refspec rs;\n \tconst char *remote_name = NULL;\n@@ -212,10 +213,10 @@ int cmd_send_pack(int argc,\n \t\tOPT_END()\n \t};\n \n-\trepo_config(repo, send_pack_config, NULL);\n+\trepo_config(the_repository, send_pack_config, NULL);\n \targc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);\n \n-\trefspec_init_push(&rs, repo->hash_algo);\n+\trefspec_init_push(&rs, the_repository->hash_algo);\n \n \tif (argc > 0) {\n \t\tdest = argv[0];\n@@ -322,7 +323,7 @@ int cmd_send_pack(int argc,\n \tset_ref_status_for_push(remote_refs, args.send_mirror,\n \t\targs.force_update);\n \n-\tret = send_pack(repo, &args, fd, conn, remote_refs, &extra_have);\n+\tret = send_pack(the_repository, &args, fd, conn, remote_refs, &extra_have);\n \n \tif (helper_status)\n \t\tprint_helper_status(remote_refs);\ndiff --git c/builtin/shortlog.c w/builtin/shortlog.c\nindex 4c78d2e5ba..28d34a72fa 100644\n--- c/builtin/shortlog.c\n+++ w/builtin/shortlog.c\n@@ -383,7 +383,7 @@ void shortlog_finish_setup(struct shortlog *log)\n int cmd_shortlog(int argc,\n \t\t const char **argv,\n \t\t const char *prefix,\n-\t\t struct repository *repo UNUSED)\n+\t\t bool has_repo UNUSED)\n {\n \tstruct shortlog log = { STRING_LIST_INIT_NODUP };\n \tstruct rev_info rev;\ndiff --git c/builtin/show-branch.c w/builtin/show-branch.c\nindex 2435e8aeda..9b6946e3bc 100644\n--- c/builtin/show-branch.c\n+++ w/builtin/show-branch.c\n@@ -636,7 +636,7 @@ static int parse_reflog_param(const struct option *opt, const char *arg,\n int cmd_show_branch(int ac,\n \t\tconst char **av,\n \t\tconst char *prefix,\n-\t\tstruct repository *repo UNUSED)\n+\t\tbool has_repo UNUSED)\n {\n \tstruct commit *rev[MAX_REVS], *commit;\n \tchar *reflog_msg[MAX_REVS] = {0};\ndiff --git c/builtin/show-index.c w/builtin/show-index.c\nindex 24f0230967..ea9feab5b6 100644\n--- c/builtin/show-index.c\n+++ w/builtin/show-index.c\n@@ -16,7 +16,7 @@ static const char *const show_index_usage[] = {\n int cmd_show_index(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tint i;\n \tunsigned nr;\ndiff --git c/builtin/show-ref.c w/builtin/show-ref.c\nindex d508441632..0e725f36ca 100644\n--- c/builtin/show-ref.c\n+++ w/builtin/show-ref.c\n@@ -298,9 +298,9 @@ static int exclude_existing_callback(const struct option *opt, const char *arg,\n }\n \n int cmd_show_ref(int argc,\n-const char **argv,\n-const char *prefix,\n-struct repository *repo UNUSED)\n+\t\t const char **argv,\n+\t\t const char *prefix,\n+\t\t bool has_repo UNUSED)\n {\n \tstruct exclude_existing_options exclude_existing_opts = {0};\n \tstruct patterns_options patterns_opts = {0};\ndiff --git c/builtin/sparse-checkout.c w/builtin/sparse-checkout.c\nindex cb4a037b77..1887b745e5 100644\n--- c/builtin/sparse-checkout.c\n+++ w/builtin/sparse-checkout.c\n@@ -1183,7 +1183,7 @@ static int sparse_checkout_check_rules(int argc, const char **argv, const char *\n int cmd_sparse_checkout(int argc,\n \t\t\tconst char **argv,\n \t\t\tconst char *prefix,\n-\t\t\tstruct repository *repo)\n+\t\t\tbool has_repo UNUSED)\n {\n \tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option builtin_sparse_checkout_options[] = {\n@@ -1204,8 +1204,8 @@ int cmd_sparse_checkout(int argc,\n \n \trepo_config(the_repository, git_default_config, NULL);\n \n-\tprepare_repo_settings(repo);\n-\trepo->settings.command_requires_full_index = 0;\n+\tprepare_repo_settings(the_repository);\n+\tthe_repository->settings.command_requires_full_index = 0;\n \n-\treturn fn(argc, argv, prefix, repo);\n+\treturn fn(argc, argv, prefix, the_repository);\n }\ndiff --git c/builtin/stash.c w/builtin/stash.c\nindex 72c52571f8..4bf8a68212 100644\n--- c/builtin/stash.c\n+++ w/builtin/stash.c\n@@ -2453,7 +2453,7 @@ static int export_stash(int argc,\n int cmd_stash(int argc,\n \t      const char **argv,\n \t      const char *prefix,\n-\t      struct repository *repo)\n+\t      bool has_repo UNUSED)\n {\n \tpid_t pid = getpid();\n \tconst char *index_file;\n@@ -2493,9 +2493,9 @@ int cmd_stash(int argc,\n \t\t    (uintmax_t)pid);\n \n \tif (fn)\n-\t\treturn !!fn(argc, argv, prefix, repo);\n+\t\treturn !!fn(argc, argv, prefix, the_repository);\n \telse if (!argc)\n-\t\treturn !!push_stash_unassumed(0, NULL, prefix, repo);\n+\t\treturn !!push_stash_unassumed(0, NULL, prefix, the_repository);\n \n \t/* Assume 'stash push' */\n \tstrvec_push(&args, \"push\");\ndiff --git c/builtin/stripspace.c w/builtin/stripspace.c\nindex 18705f1a5b..b27e4bfb26 100644\n--- c/builtin/stripspace.c\n+++ w/builtin/stripspace.c\n@@ -33,7 +33,7 @@ enum stripspace_mode {\n int cmd_stripspace(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tenum stripspace_mode mode = STRIP_DEFAULT;\ndiff --git c/builtin/submodule--helper.c w/builtin/submodule--helper.c\nindex e7cd3225fa..a86cec5798 100644\n--- c/builtin/submodule--helper.c\n+++ w/builtin/submodule--helper.c\n@@ -3804,7 +3804,7 @@ static int module_add(int argc, const char **argv, const char *prefix,\n int cmd_submodule__helper(int argc,\n \t\t\t  const char **argv,\n \t\t\t  const char *prefix,\n-\t\t\t  struct repository *repo)\n+\t\t\t  bool has_repo UNUSED)\n {\n \tparse_opt_subcommand_fn *fn = NULL;\n \tconst char *const usage[] = {\n@@ -3833,5 +3833,5 @@ int cmd_submodule__helper(int argc,\n \t};\n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n \n-\treturn fn(argc, argv, prefix, repo);\n+\treturn fn(argc, argv, prefix, the_repository);\n }\ndiff --git c/builtin/symbolic-ref.c w/builtin/symbolic-ref.c\nindex 231e41e715..8644548c9a 100644\n--- c/builtin/symbolic-ref.c\n+++ w/builtin/symbolic-ref.c\n@@ -46,7 +46,7 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, i\n int cmd_symbolic_ref(int argc,\n \t\t     const char **argv,\n \t\t     const char *prefix,\n-\t\t     struct repository *repo UNUSED)\n+\t\t     bool has_repo UNUSED)\n {\n \tint quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;\n \tconst char *msg = NULL;\ndiff --git c/builtin/tag.c w/builtin/tag.c\nindex 06c125b53c..1fa660497e 100644\n--- c/builtin/tag.c\n+++ w/builtin/tag.c\n@@ -454,7 +454,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n int cmd_tag(int argc,\n \t    const char **argv,\n \t    const char *prefix,\n-\t    struct repository *repo UNUSED)\n+\t    bool has_repo UNUSED)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct strbuf ref = STRBUF_INIT;\ndiff --git c/builtin/unpack-file.c w/builtin/unpack-file.c\nindex 387389ed49..7e660b18b1 100644\n--- c/builtin/unpack-file.c\n+++ w/builtin/unpack-file.c\n@@ -34,7 +34,7 @@ static const char usage_msg[] =\n int cmd_unpack_file(int argc,\n \t\t    const char **argv,\n \t\t    const char *prefix UNUSED,\n-\t\t    struct repository *repo UNUSED)\n+\t\t    bool has_repo UNUSED)\n {\n \tstruct object_id oid;\n \ndiff --git c/builtin/unpack-objects.c w/builtin/unpack-objects.c\nindex 3392a3b87d..73e2e450c9 100644\n--- c/builtin/unpack-objects.c\n+++ w/builtin/unpack-objects.c\n@@ -617,7 +617,7 @@ static void unpack_all(void)\n int cmd_unpack_objects(int argc,\n \t\t       const char **argv,\n \t\t       const char *prefix UNUSED,\n-\t\t       struct repository *repo)\n+\t\t       bool has_repo UNUSED)\n {\n \tint i;\n \tstruct object_id oid;\n@@ -631,7 +631,7 @@ int cmd_unpack_objects(int argc,\n \n \tshow_usage_if_asked(argc, argv, unpack_usage);\n \n-\tfsck_options_init(&fsck_options, repo, FSCK_OPTIONS_STRICT);\n+\tfsck_options_init(&fsck_options, the_repository, FSCK_OPTIONS_STRICT);\n \n \tfor (i = 1 ; i < argc; i++) {\n \t\tconst char *arg = argv[i];\ndiff --git c/builtin/update-index.c w/builtin/update-index.c\nindex 241abd4332..d3398392b2 100644\n--- c/builtin/update-index.c\n+++ w/builtin/update-index.c\n@@ -915,7 +915,7 @@ static enum parse_opt_result reupdate_callback(\n int cmd_update_index(int argc,\n \t\t     const char **argv,\n \t\t     const char *prefix,\n-\t\t     struct repository *repo UNUSED)\n+\t\t     bool has_repo UNUSED)\n {\n \tint newfd, entries, has_errors = 0, nul_term_line = 0;\n \tenum uc_mode untracked_cache = UC_UNSPECIFIED;\ndiff --git c/builtin/update-ref.c w/builtin/update-ref.c\nindex 6355c3dd3e..1511ce43bd 100644\n--- c/builtin/update-ref.c\n+++ w/builtin/update-ref.c\n@@ -810,7 +810,7 @@ static void update_refs_stdin(unsigned int flags)\n int cmd_update_ref(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tconst char *refname, *oldval;\n \tstruct object_id oid, oldoid;\ndiff --git c/builtin/update-server-info.c w/builtin/update-server-info.c\nindex 4c12968a83..2d13e710e1 100644\n--- c/builtin/update-server-info.c\n+++ w/builtin/update-server-info.c\n@@ -1,3 +1,4 @@\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"config.h\"\n #include \"environment.h\"\n@@ -13,7 +14,7 @@ static const char * const update_server_info_usage[] = {\n int cmd_update_server_info(int argc,\n \t\t\t   const char **argv,\n \t\t\t   const char *prefix,\n-\t\t\t   struct repository *repo)\n+\t\t\t   bool has_repo UNUSED)\n {\n \tint force = 0;\n \tstruct option options[] = {\n@@ -21,12 +22,12 @@ int cmd_update_server_info(int argc,\n \t\tOPT_END()\n \t};\n \n-\trepo_config(repo, git_default_config, NULL);\n+\trepo_config(the_repository, git_default_config, NULL);\n \n \targc = parse_options(argc, argv, prefix, options,\n \t\t\t     update_server_info_usage, 0);\n \tif (argc > 0)\n \t\tusage_with_options(update_server_info_usage, options);\n \n-\treturn !!update_server_info(repo, force);\n+\treturn !!update_server_info(the_repository, force);\n }\ndiff --git c/builtin/upload-archive.c w/builtin/upload-archive.c\nindex 718e74b3ac..510540dd78 100644\n--- c/builtin/upload-archive.c\n+++ w/builtin/upload-archive.c\n@@ -21,7 +21,7 @@ static const char deadchild[] =\n int cmd_upload_archive_writer(int argc,\n \t\t\t      const char **argv,\n \t\t\t      const char *prefix,\n-\t\t\t      struct repository *repo UNUSED)\n+\t\t\t      bool has_repo UNUSED)\n {\n \tstruct strvec sent_argv = STRVEC_INIT;\n \tconst char *arg_cmd = \"argument \";\n@@ -85,9 +85,9 @@ static ssize_t process_input(int child_fd, int band)\n }\n \n int cmd_upload_archive(int argc,\n-const char **argv,\n-const char *prefix,\n-struct repository *repo UNUSED)\n+\t\t       const char **argv,\n+\t\t       const char *prefix,\n+\t\t       bool has_repo UNUSED)\n {\n \tstruct child_process writer = CHILD_PROCESS_INIT;\n \ndiff --git c/builtin/upload-pack.c w/builtin/upload-pack.c\nindex 32831fb879..ffd5a4a70c 100644\n--- c/builtin/upload-pack.c\n+++ w/builtin/upload-pack.c\n@@ -22,7 +22,7 @@ static const char * const upload_pack_usage[] = {\n int cmd_upload_pack(int argc,\n \t\t    const char **argv,\n \t\t    const char *prefix,\n-\t\t    struct repository *repo UNUSED)\n+\t\t    bool has_repo UNUSED)\n {\n \tconst char *dir;\n \tint strict = 0;\ndiff --git c/builtin/url-parse.c w/builtin/url-parse.c\nindex 7e705538c0..87309bd58c 100644\n--- c/builtin/url-parse.c\n+++ w/builtin/url-parse.c\n@@ -100,7 +100,7 @@ static char *extract_component(enum url_component component,\n int cmd_url_parse(int argc,\n \t\t  const char **argv,\n \t\t  const char *prefix,\n-\t\t  struct repository *repo UNUSED)\n+\t\t  bool has_repo UNUSED)\n {\n \tstruct url_info info;\n \tenum url_component selected = URL_NONE;\ndiff --git c/builtin/var.c w/builtin/var.c\nindex cc3a43cde2..102e1ce58d 100644\n--- c/builtin/var.c\n+++ w/builtin/var.c\n@@ -217,7 +217,7 @@ static int show_config(const char *var, const char *value,\n int cmd_var(int argc,\n \t    const char **argv,\n \t    const char *prefix UNUSED,\n-\t    struct repository *repo UNUSED)\n+\t    bool has_repo UNUSED)\n {\n \tconst struct git_var *git_var;\n \tchar *val;\ndiff --git c/builtin/verify-commit.c w/builtin/verify-commit.c\nindex 62398acd72..c10f4d31a2 100644\n--- c/builtin/verify-commit.c\n+++ w/builtin/verify-commit.c\n@@ -5,6 +5,7 @@\n  *\n  * Based on git-verify-tag\n  */\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"config.h\"\n #include \"environment.h\"\n@@ -54,7 +55,7 @@ static int verify_commit(struct repository *repo, const char *name, unsigned fla\n int cmd_verify_commit(int argc,\n \t\t      const char **argv,\n \t\t      const char *prefix,\n-\t\t      struct repository *repo)\n+\t\t      bool has_repo UNUSED)\n {\n \tint i = 1, verbose = 0, had_error = 0;\n \tunsigned flags = 0;\n@@ -64,7 +65,7 @@ int cmd_verify_commit(int argc,\n \t\tOPT_END()\n \t};\n \n-\trepo_config(repo, git_default_config, NULL);\n+\trepo_config(the_repository, git_default_config, NULL);\n \n \targc = parse_options(argc, argv, prefix, verify_commit_options,\n \t\t\t     verify_commit_usage, PARSE_OPT_KEEP_ARGV0);\n@@ -78,7 +79,7 @@ int cmd_verify_commit(int argc,\n \t * was received in the process of writing the gpg input: */\n \tsignal(SIGPIPE, SIG_IGN);\n \twhile (i < argc)\n-\t\tif (verify_commit(repo, argv[i++], flags))\n+\t\tif (verify_commit(the_repository, argv[i++], flags))\n \t\t\thad_error = 1;\n \treturn had_error;\n }\ndiff --git c/builtin/verify-pack.c w/builtin/verify-pack.c\nindex 65fd6629a0..04d40333c9 100644\n--- c/builtin/verify-pack.c\n+++ w/builtin/verify-pack.c\n@@ -66,7 +66,7 @@ static const char * const verify_pack_usage[] = {\n int cmd_verify_pack(int argc,\n \t\t    const char **argv,\n \t\t    const char *prefix,\n-\t\t    struct repository *repo UNUSED)\n+\t\t    bool has_repo UNUSED)\n {\n \tint err = 0;\n \tunsigned int flags = 0;\ndiff --git c/builtin/verify-tag.c w/builtin/verify-tag.c\nindex 4a261b2369..ed019201de 100644\n--- c/builtin/verify-tag.c\n+++ w/builtin/verify-tag.c\n@@ -5,6 +5,7 @@\n  *\n  * Based on git-verify-tag.sh\n  */\n+#define USE_THE_REPOSITORY_VARIABLE\n #include \"builtin.h\"\n #include \"config.h\"\n #include \"environment.h\"\n@@ -23,7 +24,7 @@ static const char * const verify_tag_usage[] = {\n int cmd_verify_tag(int argc,\n \t\t   const char **argv,\n \t\t   const char *prefix,\n-\t\t   struct repository *repo)\n+\t\t   bool has_repo UNUSED)\n {\n \tint i = 1, verbose = 0, had_error = 0;\n \tunsigned flags = 0;\n@@ -35,7 +36,7 @@ int cmd_verify_tag(int argc,\n \t\tOPT_END()\n \t};\n \n-\trepo_config(repo, git_default_config, NULL);\n+\trepo_config(the_repository, git_default_config, NULL);\n \n \targc = parse_options(argc, argv, prefix, verify_tag_options,\n \t\t\t     verify_tag_usage, PARSE_OPT_KEEP_ARGV0);\n@@ -56,12 +57,12 @@ int cmd_verify_tag(int argc,\n \t\tstruct object_id oid;\n \t\tconst char *name = argv[i++];\n \n-\t\tif (repo_get_oid(repo, name, &oid)) {\n+\t\tif (repo_get_oid(the_repository, name, &oid)) {\n \t\t\thad_error = !!error(\"tag '%s' not found.\", name);\n \t\t\tcontinue;\n \t\t}\n \n-\t\tif (gpg_verify_tag(repo, &oid, name, flags)) {\n+\t\tif (gpg_verify_tag(the_repository, &oid, name, flags)) {\n \t\t\thad_error = 1;\n \t\t\tcontinue;\n \t\t}\ndiff --git c/builtin/worktree.c w/builtin/worktree.c\nindex 654d27c3e1..db29e28432 100644\n--- c/builtin/worktree.c\n+++ w/builtin/worktree.c\n@@ -1469,7 +1469,7 @@ static int repair(int ac, const char **av, const char *prefix,\n int cmd_worktree(int ac,\n \t\t const char **av,\n \t\t const char *prefix,\n-\t\t struct repository *repo)\n+\t\t bool has_repo UNUSED)\n {\n \tparse_opt_subcommand_fn *fn = NULL;\n \tstruct option options[] = {\n@@ -1494,5 +1494,5 @@ int cmd_worktree(int ac,\n \tprepare_repo_settings(the_repository);\n \tthe_repository->settings.command_requires_full_index = 0;\n \n-\treturn fn(ac, av, prefix, repo);\n+\treturn fn(ac, av, prefix, the_repository);\n }\ndiff --git c/builtin/write-tree.c w/builtin/write-tree.c\nindex e3bd1a40db..5c906d4c06 100644\n--- c/builtin/write-tree.c\n+++ w/builtin/write-tree.c\n@@ -21,7 +21,7 @@ static const char * const write_tree_usage[] = {\n int cmd_write_tree(int argc,\n \t\t   const char **argv,\n \t\t   const char *cmd_prefix,\n-\t\t   struct repository *repo UNUSED)\n+\t\t   bool has_repo UNUSED)\n {\n \tint flags = 0, ret;\n \tconst char *tree_prefix = NULL;\ndiff --git c/git.c w/git.c\nindex 96df15b5cd..ff0b2720a2 100644\n--- c/git.c\n+++ w/git.c\n@@ -32,7 +32,7 @@\n \n struct cmd_struct {\n \tconst char *cmd;\n-\tint (*fn)(int, const char **, const char *, struct repository *);\n+\tint (*fn)(int, const char **, const char *, bool);\n \tunsigned int option;\n };\n \n@@ -507,7 +507,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv, struct\n \ttrace2_cmd_name(p->cmd);\n \n \tvalidate_cache_entries(repo->index);\n-\tstatus = p->fn(argc, argv, prefix, no_repo ? NULL : repo);\n+\tstatus = p->fn(argc, argv, prefix, !no_repo);\n \tvalidate_cache_entries(repo->index);\n \n \tif (status)\ndiff --git c/help.c w/help.c\nindex 46241492ce..df1dc3d398 100644\n--- c/help.c\n+++ w/help.c\n@@ -830,7 +830,7 @@ void get_version_info(struct strbuf *buf, int show_build_options)\n \t}\n }\n \n-int cmd_version(int argc, const char **argv, const char *prefix, struct repository *repository UNUSED)\n+int cmd_version(int argc, const char **argv, const char *prefix, bool has_repo UNUSED)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tint build_options = 0;\n"},{"id":"551394","messageId":"xmqqik4v6y6i.fsf@gitster.g","threadId":"66230","inReplyTo":"F276C11F-1904-496E-AA77-953724362C9A@gmail.com","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-27T21:39:01Z","receivedAt":"2026-08-27T21:39:04Z","isPatch":true,"body":"Ben Knoble <ben.knoble@gmail.com> writes:\n\n>> Le 27 août 2026 à 16:30, Junio C Hamano <gitster@pobox.com> a écrit :\n>> \n>> ﻿\"Hardik Kumar\" <hardikxk@gmail.com> writes:\n>> \n>>>> In general, builtin/foo.c::cmd_foo() are concrete programs that work\n>>>> on specific repository (i.e., the_repository), and there is not much\n>>>> reason to rewrite the use of the_repository to use \"repo\" given by\n>>>> the caller which is git potty.  You'd also need to deal with the\n>>>> case where \"repo\" is NULL (hint: \"cd / && git foo -h\").\n>\n> [snip]\n>\n>> The utility functions builtin/foo.c borrows from outside builtin/\n>> directory are being \"libified\" to reduce the hardcoded dependence on\n>> the_repository, and cmd_foo() can call these functions with\n>> the_repository as a parameter.  But we have no reason to waste our\n>> time updating (and also reviewing patches that make such updates)\n>> the built-in implementations themselves to take a pointer to an\n>> arbitrary repository.\n\nLine wrap to reasonable length.\n\n> Hm. What if a program wants to do « exactly what ‘git switch’ does\n> » sans shelling out?\n\nInstead of cheating, properly factor out reusable part from\ncmd_checkout() into a set of libified routines, and make both\ncmd_checkout() and cmd_switch() to call them\n\nAn approach like that would help \"libify\" things.  libifying is not\njust reducing dependence of globals.\n\nCalling main() from something else is not a libification.\n"},{"id":"551401","messageId":"DL09ZWAJ69WQ.35RUJEJ5039GR@gmail.com","threadId":"66230","inReplyTo":"xmqq7blb8g04.fsf@gitster.g","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"Hardik Kumar","fromEmail":"hardikxk@gmail.com","sentAt":"2026-08-28T04:01:20Z","receivedAt":"2026-08-28T04:01:26Z","isPatch":true,"body":"On Fri Aug 28, 2026 at 1:58 AM IST, Junio C Hamano wrote:\n> \"Hardik Kumar\" <hardikxk@gmail.com> writes:\n>\n>>> In general, builtin/foo.c::cmd_foo() are concrete programs that work\n>>> on specific repository (i.e., the_repository), and there is not much\n>>> reason to rewrite the use of the_repository to use \"repo\" given by\n>>> the caller which is git potty.  You'd also need to deal with the\n>>> case where \"repo\" is NULL (hint: \"cd / && git foo -h\").\n>>\n>> Right, but would safety check be required for single instance or better\n>> to find and work on only the specific ones which could lead to an\n>> exception.\n>\n> I do not quite get what you mean.  In a single function you use\n> the_repository and repo interchangeably, relying on repo, when it is\n> not NULL), being the same as the_repository for correctness.  If\n> they ever refer to different things, then your updated code is less\n> consistent than the original, which would not be an improvement.\n>\n> I actually think a good medium size project is to fix the last\n> parameter given to cmd_foo() built-in command implementations that\n> is a pointer to \"struct repository\".  It was a misguided design.\n>\n> This pointer is either NULL or the_repository; it never takes any\n> other value.  It is misleading and invites confusion that these\n> functions can take arbitrary repository instance.  It also invites\n> people to replace all references in cmd_foo() to \"the_repository\"\n> with \"repo\", which may lead to an error.  Depending on where\n> parse_options() call appears in the cmd_foo(), \"cd / && git foo -h\"\n> will cause segfaults with such a change.\n>\n> If we change the function signature of cmd_foo() to receive a \"bool\"\n> that says \"true\" if the command was run inside a repository and\n> \"false\" otherwise, cmd_foo() can still tell if the command was run\n> outside a repository, and programmers will not be misled to use\n> anything other than \"the_repository\" as the repository to work on.\n>\n> The utility functions builtin/foo.c borrows from outside builtin/\n> directory are being \"libified\" to reduce the hardcoded dependence on\n> the_repository, and cmd_foo() can call these functions with\n> the_repository as a parameter.  But we have no reason to waste our\n> time updating (and also reviewing patches that make such updates)\n> the built-in implementations themselves to take a pointer to an\n> arbitrary repository.\n\nUnderstood. Thanks for the clarification.\n"},{"id":"551411","messageId":"DL0GH05O36T1.1J4TSL2PU73TO@gmail.com","threadId":"66230","inReplyTo":"xmqqmru76ybk.fsf_-_@gitster.g","subject":"Re: [PATCH] do not pass \"repo\" to builtin commmand implementations","fromName":"Hardik Kumar","fromEmail":"hardikxk@gmail.com","sentAt":"2026-08-28T09:05:47Z","receivedAt":"2026-08-28T09:05:53Z","isPatch":true,"body":"This would certainly help make it more obvious as not use the pointer\nparameter. But would you not consider to eventually move towards\nsomething more efiicient in the future?\n"},{"id":"551413","messageId":"CALnO6CCsJGmgmvKyMdX3q1Kr5AnBwYJ=_UiQ9+m7jWe7hv=3Qw@mail.gmail.com","threadId":"66230","inReplyTo":"xmqqik4v6y6i.fsf@gitster.g","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-28T11:41:39Z","receivedAt":"2026-08-28T11:41:58Z","isPatch":true,"body":"On Thu, Aug 27, 2026 at 5:39 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Ben Knoble <ben.knoble@gmail.com> writes:\n>\n> >> Le 27 août 2026 à 16:30, Junio C Hamano <gitster@pobox.com> a écrit :\n> >>\n> >> ﻿\"Hardik Kumar\" <hardikxk@gmail.com> writes:\n> >>\n> >>>> In general, builtin/foo.c::cmd_foo() are concrete programs that work\n> >>>> on specific repository (i.e., the_repository), and there is not much\n> >>>> reason to rewrite the use of the_repository to use \"repo\" given by\n> >>>> the caller which is git potty.  You'd also need to deal with the\n> >>>> case where \"repo\" is NULL (hint: \"cd / && git foo -h\").\n> >\n> > [snip]\n> >\n> >> The utility functions builtin/foo.c borrows from outside builtin/\n> >> directory are being \"libified\" to reduce the hardcoded dependence on\n> >> the_repository, and cmd_foo() can call these functions with\n> >> the_repository as a parameter.  But we have no reason to waste our\n> >> time updating (and also reviewing patches that make such updates)\n> >> the built-in implementations themselves to take a pointer to an\n> >> arbitrary repository.\n>\n> Line wrap to reasonable length.\n\nYeah… my iPhone (from which I sometimes reply) supports plaintext if I\ndo things just right, but it doesn't wrap lines. It's difficult to\njudge where to break, but maybe I'll try hardbreaks every so often and\nsee if that helps.\n\n> > Hm. What if a program wants to do « exactly what ‘git switch’ does\n> > » sans shelling out?\n>\n> Instead of cheating, properly factor out reusable part from\n> cmd_checkout() into a set of libified routines, and make both\n> cmd_checkout() and cmd_switch() to call them\n>\n> An approach like that would help \"libify\" things.  libifying is not\n> just reducing dependence of globals.\n>\n> Calling main() from something else is not a libification.\n\nSensible. Thanks!\n\n-- \nD. Ben Knoble\n"},{"id":"551433","messageId":"xmqq5x0u3qr8.fsf@gitster.g","threadId":"66230","inReplyTo":"DL0GH05O36T1.1J4TSL2PU73TO@gmail.com","subject":"Re: [PATCH] do not pass \"repo\" to builtin commmand implementations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T20:59:55Z","receivedAt":"2026-08-28T20:59:58Z","isPatch":true,"body":"\"Hardik Kumar\" <hardikxk@gmail.com> writes:\n\n> This would certainly help make it more obvious as not use the pointer\n> parameter. But would you not consider to eventually move towards\n> something more efiicient in the future?\n\nIt is unclear what kind of more efficient alternative you have in\nmind.\n\nThe primary motivation for this change is to make the implementation\nof built-in commands less error-prone and harder to abuse.  The\nimplementation of 'git foo' in cmd_foo() in builtin/foo.c performs\none-time initialization (such as calling git_config()) and\nfinalization that cannot be repeated, making it an anti-pattern to\ncall cmd_foo() from within cmd_bar().  Refraining from pretending\nthese functions can operate on an arbitrary caller-supplied\nrepository instance is one step toward preventing such misuse.\n\nHowever, another motivation for this change is to encourage\ndevelopers who want to aid the libification effort to refactor code\nout of cmd_foo() into reusable helper functions.  Instead of keeping\nthose helpers within builtin/foo.c, they can be moved to library\nfiles outside the builtin/ directory and take a pointer to 'struct\nrepository'.\n\nThe top-level cmd_foo() can still access 'the_repository' directly\nand orchestrate the execution of 'git foo' by passing a pointer to\nthese helper functions.  That way, more code becomes reusable.\n"},{"id":"551435","messageId":"xmqqh5kd3lm3.fsf@gitster.g","threadId":"66230","inReplyTo":"CALnO6CCsJGmgmvKyMdX3q1Kr5AnBwYJ=_UiQ9+m7jWe7hv=3Qw@mail.gmail.com","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:51:00Z","receivedAt":"2026-08-28T22:51:02Z","isPatch":true,"body":"\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n\n>> > Hm. What if a program wants to do « exactly what ‘git switch’ does\n>> > » sans shelling out?\n>>\n>> Instead of cheating, properly factor out reusable part from\n>> cmd_checkout() into a set of libified routines, and make both\n>> cmd_checkout() and cmd_switch() to call them\n>>\n>> An approach like that would help \"libify\" things.  libifying is not\n>> just reducing dependence of globals.\n>>\n>> Calling main() from something else is not a libification.\n>\n> Sensible. Thanks!\n\nI actually answered a wrong question though ;-) \n\nThe way cmd_switch() and cmd_restore() were introduced by sharing\nwhat used to serve cmd_checkout() was serviceable, but ugly.  Had we\nstarted from separate implementations for 'switch' and 'restore'\nthat were later merged into 'checkout', we would not have ended up\nwith a design centered on a single monolithic choke point like\ncheckout_main().\n\nThat is what I meant by \"cheating instead of refactoring reusable\nparts\".  However, that is not directly relevant to your example.\n\nIt is an anti-pattern to call the top-level implementation of 'git\nfoo' in cmd_foo() directly from cmd_bar(), since these cmd_foo()\nfunctions are like main() in ordinary programs, performing one-time\ninitialization (such as git_config() calls) and finalization that\ncannot be repeated.  To help our codebase, as well as the use case\nyou imagined in your message, it would help to trim down these\nnon-reusable cmd_foo() implementations by turning them into mere\norchestrators that call refactored helper functions.  Such a change\nwould put cmd_foo() and a client that wants to reuse 'git switch'\nfunctionality on the same footing, allowing more of our code to be\nused in different contexts.  I think that is what people mean by\nthe \"libification\" effort.\n"},{"id":"551436","messageId":"20260828225206.310500-1-gitster@pobox.com","threadId":"66230","inReplyTo":"xmqqh5kd3lm3.fsf@gitster.g","subject":"[PATCH 0/8] More sensible checkout/switch/restore code refactoring","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:51:58Z","receivedAt":"2026-08-28T22:52:08Z","isPatch":true,"body":"In the beginning, there was only 'git checkout'.  We then introduced\n'git switch' and 'git restore', borrowing as much original code as\npossible from the implementation of 'git checkout'.\n\nUnfortunately, this has left the code in a strange shape.  Had we\nstarted from separate implementations for 'switch' and 'restore'\nthen later merged them into 'checkout', we would not have arrived at\na design where three front-end routines, cmd_checkout(),\ncmd_switch(), and cmd_restore(), funnel into a single monolithic\nchoke point in checkout_main(), which then determines whether we are\nchecking out a branch or paths, and dispatches to checkout_branch()\nor checkout_paths().\n\nThis series is an attempt to repartition the code into a better\nshape.  Because checkout_branch() and checkout_paths() already exist\nas two reusable helper functions, with sufficient refactoring of\ncheckout_main(), the two newer entry points, cmd_switch() and\ncmd_restore(), can parse command-line arguments and configuration\nsettings and jump straight into checkout_branch() or\ncheckout_paths() respectively, without worrying about the other path.\n\nOf course, cmd_checkout() still needs to decide whether to check out\na branch or a set of paths and dispatch between these two backends.\n\nThe series begins with three fairly isolated cleanups that are worth\nmaking on their own, even if we do not follow through with the rest\nof the series.  Patches 4 and 5 then refactor various utility\nfunctions out of existing code paths, and patch 6 uses them to\nrewrite the three top-level command entry points to call these\nfunctions without going through checkout_main().  Patch 7 is a\nstyle-only fix done after the dust settles, which was deliberately\nkept separate to simplify review.\n\nThe final step moves one helper utility out of builtin/checkout.c to\ntop-level checkout.c as an illustration of the libification discussed\nin our recent threads.\n\nNote that I consider this a fairly early and rough draft for\nillustration only.  There may be a few topics that touch 'git\ncheckout', and a refactoring of this scale might adversely impact\nthem, so I will not even merge these patches to 'seen'.\n\n 1/8: checkout: pass cb_option explicitly to branch name parsers\n 2/8: checkout: validate new branch name in checkout_branch()\n 3/8: checkout: validate stage and merge option compatibility in\n        checkout_paths()\n 4/8: checkout: extract option validation and pathspec helpers\n 5/8: checkout: extract branch setup and tracking helpers\n 6/8: checkout: restructure switch, restore, and checkout\n        entrypoints\n 7/8: checkout: wrap overly long lines\n 8/8: checkout: move post_checkout_hook() to checkout.c\n\n builtin/checkout.c | 545 +++++++++++++++++++++++----------------------\n checkout.c         |  22 ++\n checkout.h         |   8 +\n 3 files changed, 311 insertions(+), 264 deletions(-)\n\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551437","messageId":"20260828225206.310500-2-gitster@pobox.com","threadId":"66230","inReplyTo":"20260828225206.310500-1-gitster@pobox.com","subject":"[PATCH 1/8] checkout: pass cb_option explicitly to branch name parsers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:51:59Z","receivedAt":"2026-08-28T22:52:10Z","isPatch":true,"body":"The file-scope static variable 'cb_option' is used to record whether\na new branch is being created via '-b' (in 'git checkout') or '-c'\n(in 'git switch'), primarily for error reporting and advice messages\nin parse_remote_branch().\n\nGlobal mutable state makes the code harder to reason about and refactor.\n\nPass 'cb_option' explicitly as a parameter to parse_remote_branch()\nand parse_branchname_arg(), removing the file-scope static variable.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 23 +++++++++--------------\n 1 file changed, 9 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 55e3a89a85..774e4fd5b3 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1346,7 +1346,7 @@ enum checkout_command {\n static char *parse_remote_branch(const char *arg,\n \t\t\t\t struct object_id *rev,\n \t\t\t\t int could_be_checkout_paths,\n-\t\t\t\t enum checkout_command which_command)\n+\t\t\t\t char cb_option)\n {\n \tint num_matches = 0;\n \tchar *remote = unique_tracking_name(arg, rev, &num_matches);\n@@ -1361,16 +1361,15 @@ static char *parse_remote_branch(const char *arg,\n \t    if (advice_enabled(ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME)) {\n \t\t    const char *cmdname;\n \n-\t\t    switch (which_command) {\n-\t\t    case CHECKOUT_CHECKOUT:\n+\t\t    switch (cb_option) {\n+\t\t    case 'b':\n \t\t\t    cmdname = \"checkout\";\n \t\t\t    break;\n-\t\t    case CHECKOUT_SWITCH:\n+\t\t    case 'c':\n \t\t\t    cmdname = \"switch\";\n \t\t\t    break;\n \t\t    default:\n-\t\t\t    BUG(\"command <%d> should not reach parse_remote_branch\",\n-\t\t\t\twhich_command);\n+\t\t\t    BUG(\"unexpected cb_option '%c'\", cb_option);\n \t\t\t    break;\n \t\t    }\n \n@@ -1394,7 +1393,7 @@ static char *parse_remote_branch(const char *arg,\n \n static int parse_branchname_arg(int argc, const char **argv,\n \t\t\t\tint dwim_new_local_branch_ok,\n-\t\t\t\tenum checkout_command which_command,\n+\t\t\t\tchar cb_option,\n \t\t\t\tstruct branch_info *new_branch_info,\n \t\t\t\tstruct checkout_opts *opts,\n \t\t\t\tstruct object_id *rev)\n@@ -1505,7 +1504,7 @@ static int parse_branchname_arg(int argc, const char **argv,\n \t\tif (recover_with_dwim) {\n \t\t\tremote = parse_remote_branch(arg, rev,\n \t\t\t\t\t\t     could_be_checkout_paths,\n-\t\t\t\t\t\t     which_command);\n+\t\t\t\t\t\t     cb_option);\n \t\t\tif (remote) {\n \t\t\t\t*new_branch = arg;\n \t\t\t\targ = remote;\n@@ -1832,9 +1831,6 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts,\n \treturn newopts;\n }\n \n-/* create-branch option (either b or c) */\n-static char cb_option = 'b';\n-\n static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\t struct checkout_opts *opts, struct option *options,\n \t\t\t enum checkout_command which_command)\n@@ -1842,6 +1838,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \tint parseopt_flags = 0;\n \tstruct branch_info new_branch_info = { 0 };\n \tint ret;\n+\tchar cb_option = (which_command == CHECKOUT_SWITCH) ? 'c' : 'b';\n \n \tstatic const char * const checkout_usage[] = {\n \t\tN_(\"git checkout [<options>] <branch>\"),\n@@ -1997,7 +1994,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\topts->dwim_new_local_branch &&\n \t\t\topts->track == BRANCH_TRACK_UNSPECIFIED &&\n \t\t\t!opts->new_branch;\n-\t\tint n = parse_branchname_arg(argc, argv, dwim_ok, which_command,\n+\t\tint n = parse_branchname_arg(argc, argv, dwim_ok, cb_option,\n \t\t\t\t\t     &new_branch_info, opts, &rev);\n \t\targv += n;\n \t\targc -= n;\n@@ -2174,8 +2171,6 @@ int cmd_switch(int argc,\n \toptions = add_common_options(&opts, options);\n \toptions = add_common_switch_branch_options(&opts, options);\n \n-\tcb_option = 'c';\n-\n \treturn checkout_main(argc, argv, prefix, &opts, options,\n \t\t\t     CHECKOUT_SWITCH);\n }\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551438","messageId":"20260828225206.310500-3-gitster@pobox.com","threadId":"66230","inReplyTo":"20260828225206.310500-1-gitster@pobox.com","subject":"[PATCH 2/8] checkout: validate new branch name in checkout_branch()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:52:00Z","receivedAt":"2026-08-28T22:52:11Z","isPatch":true,"body":"In checkout_main(), new branch name validation is performed before\ndispatching to checkout_branch() or checkout_paths().  Checking out\npaths does not create new branches, so this validation only belongs\nin checkout_branch().\n\nMove the validate_branchname() and validate_new_branchname() calls\nfrom checkout_main() into checkout_branch().  checkout_paths()\nchecks and fails if '.new_branch' is set before doing anything,\nwhich indicates that this change is safe and makes good sense.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 22 +++++++++++-----------\n 1 file changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 774e4fd5b3..14542626e9 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1734,6 +1734,17 @@ static int checkout_branch(struct checkout_opts *opts,\n \t\tfree(full_ref);\n \t}\n \n+\tif (opts->new_branch) {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\n+\t\tif (opts->new_branch_force)\n+\t\t\topts->branch_exists = validate_branchname(opts->new_branch, &buf);\n+\t\telse\n+\t\t\topts->branch_exists =\n+\t\t\t\tvalidate_new_branchname(opts->new_branch, &buf, 0);\n+\t\tstrbuf_release(&buf);\n+\t}\n+\n \tif (!new_branch_info->commit && opts->new_branch) {\n \t\tstruct object_id rev;\n \t\tint flag;\n@@ -2062,17 +2073,6 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\tdie(_(\"you must specify path(s) to restore\"));\n \t}\n \n-\tif (opts->new_branch) {\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\n-\t\tif (opts->new_branch_force)\n-\t\t\topts->branch_exists = validate_branchname(opts->new_branch, &buf);\n-\t\telse\n-\t\t\topts->branch_exists =\n-\t\t\t\tvalidate_new_branchname(opts->new_branch, &buf, 0);\n-\t\tstrbuf_release(&buf);\n-\t}\n-\n \tif (opts->patch_mode || opts->pathspec.nr)\n \t\tret = checkout_paths(opts, &new_branch_info);\n \telse\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551439","messageId":"20260828225206.310500-4-gitster@pobox.com","threadId":"66230","inReplyTo":"20260828225206.310500-1-gitster@pobox.com","subject":"[PATCH 3/8] checkout: validate stage and merge option compatibility in checkout_paths()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:52:01Z","receivedAt":"2026-08-28T22:52:13Z","isPatch":true,"body":"In checkout_main(), checking that no more than one of --ours/--theirs,\n--force, and --merge is specified is performed when pathspecs are\npresent, before dispatching to checkout_paths().  Checking out a\nbranch does not use index stages, so this validation belongs in\ncheckout_paths().\n\nMove the incompatibility check from checkout_main() into\ncheckout_paths().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 14542626e9..e3d23256e2 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -591,6 +591,10 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\tdie(_(\"'%s', '%s', or '%s' cannot be used when checking out of a tree\"),\n \t\t    \"--merge\", \"--ours\", \"--theirs\");\n \n+\tif (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)\n+\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\n\"\n+\t\t      \"checking out of the index.\"));\n+\n \tif (opts->patch_mode) {\n \t\tenum add_p_mode patch_mode;\n \t\tstruct interactive_options interactive_opts = {\n@@ -2063,11 +2067,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \n \topts->pathspec.recursive = 1;\n \n-\tif (opts->pathspec.nr) {\n-\t\tif (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)\n-\t\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\n\"\n-\t\t\t      \"checking out of the index.\"));\n-\t} else {\n+\tif (!opts->pathspec.nr) {\n \t\tif (opts->accept_pathspec && !opts->empty_pathspec_ok &&\n \t\t    !opts->patch_mode)\t/* patch mode is special */\n \t\t\tdie(_(\"you must specify path(s) to restore\"));\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551440","messageId":"20260828225206.310500-5-gitster@pobox.com","threadId":"66230","inReplyTo":"20260828225206.310500-1-gitster@pobox.com","subject":"[PATCH 4/8] checkout: extract option validation and pathspec helpers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:52:02Z","receivedAt":"2026-08-28T22:52:15Z","isPatch":true,"body":"The checkout_main() function handles initialization, option parsing,\noption validation, and pathspec resolution.\n\nExtract option validation and pathspec handling logic into static\nhelper functions:\n\n  - init_checkout_opts() initializes default checkout options and\n    repo settings.\n\n  - validate_path_options() validates patch context and\n    index/worktree flags.\n\n  - prepare_common_options() prepares progress, merge, and force\n    options.\n\n  - parse_pathspec_from_file_options() parses and validates\n    pathspecs read from a file.\n\nCall these helpers from checkout_main().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 171 +++++++++++++++++++++++++--------------------\n 1 file changed, 96 insertions(+), 75 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex e3d23256e2..8d567def7e 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1846,6 +1846,98 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts,\n \treturn newopts;\n }\n \n+static void init_checkout_opts(struct checkout_opts *opts, const char *prefix)\n+{\n+\topts->overwrite_ignore = 1;\n+\topts->prefix = prefix;\n+\topts->show_progress = -1;\n+\n+\trepo_config(the_repository, git_checkout_config, opts);\n+\tif (the_repository->gitdir) {\n+\t\tprepare_repo_settings(the_repository);\n+\t\tthe_repository->settings.command_requires_full_index = 0;\n+\t}\n+\n+\topts->track = BRANCH_TRACK_UNSPECIFIED;\n+}\n+\n+static void validate_path_options(struct checkout_opts *opts)\n+{\n+\tif (opts->patch_context < -1)\n+\t\tdie(_(\"'%s' cannot be negative\"), \"--unified\");\n+\tif (opts->patch_interhunk_context < -1)\n+\t\tdie(_(\"'%s' cannot be negative\"), \"--inter-hunk-context\");\n+\n+\tif (!opts->patch_mode) {\n+\t\tif (opts->patch_context != -1)\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--unified\", \"--patch\");\n+\t\tif (opts->patch_interhunk_context != -1)\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--inter-hunk-context\", \"--patch\");\n+\t\tif (!opts->auto_advance)\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--no-auto-advance\", \"--patch\");\n+\t}\n+\n+\tif (opts->overlay_mode == 1 && opts->patch_mode)\n+\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"-p\", \"--overlay\");\n+\n+\tif (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {\n+\t\tif (opts->checkout_index < 0)\n+\t\t\topts->checkout_index = 0;\n+\t\tif (opts->checkout_worktree < 0)\n+\t\t\topts->checkout_worktree = 0;\n+\t} else {\n+\t\tif (opts->checkout_index < 0)\n+\t\t\topts->checkout_index = -opts->checkout_index - 1;\n+\t\tif (opts->checkout_worktree < 0)\n+\t\t\topts->checkout_worktree = -opts->checkout_worktree - 1;\n+\t}\n+\tif (opts->checkout_index < 0 || opts->checkout_worktree < 0)\n+\t\tBUG(\"these flags should be non-negative by now\");\n+}\n+\n+static void prepare_common_options(struct checkout_opts *opts)\n+{\n+\tif (opts->show_progress < 0) {\n+\t\tif (opts->quiet)\n+\t\t\topts->show_progress = 0;\n+\t\telse\n+\t\t\topts->show_progress = isatty(2);\n+\t}\n+\n+\t/* --conflicts implies --merge */\n+\tif (opts->merge == -1)\n+\t\topts->merge = opts->conflict_style >= 0;\n+\n+\tif (opts->force) {\n+\t\topts->discard_changes = 1;\n+\t\topts->ignore_unmerged_opt = \"--force\";\n+\t\topts->ignore_unmerged = 1;\n+\t}\n+}\n+\n+static void parse_pathspec_from_file_options(struct checkout_opts *opts,\n+\t\t\t\t\t     const char *prefix)\n+{\n+\tif (opts->pathspec_from_file) {\n+\t\tif (opts->pathspec.nr)\n+\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"), \"--pathspec-from-file\");\n+\n+\t\tif (opts->force_detach)\n+\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--detach\");\n+\n+\t\tif (opts->patch_mode)\n+\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--patch\");\n+\n+\t\tparse_pathspec_file(&opts->pathspec, 0,\n+\t\t\t\t    0,\n+\t\t\t\t    prefix, opts->pathspec_from_file, opts->pathspec_file_nul);\n+\t} else if (opts->pathspec_file_nul) {\n+\t\tdie(_(\"the option '%s' requires '%s'\"), \"--pathspec-file-nul\", \"--pathspec-from-file\");\n+\t}\n+\n+\topts->pathspec.recursive = 1;\n+}\n+\n static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\t struct checkout_opts *opts, struct option *options,\n \t\t\t enum checkout_command which_command)\n@@ -1887,17 +1979,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\tBUG(\"no such checkout variant %d\", which_command);\n \t}\n \n-\topts->overwrite_ignore = 1;\n-\topts->prefix = prefix;\n-\topts->show_progress = -1;\n-\n-\trepo_config(the_repository, git_checkout_config, opts);\n-\tif (the_repository->gitdir) {\n-\t\tprepare_repo_settings(the_repository);\n-\t\tthe_repository->settings.command_requires_full_index = 0;\n-\t}\n-\n-\topts->track = BRANCH_TRACK_UNSPECIFIED;\n+\tinit_checkout_opts(opts, prefix);\n \n \tif (!opts->accept_pathspec && !opts->accept_ref)\n \t\tBUG(\"make up your mind, you need to take _something_\");\n@@ -1907,57 +1989,13 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \targc = parse_options(argc, argv, prefix, options,\n \t\t\t     usagestr, parseopt_flags);\n \n-\tif (opts->patch_context < -1)\n-\t\tdie(_(\"'%s' cannot be negative\"), \"--unified\");\n-\tif (opts->patch_interhunk_context < -1)\n-\t\tdie(_(\"'%s' cannot be negative\"), \"--inter-hunk-context\");\n-\n-\tif (!opts->patch_mode) {\n-\t\tif (opts->patch_context != -1)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--unified\", \"--patch\");\n-\t\tif (opts->patch_interhunk_context != -1)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--inter-hunk-context\", \"--patch\");\n-\t\tif (!opts->auto_advance)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--no-auto-advance\", \"--patch\");\n-\t}\n-\n-\tif (opts->show_progress < 0) {\n-\t\tif (opts->quiet)\n-\t\t\topts->show_progress = 0;\n-\t\telse\n-\t\t\topts->show_progress = isatty(2);\n-\t}\n-\n-\t/* --conflicts implies --merge */\n-\tif (opts->merge == -1)\n-\t\topts->merge = opts->conflict_style >= 0;\n-\n-\tif (opts->force) {\n-\t\topts->discard_changes = 1;\n-\t\topts->ignore_unmerged_opt = \"--force\";\n-\t\topts->ignore_unmerged = 1;\n-\t}\n+\tvalidate_path_options(opts);\n+\tprepare_common_options(opts);\n \n \tif ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)\n \t\tdie(_(\"options '-%c', '-%c', and '%s' cannot be used together\"),\n \t\t\tcb_option, toupper(cb_option), \"--orphan\");\n \n-\tif (opts->overlay_mode == 1 && opts->patch_mode)\n-\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"-p\", \"--overlay\");\n-\n-\tif (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {\n-\t\tif (opts->checkout_index < 0)\n-\t\t\topts->checkout_index = 0;\n-\t\tif (opts->checkout_worktree < 0)\n-\t\t\topts->checkout_worktree = 0;\n-\t} else {\n-\t\tif (opts->checkout_index < 0)\n-\t\t\topts->checkout_index = -opts->checkout_index - 1;\n-\t\tif (opts->checkout_worktree < 0)\n-\t\t\topts->checkout_worktree = -opts->checkout_worktree - 1;\n-\t}\n-\tif (opts->checkout_index < 0 || opts->checkout_worktree < 0)\n-\t\tBUG(\"these flags should be non-negative by now\");\n \t/*\n \t * convenient shortcut: \"git restore --staged [--worktree]\" equals\n \t * \"git restore --staged [--worktree] --source HEAD\"\n@@ -2048,24 +2086,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\t    argv[0]);\n \t}\n \n-\tif (opts->pathspec_from_file) {\n-\t\tif (opts->pathspec.nr)\n-\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"), \"--pathspec-from-file\");\n-\n-\t\tif (opts->force_detach)\n-\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--detach\");\n-\n-\t\tif (opts->patch_mode)\n-\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--patch\");\n-\n-\t\tparse_pathspec_file(&opts->pathspec, 0,\n-\t\t\t\t    0,\n-\t\t\t\t    prefix, opts->pathspec_from_file, opts->pathspec_file_nul);\n-\t} else if (opts->pathspec_file_nul) {\n-\t\tdie(_(\"the option '%s' requires '%s'\"), \"--pathspec-file-nul\", \"--pathspec-from-file\");\n-\t}\n-\n-\topts->pathspec.recursive = 1;\n+\tparse_pathspec_from_file_options(opts, prefix);\n \n \tif (!opts->pathspec.nr) {\n \t\tif (opts->accept_pathspec && !opts->empty_pathspec_ok &&\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551441","messageId":"20260828225206.310500-6-gitster@pobox.com","threadId":"66230","inReplyTo":"20260828225206.310500-1-gitster@pobox.com","subject":"[PATCH 5/8] checkout: extract branch setup and tracking helpers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:52:03Z","receivedAt":"2026-08-28T22:52:16Z","isPatch":true,"body":"The checkout_main() function validates branch-creation options,\nDWIMs tracking branch options, and sets up branch information\ndirectly in its body.\n\nExtract these branch setup operations into static helper functions:\n\n  - validate_branch_options() validates compatibility of '-b', '-B',\n    and '--orphan' options.\n\n  - dwim_branch_track_option() infers the branch name when '--track'\n    is given without an explicit branch name.\n\n  - setup_branch_name_and_info() drives branch validation and parses\n    the branch name argument.\n\nCall the new setup helper from checkout_main().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 104 +++++++++++++++++++++++----------------------\n 1 file changed, 54 insertions(+), 50 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 8d567def7e..2edaca5539 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1938,6 +1938,57 @@ static void parse_pathspec_from_file_options(struct checkout_opts *opts,\n \topts->pathspec.recursive = 1;\n }\n \n+static void validate_branch_options(struct checkout_opts *opts, char cb_option)\n+{\n+\tif ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)\n+\t\tdie(_(\"options '-%c', '-%c', and '%s' cannot be used together\"),\n+\t\t\tcb_option, toupper(cb_option), \"--orphan\");\n+\n+\tif (opts->new_branch_force)\n+\t\topts->new_branch = opts->new_branch_force;\n+\n+\tif (opts->new_orphan_branch)\n+\t\topts->new_branch = opts->new_orphan_branch;\n+}\n+\n+static void dwim_branch_track_option(int argc, const char **argv,\n+\t\t\t\t     struct checkout_opts *opts, char cb_option)\n+{\n+\t/* --track without -c/-C/-b/-B/--orphan should DWIM */\n+\tif (opts->track != BRANCH_TRACK_UNSPECIFIED && !opts->new_branch) {\n+\t\tconst char *argv0 = argv[0];\n+\t\tif (!argc || !strcmp(argv0, \"--\"))\n+\t\t\tdie(_(\"--track needs a branch name\"));\n+\t\tskip_prefix(argv0, \"refs/\", &argv0);\n+\t\tskip_prefix(argv0, \"remotes/\", &argv0);\n+\t\targv0 = strchr(argv0, '/');\n+\t\tif (!argv0 || !argv0[1])\n+\t\t\tdie(_(\"missing branch name; try -%c\"), cb_option);\n+\t\topts->new_branch = argv0 + 1;\n+\t}\n+}\n+\n+static int setup_branch_name_and_info(int argc, const char **argv,\n+\t\t\t\t      struct checkout_opts *opts,\n+\t\t\t\t      struct branch_info *new_branch_info,\n+\t\t\t\t      char cb_option)\n+{\n+\tvalidate_branch_options(opts, cb_option);\n+\tdwim_branch_track_option(argc, argv, opts, cb_option);\n+\n+\tif (argc) {\n+\t\tstruct object_id rev;\n+\t\tint dwim_ok =\n+\t\t\t!opts->patch_mode &&\n+\t\t\topts->dwim_new_local_branch &&\n+\t\t\topts->track == BRANCH_TRACK_UNSPECIFIED &&\n+\t\t\t!opts->new_branch;\n+\t\treturn parse_branchname_arg(argc, argv, dwim_ok, cb_option,\n+\t\t\t\t\t    new_branch_info, opts, &rev);\n+\t}\n+\treturn 0;\n+}\n+\n static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\t struct checkout_opts *opts, struct option *options,\n \t\t\t enum checkout_command which_command)\n@@ -1992,10 +2043,6 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \tvalidate_path_options(opts);\n \tprepare_common_options(opts);\n \n-\tif ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)\n-\t\tdie(_(\"options '-%c', '-%c', and '%s' cannot be used together\"),\n-\t\t\tcb_option, toupper(cb_option), \"--orphan\");\n-\n \t/*\n \t * convenient shortcut: \"git restore --staged [--worktree]\" equals\n \t * \"git restore --staged [--worktree] --source HEAD\"\n@@ -2003,52 +2050,9 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \tif (!opts->from_treeish && opts->checkout_index)\n \t\topts->from_treeish = \"HEAD\";\n \n-\t/*\n-\t * From here on, new_branch will contain the branch to be checked out,\n-\t * and new_branch_force and new_orphan_branch will tell us which one of\n-\t * -b/-B/-c/-C/--orphan is being used.\n-\t */\n-\tif (opts->new_branch_force)\n-\t\topts->new_branch = opts->new_branch_force;\n-\n-\tif (opts->new_orphan_branch)\n-\t\topts->new_branch = opts->new_orphan_branch;\n-\n-\t/* --track without -c/-C/-b/-B/--orphan should DWIM */\n-\tif (opts->track != BRANCH_TRACK_UNSPECIFIED && !opts->new_branch) {\n-\t\tconst char *argv0 = argv[0];\n-\t\tif (!argc || !strcmp(argv0, \"--\"))\n-\t\t\tdie(_(\"--track needs a branch name\"));\n-\t\tskip_prefix(argv0, \"refs/\", &argv0);\n-\t\tskip_prefix(argv0, \"remotes/\", &argv0);\n-\t\targv0 = strchr(argv0, '/');\n-\t\tif (!argv0 || !argv0[1])\n-\t\t\tdie(_(\"missing branch name; try -%c\"), cb_option);\n-\t\topts->new_branch = argv0 + 1;\n-\t}\n-\n-\t/*\n-\t * Extract branch name from command line arguments, so\n-\t * all that is left is pathspecs.\n-\t *\n-\t * Handle\n-\t *\n-\t *  1) git checkout <tree> -- [<paths>]\n-\t *  2) git checkout -- [<paths>]\n-\t *  3) git checkout <something> [<paths>]\n-\t *\n-\t * including \"last branch\" syntax and DWIM-ery for names of\n-\t * remote branches, erroring out for invalid or ambiguous cases.\n-\t */\n-\tif (argc && opts->accept_ref) {\n-\t\tstruct object_id rev;\n-\t\tint dwim_ok =\n-\t\t\t!opts->patch_mode &&\n-\t\t\topts->dwim_new_local_branch &&\n-\t\t\topts->track == BRANCH_TRACK_UNSPECIFIED &&\n-\t\t\t!opts->new_branch;\n-\t\tint n = parse_branchname_arg(argc, argv, dwim_ok, cb_option,\n-\t\t\t\t\t     &new_branch_info, opts, &rev);\n+\tif (opts->accept_ref) {\n+\t\tint n = setup_branch_name_and_info(argc, argv, opts,\n+\t\t\t\t\t\t   &new_branch_info, cb_option);\n \t\targv += n;\n \t\targc -= n;\n \t} else if (!opts->accept_ref && opts->from_treeish) {\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551442","messageId":"20260828225206.310500-7-gitster@pobox.com","threadId":"66230","inReplyTo":"20260828225206.310500-1-gitster@pobox.com","subject":"[PATCH 6/8] checkout: restructure switch, restore, and checkout entrypoints","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:52:04Z","receivedAt":"2026-08-28T22:52:18Z","isPatch":true,"body":"cmd_switch(), cmd_restore(), and cmd_checkout() pass their options\nto checkout_main(), which parses options and configuration,\nvalidates and dispatches to checkout_branch() or checkout_paths().\n\nNow that option initialization, validation, and branch setup have been\nsplit into dedicated helper functions, restructure cmd_switch(),\ncmd_restore(), and cmd_checkout() to invoke these helpers directly and\ndispatch to checkout_branch() or checkout_paths().\n\nIn cmd_restore(), handle the --staged default from_treeish = \"HEAD\" and\nresolve opts.from_treeish into new_branch_info and opts.source_tree.\n\nThis allows us to remove checkout_main() and enum checkout_command\nas they are no longer needed.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 297 +++++++++++++++++++++++----------------------\n 1 file changed, 149 insertions(+), 148 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2edaca5539..b18515ac7f 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1341,12 +1341,6 @@ static void setup_new_branch_info_and_source_tree(\n }\n \n \n-enum checkout_command {\n-\tCHECKOUT_CHECKOUT = 1,\n-\tCHECKOUT_SWITCH = 2,\n-\tCHECKOUT_RESTORE = 3,\n-};\n-\n static char *parse_remote_branch(const char *arg,\n \t\t\t\t struct object_id *rev,\n \t\t\t\t int could_be_checkout_paths,\n@@ -1989,19 +1983,25 @@ static int setup_branch_name_and_info(int argc, const char **argv,\n \treturn 0;\n }\n \n-static int checkout_main(int argc, const char **argv, const char *prefix,\n-\t\t\t struct checkout_opts *opts, struct option *options,\n-\t\t\t enum checkout_command which_command)\n+int cmd_switch(int argc,\n+\t       const char **argv,\n+\t       const char *prefix,\n+\t       struct repository *repo UNUSED)\n {\n-\tint parseopt_flags = 0;\n+\tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n+\tstruct option *options = NULL;\n \tstruct branch_info new_branch_info = { 0 };\n \tint ret;\n-\tchar cb_option = (which_command == CHECKOUT_SWITCH) ? 'c' : 'b';\n-\n-\tstatic const char * const checkout_usage[] = {\n-\t\tN_(\"git checkout [<options>] <branch>\"),\n-\t\tN_(\"git checkout [<options>] [<branch>] -- <file>...\"),\n-\t\tNULL,\n+\tstruct option switch_options[] = {\n+\t\tOPT_STRING('c', \"create\", &opts.new_branch, N_(\"branch\"),\n+\t\t\t   N_(\"create and switch to a new branch\")),\n+\t\tOPT_STRING('C', \"force-create\", &opts.new_branch_force, N_(\"branch\"),\n+\t\t\t   N_(\"create/reset and switch to a branch\")),\n+\t\tOPT_BOOL(0, \"guess\", &opts.dwim_new_local_branch,\n+\t\t\t N_(\"second guess 'git switch <no-such-branch>'\")),\n+\t\tOPT_BOOL(0, \"discard-changes\", &opts.discard_changes,\n+\t\t\t N_(\"throw away local modifications\")),\n+\t\tOPT_END()\n \t};\n \n \tstatic const char * const switch_branch_usage[] = {\n@@ -2009,103 +2009,125 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\tNULL,\n \t};\n \n+\topts.dwim_new_local_branch = 1;\n+\topts.accept_ref = 1;\n+\topts.accept_pathspec = 0;\n+\topts.switch_branch_doing_nothing_is_ok = 0;\n+\topts.only_merge_on_switching_branches = 1;\n+\topts.implicit_detach = 0;\n+\topts.can_switch_when_in_progress = 0;\n+\topts.orphan_from_empty_tree = 1;\n+\topts.overlay_mode = -1;\n+\n+\tinit_checkout_opts(&opts, prefix);\n+\n+\toptions = parse_options_dup(switch_options);\n+\toptions = add_common_options(&opts, options);\n+\toptions = add_common_switch_branch_options(&opts, options);\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     switch_branch_usage, 0);\n+\n+\tprepare_common_options(&opts);\n+\tsetup_branch_name_and_info(argc, argv, &opts, &new_branch_info, 'c');\n+\n+\tret = checkout_branch(&opts, &new_branch_info);\n+\n+\tbranch_info_release(&new_branch_info);\n+\tclear_pathspec(&opts.pathspec);\n+\tfree(opts.pathspec_from_file);\n+\tfree(options);\n+\n+\treturn ret;\n+}\n+\n+int cmd_restore(int argc,\n+\t\tconst char **argv,\n+\t\tconst char *prefix,\n+\t\tstruct repository *repo UNUSED)\n+{\n+\tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n+\tstruct option *options;\n+\tstruct branch_info new_branch_info = { 0 };\n+\tint ret;\n+\tstruct option restore_options[] = {\n+\t\tOPT_STRING('s', \"source\", &opts.from_treeish, \"<tree-ish>\",\n+\t\t\t   N_(\"which tree-ish to checkout from\")),\n+\t\tOPT_BOOL('S', \"staged\", &opts.checkout_index,\n+\t\t\t   N_(\"restore the index\")),\n+\t\tOPT_BOOL('W', \"worktree\", &opts.checkout_worktree,\n+\t\t\t   N_(\"restore the working tree (default)\")),\n+\t\tOPT_BOOL(0, \"ignore-unmerged\", &opts.ignore_unmerged,\n+\t\t\t N_(\"ignore unmerged entries\")),\n+\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n+\t\tOPT_END()\n+\t};\n+\n \tstatic const char * const restore_usage[] = {\n \t\tN_(\"git restore [<options>] [--source=<branch>] <file>...\"),\n \t\tNULL,\n \t};\n \n-\tconst char * const *usagestr;\n-\n-\tswitch (which_command) {\n-\tcase CHECKOUT_CHECKOUT:\n-\t\tusagestr = checkout_usage;\n-\t\tbreak;\n-\tcase CHECKOUT_SWITCH:\n-\t\tusagestr = switch_branch_usage;\n-\t\tbreak;\n-\tcase CHECKOUT_RESTORE:\n-\t\tusagestr = restore_usage;\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"no such checkout variant %d\", which_command);\n-\t}\n+\topts.accept_ref = 0;\n+\topts.accept_pathspec = 1;\n+\topts.empty_pathspec_ok = 0;\n+\topts.overlay_mode = 0;\n+\topts.checkout_index = -1;    /* default off */\n+\topts.checkout_worktree = -2; /* default on */\n+\topts.ignore_unmerged_opt = \"--ignore-unmerged\";\n \n-\tinit_checkout_opts(opts, prefix);\n+\tinit_checkout_opts(&opts, prefix);\n \n-\tif (!opts->accept_pathspec && !opts->accept_ref)\n-\t\tBUG(\"make up your mind, you need to take _something_\");\n-\tif (opts->accept_pathspec && opts->accept_ref)\n-\t\tparseopt_flags = PARSE_OPT_KEEP_DASHDASH;\n+\toptions = parse_options_dup(restore_options);\n+\toptions = add_common_options(&opts, options);\n+\toptions = add_checkout_path_options(&opts, options);\n \n \targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     usagestr, parseopt_flags);\n+\t\t\t     restore_usage, 0);\n \n-\tvalidate_path_options(opts);\n-\tprepare_common_options(opts);\n+\tvalidate_path_options(&opts);\n+\tprepare_common_options(&opts);\n \n \t/*\n \t * convenient shortcut: \"git restore --staged [--worktree]\" equals\n \t * \"git restore --staged [--worktree] --source HEAD\"\n \t */\n-\tif (!opts->from_treeish && opts->checkout_index)\n-\t\topts->from_treeish = \"HEAD\";\n-\n-\tif (opts->accept_ref) {\n-\t\tint n = setup_branch_name_and_info(argc, argv, opts,\n-\t\t\t\t\t\t   &new_branch_info, cb_option);\n-\t\targv += n;\n-\t\targc -= n;\n-\t} else if (!opts->accept_ref && opts->from_treeish) {\n+\tif (!opts.from_treeish && opts.checkout_index)\n+\t\topts.from_treeish = \"HEAD\";\n+\n+\tif (opts.from_treeish) {\n \t\tstruct object_id rev;\n \n-\t\tif (repo_get_oid_mb(the_repository, opts->from_treeish, &rev))\n-\t\t\tdie(_(\"could not resolve '%s'\"), opts->from_treeish);\n+\t\tif (repo_get_oid_mb(the_repository, opts.from_treeish, &rev))\n+\t\t\tdie(_(\"could not resolve '%s'\"), opts.from_treeish);\n \n \t\tsetup_new_branch_info_and_source_tree(&new_branch_info,\n-\t\t\t\t\t\t      opts, &rev,\n-\t\t\t\t\t\t      opts->from_treeish);\n+\t\t\t\t\t\t      &opts, &rev,\n+\t\t\t\t\t\t      opts.from_treeish);\n \n-\t\tif (!opts->source_tree)\n-\t\t\tdie(_(\"reference is not a tree: %s\"), opts->from_treeish);\n+\t\tif (!opts.source_tree)\n+\t\t\tdie(_(\"reference is not a tree: %s\"), opts.from_treeish);\n \t}\n \n \tif (argc) {\n-\t\tparse_pathspec(&opts->pathspec, 0,\n-\t\t\t       opts->patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n+\t\tparse_pathspec(&opts.pathspec, 0,\n+\t\t\t       opts.patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n \t\t\t       prefix, argv);\n \n-\t\tif (!opts->pathspec.nr)\n+\t\tif (!opts.pathspec.nr)\n \t\t\tdie(_(\"invalid path specification\"));\n-\n-\t\t/*\n-\t\t * Try to give more helpful suggestion.\n-\t\t * new_branch && argc > 1 will be caught later.\n-\t\t */\n-\t\tif (opts->new_branch && argc == 1 && !new_branch_info.commit)\n-\t\t\tdie(_(\"'%s' is not a commit and a branch '%s' cannot be created from it\"),\n-\t\t\t\targv[0], opts->new_branch);\n-\n-\t\tif (opts->force_detach)\n-\t\t\tdie(_(\"git checkout: --detach does not take a path argument '%s'\"),\n-\t\t\t    argv[0]);\n \t}\n \n-\tparse_pathspec_from_file_options(opts, prefix);\n+\tparse_pathspec_from_file_options(&opts, prefix);\n \n-\tif (!opts->pathspec.nr) {\n-\t\tif (opts->accept_pathspec && !opts->empty_pathspec_ok &&\n-\t\t    !opts->patch_mode)\t/* patch mode is special */\n-\t\t\tdie(_(\"you must specify path(s) to restore\"));\n-\t}\n+\tif (!opts.pathspec.nr && !opts.patch_mode)\n+\t\tdie(_(\"you must specify path(s) to restore\"));\n \n-\tif (opts->patch_mode || opts->pathspec.nr)\n-\t\tret = checkout_paths(opts, &new_branch_info);\n-\telse\n-\t\tret = checkout_branch(opts, &new_branch_info);\n+\tret = checkout_paths(&opts, &new_branch_info);\n \n \tbranch_info_release(&new_branch_info);\n-\tclear_pathspec(&opts->pathspec);\n-\tfree(opts->pathspec_from_file);\n+\tclear_pathspec(&opts.pathspec);\n+\tfree(opts.pathspec_from_file);\n \tfree(options);\n \n \treturn ret;\n@@ -2118,6 +2140,8 @@ int cmd_checkout(int argc,\n {\n \tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n \tstruct option *options;\n+\tstruct branch_info new_branch_info = { 0 };\n+\tint ret, n;\n \tstruct option checkout_options[] = {\n \t\tOPT_STRING('b', NULL, &opts.new_branch, N_(\"branch\"),\n \t\t\t   N_(\"create and checkout a new branch\")),\n@@ -2132,6 +2156,12 @@ int cmd_checkout(int argc,\n \t\tOPT_END()\n \t};\n \n+\tstatic const char * const checkout_usage[] = {\n+\t\tN_(\"git checkout [<options>] <branch>\"),\n+\t\tN_(\"git checkout [<options>] [<branch>] -- <file>...\"),\n+\t\tNULL,\n+\t};\n+\n \topts.dwim_new_local_branch = 1;\n \topts.switch_branch_doing_nothing_is_ok = 1;\n \topts.only_merge_on_switching_branches = 0;\n@@ -2154,84 +2184,55 @@ int cmd_checkout(int argc,\n \t\topts.only_merge_on_switching_branches = 1;\n \t}\n \n+\tinit_checkout_opts(&opts, prefix);\n+\n \toptions = parse_options_dup(checkout_options);\n \toptions = add_common_options(&opts, options);\n \toptions = add_common_switch_branch_options(&opts, options);\n \toptions = add_checkout_path_options(&opts, options);\n \n-\treturn checkout_main(argc, argv, prefix, &opts, options,\n-\t\t\t     CHECKOUT_CHECKOUT);\n-}\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     checkout_usage, PARSE_OPT_KEEP_DASHDASH);\n \n-int cmd_switch(int argc,\n-\t       const char **argv,\n-\t       const char *prefix,\n-\t       struct repository *repo UNUSED)\n-{\n-\tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n-\tstruct option *options = NULL;\n-\tstruct option switch_options[] = {\n-\t\tOPT_STRING('c', \"create\", &opts.new_branch, N_(\"branch\"),\n-\t\t\t   N_(\"create and switch to a new branch\")),\n-\t\tOPT_STRING('C', \"force-create\", &opts.new_branch_force, N_(\"branch\"),\n-\t\t\t   N_(\"create/reset and switch to a branch\")),\n-\t\tOPT_BOOL(0, \"guess\", &opts.dwim_new_local_branch,\n-\t\t\t N_(\"second guess 'git switch <no-such-branch>'\")),\n-\t\tOPT_BOOL(0, \"discard-changes\", &opts.discard_changes,\n-\t\t\t N_(\"throw away local modifications\")),\n-\t\tOPT_END()\n-\t};\n+\tvalidate_path_options(&opts);\n+\tprepare_common_options(&opts);\n \n-\topts.dwim_new_local_branch = 1;\n-\topts.accept_ref = 1;\n-\topts.accept_pathspec = 0;\n-\topts.switch_branch_doing_nothing_is_ok = 0;\n-\topts.only_merge_on_switching_branches = 1;\n-\topts.implicit_detach = 0;\n-\topts.can_switch_when_in_progress = 0;\n-\topts.orphan_from_empty_tree = 1;\n-\topts.overlay_mode = -1;\n+\tn = setup_branch_name_and_info(argc, argv, &opts, &new_branch_info, 'b');\n+\targv += n;\n+\targc -= n;\n \n-\toptions = parse_options_dup(switch_options);\n-\toptions = add_common_options(&opts, options);\n-\toptions = add_common_switch_branch_options(&opts, options);\n+\tif (argc) {\n+\t\tparse_pathspec(&opts.pathspec, 0,\n+\t\t\t       opts.patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n+\t\t\t       prefix, argv);\n \n-\treturn checkout_main(argc, argv, prefix, &opts, options,\n-\t\t\t     CHECKOUT_SWITCH);\n-}\n+\t\tif (!opts.pathspec.nr)\n+\t\t\tdie(_(\"invalid path specification\"));\n \n-int cmd_restore(int argc,\n-\t\tconst char **argv,\n-\t\tconst char *prefix,\n-\t\tstruct repository *repo UNUSED)\n-{\n-\tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n-\tstruct option *options;\n-\tstruct option restore_options[] = {\n-\t\tOPT_STRING('s', \"source\", &opts.from_treeish, \"<tree-ish>\",\n-\t\t\t   N_(\"which tree-ish to checkout from\")),\n-\t\tOPT_BOOL('S', \"staged\", &opts.checkout_index,\n-\t\t\t   N_(\"restore the index\")),\n-\t\tOPT_BOOL('W', \"worktree\", &opts.checkout_worktree,\n-\t\t\t   N_(\"restore the working tree (default)\")),\n-\t\tOPT_BOOL(0, \"ignore-unmerged\", &opts.ignore_unmerged,\n-\t\t\t N_(\"ignore unmerged entries\")),\n-\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n-\t\tOPT_END()\n-\t};\n+\t\t/*\n+\t\t * Try to give more helpful suggestion.\n+\t\t * new_branch && argc > 1 will be caught later.\n+\t\t */\n+\t\tif (opts.new_branch && argc == 1 && !new_branch_info.commit)\n+\t\t\tdie(_(\"'%s' is not a commit and a branch '%s' cannot be created from it\"),\n+\t\t\t\targv[0], opts.new_branch);\n \n-\topts.accept_ref = 0;\n-\topts.accept_pathspec = 1;\n-\topts.empty_pathspec_ok = 0;\n-\topts.overlay_mode = 0;\n-\topts.checkout_index = -1;    /* default off */\n-\topts.checkout_worktree = -2; /* default on */\n-\topts.ignore_unmerged_opt = \"--ignore-unmerged\";\n+\t\tif (opts.force_detach)\n+\t\t\tdie(_(\"git checkout: --detach does not take a path argument '%s'\"),\n+\t\t\t    argv[0]);\n+\t}\n \n-\toptions = parse_options_dup(restore_options);\n-\toptions = add_common_options(&opts, options);\n-\toptions = add_checkout_path_options(&opts, options);\n+\tparse_pathspec_from_file_options(&opts, prefix);\n \n-\treturn checkout_main(argc, argv, prefix, &opts, options,\n-\t\t\t     CHECKOUT_RESTORE);\n+\tif (opts.patch_mode || opts.pathspec.nr)\n+\t\tret = checkout_paths(&opts, &new_branch_info);\n+\telse\n+\t\tret = checkout_branch(&opts, &new_branch_info);\n+\n+\tbranch_info_release(&new_branch_info);\n+\tclear_pathspec(&opts.pathspec);\n+\tfree(opts.pathspec_from_file);\n+\tfree(options);\n+\n+\treturn ret;\n }\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551443","messageId":"20260828225206.310500-8-gitster@pobox.com","threadId":"66230","inReplyTo":"20260828225206.310500-1-gitster@pobox.com","subject":"[PATCH 7/8] checkout: wrap overly long lines","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:52:05Z","receivedAt":"2026-08-28T22:52:20Z","isPatch":true,"body":"So far, the patches in this series have tried to leave the original\ncode intact as much as possible when moving it, to make the\nrefactoring easier to review.\n\nHowever, there are quite a few overly long lines that are hard to\nread.  There are also several manual checks for mutually\nincompatible options where die_for_incompatible_optN() could be\nused instead.\n\nNow that most of the refactoring is complete, tidy up these warts to\nfinish off the series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 54 +++++++++++++++++++++++++++++-----------------\n 1 file changed, 34 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex b18515ac7f..f13d70b224 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1864,15 +1864,18 @@ static void validate_path_options(struct checkout_opts *opts)\n \n \tif (!opts->patch_mode) {\n \t\tif (opts->patch_context != -1)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--unified\", \"--patch\");\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t\t    \"--unified\", \"--patch\");\n \t\tif (opts->patch_interhunk_context != -1)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--inter-hunk-context\", \"--patch\");\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t\t    \"--inter-hunk-context\", \"--patch\");\n \t\tif (!opts->auto_advance)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--no-auto-advance\", \"--patch\");\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t\t    \"--no-auto-advance\", \"--patch\");\n \t}\n \n-\tif (opts->overlay_mode == 1 && opts->patch_mode)\n-\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"-p\", \"--overlay\");\n+\tdie_for_incompatible_opt2(opts->overlay_mode == 1, \"--overlay\",\n+\t\t\t\t  opts->patch_mode, \"-p\");\n \n \tif (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {\n \t\tif (opts->checkout_index < 0)\n@@ -1914,19 +1917,20 @@ static void parse_pathspec_from_file_options(struct checkout_opts *opts,\n {\n \tif (opts->pathspec_from_file) {\n \t\tif (opts->pathspec.nr)\n-\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"), \"--pathspec-from-file\");\n+\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"),\n+\t\t\t    \"--pathspec-from-file\");\n \n-\t\tif (opts->force_detach)\n-\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--detach\");\n+\t\tdie_for_incompatible_opt2(opts->force_detach, \"--detach\",\n+\t\t\t\t\t  1, \"--pathspec-from-file\");\n \n-\t\tif (opts->patch_mode)\n-\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--patch\");\n-\n-\t\tparse_pathspec_file(&opts->pathspec, 0,\n-\t\t\t\t    0,\n-\t\t\t\t    prefix, opts->pathspec_from_file, opts->pathspec_file_nul);\n+\t\tdie_for_incompatible_opt2(opts->patch_mode, \"--patch\",\n+\t\t\t\t\t  1, \"--pathspec-from-file\");\n+\t\tparse_pathspec_file(&opts->pathspec, 0, 0,\n+\t\t\t\t    prefix, opts->pathspec_from_file,\n+\t\t\t\t    opts->pathspec_file_nul);\n \t} else if (opts->pathspec_file_nul) {\n-\t\tdie(_(\"the option '%s' requires '%s'\"), \"--pathspec-file-nul\", \"--pathspec-from-file\");\n+\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t    \"--pathspec-file-nul\", \"--pathspec-from-file\");\n \t}\n \n \topts->pathspec.recursive = 1;\n@@ -1934,9 +1938,17 @@ static void parse_pathspec_from_file_options(struct checkout_opts *opts,\n \n static void validate_branch_options(struct checkout_opts *opts, char cb_option)\n {\n-\tif ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)\n-\t\tdie(_(\"options '-%c', '-%c', and '%s' cannot be used together\"),\n-\t\t\tcb_option, toupper(cb_option), \"--orphan\");\n+\tchar new_branch_opt[] = \"-c\";\n+\tchar new_branch_force_opt[] = \"-C\";\n+\n+\tnew_branch_opt[1] = cb_option;\n+\tnew_branch_force_opt[1] = toupper(cb_option);\n+\n+\tdie_for_incompatible_opt3(opts->new_branch,\n+\t\t\t\t  new_branch_opt,\n+\t\t\t\t  opts->new_new_branch_force,\n+\t\t\t\t  new_branch_force_opt,\n+\t\t\t\t  opts->new_orphan_branch, \"--orphan\");\n \n \tif (opts->new_branch_force)\n \t\topts->new_branch = opts->new_branch_force;\n@@ -2147,10 +2159,12 @@ int cmd_checkout(int argc,\n \t\t\t   N_(\"create and checkout a new branch\")),\n \t\tOPT_STRING('B', NULL, &opts.new_branch_force, N_(\"branch\"),\n \t\t\t   N_(\"create/reset and checkout a branch\")),\n-\t\tOPT_BOOL('l', NULL, &opts.new_branch_log, N_(\"create reflog for new branch\")),\n+\t\tOPT_BOOL('l', NULL, &opts.new_branch_log,\n+\t\t\t N_(\"create reflog for new branch\")),\n \t\tOPT_BOOL(0, \"guess\", &opts.dwim_new_local_branch,\n \t\t\t N_(\"second guess 'git checkout <no-such-branch>' (default)\")),\n-\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode (default)\")),\n+\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode,\n+\t\t\t N_(\"use overlay mode (default)\")),\n \t\tOPT_BOOL(0, \"auto-advance\", &opts.auto_advance,\n \t\t\t N_(\"auto advance to the next file when selecting hunks interactively\")),\n \t\tOPT_END()\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551444","messageId":"20260828225206.310500-9-gitster@pobox.com","threadId":"66230","inReplyTo":"20260828225206.310500-1-gitster@pobox.com","subject":"[PATCH 8/8] checkout: move post_checkout_hook() to checkout.c","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:52:06Z","receivedAt":"2026-08-28T22:52:21Z","isPatch":true,"body":"post_checkout_hook() in builtin/checkout.c runs the 'post-checkout' hook\nafter switching branches or checking out paths.\n\nMove post_checkout_hook() to checkout.c and declare it in checkout.h\nso that other subsystems can invoke the post-checkout hook without\ndepending on builtin/checkout.c.\n\nThis step in the series is entirely optional and is here primarily\nfor illustration.  We may later want to teach 'git worktree' to\ntrigger the 'post-checkout' hook, for example, in which case such\nlibification may turn out to be useful.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 18 ------------------\n checkout.c         | 22 ++++++++++++++++++++++\n checkout.h         |  8 ++++++++\n 3 files changed, 30 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex f13d70b224..b13e2ff205 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -124,24 +124,6 @@ static void branch_info_release(struct branch_info *info)\n \tfree(info->checkout);\n }\n \n-static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,\n-\t\t\t      int changed)\n-{\n-\tstruct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;\n-\n-\t/*\n-\t * \"new_commit\" can be NULL when checking out from the index before\n-\t * a commit exists.\n-\t */\n-\tstrvec_pushl(&opt.args,\n-\t\t     oid_to_hex(old_commit ? &old_commit->object.oid : null_oid(the_hash_algo)),\n-\t\t     oid_to_hex(new_commit ? &new_commit->object.oid : null_oid(the_hash_algo)),\n-\t\t     changed ? \"1\" : \"0\",\n-\t\t     NULL);\n-\n-\treturn run_hooks_opt(the_repository, \"post-checkout\", &opt);\n-}\n-\n /*\n  * Handle a tree object and determine if we need to recurse into the\n  * tree (READ_TREE_RECURSIVE) or skip it (0).\ndiff --git a/checkout.c b/checkout.c\nindex 1588b116ee..d007648f50 100644\n--- a/checkout.c\n+++ b/checkout.c\n@@ -1,6 +1,9 @@\n #define USE_THE_REPOSITORY_VARIABLE\n \n #include \"git-compat-util.h\"\n+#include \"commit.h\"\n+#include \"hex.h\"\n+#include \"hook.h\"\n #include \"object-name.h\"\n #include \"remote.h\"\n #include \"refspec.h\"\n@@ -8,6 +11,7 @@\n #include \"checkout.h\"\n #include \"config.h\"\n #include \"strbuf.h\"\n+#include \"strvec.h\"\n \n struct tracking_name_data {\n \t/* const */ char *src_ref;\n@@ -73,3 +77,21 @@ char *unique_tracking_name(const char *name, struct object_id *oid,\n \t}\n \treturn NULL;\n }\n+\n+int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,\n+\t\t       int changed)\n+{\n+\tstruct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;\n+\n+\t/*\n+\t * \"new_commit\" can be NULL when checking out from the index before\n+\t * a commit exists.\n+\t */\n+\tstrvec_pushl(&opt.args,\n+\t\t     oid_to_hex(old_commit ? &old_commit->object.oid : null_oid(the_hash_algo)),\n+\t\t     oid_to_hex(new_commit ? &new_commit->object.oid : null_oid(the_hash_algo)),\n+\t\t     changed ? \"1\" : \"0\",\n+\t\t     NULL);\n+\n+\treturn run_hooks_opt(the_repository, \"post-checkout\", &opt);\n+}\ndiff --git a/checkout.h b/checkout.h\nindex 55920e7aeb..9c2f2449dc 100644\n--- a/checkout.h\n+++ b/checkout.h\n@@ -3,6 +3,8 @@\n \n #include \"hash.h\"\n \n+struct commit;\n+\n /*\n  * Check if the branch name uniquely matches a branch name on a remote\n  * tracking branch.  Return the name of the remote if such a branch\n@@ -12,4 +14,10 @@ char *unique_tracking_name(const char *name,\n \t\t\t   struct object_id *oid,\n \t\t\t   int *dwim_remotes_matched);\n \n+/*\n+ * Run the post-checkout hook.\n+ */\n+int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,\n+\t\t       int changed);\n+\n #endif /* CHECKOUT_H */\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551445","messageId":"xmqqcxv13ldw.fsf@gitster.g","threadId":"66230","inReplyTo":"20260828225206.310500-8-gitster@pobox.com","subject":"Re: [PATCH 7/8] checkout: wrap overly long lines","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:55:55Z","receivedAt":"2026-08-28T22:55:58Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> So far, the patches in this series have tried to leave the original\n> code intact as much as possible when moving it, to make the\n> refactoring easier to review.\n>\n> However, there are quite a few overly long lines that are hard to\n> read.  There are also several manual checks for mutually\n> incompatible options where die_for_incompatible_optN() could be\n> used instead.\n>\n> Now that most of the refactoring is complete, tidy up these warts to\n> finish off the series.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/checkout.c | 54 +++++++++++++++++++++++++++++-----------------\n>  1 file changed, 34 insertions(+), 20 deletions(-)\n> ...\n> +\tdie_for_incompatible_opt3(opts->new_branch,\n> +\t\t\t\t  new_branch_opt,\n> +\t\t\t\t  opts->new_new_branch_force,\n\nEditor slip.  This should of course be \"opts->new_branch_force\".\n\n> +\t\t\t\t  new_branch_force_opt,\n> +\t\t\t\t  opts->new_orphan_branch, \"--orphan\");\n"},{"id":"551446","messageId":"xmqq7bl93lbk.fsf@gitster.g","threadId":"66230","inReplyTo":"20260828225206.310500-9-gitster@pobox.com","subject":"Re: [PATCH 8/8] checkout: move post_checkout_hook() to checkout.c","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-28T22:57:19Z","receivedAt":"2026-08-28T22:57:21Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> +int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,\n> +\t\t       int changed)\n> +{\n> +\tstruct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;\n> +\n> +\t/*\n> +\t * \"new_commit\" can be NULL when checking out from the index before\n> +\t * a commit exists.\n> +\t */\n> +\tstrvec_pushl(&opt.args,\n> +\t\t     oid_to_hex(old_commit ? &old_commit->object.oid : null_oid(the_hash_algo)),\n> +\t\t     oid_to_hex(new_commit ? &new_commit->object.oid : null_oid(the_hash_algo)),\n> +\t\t     changed ? \"1\" : \"0\",\n> +\t\t     NULL);\n> +\n> +\treturn run_hooks_opt(the_repository, \"post-checkout\", &opt);\n> +}\n\nNot a very good illustration.  We should teach the caller to pass\n\"struct repository *repo\" to this function, and then teach this\nfunction to learn what hash algorithm to use from the given\nrepository instance.\n\n> +/*\n> + * Run the post-checkout hook.\n> + */\n> +int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,\n> +\t\t       int changed);\n> +\n>  #endif /* CHECKOUT_H */\n"},{"id":"551449","messageId":"xmqqse3x1y20.fsf@gitster.g","threadId":"66230","inReplyTo":"xmqq7bl93lbk.fsf@gitster.g","subject":"Re: [PATCH 8/8] checkout: move post_checkout_hook() to checkout.c","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-29T02:05:11Z","receivedAt":"2026-08-29T02:05:14Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Not a very good illustration.  We should teach the caller to pass\n> \"struct repository *repo\" to this function, and then teach this\n> function to learn what hash algorithm to use from the given\n> repository instance.\n\nI've locally amended this step like so.\n\nThe dependency on 'the_repository' has been removed.  While OK when\nthe helper was in builtin/checkout.c as an integral part of 'git\ncheckout' (and 'git restore'), this is no longer true for a common\nutility function.  So it now takes a pointer to 'struct repository'\nand uses its associated hash algorithm.\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 9771c848c5..c6e29e9526 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -124,24 +124,6 @@ static void branch_info_release(struct branch_info *info)\n \tfree(info->checkout);\n }\n \n-static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,\n-\t\t\t      int changed)\n-{\n-\tstruct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;\n-\n-\t/*\n-\t * \"new_commit\" can be NULL when checking out from the index before\n-\t * a commit exists.\n-\t */\n-\tstrvec_pushl(&opt.args,\n-\t\t     oid_to_hex(old_commit ? &old_commit->object.oid : null_oid(the_hash_algo)),\n-\t\t     oid_to_hex(new_commit ? &new_commit->object.oid : null_oid(the_hash_algo)),\n-\t\t     changed ? \"1\" : \"0\",\n-\t\t     NULL);\n-\n-\treturn run_hooks_opt(the_repository, \"post-checkout\", &opt);\n-}\n-\n /*\n  * Handle a tree object and determine if we need to recurse into the\n  * tree (READ_TREE_RECURSIVE) or skip it (0).\n@@ -718,7 +700,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\t   &rev, NULL);\n \thead = lookup_commit_reference_gently(the_repository, &rev, 1);\n \n-\terrs |= post_checkout_hook(head, head, 0);\n+\terrs |= post_checkout_hook(the_repository, head, head, 0);\n \treturn errs;\n }\n \n@@ -1273,7 +1255,8 @@ static int switch_branches(const struct checkout_opts *opts,\n \t\t}\n \t}\n \n-\tret = post_checkout_hook(old_branch_info.commit, new_branch_info->commit, 1);\n+\tret = post_checkout_hook(the_repository,\n+\t\t\t\t old_branch_info.commit, new_branch_info->commit, 1);\n \tbranch_info_release(&old_branch_info);\n \tstrbuf_release(&old_commit_shortname);\n \tstrbuf_release(&autostash_msg);\ndiff --git a/checkout.c b/checkout.c\nindex 1588b116ee..28c5c18d96 100644\n--- a/checkout.c\n+++ b/checkout.c\n@@ -1,6 +1,9 @@\n #define USE_THE_REPOSITORY_VARIABLE\n \n #include \"git-compat-util.h\"\n+#include \"commit.h\"\n+#include \"hex.h\"\n+#include \"hook.h\"\n #include \"object-name.h\"\n #include \"remote.h\"\n #include \"refspec.h\"\n@@ -8,6 +11,7 @@\n #include \"checkout.h\"\n #include \"config.h\"\n #include \"strbuf.h\"\n+#include \"strvec.h\"\n \n struct tracking_name_data {\n \t/* const */ char *src_ref;\n@@ -73,3 +77,27 @@ char *unique_tracking_name(const char *name, struct object_id *oid,\n \t}\n \treturn NULL;\n }\n+\n+int post_checkout_hook(struct repository *repo,\n+\t\t       struct commit *old_commit, struct commit *new_commit,\n+\t\t       int changed)\n+{\n+\tstruct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;\n+\tconst struct git_hash_algo *hash_algo = repo->hash_algo;\n+\n+\t/*\n+\t * \"new_commit\" can be NULL when checking out from the index before\n+\t * a commit exists.\n+\t */\n+\tstrvec_pushl(&opt.args,\n+\t\t     oid_to_hex(old_commit\n+\t\t\t\t? &old_commit->object.oid\n+\t\t\t\t: null_oid(hash_algo)),\n+\t\t     oid_to_hex(new_commit ?\n+\t\t\t\t&new_commit->object.oid\n+\t\t\t\t: null_oid(hash_algo)),\n+\t\t     changed ? \"1\" : \"0\",\n+\t\t     NULL);\n+\n+\treturn run_hooks_opt(repo, \"post-checkout\", &opt);\n+}\ndiff --git a/checkout.h b/checkout.h\nindex 55920e7aeb..6d8d2c2bab 100644\n--- a/checkout.h\n+++ b/checkout.h\n@@ -3,6 +3,9 @@\n \n #include \"hash.h\"\n \n+struct commit;\n+struct repository;\n+\n /*\n  * Check if the branch name uniquely matches a branch name on a remote\n  * tracking branch.  Return the name of the remote if such a branch\n@@ -12,4 +15,11 @@ char *unique_tracking_name(const char *name,\n \t\t\t   struct object_id *oid,\n \t\t\t   int *dwim_remotes_matched);\n \n+/*\n+ * Run the post-checkout hook.\n+ */\n+int post_checkout_hook(struct repository *,\n+\t\t       struct commit *old_commit, struct commit *new_commit,\n+\t\t       int changed);\n+\n #endif /* CHECKOUT_H */\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551450","messageId":"xmqqo6el1xz0.fsf@gitster.g","threadId":"66230","inReplyTo":"xmqqcxv13ldw.fsf@gitster.g","subject":"Re: [PATCH 7/8] checkout: wrap overly long lines","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-29T02:06:59Z","receivedAt":"2026-08-29T02:07:01Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> +\tdie_for_incompatible_opt3(opts->new_branch,\n>> +\t\t\t\t  new_branch_opt,\n>> +\t\t\t\t  opts->new_new_branch_force,\n>\n> Editor slip.  This should of course be \"opts->new_branch_force\".\n\nNot just that, but some uses of die_for_incompatible_optN() changed\nthe order of the options in the error message.  Here is a fixed\nversion.\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex b18515ac7f..9771c848c5 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1864,15 +1864,18 @@ static void validate_path_options(struct checkout_opts *opts)\n \n \tif (!opts->patch_mode) {\n \t\tif (opts->patch_context != -1)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--unified\", \"--patch\");\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t\t    \"--unified\", \"--patch\");\n \t\tif (opts->patch_interhunk_context != -1)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--inter-hunk-context\", \"--patch\");\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t\t    \"--inter-hunk-context\", \"--patch\");\n \t\tif (!opts->auto_advance)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--no-auto-advance\", \"--patch\");\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t\t    \"--no-auto-advance\", \"--patch\");\n \t}\n \n-\tif (opts->overlay_mode == 1 && opts->patch_mode)\n-\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"-p\", \"--overlay\");\n+\tdie_for_incompatible_opt2(opts->patch_mode, \"-p\",\n+\t\t\t\t  opts->overlay_mode == 1, \"--overlay\");\n \n \tif (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {\n \t\tif (opts->checkout_index < 0)\n@@ -1914,19 +1917,25 @@ static void parse_pathspec_from_file_options(struct checkout_opts *opts,\n {\n \tif (opts->pathspec_from_file) {\n \t\tif (opts->pathspec.nr)\n-\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"), \"--pathspec-from-file\");\n-\n-\t\tif (opts->force_detach)\n-\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--detach\");\n-\n-\t\tif (opts->patch_mode)\n-\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--patch\");\n-\n-\t\tparse_pathspec_file(&opts->pathspec, 0,\n-\t\t\t\t    0,\n-\t\t\t\t    prefix, opts->pathspec_from_file, opts->pathspec_file_nul);\n+\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"),\n+\t\t\t    \"--pathspec-from-file\");\n+\n+\t\tdie_for_incompatible_opt2(!!opts->pathspec_from_file,\n+\t\t\t\t\t  \"--pathspec-from-file\",\n+\t\t\t\t\t  opts->force_detach,\n+\t\t\t\t\t  \"--detach\");\n+\n+\t\tdie_for_incompatible_opt2(!!opts->pathspec_from_file,\n+\t\t\t\t\t  \"--pathspec-from-file\",\n+\t\t\t\t\t  opts->patch_mode,\n+\t\t\t\t\t  \"--patch\");\n+\n+\t\tparse_pathspec_file(&opts->pathspec, 0, 0,\n+\t\t\t\t    prefix, opts->pathspec_from_file,\n+\t\t\t\t    opts->pathspec_file_nul);\n \t} else if (opts->pathspec_file_nul) {\n-\t\tdie(_(\"the option '%s' requires '%s'\"), \"--pathspec-file-nul\", \"--pathspec-from-file\");\n+\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t    \"--pathspec-file-nul\", \"--pathspec-from-file\");\n \t}\n \n \topts->pathspec.recursive = 1;\n@@ -1934,9 +1943,17 @@ static void parse_pathspec_from_file_options(struct checkout_opts *opts,\n \n static void validate_branch_options(struct checkout_opts *opts, char cb_option)\n {\n-\tif ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)\n-\t\tdie(_(\"options '-%c', '-%c', and '%s' cannot be used together\"),\n-\t\t\tcb_option, toupper(cb_option), \"--orphan\");\n+\tchar new_branch_opt[] = \"-c\";\n+\tchar new_branch_force_opt[] = \"-C\";\n+\n+\tnew_branch_opt[1] = cb_option;\n+\tnew_branch_force_opt[1] = toupper(cb_option);\n+\n+\tdie_for_incompatible_opt3(!!opts->new_branch,\n+\t\t\t\t  new_branch_opt,\n+\t\t\t\t  !!opts->new_branch_force,\n+\t\t\t\t  new_branch_force_opt,\n+\t\t\t\t  !!opts->new_orphan_branch, \"--orphan\");\n \n \tif (opts->new_branch_force)\n \t\topts->new_branch = opts->new_branch_force;\n@@ -2147,10 +2164,12 @@ int cmd_checkout(int argc,\n \t\t\t   N_(\"create and checkout a new branch\")),\n \t\tOPT_STRING('B', NULL, &opts.new_branch_force, N_(\"branch\"),\n \t\t\t   N_(\"create/reset and checkout a branch\")),\n-\t\tOPT_BOOL('l', NULL, &opts.new_branch_log, N_(\"create reflog for new branch\")),\n+\t\tOPT_BOOL('l', NULL, &opts.new_branch_log,\n+\t\t\t N_(\"create reflog for new branch\")),\n \t\tOPT_BOOL(0, \"guess\", &opts.dwim_new_local_branch,\n \t\t\t N_(\"second guess 'git checkout <no-such-branch>' (default)\")),\n-\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode (default)\")),\n+\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode,\n+\t\t\t N_(\"use overlay mode (default)\")),\n \t\tOPT_BOOL(0, \"auto-advance\", &opts.auto_advance,\n \t\t\t N_(\"auto advance to the next file when selecting hunks interactively\")),\n \t\tOPT_END()\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551462","messageId":"CALnO6CC9ModYeMp+D6kSDxW9iPgn3Hy1wY+0Cv-3DyKJOwAWkw@mail.gmail.com","threadId":"66230","inReplyTo":"xmqqh5kd3lm3.fsf@gitster.g","subject":"Re: [PATCH] builtin: replace the_repository parameter in is_bare_repository()","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-29T13:24:30Z","receivedAt":"2026-08-29T13:24:42Z","isPatch":true,"body":"On Fri, Aug 28, 2026 at 6:51 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n>\n> >> > Hm. What if a program wants to do « exactly what ‘git switch’ does\n> >> > » sans shelling out?\n> >>\n> >> Instead of cheating, properly factor out reusable part from\n> >> cmd_checkout() into a set of libified routines, and make both\n> >> cmd_checkout() and cmd_switch() to call them\n> >>\n> >> An approach like that would help \"libify\" things.  libifying is not\n> >> just reducing dependence of globals.\n> >>\n> >> Calling main() from something else is not a libification.\n> >\n> > Sensible. Thanks!\n>\n> I actually answered a wrong question though ;-)\n>\n> The way cmd_switch() and cmd_restore() were introduced by sharing\n> what used to serve cmd_checkout() was serviceable, but ugly.  Had we\n> started from separate implementations for 'switch' and 'restore'\n> that were later merged into 'checkout', we would not have ended up\n> with a design centered on a single monolithic choke point like\n> checkout_main().\n>\n> That is what I meant by \"cheating instead of refactoring reusable\n> parts\".  However, that is not directly relevant to your example.\n>\n> It is an anti-pattern to call the top-level implementation of 'git\n> foo' in cmd_foo() directly from cmd_bar(), since these cmd_foo()\n> functions are like main() in ordinary programs, performing one-time\n> initialization (such as git_config() calls) and finalization that\n> cannot be repeated.  To help our codebase, as well as the use case\n> you imagined in your message, it would help to trim down these\n> non-reusable cmd_foo() implementations by turning them into mere\n> orchestrators that call refactored helper functions.  Such a change\n> would put cmd_foo() and a client that wants to reuse 'git switch'\n> functionality on the same footing, allowing more of our code to be\n> used in different contexts.  I think that is what people mean by\n> the \"libification\" effort.\n\nYes, I think such an organization would end up being quite lovely.\n\n-- \nD. Ben Knoble\n"},{"id":"551476","messageId":"20260830204835.1040408-1-gitster@pobox.com","threadId":"66230","inReplyTo":"20260828225206.310500-1-gitster@pobox.com","subject":"[PATCH v2 0/8] More sensible checkout/switch/restore code refactoring","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T20:48:27Z","receivedAt":"2026-08-30T20:48:37Z","isPatch":true,"body":"In the beginning, there was only 'git checkout'.  We then introduced\n'git switch' and 'git restore', borrowing as much original code as\npossible from the implementation of 'git checkout'.\n\nUnfortunately, this has left the code in a strange shape.  Had we\nstarted from separate implementations for 'switch' and 'restore'\nthen later merged them into 'checkout', we would not have arrived at\na design where three front-end routines, cmd_checkout(),\ncmd_switch(), and cmd_restore(), funnel into a single monolithic\nchoke point in checkout_main(), which then determines whether we are\nchecking out a branch or paths, and dispatches to checkout_branch()\nor checkout_paths().\n\nThis series is an attempt to repartition the code into a better\nshape.  Because checkout_branch() and checkout_paths() already exist\nas two reusable helper functions, with sufficient refactoring of\ncheckout_main(), the two newer entry points, cmd_switch() and\ncmd_restore(), can parse command-line arguments and configuration\nsettings and jump straight into checkout_branch() or\ncheckout_paths() respectively, without worrying about the other path.\n\nOf course, cmd_checkout() still needs to decide whether to check out\na branch or a set of paths and dispatch between these two backends.\n\nThe series begins with three fairly isolated cleanups that are worth\nmaking on their own, even if we do not follow through with the rest\nof the series.  Patches 4 and 5 then refactor various utility\nfunctions out of existing code paths, and patch 6 uses them to\nrewrite the three top-level command entry points to call these\nfunctions without going through checkout_main().  Patch 7 is a\nstyle-only fix done after the dust settles, which was deliberately\nkept separate to simplify review.\n\nThe final step moves one helper utility out of builtin/checkout.c to\ntop-level checkout.c as an illustration of the libification discussed\nin our recent threads.\n\nNote that I consider this a fairly early and rough draft for\nillustration only.  There may be a few topics that touch 'git\ncheckout', and a refactoring of this scale might adversely impact\nthem, so I will not even merge these patches to 'seen'.\n\n 1/8: checkout: pass cb_option explicitly to branch name parsers\n 2/8: checkout: validate new branch name in checkout_branch()\n 3/8: checkout: validate stage and merge option compatibility in\n        checkout_paths()\n 4/8: checkout: extract option validation and pathspec helpers\n 5/8: checkout: extract branch setup and tracking helpers\n 6/8: checkout: restructure switch, restore, and checkout\n        entrypoints\n 7/8: checkout: wrap overly long lines\n 8/8: checkout: move post_checkout_hook() to checkout.c\n\nChanges since the initial version are:\n\n* [7/8] corrects the arguments to die_for_incompatible_optN() to\n  preserve similarity to the original as well as the output\n  message.\n\n* [8/8] corrects the function signature of post_checkout_hook() to\n  make it independent of 'the_repository'.\n\n\n builtin/checkout.c | 557 +++++++++++++++++++++++----------------------\n checkout.c         |  28 +++\n checkout.h         |  10 +\n 3 files changed, 328 insertions(+), 267 deletions(-)\n\nRange-diff against v1:\n1:  346f98225a = 1:  346f98225a checkout: pass cb_option explicitly to branch name parsers\n2:  51320f57c9 = 2:  51320f57c9 checkout: validate new branch name in checkout_branch()\n3:  6c321a88d6 = 3:  6c321a88d6 checkout: validate stage and merge option compatibility in checkout_paths()\n4:  4eefe85ca7 = 4:  4eefe85ca7 checkout: extract option validation and pathspec helpers\n5:  0154ed2547 = 5:  0154ed2547 checkout: extract branch setup and tracking helpers\n6:  c431b36468 = 6:  c431b36468 checkout: restructure switch, restore, and checkout entrypoints\n7:  9fdd854d1b ! 7:  c8869d0b6a checkout: wrap overly long lines\n    @@ builtin/checkout.c: static void validate_path_options(struct checkout_opts *opts\n      \n     -\tif (opts->overlay_mode == 1 && opts->patch_mode)\n     -\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"-p\", \"--overlay\");\n    -+\tdie_for_incompatible_opt2(opts->overlay_mode == 1, \"--overlay\",\n    -+\t\t\t\t  opts->patch_mode, \"-p\");\n    ++\tdie_for_incompatible_opt2(opts->patch_mode, \"-p\",\n    ++\t\t\t\t  opts->overlay_mode == 1, \"--overlay\");\n      \n      \tif (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {\n      \t\tif (opts->checkout_index < 0)\n    @@ builtin/checkout.c: static void parse_pathspec_from_file_options(struct checkout\n      \tif (opts->pathspec_from_file) {\n      \t\tif (opts->pathspec.nr)\n     -\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"), \"--pathspec-from-file\");\n    -+\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"),\n    -+\t\t\t    \"--pathspec-from-file\");\n    - \n    +-\n     -\t\tif (opts->force_detach)\n     -\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--detach\");\n    -+\t\tdie_for_incompatible_opt2(opts->force_detach, \"--detach\",\n    -+\t\t\t\t\t  1, \"--pathspec-from-file\");\n    - \n    +-\n     -\t\tif (opts->patch_mode)\n     -\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--patch\");\n     -\n     -\t\tparse_pathspec_file(&opts->pathspec, 0,\n     -\t\t\t\t    0,\n     -\t\t\t\t    prefix, opts->pathspec_from_file, opts->pathspec_file_nul);\n    -+\t\tdie_for_incompatible_opt2(opts->patch_mode, \"--patch\",\n    -+\t\t\t\t\t  1, \"--pathspec-from-file\");\n    ++\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"),\n    ++\t\t\t    \"--pathspec-from-file\");\n    ++\n    ++\t\tdie_for_incompatible_opt2(!!opts->pathspec_from_file,\n    ++\t\t\t\t\t  \"--pathspec-from-file\",\n    ++\t\t\t\t\t  opts->force_detach,\n    ++\t\t\t\t\t  \"--detach\");\n    ++\n    ++\t\tdie_for_incompatible_opt2(!!opts->pathspec_from_file,\n    ++\t\t\t\t\t  \"--pathspec-from-file\",\n    ++\t\t\t\t\t  opts->patch_mode,\n    ++\t\t\t\t\t  \"--patch\");\n    ++\n     +\t\tparse_pathspec_file(&opts->pathspec, 0, 0,\n     +\t\t\t\t    prefix, opts->pathspec_from_file,\n     +\t\t\t\t    opts->pathspec_file_nul);\n    @@ builtin/checkout.c: static void parse_pathspec_from_file_options(struct checkout\n     +\tnew_branch_opt[1] = cb_option;\n     +\tnew_branch_force_opt[1] = toupper(cb_option);\n     +\n    -+\tdie_for_incompatible_opt3(opts->new_branch,\n    ++\tdie_for_incompatible_opt3(!!opts->new_branch,\n     +\t\t\t\t  new_branch_opt,\n    -+\t\t\t\t  opts->new_new_branch_force,\n    ++\t\t\t\t  !!opts->new_branch_force,\n     +\t\t\t\t  new_branch_force_opt,\n    -+\t\t\t\t  opts->new_orphan_branch, \"--orphan\");\n    ++\t\t\t\t  !!opts->new_orphan_branch, \"--orphan\");\n      \n      \tif (opts->new_branch_force)\n      \t\topts->new_branch = opts->new_branch_force;\n8:  295188d521 ! 8:  b5b31c33ae checkout: move post_checkout_hook() to checkout.c\n    @@ Commit message\n         so that other subsystems can invoke the post-checkout hook without\n         depending on builtin/checkout.c.\n     \n    +    Remove the dependency on 'the_repository'.  While OK when the helper\n    +    was in builtin/checkout.c as an integral part of 'git checkout' (and\n    +    'git restore'), this is no longer true for a common utility\n    +    function.  Have it take a pointer to 'struct repository' and use its\n    +    associated hash algorithm.\n    +\n         This step in the series is entirely optional and is here primarily\n         for illustration.  We may later want to teach 'git worktree' to\n         trigger the 'post-checkout' hook, for example, in which case such\n    @@ builtin/checkout.c: static void branch_info_release(struct branch_info *info)\n      /*\n       * Handle a tree object and determine if we need to recurse into the\n       * tree (READ_TREE_RECURSIVE) or skip it (0).\n    +@@ builtin/checkout.c: static int checkout_paths(const struct checkout_opts *opts,\n    + \t\t\t   &rev, NULL);\n    + \thead = lookup_commit_reference_gently(the_repository, &rev, 1);\n    + \n    +-\terrs |= post_checkout_hook(head, head, 0);\n    ++\terrs |= post_checkout_hook(the_repository, head, head, 0);\n    + \treturn errs;\n    + }\n    + \n    +@@ builtin/checkout.c: static int switch_branches(const struct checkout_opts *opts,\n    + \t\t}\n    + \t}\n    + \n    +-\tret = post_checkout_hook(old_branch_info.commit, new_branch_info->commit, 1);\n    ++\tret = post_checkout_hook(the_repository,\n    ++\t\t\t\t old_branch_info.commit, new_branch_info->commit, 1);\n    + \tbranch_info_release(&old_branch_info);\n    + \tstrbuf_release(&old_commit_shortname);\n    + \tstrbuf_release(&autostash_msg);\n     \n      ## checkout.c ##\n     @@\n    @@ checkout.c: char *unique_tracking_name(const char *name, struct object_id *oid,\n      \treturn NULL;\n      }\n     +\n    -+int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,\n    ++int post_checkout_hook(struct repository *repo,\n    ++\t\t       struct commit *old_commit, struct commit *new_commit,\n     +\t\t       int changed)\n     +{\n     +\tstruct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;\n    ++\tconst struct git_hash_algo *hash_algo = repo->hash_algo;\n     +\n     +\t/*\n     +\t * \"new_commit\" can be NULL when checking out from the index before\n     +\t * a commit exists.\n     +\t */\n     +\tstrvec_pushl(&opt.args,\n    -+\t\t     oid_to_hex(old_commit ? &old_commit->object.oid : null_oid(the_hash_algo)),\n    -+\t\t     oid_to_hex(new_commit ? &new_commit->object.oid : null_oid(the_hash_algo)),\n    ++\t\t     oid_to_hex(old_commit\n    ++\t\t\t\t? &old_commit->object.oid\n    ++\t\t\t\t: null_oid(hash_algo)),\n    ++\t\t     oid_to_hex(new_commit ?\n    ++\t\t\t\t&new_commit->object.oid\n    ++\t\t\t\t: null_oid(hash_algo)),\n     +\t\t     changed ? \"1\" : \"0\",\n     +\t\t     NULL);\n     +\n    -+\treturn run_hooks_opt(the_repository, \"post-checkout\", &opt);\n    ++\treturn run_hooks_opt(repo, \"post-checkout\", &opt);\n     +}\n     \n      ## checkout.h ##\n    @@ checkout.h\n      #include \"hash.h\"\n      \n     +struct commit;\n    ++struct repository;\n     +\n      /*\n       * Check if the branch name uniquely matches a branch name on a remote\n    @@ checkout.h: char *unique_tracking_name(const char *name,\n     +/*\n     + * Run the post-checkout hook.\n     + */\n    -+int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,\n    ++int post_checkout_hook(struct repository *,\n    ++\t\t       struct commit *old_commit, struct commit *new_commit,\n     +\t\t       int changed);\n     +\n      #endif /* CHECKOUT_H */\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551477","messageId":"20260830204835.1040408-2-gitster@pobox.com","threadId":"66230","inReplyTo":"20260830204835.1040408-1-gitster@pobox.com","subject":"[PATCH v2 1/8] checkout: pass cb_option explicitly to branch name parsers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T20:48:28Z","receivedAt":"2026-08-30T20:48:38Z","isPatch":true,"body":"The file-scope static variable 'cb_option' is used to record whether\na new branch is being created via '-b' (in 'git checkout') or '-c'\n(in 'git switch'), primarily for error reporting and advice messages\nin parse_remote_branch().\n\nGlobal mutable state makes the code harder to reason about and refactor.\n\nPass 'cb_option' explicitly as a parameter to parse_remote_branch()\nand parse_branchname_arg(), removing the file-scope static variable.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 23 +++++++++--------------\n 1 file changed, 9 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 55e3a89a85..774e4fd5b3 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1346,7 +1346,7 @@ enum checkout_command {\n static char *parse_remote_branch(const char *arg,\n \t\t\t\t struct object_id *rev,\n \t\t\t\t int could_be_checkout_paths,\n-\t\t\t\t enum checkout_command which_command)\n+\t\t\t\t char cb_option)\n {\n \tint num_matches = 0;\n \tchar *remote = unique_tracking_name(arg, rev, &num_matches);\n@@ -1361,16 +1361,15 @@ static char *parse_remote_branch(const char *arg,\n \t    if (advice_enabled(ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME)) {\n \t\t    const char *cmdname;\n \n-\t\t    switch (which_command) {\n-\t\t    case CHECKOUT_CHECKOUT:\n+\t\t    switch (cb_option) {\n+\t\t    case 'b':\n \t\t\t    cmdname = \"checkout\";\n \t\t\t    break;\n-\t\t    case CHECKOUT_SWITCH:\n+\t\t    case 'c':\n \t\t\t    cmdname = \"switch\";\n \t\t\t    break;\n \t\t    default:\n-\t\t\t    BUG(\"command <%d> should not reach parse_remote_branch\",\n-\t\t\t\twhich_command);\n+\t\t\t    BUG(\"unexpected cb_option '%c'\", cb_option);\n \t\t\t    break;\n \t\t    }\n \n@@ -1394,7 +1393,7 @@ static char *parse_remote_branch(const char *arg,\n \n static int parse_branchname_arg(int argc, const char **argv,\n \t\t\t\tint dwim_new_local_branch_ok,\n-\t\t\t\tenum checkout_command which_command,\n+\t\t\t\tchar cb_option,\n \t\t\t\tstruct branch_info *new_branch_info,\n \t\t\t\tstruct checkout_opts *opts,\n \t\t\t\tstruct object_id *rev)\n@@ -1505,7 +1504,7 @@ static int parse_branchname_arg(int argc, const char **argv,\n \t\tif (recover_with_dwim) {\n \t\t\tremote = parse_remote_branch(arg, rev,\n \t\t\t\t\t\t     could_be_checkout_paths,\n-\t\t\t\t\t\t     which_command);\n+\t\t\t\t\t\t     cb_option);\n \t\t\tif (remote) {\n \t\t\t\t*new_branch = arg;\n \t\t\t\targ = remote;\n@@ -1832,9 +1831,6 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts,\n \treturn newopts;\n }\n \n-/* create-branch option (either b or c) */\n-static char cb_option = 'b';\n-\n static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\t struct checkout_opts *opts, struct option *options,\n \t\t\t enum checkout_command which_command)\n@@ -1842,6 +1838,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \tint parseopt_flags = 0;\n \tstruct branch_info new_branch_info = { 0 };\n \tint ret;\n+\tchar cb_option = (which_command == CHECKOUT_SWITCH) ? 'c' : 'b';\n \n \tstatic const char * const checkout_usage[] = {\n \t\tN_(\"git checkout [<options>] <branch>\"),\n@@ -1997,7 +1994,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\topts->dwim_new_local_branch &&\n \t\t\topts->track == BRANCH_TRACK_UNSPECIFIED &&\n \t\t\t!opts->new_branch;\n-\t\tint n = parse_branchname_arg(argc, argv, dwim_ok, which_command,\n+\t\tint n = parse_branchname_arg(argc, argv, dwim_ok, cb_option,\n \t\t\t\t\t     &new_branch_info, opts, &rev);\n \t\targv += n;\n \t\targc -= n;\n@@ -2174,8 +2171,6 @@ int cmd_switch(int argc,\n \toptions = add_common_options(&opts, options);\n \toptions = add_common_switch_branch_options(&opts, options);\n \n-\tcb_option = 'c';\n-\n \treturn checkout_main(argc, argv, prefix, &opts, options,\n \t\t\t     CHECKOUT_SWITCH);\n }\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551478","messageId":"20260830204835.1040408-3-gitster@pobox.com","threadId":"66230","inReplyTo":"20260830204835.1040408-1-gitster@pobox.com","subject":"[PATCH v2 2/8] checkout: validate new branch name in checkout_branch()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T20:48:29Z","receivedAt":"2026-08-30T20:48:40Z","isPatch":true,"body":"In checkout_main(), new branch name validation is performed before\ndispatching to checkout_branch() or checkout_paths().  Checking out\npaths does not create new branches, so this validation only belongs\nin checkout_branch().\n\nMove the validate_branchname() and validate_new_branchname() calls\nfrom checkout_main() into checkout_branch().  checkout_paths()\nchecks and fails if '.new_branch' is set before doing anything,\nwhich indicates that this change is safe and makes good sense.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 22 +++++++++++-----------\n 1 file changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 774e4fd5b3..14542626e9 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1734,6 +1734,17 @@ static int checkout_branch(struct checkout_opts *opts,\n \t\tfree(full_ref);\n \t}\n \n+\tif (opts->new_branch) {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\n+\t\tif (opts->new_branch_force)\n+\t\t\topts->branch_exists = validate_branchname(opts->new_branch, &buf);\n+\t\telse\n+\t\t\topts->branch_exists =\n+\t\t\t\tvalidate_new_branchname(opts->new_branch, &buf, 0);\n+\t\tstrbuf_release(&buf);\n+\t}\n+\n \tif (!new_branch_info->commit && opts->new_branch) {\n \t\tstruct object_id rev;\n \t\tint flag;\n@@ -2062,17 +2073,6 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\tdie(_(\"you must specify path(s) to restore\"));\n \t}\n \n-\tif (opts->new_branch) {\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\n-\t\tif (opts->new_branch_force)\n-\t\t\topts->branch_exists = validate_branchname(opts->new_branch, &buf);\n-\t\telse\n-\t\t\topts->branch_exists =\n-\t\t\t\tvalidate_new_branchname(opts->new_branch, &buf, 0);\n-\t\tstrbuf_release(&buf);\n-\t}\n-\n \tif (opts->patch_mode || opts->pathspec.nr)\n \t\tret = checkout_paths(opts, &new_branch_info);\n \telse\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551479","messageId":"20260830204835.1040408-4-gitster@pobox.com","threadId":"66230","inReplyTo":"20260830204835.1040408-1-gitster@pobox.com","subject":"[PATCH v2 3/8] checkout: validate stage and merge option compatibility in checkout_paths()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T20:48:30Z","receivedAt":"2026-08-30T20:48:41Z","isPatch":true,"body":"In checkout_main(), checking that no more than one of --ours/--theirs,\n--force, and --merge is specified is performed when pathspecs are\npresent, before dispatching to checkout_paths().  Checking out a\nbranch does not use index stages, so this validation belongs in\ncheckout_paths().\n\nMove the incompatibility check from checkout_main() into\ncheckout_paths().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 14542626e9..e3d23256e2 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -591,6 +591,10 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\tdie(_(\"'%s', '%s', or '%s' cannot be used when checking out of a tree\"),\n \t\t    \"--merge\", \"--ours\", \"--theirs\");\n \n+\tif (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)\n+\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\n\"\n+\t\t      \"checking out of the index.\"));\n+\n \tif (opts->patch_mode) {\n \t\tenum add_p_mode patch_mode;\n \t\tstruct interactive_options interactive_opts = {\n@@ -2063,11 +2067,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \n \topts->pathspec.recursive = 1;\n \n-\tif (opts->pathspec.nr) {\n-\t\tif (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)\n-\t\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\n\"\n-\t\t\t      \"checking out of the index.\"));\n-\t} else {\n+\tif (!opts->pathspec.nr) {\n \t\tif (opts->accept_pathspec && !opts->empty_pathspec_ok &&\n \t\t    !opts->patch_mode)\t/* patch mode is special */\n \t\t\tdie(_(\"you must specify path(s) to restore\"));\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551480","messageId":"20260830204835.1040408-5-gitster@pobox.com","threadId":"66230","inReplyTo":"20260830204835.1040408-1-gitster@pobox.com","subject":"[PATCH v2 4/8] checkout: extract option validation and pathspec helpers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T20:48:31Z","receivedAt":"2026-08-30T20:48:43Z","isPatch":true,"body":"The checkout_main() function handles initialization, option parsing,\noption validation, and pathspec resolution.\n\nExtract option validation and pathspec handling logic into static\nhelper functions:\n\n  - init_checkout_opts() initializes default checkout options and\n    repo settings.\n\n  - validate_path_options() validates patch context and\n    index/worktree flags.\n\n  - prepare_common_options() prepares progress, merge, and force\n    options.\n\n  - parse_pathspec_from_file_options() parses and validates\n    pathspecs read from a file.\n\nCall these helpers from checkout_main().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 171 +++++++++++++++++++++++++--------------------\n 1 file changed, 96 insertions(+), 75 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex e3d23256e2..8d567def7e 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1846,6 +1846,98 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts,\n \treturn newopts;\n }\n \n+static void init_checkout_opts(struct checkout_opts *opts, const char *prefix)\n+{\n+\topts->overwrite_ignore = 1;\n+\topts->prefix = prefix;\n+\topts->show_progress = -1;\n+\n+\trepo_config(the_repository, git_checkout_config, opts);\n+\tif (the_repository->gitdir) {\n+\t\tprepare_repo_settings(the_repository);\n+\t\tthe_repository->settings.command_requires_full_index = 0;\n+\t}\n+\n+\topts->track = BRANCH_TRACK_UNSPECIFIED;\n+}\n+\n+static void validate_path_options(struct checkout_opts *opts)\n+{\n+\tif (opts->patch_context < -1)\n+\t\tdie(_(\"'%s' cannot be negative\"), \"--unified\");\n+\tif (opts->patch_interhunk_context < -1)\n+\t\tdie(_(\"'%s' cannot be negative\"), \"--inter-hunk-context\");\n+\n+\tif (!opts->patch_mode) {\n+\t\tif (opts->patch_context != -1)\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--unified\", \"--patch\");\n+\t\tif (opts->patch_interhunk_context != -1)\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--inter-hunk-context\", \"--patch\");\n+\t\tif (!opts->auto_advance)\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--no-auto-advance\", \"--patch\");\n+\t}\n+\n+\tif (opts->overlay_mode == 1 && opts->patch_mode)\n+\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"-p\", \"--overlay\");\n+\n+\tif (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {\n+\t\tif (opts->checkout_index < 0)\n+\t\t\topts->checkout_index = 0;\n+\t\tif (opts->checkout_worktree < 0)\n+\t\t\topts->checkout_worktree = 0;\n+\t} else {\n+\t\tif (opts->checkout_index < 0)\n+\t\t\topts->checkout_index = -opts->checkout_index - 1;\n+\t\tif (opts->checkout_worktree < 0)\n+\t\t\topts->checkout_worktree = -opts->checkout_worktree - 1;\n+\t}\n+\tif (opts->checkout_index < 0 || opts->checkout_worktree < 0)\n+\t\tBUG(\"these flags should be non-negative by now\");\n+}\n+\n+static void prepare_common_options(struct checkout_opts *opts)\n+{\n+\tif (opts->show_progress < 0) {\n+\t\tif (opts->quiet)\n+\t\t\topts->show_progress = 0;\n+\t\telse\n+\t\t\topts->show_progress = isatty(2);\n+\t}\n+\n+\t/* --conflicts implies --merge */\n+\tif (opts->merge == -1)\n+\t\topts->merge = opts->conflict_style >= 0;\n+\n+\tif (opts->force) {\n+\t\topts->discard_changes = 1;\n+\t\topts->ignore_unmerged_opt = \"--force\";\n+\t\topts->ignore_unmerged = 1;\n+\t}\n+}\n+\n+static void parse_pathspec_from_file_options(struct checkout_opts *opts,\n+\t\t\t\t\t     const char *prefix)\n+{\n+\tif (opts->pathspec_from_file) {\n+\t\tif (opts->pathspec.nr)\n+\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"), \"--pathspec-from-file\");\n+\n+\t\tif (opts->force_detach)\n+\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--detach\");\n+\n+\t\tif (opts->patch_mode)\n+\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--patch\");\n+\n+\t\tparse_pathspec_file(&opts->pathspec, 0,\n+\t\t\t\t    0,\n+\t\t\t\t    prefix, opts->pathspec_from_file, opts->pathspec_file_nul);\n+\t} else if (opts->pathspec_file_nul) {\n+\t\tdie(_(\"the option '%s' requires '%s'\"), \"--pathspec-file-nul\", \"--pathspec-from-file\");\n+\t}\n+\n+\topts->pathspec.recursive = 1;\n+}\n+\n static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\t struct checkout_opts *opts, struct option *options,\n \t\t\t enum checkout_command which_command)\n@@ -1887,17 +1979,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\tBUG(\"no such checkout variant %d\", which_command);\n \t}\n \n-\topts->overwrite_ignore = 1;\n-\topts->prefix = prefix;\n-\topts->show_progress = -1;\n-\n-\trepo_config(the_repository, git_checkout_config, opts);\n-\tif (the_repository->gitdir) {\n-\t\tprepare_repo_settings(the_repository);\n-\t\tthe_repository->settings.command_requires_full_index = 0;\n-\t}\n-\n-\topts->track = BRANCH_TRACK_UNSPECIFIED;\n+\tinit_checkout_opts(opts, prefix);\n \n \tif (!opts->accept_pathspec && !opts->accept_ref)\n \t\tBUG(\"make up your mind, you need to take _something_\");\n@@ -1907,57 +1989,13 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \targc = parse_options(argc, argv, prefix, options,\n \t\t\t     usagestr, parseopt_flags);\n \n-\tif (opts->patch_context < -1)\n-\t\tdie(_(\"'%s' cannot be negative\"), \"--unified\");\n-\tif (opts->patch_interhunk_context < -1)\n-\t\tdie(_(\"'%s' cannot be negative\"), \"--inter-hunk-context\");\n-\n-\tif (!opts->patch_mode) {\n-\t\tif (opts->patch_context != -1)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--unified\", \"--patch\");\n-\t\tif (opts->patch_interhunk_context != -1)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--inter-hunk-context\", \"--patch\");\n-\t\tif (!opts->auto_advance)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--no-auto-advance\", \"--patch\");\n-\t}\n-\n-\tif (opts->show_progress < 0) {\n-\t\tif (opts->quiet)\n-\t\t\topts->show_progress = 0;\n-\t\telse\n-\t\t\topts->show_progress = isatty(2);\n-\t}\n-\n-\t/* --conflicts implies --merge */\n-\tif (opts->merge == -1)\n-\t\topts->merge = opts->conflict_style >= 0;\n-\n-\tif (opts->force) {\n-\t\topts->discard_changes = 1;\n-\t\topts->ignore_unmerged_opt = \"--force\";\n-\t\topts->ignore_unmerged = 1;\n-\t}\n+\tvalidate_path_options(opts);\n+\tprepare_common_options(opts);\n \n \tif ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)\n \t\tdie(_(\"options '-%c', '-%c', and '%s' cannot be used together\"),\n \t\t\tcb_option, toupper(cb_option), \"--orphan\");\n \n-\tif (opts->overlay_mode == 1 && opts->patch_mode)\n-\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"-p\", \"--overlay\");\n-\n-\tif (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {\n-\t\tif (opts->checkout_index < 0)\n-\t\t\topts->checkout_index = 0;\n-\t\tif (opts->checkout_worktree < 0)\n-\t\t\topts->checkout_worktree = 0;\n-\t} else {\n-\t\tif (opts->checkout_index < 0)\n-\t\t\topts->checkout_index = -opts->checkout_index - 1;\n-\t\tif (opts->checkout_worktree < 0)\n-\t\t\topts->checkout_worktree = -opts->checkout_worktree - 1;\n-\t}\n-\tif (opts->checkout_index < 0 || opts->checkout_worktree < 0)\n-\t\tBUG(\"these flags should be non-negative by now\");\n \t/*\n \t * convenient shortcut: \"git restore --staged [--worktree]\" equals\n \t * \"git restore --staged [--worktree] --source HEAD\"\n@@ -2048,24 +2086,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\t    argv[0]);\n \t}\n \n-\tif (opts->pathspec_from_file) {\n-\t\tif (opts->pathspec.nr)\n-\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"), \"--pathspec-from-file\");\n-\n-\t\tif (opts->force_detach)\n-\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--detach\");\n-\n-\t\tif (opts->patch_mode)\n-\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--patch\");\n-\n-\t\tparse_pathspec_file(&opts->pathspec, 0,\n-\t\t\t\t    0,\n-\t\t\t\t    prefix, opts->pathspec_from_file, opts->pathspec_file_nul);\n-\t} else if (opts->pathspec_file_nul) {\n-\t\tdie(_(\"the option '%s' requires '%s'\"), \"--pathspec-file-nul\", \"--pathspec-from-file\");\n-\t}\n-\n-\topts->pathspec.recursive = 1;\n+\tparse_pathspec_from_file_options(opts, prefix);\n \n \tif (!opts->pathspec.nr) {\n \t\tif (opts->accept_pathspec && !opts->empty_pathspec_ok &&\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551481","messageId":"20260830204835.1040408-6-gitster@pobox.com","threadId":"66230","inReplyTo":"20260830204835.1040408-1-gitster@pobox.com","subject":"[PATCH v2 5/8] checkout: extract branch setup and tracking helpers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T20:48:32Z","receivedAt":"2026-08-30T20:48:44Z","isPatch":true,"body":"The checkout_main() function validates branch-creation options,\nDWIMs tracking branch options, and sets up branch information\ndirectly in its body.\n\nExtract these branch setup operations into static helper functions:\n\n  - validate_branch_options() validates compatibility of '-b', '-B',\n    and '--orphan' options.\n\n  - dwim_branch_track_option() infers the branch name when '--track'\n    is given without an explicit branch name.\n\n  - setup_branch_name_and_info() drives branch validation and parses\n    the branch name argument.\n\nCall the new setup helper from checkout_main().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 104 +++++++++++++++++++++++----------------------\n 1 file changed, 54 insertions(+), 50 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 8d567def7e..2edaca5539 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1938,6 +1938,57 @@ static void parse_pathspec_from_file_options(struct checkout_opts *opts,\n \topts->pathspec.recursive = 1;\n }\n \n+static void validate_branch_options(struct checkout_opts *opts, char cb_option)\n+{\n+\tif ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)\n+\t\tdie(_(\"options '-%c', '-%c', and '%s' cannot be used together\"),\n+\t\t\tcb_option, toupper(cb_option), \"--orphan\");\n+\n+\tif (opts->new_branch_force)\n+\t\topts->new_branch = opts->new_branch_force;\n+\n+\tif (opts->new_orphan_branch)\n+\t\topts->new_branch = opts->new_orphan_branch;\n+}\n+\n+static void dwim_branch_track_option(int argc, const char **argv,\n+\t\t\t\t     struct checkout_opts *opts, char cb_option)\n+{\n+\t/* --track without -c/-C/-b/-B/--orphan should DWIM */\n+\tif (opts->track != BRANCH_TRACK_UNSPECIFIED && !opts->new_branch) {\n+\t\tconst char *argv0 = argv[0];\n+\t\tif (!argc || !strcmp(argv0, \"--\"))\n+\t\t\tdie(_(\"--track needs a branch name\"));\n+\t\tskip_prefix(argv0, \"refs/\", &argv0);\n+\t\tskip_prefix(argv0, \"remotes/\", &argv0);\n+\t\targv0 = strchr(argv0, '/');\n+\t\tif (!argv0 || !argv0[1])\n+\t\t\tdie(_(\"missing branch name; try -%c\"), cb_option);\n+\t\topts->new_branch = argv0 + 1;\n+\t}\n+}\n+\n+static int setup_branch_name_and_info(int argc, const char **argv,\n+\t\t\t\t      struct checkout_opts *opts,\n+\t\t\t\t      struct branch_info *new_branch_info,\n+\t\t\t\t      char cb_option)\n+{\n+\tvalidate_branch_options(opts, cb_option);\n+\tdwim_branch_track_option(argc, argv, opts, cb_option);\n+\n+\tif (argc) {\n+\t\tstruct object_id rev;\n+\t\tint dwim_ok =\n+\t\t\t!opts->patch_mode &&\n+\t\t\topts->dwim_new_local_branch &&\n+\t\t\topts->track == BRANCH_TRACK_UNSPECIFIED &&\n+\t\t\t!opts->new_branch;\n+\t\treturn parse_branchname_arg(argc, argv, dwim_ok, cb_option,\n+\t\t\t\t\t    new_branch_info, opts, &rev);\n+\t}\n+\treturn 0;\n+}\n+\n static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\t\t struct checkout_opts *opts, struct option *options,\n \t\t\t enum checkout_command which_command)\n@@ -1992,10 +2043,6 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \tvalidate_path_options(opts);\n \tprepare_common_options(opts);\n \n-\tif ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)\n-\t\tdie(_(\"options '-%c', '-%c', and '%s' cannot be used together\"),\n-\t\t\tcb_option, toupper(cb_option), \"--orphan\");\n-\n \t/*\n \t * convenient shortcut: \"git restore --staged [--worktree]\" equals\n \t * \"git restore --staged [--worktree] --source HEAD\"\n@@ -2003,52 +2050,9 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \tif (!opts->from_treeish && opts->checkout_index)\n \t\topts->from_treeish = \"HEAD\";\n \n-\t/*\n-\t * From here on, new_branch will contain the branch to be checked out,\n-\t * and new_branch_force and new_orphan_branch will tell us which one of\n-\t * -b/-B/-c/-C/--orphan is being used.\n-\t */\n-\tif (opts->new_branch_force)\n-\t\topts->new_branch = opts->new_branch_force;\n-\n-\tif (opts->new_orphan_branch)\n-\t\topts->new_branch = opts->new_orphan_branch;\n-\n-\t/* --track without -c/-C/-b/-B/--orphan should DWIM */\n-\tif (opts->track != BRANCH_TRACK_UNSPECIFIED && !opts->new_branch) {\n-\t\tconst char *argv0 = argv[0];\n-\t\tif (!argc || !strcmp(argv0, \"--\"))\n-\t\t\tdie(_(\"--track needs a branch name\"));\n-\t\tskip_prefix(argv0, \"refs/\", &argv0);\n-\t\tskip_prefix(argv0, \"remotes/\", &argv0);\n-\t\targv0 = strchr(argv0, '/');\n-\t\tif (!argv0 || !argv0[1])\n-\t\t\tdie(_(\"missing branch name; try -%c\"), cb_option);\n-\t\topts->new_branch = argv0 + 1;\n-\t}\n-\n-\t/*\n-\t * Extract branch name from command line arguments, so\n-\t * all that is left is pathspecs.\n-\t *\n-\t * Handle\n-\t *\n-\t *  1) git checkout <tree> -- [<paths>]\n-\t *  2) git checkout -- [<paths>]\n-\t *  3) git checkout <something> [<paths>]\n-\t *\n-\t * including \"last branch\" syntax and DWIM-ery for names of\n-\t * remote branches, erroring out for invalid or ambiguous cases.\n-\t */\n-\tif (argc && opts->accept_ref) {\n-\t\tstruct object_id rev;\n-\t\tint dwim_ok =\n-\t\t\t!opts->patch_mode &&\n-\t\t\topts->dwim_new_local_branch &&\n-\t\t\topts->track == BRANCH_TRACK_UNSPECIFIED &&\n-\t\t\t!opts->new_branch;\n-\t\tint n = parse_branchname_arg(argc, argv, dwim_ok, cb_option,\n-\t\t\t\t\t     &new_branch_info, opts, &rev);\n+\tif (opts->accept_ref) {\n+\t\tint n = setup_branch_name_and_info(argc, argv, opts,\n+\t\t\t\t\t\t   &new_branch_info, cb_option);\n \t\targv += n;\n \t\targc -= n;\n \t} else if (!opts->accept_ref && opts->from_treeish) {\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551482","messageId":"20260830204835.1040408-7-gitster@pobox.com","threadId":"66230","inReplyTo":"20260830204835.1040408-1-gitster@pobox.com","subject":"[PATCH v2 6/8] checkout: restructure switch, restore, and checkout entrypoints","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T20:48:33Z","receivedAt":"2026-08-30T20:48:46Z","isPatch":true,"body":"cmd_switch(), cmd_restore(), and cmd_checkout() pass their options\nto checkout_main(), which parses options and configuration,\nvalidates and dispatches to checkout_branch() or checkout_paths().\n\nNow that option initialization, validation, and branch setup have been\nsplit into dedicated helper functions, restructure cmd_switch(),\ncmd_restore(), and cmd_checkout() to invoke these helpers directly and\ndispatch to checkout_branch() or checkout_paths().\n\nIn cmd_restore(), handle the --staged default from_treeish = \"HEAD\" and\nresolve opts.from_treeish into new_branch_info and opts.source_tree.\n\nThis allows us to remove checkout_main() and enum checkout_command\nas they are no longer needed.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 297 +++++++++++++++++++++++----------------------\n 1 file changed, 149 insertions(+), 148 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2edaca5539..b18515ac7f 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1341,12 +1341,6 @@ static void setup_new_branch_info_and_source_tree(\n }\n \n \n-enum checkout_command {\n-\tCHECKOUT_CHECKOUT = 1,\n-\tCHECKOUT_SWITCH = 2,\n-\tCHECKOUT_RESTORE = 3,\n-};\n-\n static char *parse_remote_branch(const char *arg,\n \t\t\t\t struct object_id *rev,\n \t\t\t\t int could_be_checkout_paths,\n@@ -1989,19 +1983,25 @@ static int setup_branch_name_and_info(int argc, const char **argv,\n \treturn 0;\n }\n \n-static int checkout_main(int argc, const char **argv, const char *prefix,\n-\t\t\t struct checkout_opts *opts, struct option *options,\n-\t\t\t enum checkout_command which_command)\n+int cmd_switch(int argc,\n+\t       const char **argv,\n+\t       const char *prefix,\n+\t       struct repository *repo UNUSED)\n {\n-\tint parseopt_flags = 0;\n+\tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n+\tstruct option *options = NULL;\n \tstruct branch_info new_branch_info = { 0 };\n \tint ret;\n-\tchar cb_option = (which_command == CHECKOUT_SWITCH) ? 'c' : 'b';\n-\n-\tstatic const char * const checkout_usage[] = {\n-\t\tN_(\"git checkout [<options>] <branch>\"),\n-\t\tN_(\"git checkout [<options>] [<branch>] -- <file>...\"),\n-\t\tNULL,\n+\tstruct option switch_options[] = {\n+\t\tOPT_STRING('c', \"create\", &opts.new_branch, N_(\"branch\"),\n+\t\t\t   N_(\"create and switch to a new branch\")),\n+\t\tOPT_STRING('C', \"force-create\", &opts.new_branch_force, N_(\"branch\"),\n+\t\t\t   N_(\"create/reset and switch to a branch\")),\n+\t\tOPT_BOOL(0, \"guess\", &opts.dwim_new_local_branch,\n+\t\t\t N_(\"second guess 'git switch <no-such-branch>'\")),\n+\t\tOPT_BOOL(0, \"discard-changes\", &opts.discard_changes,\n+\t\t\t N_(\"throw away local modifications\")),\n+\t\tOPT_END()\n \t};\n \n \tstatic const char * const switch_branch_usage[] = {\n@@ -2009,103 +2009,125 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n \t\tNULL,\n \t};\n \n+\topts.dwim_new_local_branch = 1;\n+\topts.accept_ref = 1;\n+\topts.accept_pathspec = 0;\n+\topts.switch_branch_doing_nothing_is_ok = 0;\n+\topts.only_merge_on_switching_branches = 1;\n+\topts.implicit_detach = 0;\n+\topts.can_switch_when_in_progress = 0;\n+\topts.orphan_from_empty_tree = 1;\n+\topts.overlay_mode = -1;\n+\n+\tinit_checkout_opts(&opts, prefix);\n+\n+\toptions = parse_options_dup(switch_options);\n+\toptions = add_common_options(&opts, options);\n+\toptions = add_common_switch_branch_options(&opts, options);\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     switch_branch_usage, 0);\n+\n+\tprepare_common_options(&opts);\n+\tsetup_branch_name_and_info(argc, argv, &opts, &new_branch_info, 'c');\n+\n+\tret = checkout_branch(&opts, &new_branch_info);\n+\n+\tbranch_info_release(&new_branch_info);\n+\tclear_pathspec(&opts.pathspec);\n+\tfree(opts.pathspec_from_file);\n+\tfree(options);\n+\n+\treturn ret;\n+}\n+\n+int cmd_restore(int argc,\n+\t\tconst char **argv,\n+\t\tconst char *prefix,\n+\t\tstruct repository *repo UNUSED)\n+{\n+\tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n+\tstruct option *options;\n+\tstruct branch_info new_branch_info = { 0 };\n+\tint ret;\n+\tstruct option restore_options[] = {\n+\t\tOPT_STRING('s', \"source\", &opts.from_treeish, \"<tree-ish>\",\n+\t\t\t   N_(\"which tree-ish to checkout from\")),\n+\t\tOPT_BOOL('S', \"staged\", &opts.checkout_index,\n+\t\t\t   N_(\"restore the index\")),\n+\t\tOPT_BOOL('W', \"worktree\", &opts.checkout_worktree,\n+\t\t\t   N_(\"restore the working tree (default)\")),\n+\t\tOPT_BOOL(0, \"ignore-unmerged\", &opts.ignore_unmerged,\n+\t\t\t N_(\"ignore unmerged entries\")),\n+\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n+\t\tOPT_END()\n+\t};\n+\n \tstatic const char * const restore_usage[] = {\n \t\tN_(\"git restore [<options>] [--source=<branch>] <file>...\"),\n \t\tNULL,\n \t};\n \n-\tconst char * const *usagestr;\n-\n-\tswitch (which_command) {\n-\tcase CHECKOUT_CHECKOUT:\n-\t\tusagestr = checkout_usage;\n-\t\tbreak;\n-\tcase CHECKOUT_SWITCH:\n-\t\tusagestr = switch_branch_usage;\n-\t\tbreak;\n-\tcase CHECKOUT_RESTORE:\n-\t\tusagestr = restore_usage;\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"no such checkout variant %d\", which_command);\n-\t}\n+\topts.accept_ref = 0;\n+\topts.accept_pathspec = 1;\n+\topts.empty_pathspec_ok = 0;\n+\topts.overlay_mode = 0;\n+\topts.checkout_index = -1;    /* default off */\n+\topts.checkout_worktree = -2; /* default on */\n+\topts.ignore_unmerged_opt = \"--ignore-unmerged\";\n \n-\tinit_checkout_opts(opts, prefix);\n+\tinit_checkout_opts(&opts, prefix);\n \n-\tif (!opts->accept_pathspec && !opts->accept_ref)\n-\t\tBUG(\"make up your mind, you need to take _something_\");\n-\tif (opts->accept_pathspec && opts->accept_ref)\n-\t\tparseopt_flags = PARSE_OPT_KEEP_DASHDASH;\n+\toptions = parse_options_dup(restore_options);\n+\toptions = add_common_options(&opts, options);\n+\toptions = add_checkout_path_options(&opts, options);\n \n \targc = parse_options(argc, argv, prefix, options,\n-\t\t\t     usagestr, parseopt_flags);\n+\t\t\t     restore_usage, 0);\n \n-\tvalidate_path_options(opts);\n-\tprepare_common_options(opts);\n+\tvalidate_path_options(&opts);\n+\tprepare_common_options(&opts);\n \n \t/*\n \t * convenient shortcut: \"git restore --staged [--worktree]\" equals\n \t * \"git restore --staged [--worktree] --source HEAD\"\n \t */\n-\tif (!opts->from_treeish && opts->checkout_index)\n-\t\topts->from_treeish = \"HEAD\";\n-\n-\tif (opts->accept_ref) {\n-\t\tint n = setup_branch_name_and_info(argc, argv, opts,\n-\t\t\t\t\t\t   &new_branch_info, cb_option);\n-\t\targv += n;\n-\t\targc -= n;\n-\t} else if (!opts->accept_ref && opts->from_treeish) {\n+\tif (!opts.from_treeish && opts.checkout_index)\n+\t\topts.from_treeish = \"HEAD\";\n+\n+\tif (opts.from_treeish) {\n \t\tstruct object_id rev;\n \n-\t\tif (repo_get_oid_mb(the_repository, opts->from_treeish, &rev))\n-\t\t\tdie(_(\"could not resolve '%s'\"), opts->from_treeish);\n+\t\tif (repo_get_oid_mb(the_repository, opts.from_treeish, &rev))\n+\t\t\tdie(_(\"could not resolve '%s'\"), opts.from_treeish);\n \n \t\tsetup_new_branch_info_and_source_tree(&new_branch_info,\n-\t\t\t\t\t\t      opts, &rev,\n-\t\t\t\t\t\t      opts->from_treeish);\n+\t\t\t\t\t\t      &opts, &rev,\n+\t\t\t\t\t\t      opts.from_treeish);\n \n-\t\tif (!opts->source_tree)\n-\t\t\tdie(_(\"reference is not a tree: %s\"), opts->from_treeish);\n+\t\tif (!opts.source_tree)\n+\t\t\tdie(_(\"reference is not a tree: %s\"), opts.from_treeish);\n \t}\n \n \tif (argc) {\n-\t\tparse_pathspec(&opts->pathspec, 0,\n-\t\t\t       opts->patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n+\t\tparse_pathspec(&opts.pathspec, 0,\n+\t\t\t       opts.patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n \t\t\t       prefix, argv);\n \n-\t\tif (!opts->pathspec.nr)\n+\t\tif (!opts.pathspec.nr)\n \t\t\tdie(_(\"invalid path specification\"));\n-\n-\t\t/*\n-\t\t * Try to give more helpful suggestion.\n-\t\t * new_branch && argc > 1 will be caught later.\n-\t\t */\n-\t\tif (opts->new_branch && argc == 1 && !new_branch_info.commit)\n-\t\t\tdie(_(\"'%s' is not a commit and a branch '%s' cannot be created from it\"),\n-\t\t\t\targv[0], opts->new_branch);\n-\n-\t\tif (opts->force_detach)\n-\t\t\tdie(_(\"git checkout: --detach does not take a path argument '%s'\"),\n-\t\t\t    argv[0]);\n \t}\n \n-\tparse_pathspec_from_file_options(opts, prefix);\n+\tparse_pathspec_from_file_options(&opts, prefix);\n \n-\tif (!opts->pathspec.nr) {\n-\t\tif (opts->accept_pathspec && !opts->empty_pathspec_ok &&\n-\t\t    !opts->patch_mode)\t/* patch mode is special */\n-\t\t\tdie(_(\"you must specify path(s) to restore\"));\n-\t}\n+\tif (!opts.pathspec.nr && !opts.patch_mode)\n+\t\tdie(_(\"you must specify path(s) to restore\"));\n \n-\tif (opts->patch_mode || opts->pathspec.nr)\n-\t\tret = checkout_paths(opts, &new_branch_info);\n-\telse\n-\t\tret = checkout_branch(opts, &new_branch_info);\n+\tret = checkout_paths(&opts, &new_branch_info);\n \n \tbranch_info_release(&new_branch_info);\n-\tclear_pathspec(&opts->pathspec);\n-\tfree(opts->pathspec_from_file);\n+\tclear_pathspec(&opts.pathspec);\n+\tfree(opts.pathspec_from_file);\n \tfree(options);\n \n \treturn ret;\n@@ -2118,6 +2140,8 @@ int cmd_checkout(int argc,\n {\n \tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n \tstruct option *options;\n+\tstruct branch_info new_branch_info = { 0 };\n+\tint ret, n;\n \tstruct option checkout_options[] = {\n \t\tOPT_STRING('b', NULL, &opts.new_branch, N_(\"branch\"),\n \t\t\t   N_(\"create and checkout a new branch\")),\n@@ -2132,6 +2156,12 @@ int cmd_checkout(int argc,\n \t\tOPT_END()\n \t};\n \n+\tstatic const char * const checkout_usage[] = {\n+\t\tN_(\"git checkout [<options>] <branch>\"),\n+\t\tN_(\"git checkout [<options>] [<branch>] -- <file>...\"),\n+\t\tNULL,\n+\t};\n+\n \topts.dwim_new_local_branch = 1;\n \topts.switch_branch_doing_nothing_is_ok = 1;\n \topts.only_merge_on_switching_branches = 0;\n@@ -2154,84 +2184,55 @@ int cmd_checkout(int argc,\n \t\topts.only_merge_on_switching_branches = 1;\n \t}\n \n+\tinit_checkout_opts(&opts, prefix);\n+\n \toptions = parse_options_dup(checkout_options);\n \toptions = add_common_options(&opts, options);\n \toptions = add_common_switch_branch_options(&opts, options);\n \toptions = add_checkout_path_options(&opts, options);\n \n-\treturn checkout_main(argc, argv, prefix, &opts, options,\n-\t\t\t     CHECKOUT_CHECKOUT);\n-}\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t     checkout_usage, PARSE_OPT_KEEP_DASHDASH);\n \n-int cmd_switch(int argc,\n-\t       const char **argv,\n-\t       const char *prefix,\n-\t       struct repository *repo UNUSED)\n-{\n-\tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n-\tstruct option *options = NULL;\n-\tstruct option switch_options[] = {\n-\t\tOPT_STRING('c', \"create\", &opts.new_branch, N_(\"branch\"),\n-\t\t\t   N_(\"create and switch to a new branch\")),\n-\t\tOPT_STRING('C', \"force-create\", &opts.new_branch_force, N_(\"branch\"),\n-\t\t\t   N_(\"create/reset and switch to a branch\")),\n-\t\tOPT_BOOL(0, \"guess\", &opts.dwim_new_local_branch,\n-\t\t\t N_(\"second guess 'git switch <no-such-branch>'\")),\n-\t\tOPT_BOOL(0, \"discard-changes\", &opts.discard_changes,\n-\t\t\t N_(\"throw away local modifications\")),\n-\t\tOPT_END()\n-\t};\n+\tvalidate_path_options(&opts);\n+\tprepare_common_options(&opts);\n \n-\topts.dwim_new_local_branch = 1;\n-\topts.accept_ref = 1;\n-\topts.accept_pathspec = 0;\n-\topts.switch_branch_doing_nothing_is_ok = 0;\n-\topts.only_merge_on_switching_branches = 1;\n-\topts.implicit_detach = 0;\n-\topts.can_switch_when_in_progress = 0;\n-\topts.orphan_from_empty_tree = 1;\n-\topts.overlay_mode = -1;\n+\tn = setup_branch_name_and_info(argc, argv, &opts, &new_branch_info, 'b');\n+\targv += n;\n+\targc -= n;\n \n-\toptions = parse_options_dup(switch_options);\n-\toptions = add_common_options(&opts, options);\n-\toptions = add_common_switch_branch_options(&opts, options);\n+\tif (argc) {\n+\t\tparse_pathspec(&opts.pathspec, 0,\n+\t\t\t       opts.patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,\n+\t\t\t       prefix, argv);\n \n-\treturn checkout_main(argc, argv, prefix, &opts, options,\n-\t\t\t     CHECKOUT_SWITCH);\n-}\n+\t\tif (!opts.pathspec.nr)\n+\t\t\tdie(_(\"invalid path specification\"));\n \n-int cmd_restore(int argc,\n-\t\tconst char **argv,\n-\t\tconst char *prefix,\n-\t\tstruct repository *repo UNUSED)\n-{\n-\tstruct checkout_opts opts = CHECKOUT_OPTS_INIT;\n-\tstruct option *options;\n-\tstruct option restore_options[] = {\n-\t\tOPT_STRING('s', \"source\", &opts.from_treeish, \"<tree-ish>\",\n-\t\t\t   N_(\"which tree-ish to checkout from\")),\n-\t\tOPT_BOOL('S', \"staged\", &opts.checkout_index,\n-\t\t\t   N_(\"restore the index\")),\n-\t\tOPT_BOOL('W', \"worktree\", &opts.checkout_worktree,\n-\t\t\t   N_(\"restore the working tree (default)\")),\n-\t\tOPT_BOOL(0, \"ignore-unmerged\", &opts.ignore_unmerged,\n-\t\t\t N_(\"ignore unmerged entries\")),\n-\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n-\t\tOPT_END()\n-\t};\n+\t\t/*\n+\t\t * Try to give more helpful suggestion.\n+\t\t * new_branch && argc > 1 will be caught later.\n+\t\t */\n+\t\tif (opts.new_branch && argc == 1 && !new_branch_info.commit)\n+\t\t\tdie(_(\"'%s' is not a commit and a branch '%s' cannot be created from it\"),\n+\t\t\t\targv[0], opts.new_branch);\n \n-\topts.accept_ref = 0;\n-\topts.accept_pathspec = 1;\n-\topts.empty_pathspec_ok = 0;\n-\topts.overlay_mode = 0;\n-\topts.checkout_index = -1;    /* default off */\n-\topts.checkout_worktree = -2; /* default on */\n-\topts.ignore_unmerged_opt = \"--ignore-unmerged\";\n+\t\tif (opts.force_detach)\n+\t\t\tdie(_(\"git checkout: --detach does not take a path argument '%s'\"),\n+\t\t\t    argv[0]);\n+\t}\n \n-\toptions = parse_options_dup(restore_options);\n-\toptions = add_common_options(&opts, options);\n-\toptions = add_checkout_path_options(&opts, options);\n+\tparse_pathspec_from_file_options(&opts, prefix);\n \n-\treturn checkout_main(argc, argv, prefix, &opts, options,\n-\t\t\t     CHECKOUT_RESTORE);\n+\tif (opts.patch_mode || opts.pathspec.nr)\n+\t\tret = checkout_paths(&opts, &new_branch_info);\n+\telse\n+\t\tret = checkout_branch(&opts, &new_branch_info);\n+\n+\tbranch_info_release(&new_branch_info);\n+\tclear_pathspec(&opts.pathspec);\n+\tfree(opts.pathspec_from_file);\n+\tfree(options);\n+\n+\treturn ret;\n }\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551483","messageId":"20260830204835.1040408-8-gitster@pobox.com","threadId":"66230","inReplyTo":"20260830204835.1040408-1-gitster@pobox.com","subject":"[PATCH v2 7/8] checkout: wrap overly long lines","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T20:48:34Z","receivedAt":"2026-08-30T20:48:47Z","isPatch":true,"body":"So far, the patches in this series have tried to leave the original\ncode intact as much as possible when moving it, to make the\nrefactoring easier to review.\n\nHowever, there are quite a few overly long lines that are hard to\nread.  There are also several manual checks for mutually\nincompatible options where die_for_incompatible_optN() could be\nused instead.\n\nNow that most of the refactoring is complete, tidy up these warts to\nfinish off the series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 63 ++++++++++++++++++++++++++++++----------------\n 1 file changed, 41 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex b18515ac7f..9771c848c5 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1864,15 +1864,18 @@ static void validate_path_options(struct checkout_opts *opts)\n \n \tif (!opts->patch_mode) {\n \t\tif (opts->patch_context != -1)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--unified\", \"--patch\");\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t\t    \"--unified\", \"--patch\");\n \t\tif (opts->patch_interhunk_context != -1)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--inter-hunk-context\", \"--patch\");\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t\t    \"--inter-hunk-context\", \"--patch\");\n \t\tif (!opts->auto_advance)\n-\t\t\tdie(_(\"the option '%s' requires '%s'\"), \"--no-auto-advance\", \"--patch\");\n+\t\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t\t    \"--no-auto-advance\", \"--patch\");\n \t}\n \n-\tif (opts->overlay_mode == 1 && opts->patch_mode)\n-\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"-p\", \"--overlay\");\n+\tdie_for_incompatible_opt2(opts->patch_mode, \"-p\",\n+\t\t\t\t  opts->overlay_mode == 1, \"--overlay\");\n \n \tif (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {\n \t\tif (opts->checkout_index < 0)\n@@ -1914,19 +1917,25 @@ static void parse_pathspec_from_file_options(struct checkout_opts *opts,\n {\n \tif (opts->pathspec_from_file) {\n \t\tif (opts->pathspec.nr)\n-\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"), \"--pathspec-from-file\");\n-\n-\t\tif (opts->force_detach)\n-\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--detach\");\n-\n-\t\tif (opts->patch_mode)\n-\t\t\tdie(_(\"options '%s' and '%s' cannot be used together\"), \"--pathspec-from-file\", \"--patch\");\n-\n-\t\tparse_pathspec_file(&opts->pathspec, 0,\n-\t\t\t\t    0,\n-\t\t\t\t    prefix, opts->pathspec_from_file, opts->pathspec_file_nul);\n+\t\t\tdie(_(\"'%s' and pathspec arguments cannot be used together\"),\n+\t\t\t    \"--pathspec-from-file\");\n+\n+\t\tdie_for_incompatible_opt2(!!opts->pathspec_from_file,\n+\t\t\t\t\t  \"--pathspec-from-file\",\n+\t\t\t\t\t  opts->force_detach,\n+\t\t\t\t\t  \"--detach\");\n+\n+\t\tdie_for_incompatible_opt2(!!opts->pathspec_from_file,\n+\t\t\t\t\t  \"--pathspec-from-file\",\n+\t\t\t\t\t  opts->patch_mode,\n+\t\t\t\t\t  \"--patch\");\n+\n+\t\tparse_pathspec_file(&opts->pathspec, 0, 0,\n+\t\t\t\t    prefix, opts->pathspec_from_file,\n+\t\t\t\t    opts->pathspec_file_nul);\n \t} else if (opts->pathspec_file_nul) {\n-\t\tdie(_(\"the option '%s' requires '%s'\"), \"--pathspec-file-nul\", \"--pathspec-from-file\");\n+\t\tdie(_(\"the option '%s' requires '%s'\"),\n+\t\t    \"--pathspec-file-nul\", \"--pathspec-from-file\");\n \t}\n \n \topts->pathspec.recursive = 1;\n@@ -1934,9 +1943,17 @@ static void parse_pathspec_from_file_options(struct checkout_opts *opts,\n \n static void validate_branch_options(struct checkout_opts *opts, char cb_option)\n {\n-\tif ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)\n-\t\tdie(_(\"options '-%c', '-%c', and '%s' cannot be used together\"),\n-\t\t\tcb_option, toupper(cb_option), \"--orphan\");\n+\tchar new_branch_opt[] = \"-c\";\n+\tchar new_branch_force_opt[] = \"-C\";\n+\n+\tnew_branch_opt[1] = cb_option;\n+\tnew_branch_force_opt[1] = toupper(cb_option);\n+\n+\tdie_for_incompatible_opt3(!!opts->new_branch,\n+\t\t\t\t  new_branch_opt,\n+\t\t\t\t  !!opts->new_branch_force,\n+\t\t\t\t  new_branch_force_opt,\n+\t\t\t\t  !!opts->new_orphan_branch, \"--orphan\");\n \n \tif (opts->new_branch_force)\n \t\topts->new_branch = opts->new_branch_force;\n@@ -2147,10 +2164,12 @@ int cmd_checkout(int argc,\n \t\t\t   N_(\"create and checkout a new branch\")),\n \t\tOPT_STRING('B', NULL, &opts.new_branch_force, N_(\"branch\"),\n \t\t\t   N_(\"create/reset and checkout a branch\")),\n-\t\tOPT_BOOL('l', NULL, &opts.new_branch_log, N_(\"create reflog for new branch\")),\n+\t\tOPT_BOOL('l', NULL, &opts.new_branch_log,\n+\t\t\t N_(\"create reflog for new branch\")),\n \t\tOPT_BOOL(0, \"guess\", &opts.dwim_new_local_branch,\n \t\t\t N_(\"second guess 'git checkout <no-such-branch>' (default)\")),\n-\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode (default)\")),\n+\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode,\n+\t\t\t N_(\"use overlay mode (default)\")),\n \t\tOPT_BOOL(0, \"auto-advance\", &opts.auto_advance,\n \t\t\t N_(\"auto advance to the next file when selecting hunks interactively\")),\n \t\tOPT_END()\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551484","messageId":"20260830204835.1040408-9-gitster@pobox.com","threadId":"66230","inReplyTo":"20260830204835.1040408-1-gitster@pobox.com","subject":"[PATCH v2 8/8] checkout: move post_checkout_hook() to checkout.c","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T20:48:35Z","receivedAt":"2026-08-30T20:48:48Z","isPatch":true,"body":"post_checkout_hook() in builtin/checkout.c runs the 'post-checkout' hook\nafter switching branches or checking out paths.\n\nMove post_checkout_hook() to checkout.c and declare it in checkout.h\nso that other subsystems can invoke the post-checkout hook without\ndepending on builtin/checkout.c.\n\nRemove the dependency on 'the_repository'.  While OK when the helper\nwas in builtin/checkout.c as an integral part of 'git checkout' (and\n'git restore'), this is no longer true for a common utility\nfunction.  Have it take a pointer to 'struct repository' and use its\nassociated hash algorithm.\n\nThis step in the series is entirely optional and is here primarily\nfor illustration.  We may later want to teach 'git worktree' to\ntrigger the 'post-checkout' hook, for example, in which case such\nlibification may turn out to be useful.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout.c | 23 +++--------------------\n checkout.c         | 28 ++++++++++++++++++++++++++++\n checkout.h         | 10 ++++++++++\n 3 files changed, 41 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 9771c848c5..c6e29e9526 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -124,24 +124,6 @@ static void branch_info_release(struct branch_info *info)\n \tfree(info->checkout);\n }\n \n-static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,\n-\t\t\t      int changed)\n-{\n-\tstruct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;\n-\n-\t/*\n-\t * \"new_commit\" can be NULL when checking out from the index before\n-\t * a commit exists.\n-\t */\n-\tstrvec_pushl(&opt.args,\n-\t\t     oid_to_hex(old_commit ? &old_commit->object.oid : null_oid(the_hash_algo)),\n-\t\t     oid_to_hex(new_commit ? &new_commit->object.oid : null_oid(the_hash_algo)),\n-\t\t     changed ? \"1\" : \"0\",\n-\t\t     NULL);\n-\n-\treturn run_hooks_opt(the_repository, \"post-checkout\", &opt);\n-}\n-\n /*\n  * Handle a tree object and determine if we need to recurse into the\n  * tree (READ_TREE_RECURSIVE) or skip it (0).\n@@ -718,7 +700,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\t   &rev, NULL);\n \thead = lookup_commit_reference_gently(the_repository, &rev, 1);\n \n-\terrs |= post_checkout_hook(head, head, 0);\n+\terrs |= post_checkout_hook(the_repository, head, head, 0);\n \treturn errs;\n }\n \n@@ -1273,7 +1255,8 @@ static int switch_branches(const struct checkout_opts *opts,\n \t\t}\n \t}\n \n-\tret = post_checkout_hook(old_branch_info.commit, new_branch_info->commit, 1);\n+\tret = post_checkout_hook(the_repository,\n+\t\t\t\t old_branch_info.commit, new_branch_info->commit, 1);\n \tbranch_info_release(&old_branch_info);\n \tstrbuf_release(&old_commit_shortname);\n \tstrbuf_release(&autostash_msg);\ndiff --git a/checkout.c b/checkout.c\nindex 1588b116ee..28c5c18d96 100644\n--- a/checkout.c\n+++ b/checkout.c\n@@ -1,6 +1,9 @@\n #define USE_THE_REPOSITORY_VARIABLE\n \n #include \"git-compat-util.h\"\n+#include \"commit.h\"\n+#include \"hex.h\"\n+#include \"hook.h\"\n #include \"object-name.h\"\n #include \"remote.h\"\n #include \"refspec.h\"\n@@ -8,6 +11,7 @@\n #include \"checkout.h\"\n #include \"config.h\"\n #include \"strbuf.h\"\n+#include \"strvec.h\"\n \n struct tracking_name_data {\n \t/* const */ char *src_ref;\n@@ -73,3 +77,27 @@ char *unique_tracking_name(const char *name, struct object_id *oid,\n \t}\n \treturn NULL;\n }\n+\n+int post_checkout_hook(struct repository *repo,\n+\t\t       struct commit *old_commit, struct commit *new_commit,\n+\t\t       int changed)\n+{\n+\tstruct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;\n+\tconst struct git_hash_algo *hash_algo = repo->hash_algo;\n+\n+\t/*\n+\t * \"new_commit\" can be NULL when checking out from the index before\n+\t * a commit exists.\n+\t */\n+\tstrvec_pushl(&opt.args,\n+\t\t     oid_to_hex(old_commit\n+\t\t\t\t? &old_commit->object.oid\n+\t\t\t\t: null_oid(hash_algo)),\n+\t\t     oid_to_hex(new_commit ?\n+\t\t\t\t&new_commit->object.oid\n+\t\t\t\t: null_oid(hash_algo)),\n+\t\t     changed ? \"1\" : \"0\",\n+\t\t     NULL);\n+\n+\treturn run_hooks_opt(repo, \"post-checkout\", &opt);\n+}\ndiff --git a/checkout.h b/checkout.h\nindex 55920e7aeb..6d8d2c2bab 100644\n--- a/checkout.h\n+++ b/checkout.h\n@@ -3,6 +3,9 @@\n \n #include \"hash.h\"\n \n+struct commit;\n+struct repository;\n+\n /*\n  * Check if the branch name uniquely matches a branch name on a remote\n  * tracking branch.  Return the name of the remote if such a branch\n@@ -12,4 +15,11 @@ char *unique_tracking_name(const char *name,\n \t\t\t   struct object_id *oid,\n \t\t\t   int *dwim_remotes_matched);\n \n+/*\n+ * Run the post-checkout hook.\n+ */\n+int post_checkout_hook(struct repository *,\n+\t\t       struct commit *old_commit, struct commit *new_commit,\n+\t\t       int changed);\n+\n #endif /* CHECKOUT_H */\n-- \n2.55.0-884-g76cf8659c2\n\n"},{"id":"551660","messageId":"CAOLa=ZS7seJs9bt4DiSzD=hDXNTnB9qO261Er39PG2sDbj9=MA@mail.gmail.com","threadId":"66230","inReplyTo":"20260830204835.1040408-2-gitster@pobox.com","subject":"Re: [PATCH v2 1/8] checkout: pass cb_option explicitly to branch name parsers","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-09-01T11:31:21Z","receivedAt":"2026-09-01T11:31:23Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> The file-scope static variable 'cb_option' is used to record whether\n> a new branch is being created via '-b' (in 'git checkout') or '-c'\n> (in 'git switch'), primarily for error reporting and advice messages\n> in parse_remote_branch().\n>\n> Global mutable state makes the code harder to reason about and refactor.\n>\n> Pass 'cb_option' explicitly as a parameter to parse_remote_branch()\n> and parse_branchname_arg(), removing the file-scope static variable.\n>\n\nI was wondering why we couldn't simply get rid of 'cb_option' entirely?\nThe only usecase for it is for printing user facing messages in\n`checkout_main()`, where we already have access to `enum\ncheckout_command`. Wouldn't it be better to simply only keep the enum\nand drop this?\n\n[snip]\n"},{"id":"551661","messageId":"CAOLa=ZQQ6YO6GFxUnoqQpC0P45Dw3duu3j-hHuOkUw+SzHXzOg@mail.gmail.com","threadId":"66230","inReplyTo":"20260830204835.1040408-3-gitster@pobox.com","subject":"Re: [PATCH v2 2/8] checkout: validate new branch name in checkout_branch()","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-09-01T11:36:10Z","receivedAt":"2026-09-01T11:36:13Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> In checkout_main(), new branch name validation is performed before\n> dispatching to checkout_branch() or checkout_paths().  Checking out\n> paths does not create new branches, so this validation only belongs\n> in checkout_branch().\n>\n> Move the validate_branchname() and validate_new_branchname() calls\n> from checkout_main() into checkout_branch().  checkout_paths()\n> checks and fails if '.new_branch' is set before doing anything,\n> which indicates that this change is safe and makes good sense.\n>\n\nThis is straightforward and makes sense.\n\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/checkout.c | 22 +++++++++++-----------\n>  1 file changed, 11 insertions(+), 11 deletions(-)\n>\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 774e4fd5b3..14542626e9 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -1734,6 +1734,17 @@ static int checkout_branch(struct checkout_opts *opts,\n>  \t\tfree(full_ref);\n>  \t}\n>\n> +\tif (opts->new_branch) {\n> +\t\tstruct strbuf buf = STRBUF_INIT;\n> +\n> +\t\tif (opts->new_branch_force)\n> +\t\t\topts->branch_exists = validate_branchname(opts->new_branch, &buf);\n> +\t\telse\n> +\t\t\topts->branch_exists =\n> +\t\t\t\tvalidate_new_branchname(opts->new_branch, &buf, 0);\n> +\t\tstrbuf_release(&buf);\n> +\t}\n> +\n>  \tif (!new_branch_info->commit && opts->new_branch) {\n>  \t\tstruct object_id rev;\n>  \t\tint flag;\n> @@ -2062,17 +2073,6 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n>  \t\t\tdie(_(\"you must specify path(s) to restore\"));\n>  \t}\n>\n> -\tif (opts->new_branch) {\n> -\t\tstruct strbuf buf = STRBUF_INIT;\n> -\n> -\t\tif (opts->new_branch_force)\n> -\t\t\topts->branch_exists = validate_branchname(opts->new_branch, &buf);\n> -\t\telse\n> -\t\t\topts->branch_exists =\n> -\t\t\t\tvalidate_new_branchname(opts->new_branch, &buf, 0);\n> -\t\tstrbuf_release(&buf);\n> -\t}\n> -\n>  \tif (opts->patch_mode || opts->pathspec.nr)\n>  \t\tret = checkout_paths(opts, &new_branch_info);\n>  \telse\n> --\n> 2.55.0-884-g76cf8659c2\n\nThe changes looks good too.\n"},{"id":"551662","messageId":"CAOLa=ZTA=xmPnEkMsncwd=3iZA62nsXq0jk-KiUr=GU7OUhh1Q@mail.gmail.com","threadId":"66230","inReplyTo":"20260830204835.1040408-4-gitster@pobox.com","subject":"Re: [PATCH v2 3/8] checkout: validate stage and merge option compatibility in checkout_paths()","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-09-01T11:53:23Z","receivedAt":"2026-09-01T11:53:25Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> In checkout_main(), checking that no more than one of --ours/--theirs,\n> --force, and --merge is specified is performed when pathspecs are\n> present, before dispatching to checkout_paths().  Checking out a\n> branch does not use index stages, so this validation belongs in\n> checkout_paths().\n>\n> Move the incompatibility check from checkout_main() into\n> checkout_paths().\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/checkout.c | 10 +++++-----\n>  1 file changed, 5 insertions(+), 5 deletions(-)\n>\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 14542626e9..e3d23256e2 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -591,6 +591,10 @@ static int checkout_paths(const struct checkout_opts *opts,\n>  \t\tdie(_(\"'%s', '%s', or '%s' cannot be used when checking out of a tree\"),\n>  \t\t    \"--merge\", \"--ours\", \"--theirs\");\n>\n> +\tif (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)\n> +\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\n\"\n> +\t\t      \"checking out of the index.\"));\n> +\n\nDoesn't checkout_paths() also get triggered when using '--patch',\nshouldn't this go below...\n\n>  \tif (opts->patch_mode) {\n>  \t\tenum add_p_mode patch_mode;\n>  \t\tstruct interactive_options interactive_opts = {\n>\n\n...this block? As the original checked for `opts->patchspec.nr`\n\n> @@ -2063,11 +2067,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n>\n>  \topts->pathspec.recursive = 1;\n>\n> -\tif (opts->pathspec.nr) {\n> -\t\tif (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)\n> -\t\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\n\"\n> -\t\t\t      \"checking out of the index.\"));\n> -\t} else {\n> +\tif (!opts->pathspec.nr) {\n>  \t\tif (opts->accept_pathspec && !opts->empty_pathspec_ok &&\n>  \t\t    !opts->patch_mode)\t/* patch mode is special */\n>  \t\t\tdie(_(\"you must specify path(s) to restore\"));\n> --\n> 2.55.0-884-g76cf8659c2\n"},{"id":"551670","messageId":"CAOLa=ZTHGAfRZJKjrB=u-AxiUWgL2p_5HijdfJmCN_wJCE8BqA@mail.gmail.com","threadId":"66230","inReplyTo":"20260830204835.1040408-7-gitster@pobox.com","subject":"Re: [PATCH v2 6/8] checkout: restructure switch, restore, and checkout entrypoints","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-09-01T14:14:42Z","receivedAt":"2026-09-01T14:14:45Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> cmd_switch(), cmd_restore(), and cmd_checkout() pass their options\n> to checkout_main(), which parses options and configuration,\n> validates and dispatches to checkout_branch() or checkout_paths().\n>\n> Now that option initialization, validation, and branch setup have been\n> split into dedicated helper functions, restructure cmd_switch(),\n> cmd_restore(), and cmd_checkout() to invoke these helpers directly and\n> dispatch to checkout_branch() or checkout_paths().\n>\n> In cmd_restore(), handle the --staged default from_treeish = \"HEAD\" and\n> resolve opts.from_treeish into new_branch_info and opts.source_tree.\n>\n> This allows us to remove checkout_main() and enum checkout_command\n> as they are no longer needed.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/checkout.c | 297 +++++++++++++++++++++++----------------------\n>  1 file changed, 149 insertions(+), 148 deletions(-)\n>\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 2edaca5539..b18515ac7f 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -1341,12 +1341,6 @@ static void setup_new_branch_info_and_source_tree(\n>  }\n>\n>\n> -enum checkout_command {\n> -\tCHECKOUT_CHECKOUT = 1,\n> -\tCHECKOUT_SWITCH = 2,\n> -\tCHECKOUT_RESTORE = 3,\n> -};\n> -\n\nOkay so this is how the first commit fits in. Now it makes sense.\n\n[snip]\n"},{"id":"551692","messageId":"xmqqld9ksw26.fsf@gitster.g","threadId":"66230","inReplyTo":"CAOLa=ZTA=xmPnEkMsncwd=3iZA62nsXq0jk-KiUr=GU7OUhh1Q@mail.gmail.com","subject":"Re: [PATCH v2 3/8] checkout: validate stage and merge option compatibility in checkout_paths()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-01T17:47:29Z","receivedAt":"2026-09-01T17:47:32Z","isPatch":true,"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n>> @@ -591,6 +591,10 @@ static int checkout_paths(const struct checkout_opts *opts,\n>>  \t\tdie(_(\"'%s', '%s', or '%s' cannot be used when checking out of a tree\"),\n>>  \t\t    \"--merge\", \"--ours\", \"--theirs\");\n>>\n>> +\tif (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)\n>> +\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\n\"\n>> +\t\t      \"checking out of the index.\"));\n>> +\n>\n> Doesn't checkout_paths() also get triggered when using '--patch',\n> shouldn't this go below...\n>\n>>  \tif (opts->patch_mode) {\n>>  \t\tenum add_p_mode patch_mode;\n>>  \t\tstruct interactive_options interactive_opts = {\n>>\n>\n> ...this block? As the original checked for `opts->patchspec.nr`\n\nSorry, I do not quite understand your question.  \n\nThe \"if (opts->patch_mode)\" block indeed appears in checkout_paths()\nand when \"--patch\" is given the control comes here.  Are you worried\nabout\n\n    git restore --patch --merge --theirs\n\ntriggering the option compatibility check, instead of ignoring it\nand directly jumping into the patch mode?\n\n>> @@ -2063,11 +2067,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n>>\n>>  \topts->pathspec.recursive = 1;\n>>\n>> -\tif (opts->pathspec.nr) {\n>> -\t\tif (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)\n>> -\t\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\n\"\n>> -\t\t\t      \"checking out of the index.\"));\n>> -\t} else {\n>> +\tif (!opts->pathspec.nr) {\n>>  \t\tif (opts->accept_pathspec && !opts->empty_pathspec_ok &&\n>>  \t\t    !opts->patch_mode)\t/* patch mode is special */\n>>  \t\t\tdie(_(\"you must specify path(s) to restore\"));\n>> --\n>> 2.55.0-884-g76cf8659c2\n"},{"id":"551714","messageId":"xmqqik4olfk3.fsf@gitster.g","threadId":"66230","inReplyTo":"CAOLa=ZTHGAfRZJKjrB=u-AxiUWgL2p_5HijdfJmCN_wJCE8BqA@mail.gmail.com","subject":"Re: [PATCH v2 6/8] checkout: restructure switch, restore, and checkout entrypoints","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-01T23:25:48Z","receivedAt":"2026-09-01T23:25:51Z","isPatch":true,"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> cmd_switch(), cmd_restore(), and cmd_checkout() pass their options\n>> to checkout_main(), which parses options and configuration,\n>> validates and dispatches to checkout_branch() or checkout_paths().\n>>\n>> Now that option initialization, validation, and branch setup have been\n>> split into dedicated helper functions, restructure cmd_switch(),\n>> cmd_restore(), and cmd_checkout() to invoke these helpers directly and\n>> dispatch to checkout_branch() or checkout_paths().\n>>\n>> In cmd_restore(), handle the --staged default from_treeish = \"HEAD\" and\n>> resolve opts.from_treeish into new_branch_info and opts.source_tree.\n>>\n>> This allows us to remove checkout_main() and enum checkout_command\n>> as they are no longer needed.\n>>\n>> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n>> ---\n>>  builtin/checkout.c | 297 +++++++++++++++++++++++----------------------\n>>  1 file changed, 149 insertions(+), 148 deletions(-)\n>>\n>> diff --git a/builtin/checkout.c b/builtin/checkout.c\n>> index 2edaca5539..b18515ac7f 100644\n>> --- a/builtin/checkout.c\n>> +++ b/builtin/checkout.c\n>> @@ -1341,12 +1341,6 @@ static void setup_new_branch_info_and_source_tree(\n>>  }\n>>\n>>\n>> -enum checkout_command {\n>> -\tCHECKOUT_CHECKOUT = 1,\n>> -\tCHECKOUT_SWITCH = 2,\n>> -\tCHECKOUT_RESTORE = 3,\n>> -};\n>> -\n>\n> Okay so this is how the first commit fits in. Now it makes sense.\n\nYes.  The point of the series was to get rid of the monolithic\ncheckout_main() that everybody goes through.  And the enum is\nprimarily for that monolith to decide which code path the original\nrequest  is about.\n\nIn the step that gets rid of the monolith, the enum no longer\nbecomes needed, even though an error message with advice to tell\nwhich options are mutually incompatible may need to know the exact\nname of the option.  That makes [1/8] more reasonable than passing\nenums around.\n"},{"id":"551740","messageId":"CAOLa=ZSG4T7G4Y-k_V79JrMSUeYngMViTTDb7N0qSox3kXA-5w@mail.gmail.com","threadId":"66230","inReplyTo":"xmqqik4olfk3.fsf@gitster.g","subject":"Re: [PATCH v2 6/8] checkout: restructure switch, restore, and checkout entrypoints","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-09-02T11:02:30Z","receivedAt":"2026-09-02T11:02:32Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> Junio C Hamano <gitster@pobox.com> writes:\n>>\n>>> cmd_switch(), cmd_restore(), and cmd_checkout() pass their options\n>>> to checkout_main(), which parses options and configuration,\n>>> validates and dispatches to checkout_branch() or checkout_paths().\n>>>\n>>> Now that option initialization, validation, and branch setup have been\n>>> split into dedicated helper functions, restructure cmd_switch(),\n>>> cmd_restore(), and cmd_checkout() to invoke these helpers directly and\n>>> dispatch to checkout_branch() or checkout_paths().\n>>>\n>>> In cmd_restore(), handle the --staged default from_treeish = \"HEAD\" and\n>>> resolve opts.from_treeish into new_branch_info and opts.source_tree.\n>>>\n>>> This allows us to remove checkout_main() and enum checkout_command\n>>> as they are no longer needed.\n>>>\n>>> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n>>> ---\n>>>  builtin/checkout.c | 297 +++++++++++++++++++++++----------------------\n>>>  1 file changed, 149 insertions(+), 148 deletions(-)\n>>>\n>>> diff --git a/builtin/checkout.c b/builtin/checkout.c\n>>> index 2edaca5539..b18515ac7f 100644\n>>> --- a/builtin/checkout.c\n>>> +++ b/builtin/checkout.c\n>>> @@ -1341,12 +1341,6 @@ static void setup_new_branch_info_and_source_tree(\n>>>  }\n>>>\n>>>\n>>> -enum checkout_command {\n>>> -\tCHECKOUT_CHECKOUT = 1,\n>>> -\tCHECKOUT_SWITCH = 2,\n>>> -\tCHECKOUT_RESTORE = 3,\n>>> -};\n>>> -\n>>\n>> Okay so this is how the first commit fits in. Now it makes sense.\n>\n> Yes.  The point of the series was to get rid of the monolithic\n> checkout_main() that everybody goes through.  And the enum is\n> primarily for that monolith to decide which code path the original\n> request  is about.\n>\n> In the step that gets rid of the monolith, the enum no longer\n> becomes needed, even though an error message with advice to tell\n> which options are mutually incompatible may need to know the exact\n> name of the option.  That makes [1/8] more reasonable than passing\n> enums around.\n\nYeah. It makes sense, in isolation [1/8] looked odd, but together it\nfits.\n"},{"id":"551741","messageId":"CAOLa=ZSQs5umaTxT6RKQJdnnAEbK+AHgj0n5yiTM0jsbZcyiig@mail.gmail.com","threadId":"66230","inReplyTo":"xmqqld9ksw26.fsf@gitster.g","subject":"Re: [PATCH v2 3/8] checkout: validate stage and merge option compatibility in checkout_paths()","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-09-02T11:20:53Z","receivedAt":"2026-09-02T11:20:55Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>>> @@ -591,6 +591,10 @@ static int checkout_paths(const struct checkout_opts *opts,\n>>>  \t\tdie(_(\"'%s', '%s', or '%s' cannot be used when checking out of a tree\"),\n>>>  \t\t    \"--merge\", \"--ours\", \"--theirs\");\n>>>\n>>> +\tif (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)\n>>> +\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\n\"\n>>> +\t\t      \"checking out of the index.\"));\n>>> +\n>>\n>> Doesn't checkout_paths() also get triggered when using '--patch',\n>> shouldn't this go below...\n>>\n>>>  \tif (opts->patch_mode) {\n>>>  \t\tenum add_p_mode patch_mode;\n>>>  \t\tstruct interactive_options interactive_opts = {\n>>>\n>>\n>> ...this block? As the original checked for `opts->patchspec.nr`\n>\n> Sorry, I do not quite understand your question.\n>\n> The \"if (opts->patch_mode)\" block indeed appears in checkout_paths()\n> and when \"--patch\" is given the control comes here.  Are you worried\n> about\n>\n>     git restore --patch --merge --theirs\n>\n> triggering the option compatibility check, instead of ignoring it\n> and directly jumping into the patch mode?\n>\n\nSorry if I was unclear. I was stating that the condition udner which the\ncheck runs is now difference. Previously we checked `opts->pathspec.nr`,\nbut now `checkout_paths()` is also entered for '--patch' without any\npath spec.\n\nHaving a closer look, it seems to be okay. Because in patch mode, each\nof the combinations is already rejected before in `checkout_paths()`.\n\nIt still might be good to have a sentence in a the commit message, since\nthe guard did change and the reasoning why that is safe is not so\nobvious.\n\nThis does however change the precedence of the error messages:\n\n  $ git.master restore --staged --theirs --merge foo\n  fatal: git checkout: --ours/--theirs, --force and --merge are\n  incompatible when checking out of the index.\n\n  $ git.patch restore --staged --theirs --merge foo\n  fatal: '--ours' or '--theirs' cannot be used with --staged\n\nThis seems okay to me, not sure if we have tests to validate this\nbehavior.\n\n>>> @@ -2063,11 +2067,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,\n>>>\n>>>  \topts->pathspec.recursive = 1;\n>>>\n>>> -\tif (opts->pathspec.nr) {\n>>> -\t\tif (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)\n>>> -\t\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\n\"\n>>> -\t\t\t      \"checking out of the index.\"));\n>>> -\t} else {\n>>> +\tif (!opts->pathspec.nr) {\n>>>  \t\tif (opts->accept_pathspec && !opts->empty_pathspec_ok &&\n>>>  \t\t    !opts->patch_mode)\t/* patch mode is special */\n>>>  \t\t\tdie(_(\"you must specify path(s) to restore\"));\n>>> --\n>>> 2.55.0-884-g76cf8659c2\n"},{"id":"551814","messageId":"xmqqo6efff9l.fsf@gitster.g","threadId":"66230","inReplyTo":"CAOLa=ZSQs5umaTxT6RKQJdnnAEbK+AHgj0n5yiTM0jsbZcyiig@mail.gmail.com","subject":"Re: [PATCH v2 3/8] checkout: validate stage and merge option compatibility in checkout_paths()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-02T22:40:54Z","receivedAt":"2026-09-02T22:41:01Z","isPatch":true,"body":"Karthik Nayak <karthik.188@gmail.com> writes:\n\n> Sorry if I was unclear. I was stating that the condition udner which the\n> check runs is now difference. Previously we checked `opts->pathspec.nr`,\n> but now `checkout_paths()` is also entered for '--patch' without any\n> path spec.\n>\n> Having a closer look, it seems to be okay. Because in patch mode, each\n> of the combinations is already rejected before in `checkout_paths()`.\n\nYes, that was why I did not see what difference between the code\nbefore and after the change you were concerned about.\n\n> It still might be good to have a sentence in a the commit message, since\n> the guard did change and the reasoning why that is safe is not so\n> obvious.\n\nPerhaps.\n\nHaving done this, I do not particularly think these changes and\nrefactorings are all that useful.  As unit of reusable code, an\nentire command (like \"git restore\") may still be too coarse and\ncallers would want a finer grained control out of \"Git restore\ncallable from C programmatically, without having to go through\nrun_command() interface\", which means the caller has to still\nformulate argv[] array in order to call them.  These 8 patches may\ngive us a good starting point, but it merely scratches the surface.\n\n\n\n"},{"id":"551840","messageId":"CAOLa=ZSeVEAxmckAmApQ4jsOnQ9=nK5+H0-10s-TmFWqGU-URg@mail.gmail.com","threadId":"66230","inReplyTo":"xmqqo6efff9l.fsf@gitster.g","subject":"Re: [PATCH v2 3/8] checkout: validate stage and merge option compatibility in checkout_paths()","fromName":"Karthik Nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2026-09-03T09:21:26Z","receivedAt":"2026-09-03T09:21:29Z","isPatch":true,"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Karthik Nayak <karthik.188@gmail.com> writes:\n>\n>> Sorry if I was unclear. I was stating that the condition udner which the\n>> check runs is now difference. Previously we checked `opts->pathspec.nr`,\n>> but now `checkout_paths()` is also entered for '--patch' without any\n>> path spec.\n>>\n>> Having a closer look, it seems to be okay. Because in patch mode, each\n>> of the combinations is already rejected before in `checkout_paths()`.\n>\n> Yes, that was why I did not see what difference between the code\n> before and after the change you were concerned about.\n>\n>> It still might be good to have a sentence in a the commit message, since\n>> the guard did change and the reasoning why that is safe is not so\n>> obvious.\n>\n> Perhaps.\n>\n> Having done this, I do not particularly think these changes and\n> refactorings are all that useful.  As unit of reusable code, an\n> entire command (like \"git restore\") may still be too coarse and\n> callers would want a finer grained control out of \"Git restore\n> callable from C programmatically, without having to go through\n> run_command() interface\", which means the caller has to still\n> formulate argv[] array in order to call them.  These 8 patches may\n> give us a good starting point, but it merely scratches the surface.\n\nI do think there is merit in merging this down since it leaves us in a\nbetter place than before.\n"}]}