{"thread":{"id":"64731","subject":"Unexpected behavior in git diff --relative=<path>","startedAt":"2026-01-05T22:56:51Z","lastAt":"2026-01-06T16:58:21Z","messageCount":2,"participants":["Harrison McCullough","Ben Knoble"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"533090","messageId":"CAHLeu+ww7bBACO97ddkHeL2nkwmwqNL9G2Bjq18NZr5_d-MHyQ@mail.gmail.com","threadId":"64731","inReplyTo":null,"subject":"Unexpected behavior in git diff --relative=<path>","fromName":"Harrison McCullough","fromEmail":"mccullough.harrison@gmail.com","sentAt":"2026-01-05T22:56:37Z","receivedAt":"2026-01-05T22:56:51Z","isPatch":false,"sender":{"key":"mccullough.harrison@gmail.com","avatar":null},"body":"What did you do before the bug happened? (Steps to reproduce your issue)\n\n- Create a \"foo.txt\" file\n- Commit the \"foo.txt\"\n- Modify the \"foo.txt\" file\n- Create a \"foo/bar.txt\" file\n- Commit the \"foo/bar.txt\"\n- Modify the \"foo/bar.txt\" file\n- Run `git diff --name-only --relative=foo`\n\n\nWhat did you expect to happen? (Expected behavior)\n\nI would expect to only see modified files inside the \"foo/\" directory. For\nexample, I would expect this to be the output:\n\n```\n$ git diff --name-only --relative=foo\nbar.txt\n```\n\n\nWhat happened instead? (Actual behavior)\n\nBoth the \"foo/bar.txt\" _and_ the \"foo.txt\" files were listed--but the \"foo.txt\"\nfile had the \"foo\" prefix stripped, appearing as just \".txt\".\n\n```\n$ git diff --name-only --relative=foo\n.txt\nbar.txt\n```\n\n\nWhat's different between what you expected and what actually happened?\n\nUsing the `--relative=<path>` flag to `git diff` appears to simply remove the\nprefix from each file, regardless of whether that is a full path prefix or just\npart of the file name.\n\n\nAnything else you want to add:\n\nThis is the relevant part of the man page for `git-diff`:\n\n> When run from a subdirectory of the project, it can be told to exclude changes\n> outside the directory and show pathnames relative to it with this option. When\n> you are not in a subdirectory (e.g. in a bare repository), you can name which\n> subdirectory to make the output relative to by giving a <path> as an argument.\n> --no-relative can be used to countermand both diff.relative config option and\n> previous --relative.\n\nWhen I read this for the first time, I imagined that the behavior would be as\nfollows:\n\n- `git diff`: include all changes, display file names beginning from repository\n  root\n- `git diff .`: include all changes in the current directory and \"below\",\n  display file names beginning from repository root\n- `git diff --relative=. .`: include all changes in the current\ndirectory and \"below\",\n  display file names beginning from the current directory\n   - E.g. if the repository root is `/home/bob/repo/` and the current directory\n     is `/home/bob/repo/foo/bar/`, then a modified file\n     `/home/bob/repo/foo/bar/baz/qux.txt` would be displayed as `baz/qux.txt`\n- `git diff --relative=.. ..`: include all changes in the parent\ndirectory and \"below\",\n  display file names beginning from the parent directory\n   - E.g. if the repository root is `/home/bob/repo/` and the current directory\n     is `/home/bob/repo/foo/bar/`, then a modified file\n     `/home/bob/repo/foo/bar/baz/qux.txt` would be displayed as\n`bar/baz/qux.txt`\n\nI understand that my initial assumption may not be the intended\nbehavior. However, I don't think that stripping a prefix of a file name just\nbecause the file name matched the argument to `--relative` makes much sense. If\nthat _is_ the desired behavior, I think that `--strip-prefix` or something\nsimilar would be a better name. The name \"relative\", to me, makes it sound like\nit is logically connected to the directory structure.\n\nIn addition, the description of the `--relative` flag claims that \"it can be\ntold to exclude changes outside the directory ...\". This implies that the\nargument should be a directory. In practice, the argument _can_ be a directory,\nbut that isn't verified.\n\nIf this flag is working exactly as intended, then perhaps a clarifying comment\ncan be added to the documentation to explicitly state that the argument is\nmatched against the full file path, starting at the repository root, and is\nremoved from the beginning of the path (and the file is included in the output)\nif it matches--regardless of whether the match matches a full directory path or\njust the first portion of a file name.\n\nI will note that if you want to make sure that the argument to the `--relative`\nflag only matches against entire directories, not file name prefixes, you can\nsimply append a trailing slash to the end. In the case of the example I provided\nabove, I can run the following and get reasonable behavior:\n\n```\n$ git diff --name-only --relative=foo/\nbar.txt\n```\n\n\n\n\n[System Info]\ngit version:\ngit version 2.46.2\ncpu: arm64\nno commit associated with this build\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /bin/sh\nfeature: fsmonitor--daemon\nlibcurl: 8.4.0\nzlib: 1.2.12\nuname: Darwin 24.6.0 Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:55\nPDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6031 arm64\ncompiler info: clang: 15.0.0 (clang-1500.3.9.4)\nlibc info: no libc information available\n$SHELL (typically, interactive shell): /opt/homebrew/bin/bash\n\n\n[Enabled Hooks]\n\n-Harrison McCullough\n"},{"id":"533154","messageId":"8113ACE3-288F-46D5-949F-CEDF3D9D0E25@gmail.com","threadId":"64731","inReplyTo":"CAHLeu+ww7bBACO97ddkHeL2nkwmwqNL9G2Bjq18NZr5_d-MHyQ@mail.gmail.com","subject":"Re: Unexpected behavior in git diff --relative=<path>","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-01-06T16:58:09Z","receivedAt":"2026-01-06T16:58:21Z","isPatch":false,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"\n> Le 5 janv. 2026 à 17:56, Harrison McCullough <mccullough.harrison@gmail.com> a écrit :\n> \n> ﻿What did you do before the bug happened? (Steps to reproduce your issue)\n> \n> - Create a \"foo.txt\" file\n> - Commit the \"foo.txt\"\n> - Modify the \"foo.txt\" file\n> - Create a \"foo/bar.txt\" file\n> - Commit the \"foo/bar.txt\"\n> - Modify the \"foo/bar.txt\" file\n> - Run `git diff --name-only --relative=foo`\n> \n> \n> What did you expect to happen? (Expected behavior)\n> \n> I would expect to only see modified files inside the \"foo/\" directory. For\n> example, I would expect this to be the output:\n> \n> ```\n> $ git diff --name-only --relative=foo\n> bar.txt\n> ```\n> \n> \n> What happened instead? (Actual behavior)\n> \n> Both the \"foo/bar.txt\" _and_ the \"foo.txt\" files were listed--but the \"foo.txt\"\n> file had the \"foo\" prefix stripped, appearing as just \".txt\".\n> \n> ```\n> $ git diff --name-only --relative=foo\n> .txt\n> bar.txt\n> ```\n\nEasy to reproduce (with f or fo, too).\n\n> What's different between what you expected and what actually happened?\n> \n> Using the `--relative=<path>` flag to `git diff` appears to simply remove the\n> prefix from each file, regardless of whether that is a full path prefix or just\n> part of the file name.\n> \n> \n> Anything else you want to add:\n> \n> This is the relevant part of the man page for `git-diff`:\n> \n>> When run from a subdirectory of the project, it can be told to exclude changes\n>> outside the directory and show pathnames relative to it with this option. When\n>> you are not in a subdirectory (e.g. in a bare repository), you can name which\n>> subdirectory to make the output relative to by giving a <path> as an argument.\n>> --no-relative can be used to countermand both diff.relative config option and\n>> previous --relative.\n\nThe wording implies to me that “=<path>” is only intended for use with bare repositories. With working trees, use just the relative option from within a directory:\n\n    (cd foo && git diff - -relative)\n\nIf that’s right (?), then the docs should probably be more direct about the way each is intended to be used. I can imagine some use cases for the stripping behavior in non-bare repos, but mostly around ad-hoc scripts. "}]}