{"thread":{"id":"64714","subject":"bug report: git status -z doesn't respect status.relativePaths=true","startedAt":"2026-01-03T10:47:48Z","lastAt":"2026-01-03T11:35:07Z","messageCount":4,"participants":["Artur Pyrogovskyi","Pushkar Singh","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"532947","messageId":"CALiS03_X4kA47-bimcovqAsTDXOM-KbKUAApM5xHdYzk9kqkbQ@mail.gmail.com","threadId":"64714","inReplyTo":null,"subject":"bug report: git status -z doesn't respect status.relativePaths=true","fromName":"Artur Pyrogovskyi","fromEmail":"arp@letterty.com","sentAt":"2026-01-03T10:47:36Z","receivedAt":"2026-01-03T10:47:48Z","isPatch":false,"sender":{"key":"arp@letterty.com","avatar":null},"body":"According to the man page of git-status: \"-z Terminate entries with\nNUL, instead of LF.\"\n\nHowever, it ignores status.relativePaths=true and always shows absolute paths.\n\nRepro steps:\n$ mkdir test-repo && cd test-repo && git init .\n$ mkdir subdir && touch subdir/test-file.txt && cd subdir && git add\ntest-file.txt\n$ git -c status.relativePaths=true status --porcelain=2\n1 A. N... 000000 100644 100644\n0000000000000000000000000000000000000000\ne69de29bb2d1d6434b8b29ae775ad8c2e48c5391 test-file.txt\n$ git -c status.relativePaths=true status --porcelain=2 -z\n1 A. N... 000000 100644 100644\n0000000000000000000000000000000000000000\ne69de29bb2d1d6434b8b29ae775ad8c2e48c5391 subdir/test-file.txt%\n\n--porcelain=2 is for convenience here; the bug is present with or without it.\n\nHere's the full bug report:\n\nWhat did you do before the bug happened? (Steps to reproduce your issue)\n\n$ git -c status.relativePaths=true status -z\n\nWhat did you expect to happen? (Expected behavior)\n\nI expect this to show relative paths, just as this shows relative paths:\n\n$ git -c status.relativePaths=true status\n\nWhat happened instead? (Actual behavior)\n\nIt shows absolute paths, not just terminating entries with NUL as manpage says.\n\nWhat's different between what you expected and what actually happened?\n\nI expect that when I use -z option with status,\nthe only thing that changes is the line separator.\n\nHowever, for some reason, -z also enforces absolute paths\nand ignores status.relativePaths option.\n\n[System Info]\ngit version:\ngit version 2.52.0\ncpu: arm64\nno commit associated with this build\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /bin/sh\nrust: disabled\nfeature: fsmonitor--daemon\nlibcurl: 8.7.1\nzlib: 1.2.12\nSHA-1: SHA1_DC\nSHA-256: SHA256_BLK\ndefault-ref-format: files\ndefault-hash: sha1\nuname: Darwin 24.6.0 Darwin Kernel Version 24.6.0: Wed Nov  5 21:33:58\nPST 2025; root:xnu-11417.140.69.705.2~1/RELEASE_ARM64_T6000 arm64\ncompiler info: clang: 17.0.0 (clang-1700.4.4.1)\nlibc info: no libc information available\n$SHELL (typically, interactive shell): /bin/zsh\n\nArtur\n"},{"id":"532948","messageId":"CALE2CrSwMoAd6CAYHsryfqWsfPYiYQ1jns_5HVHk0Ebu9sk-Bg@mail.gmail.com","threadId":"64714","inReplyTo":"CALiS03_X4kA47-bimcovqAsTDXOM-KbKUAApM5xHdYzk9kqkbQ@mail.gmail.com","subject":"Re: bug report: git status -z doesn't respect status.relativePaths=true","fromName":"Pushkar Singh","fromEmail":"pushkarkumarsingh1970@gmail.com","sentAt":"2026-01-03T11:07:00Z","receivedAt":"2026-01-03T11:07:12Z","isPatch":false,"sender":{"key":"pushkarkumarsingh1970@gmail.com","avatar":"https://avatars.githubusercontent.com/u/173247767?v=4"},"body":"Hi Artur,\n\nThanks for the report. I can reproduce this on my end.\n\nThe issue shows up when running `git status` from a subdirectory rather than\nthe repository root. With `status.relativePaths=true`:\n\nFrom inside `subdir/`:\n\n    $ git -c status.relativePaths=true status --porcelain=2\n    ... test-file.txt\n\nbut with `-z`:\n\n    $ git -c status.relativePaths=true status --porcelain=2 -z\n    ... subdir/test-file.txt\n\nSo `-z` appears to ignore `status.relativePaths` and forces paths relative\nto the repo root, even though the documentation suggests it should only\naffect record termination.\n\nTested with git 2.52.0 on Linux/WSL.\n\nThanks,\nPushkar\n\nOn Sat, Jan 3, 2026 at 4:17 PM Artur Pyrogovskyi <arp@letterty.com> wrote:\n>\n> According to the man page of git-status: \"-z Terminate entries with\n> NUL, instead of LF.\"\n>\n> However, it ignores status.relativePaths=true and always shows absolute paths.\n>\n> Repro steps:\n> $ mkdir test-repo && cd test-repo && git init .\n> $ mkdir subdir && touch subdir/test-file.txt && cd subdir && git add\n> test-file.txt\n> $ git -c status.relativePaths=true status --porcelain=2\n> 1 A. N... 000000 100644 100644\n> 0000000000000000000000000000000000000000\n> e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 test-file.txt\n> $ git -c status.relativePaths=true status --porcelain=2 -z\n> 1 A. N... 000000 100644 100644\n> 0000000000000000000000000000000000000000\n> e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 subdir/test-file.txt%\n>\n> --porcelain=2 is for convenience here; the bug is present with or without it.\n>\n> Here's the full bug report:\n>\n> What did you do before the bug happened? (Steps to reproduce your issue)\n>\n> $ git -c status.relativePaths=true status -z\n>\n> What did you expect to happen? (Expected behavior)\n>\n> I expect this to show relative paths, just as this shows relative paths:\n>\n> $ git -c status.relativePaths=true status\n>\n> What happened instead? (Actual behavior)\n>\n> It shows absolute paths, not just terminating entries with NUL as manpage says.\n>\n> What's different between what you expected and what actually happened?\n>\n> I expect that when I use -z option with status,\n> the only thing that changes is the line separator.\n>\n> However, for some reason, -z also enforces absolute paths\n> and ignores status.relativePaths option.\n>\n> [System Info]\n> git version:\n> git version 2.52.0\n> cpu: arm64\n> no commit associated with this build\n> sizeof-long: 8\n> sizeof-size_t: 8\n> shell-path: /bin/sh\n> rust: disabled\n> feature: fsmonitor--daemon\n> libcurl: 8.7.1\n> zlib: 1.2.12\n> SHA-1: SHA1_DC\n> SHA-256: SHA256_BLK\n> default-ref-format: files\n> default-hash: sha1\n> uname: Darwin 24.6.0 Darwin Kernel Version 24.6.0: Wed Nov  5 21:33:58\n> PST 2025; root:xnu-11417.140.69.705.2~1/RELEASE_ARM64_T6000 arm64\n> compiler info: clang: 17.0.0 (clang-1700.4.4.1)\n> libc info: no libc information available\n> $SHELL (typically, interactive shell): /bin/zsh\n>\n> Artur\n>\n"},{"id":"532949","messageId":"20260103112642.GA2706421@coredump.intra.peff.net","threadId":"64714","inReplyTo":"CALiS03_X4kA47-bimcovqAsTDXOM-KbKUAApM5xHdYzk9kqkbQ@mail.gmail.com","subject":"Re: bug report: git status -z doesn't respect status.relativePaths=true","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2026-01-03T11:26:42Z","receivedAt":"2026-01-03T11:26:52Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Jan 03, 2026 at 02:47:36AM -0800, Artur Pyrogovskyi wrote:\n\n> According to the man page of git-status: \"-z Terminate entries with\n> NUL, instead of LF.\"\n> \n> However, it ignores status.relativePaths=true and always shows absolute paths.\n\nThis matches the documented behavior. In --porcelain=v1 mode, we ignore\nmost configuration options (like status.relativePaths). And -z puts us\ninto v1 porcelain mode by default:\n\n       -z\n           Terminate entries with NUL, instead of LF. This implies the\n           --porcelain=v1 output format if no other format is given.\n\nI do think there is at least one bug here, though. I'd expect from that\ndocumentation to be able to do:\n\n  git -c status.relativePaths=true status --short -z\n\nand get relative paths. But it doesn't work. The --short output code\nthat handles \"-z\" ignores the prefix entirely.\n\nSomething like this would fix it:\n\ndiff --git a/wt-status.c b/wt-status.c\nindex e12adb26b9..22797371a6 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -2005,6 +2005,13 @@ static void wt_shortstatus_unmerged(struct string_list_item *it,\n \t}\n }\n \n+static void print_with_nul(struct wt_status *s, const char *fn)\n+{\n+\tstruct strbuf scratch = STRBUF_INIT;\n+\tfprintf(s->fp, \"%s%c\", relative_path(fn, s->prefix, &scratch), 0);\n+\tstrbuf_release(&scratch);\n+}\n+\n static void wt_shortstatus_status(struct string_list_item *it,\n \t\t\t struct wt_status *s)\n {\n@@ -2020,9 +2027,9 @@ static void wt_shortstatus_status(struct string_list_item *it,\n \t\tfputc(' ', s->fp);\n \tfputc(' ', s->fp);\n \tif (s->null_termination) {\n-\t\tfprintf(s->fp, \"%s%c\", it->string, 0);\n+\t\tprint_with_nul(s, it->string);\n \t\tif (d->rename_source)\n-\t\t\tfprintf(s->fp, \"%s%c\", d->rename_source, 0);\n+\t\t\tprint_with_nul(s, d->rename_source);\n \t} else {\n \t\tstruct strbuf onebuf = STRBUF_INIT;\n \t\tconst char *one;\n\nbut:\n\n  1. it would need similar adjustments to a few other printing\n     functions; and\n\n  2. it's not clear to me if we want to change this behavior or keep\n     it as a historical quirk and document it as such.\n\n     I guess nobody noticed because using \"-z\" with \"--short\" is a bit\n     of an odd thing to want to do.\n\n\nThere's another oddity, which is this:\n\n> Repro steps:\n> $ mkdir test-repo && cd test-repo && git init .\n> $ mkdir subdir && touch subdir/test-file.txt && cd subdir && git add\n> test-file.txt\n> $ git -c status.relativePaths=true status --porcelain=2\n> 1 A. N... 000000 100644 100644\n> 0000000000000000000000000000000000000000\n> e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 test-file.txt\n\nI am surprised to see that the v2 porcelain respects that config option\nat all. I don't know if that's a bug, or a subtle change from v1. I\ndon't see it mentioned in the documentation.\n\nIf it isn't a bug, and we expect v2 porcelain to respect the config,\nthen this:\n\n> $ git -c status.relativePaths=true status --porcelain=2 -z\n> 1 A. N... 000000 100644 100644\n> 0000000000000000000000000000000000000000\n> e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 subdir/test-file.txt%\n\nis another bug similar to the --short one.\n\n-Peff\n"},{"id":"532950","messageId":"CALE2CrQ9OmCprNckT5qMwx87NZZfKTe0C6bfD76d4tyUFDgJgQ@mail.gmail.com","threadId":"64714","inReplyTo":"20260103112642.GA2706421@coredump.intra.peff.net","subject":"Re: bug report: git status -z doesn't respect status.relativePaths=true","fromName":"Pushkar Singh","fromEmail":"pushkarkumarsingh1970@gmail.com","sentAt":"2026-01-03T11:34:54Z","receivedAt":"2026-01-03T11:35:07Z","isPatch":false,"sender":{"key":"pushkarkumarsingh1970@gmail.com","avatar":"https://avatars.githubusercontent.com/u/173247767?v=4"},"body":"Hi Jeff,\n\nThanks for the detailed explanation. That clarifies why `-z` implies\n`--porcelain=v1` and why `status.relativePaths` gets ignored in that case.\n\nI agree that the `--short -z` behavior is surprising. From the\ndocumentation, I would also expect `status.relativePaths=true` to be\nhonored there, so ignoring the prefix entirely does look like a real\nissue rather than just a quirk.\n\nThe `--porcelain=v2 -z` case is interesting as well. If v2 is intended\nto respect the configuration, then the inconsistency when using `-z`\ndoes seem like a related bug.\n\nIf it would be useful, I am happy to help investigate further or work\non tests once there is consensus on the intended behavior.\n\nThanks,\nPushkar\n\nOn Sat, Jan 3, 2026 at 4:56 PM Jeff King <peff@peff.net> wrote:\n>\n> On Sat, Jan 03, 2026 at 02:47:36AM -0800, Artur Pyrogovskyi wrote:\n>\n> > According to the man page of git-status: \"-z Terminate entries with\n> > NUL, instead of LF.\"\n> >\n> > However, it ignores status.relativePaths=true and always shows absolute paths.\n>\n> This matches the documented behavior. In --porcelain=v1 mode, we ignore\n> most configuration options (like status.relativePaths). And -z puts us\n> into v1 porcelain mode by default:\n>\n>        -z\n>            Terminate entries with NUL, instead of LF. This implies the\n>            --porcelain=v1 output format if no other format is given.\n>\n> I do think there is at least one bug here, though. I'd expect from that\n> documentation to be able to do:\n>\n>   git -c status.relativePaths=true status --short -z\n>\n> and get relative paths. But it doesn't work. The --short output code\n> that handles \"-z\" ignores the prefix entirely.\n>\n> Something like this would fix it:\n>\n> diff --git a/wt-status.c b/wt-status.c\n> index e12adb26b9..22797371a6 100644\n> --- a/wt-status.c\n> +++ b/wt-status.c\n> @@ -2005,6 +2005,13 @@ static void wt_shortstatus_unmerged(struct string_list_item *it,\n>         }\n>  }\n>\n> +static void print_with_nul(struct wt_status *s, const char *fn)\n> +{\n> +       struct strbuf scratch = STRBUF_INIT;\n> +       fprintf(s->fp, \"%s%c\", relative_path(fn, s->prefix, &scratch), 0);\n> +       strbuf_release(&scratch);\n> +}\n> +\n>  static void wt_shortstatus_status(struct string_list_item *it,\n>                          struct wt_status *s)\n>  {\n> @@ -2020,9 +2027,9 @@ static void wt_shortstatus_status(struct string_list_item *it,\n>                 fputc(' ', s->fp);\n>         fputc(' ', s->fp);\n>         if (s->null_termination) {\n> -               fprintf(s->fp, \"%s%c\", it->string, 0);\n> +               print_with_nul(s, it->string);\n>                 if (d->rename_source)\n> -                       fprintf(s->fp, \"%s%c\", d->rename_source, 0);\n> +                       print_with_nul(s, d->rename_source);\n>         } else {\n>                 struct strbuf onebuf = STRBUF_INIT;\n>                 const char *one;\n>\n> but:\n>\n>   1. it would need similar adjustments to a few other printing\n>      functions; and\n>\n>   2. it's not clear to me if we want to change this behavior or keep\n>      it as a historical quirk and document it as such.\n>\n>      I guess nobody noticed because using \"-z\" with \"--short\" is a bit\n>      of an odd thing to want to do.\n>\n>\n> There's another oddity, which is this:\n>\n> > Repro steps:\n> > $ mkdir test-repo && cd test-repo && git init .\n> > $ mkdir subdir && touch subdir/test-file.txt && cd subdir && git add\n> > test-file.txt\n> > $ git -c status.relativePaths=true status --porcelain=2\n> > 1 A. N... 000000 100644 100644\n> > 0000000000000000000000000000000000000000\n> > e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 test-file.txt\n>\n> I am surprised to see that the v2 porcelain respects that config option\n> at all. I don't know if that's a bug, or a subtle change from v1. I\n> don't see it mentioned in the documentation.\n>\n> If it isn't a bug, and we expect v2 porcelain to respect the config,\n> then this:\n>\n> > $ git -c status.relativePaths=true status --porcelain=2 -z\n> > 1 A. N... 000000 100644 100644\n> > 0000000000000000000000000000000000000000\n> > e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 subdir/test-file.txt%\n>\n> is another bug similar to the --short one.\n>\n> -Peff\n>\n"}]}