{"thread":{"id":"38566","subject":"git ls-files -X option is relative to repo root","startedAt":"2015-02-13T19:23:40Z","lastAt":"2015-02-13T22:02:10Z","messageCount":5,"participants":["Daniel Finnie","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"256073","messageId":"CAG4vEKM-2sy0z3=YLS+rgH99w6ukdcNBode9CAh4C4t9eSa02A@mail.gmail.com","threadId":"38566","inReplyTo":null,"subject":"git ls-files -X option is relative to repo root","fromName":"Daniel Finnie","fromEmail":"dan@danfinnie.com","sentAt":"2015-02-13T19:23:40Z","receivedAt":"2015-02-13T19:23:40Z","isPatch":false,"sender":{"key":"dan@danfinnie.com","avatar":null},"body":"I encountered some unexpected behavior with Git today and was hoping\nto either a) clear up my misconception or b) make a bug report.\n\nMy question deals with the --exclude-from option to git-ls-files.  It\nappears that paths passed to this option are relative to the root of\nthe repository, not your current working directory.  I would have\nexpected the opposite, that the paths are relative to the working\ndirectory.  I would expect to put a colon at the beginning of the path\nto make it relative to the repository root.  Here's an example:\n\n$ tree -a -I .git\n.\n├── .gitignore\n└── example_dir\n    ├── .gitignore\n    └── example_file\n\n# (all of these files are checked in, including example_file which is\nalso in .gitignore)\n\n$ cat .gitignore\n# empty gitignore\n\n$ cat example_dir/.gitignore\nexample_file\n\n$ (cd example_dir && git ls-files --ignore --exclude-from=.gitignore)\n# No output because this references the git ignore at the project\nroot, not example_dir.  I expected this to output \"example_file\".\n\n$ (cd example_dir && git ls-files --ignore\n--exclude-from=example_dir/.gitignore)\nexample_file # works for the reason above, but I expected this to\nbreak because example_dir/example_dir/.gitignore is not a file\n\nSo, what do you think?  Am I missing a git/*nix convention explaining\noptions would be specified relative to the repository root?  Or is\nthis a git bug?\n\nThanks for your time,\nDan Finnie\n"},{"id":"256083","messageId":"xmqqmw4hmtlw.fsf@gitster.dls.corp.google.com","threadId":"38566","inReplyTo":"CAG4vEKM-2sy0z3=YLS+rgH99w6ukdcNBode9CAh4C4t9eSa02A@mail.gmail.com","subject":"Re: git ls-files -X option is relative to repo root","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-02-13T20:42:03Z","receivedAt":"2015-02-13T20:42:03Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Daniel Finnie <dan@danfinnie.com> writes:\n\n> My question deals with the --exclude-from option to git-ls-files.\n\nYou will be fine if you remember that these plumbing commands work\nby first cd'ing to the top-level of the working tree (and adjust the\npaths given from the command line by prefixing the prefix to them).\n\nThe input lines that come from --exclude-per-directory should go\nthrough the prefixing, but -X=<file> makes that single file affect\nthe whole operation.  It does not make sense to allow where you are\nto affect behaviour of the command, i.e. in these two invocations of\nls-files:\n\n\tgit ls-files -X /var/tmp/exclude -i\n        cd example && git ls-files -X /var/tmp/exclude -i\n\nif the same line in /var/tmp/exclude meant completely different\nthings, it would be crazy.\n"},{"id":"256084","messageId":"xmqqiof5mt0q.fsf@gitster.dls.corp.google.com","threadId":"38566","inReplyTo":"xmqqmw4hmtlw.fsf@gitster.dls.corp.google.com","subject":"Re: git ls-files -X option is relative to repo root","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-02-13T20:54:45Z","receivedAt":"2015-02-13T20:54:45Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> ...  It does not make sense to allow where you are\n> to affect behaviour of the command, i.e. in these two invocations of\n> ls-files:\n>\n> \tgit ls-files -X /var/tmp/exclude -i\n>         cd example && git ls-files -X /var/tmp/exclude -i\n>\n> if the same line in /var/tmp/exclude meant completely different\n> things, it would be crazy.\n\nTo put it another way, think of --exclude-from as a way to specify a\nreplacement for .git/info/excludes, and --exclude-per-directory as a\nway to specify a replacement for the in-tree .gitignore files.\n\nHistorically, we did not have the --exclude-standard option from the\nbeginning, and only after we gained experience with --exclude-from\nand --exclude-per-directory in our scripts, the --exclude-standard\nwas added to codify the (then-) best-current-practice after the fact,\nand we used --exclude-from for exactly that purpose before then.\n\ncf. 8e7b07c8 (git-ls-files: add --exclude-standard, 2007-11-15)\n"},{"id":"256088","messageId":"CAG4vEKP760_sq1fsJD_1jjz0_G+T8NosSXDqx0bvQy4tPVz5JQ@mail.gmail.com","threadId":"38566","inReplyTo":"xmqqiof5mt0q.fsf@gitster.dls.corp.google.com","subject":"Re: git ls-files -X option is relative to repo root","fromName":"Daniel Finnie","fromEmail":"dan@danfinnie.com","sentAt":"2015-02-13T21:19:28Z","receivedAt":"2015-02-13T21:19:28Z","isPatch":false,"sender":{"key":"dan@danfinnie.com","avatar":null},"body":"Hi Junio,\n\nThanks for the info and backstory.  I didn't realize that the paths in\nthe file specified by --exclude-from would be relative to the project\nroot.  That makes my original use case kind of silly (it's a long\nstory, but I was curious which files were ignored by a subset of my\n.gitignore files).  This makes the example I gave before wrong in that\nthe contents of example_dir/.gitignore should have been relative to\nthe project root.\n\nThere are 2 sets of paths that can be relative to the working\ndirectory or the project root with --exclude-from:\n* The path to the file containing exclusion rules\n* The paths of the exclusion rules themselves (the contents of the\nfile from the previous bullet point)\n\nI now see why the second needs to be relative to the project root.  I\nstill think it's more intuitive for the first (the path to the file\ncontaining exclusions) to be relative to the current directory.  Your\nexample of `git ls-files -X /var/tmp/exclude -i` uses an absolute\npath, let's look at one with a relative path.  Say you wanted to check\nwhat files were being ignored from your .git/info/exclude file from a\nsubdirectory of your project.  I would expect to run `cd subdirectory\n&& git ls-files --ignore --other --exclude-from=../.git/info/exclude`.\nThe correct command, though, is `cd subdirectory && git ls-files\n--ignore --other --exclude-from=.git/info/exclude`, even though I'm in\na subdirectory.\n\nDo you have any comments on why the path in --exclude-from=<path> is\nrelative to the project root?\n\nThanks,\nDan\n\n\nOn Fri, Feb 13, 2015 at 3:54 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> ...  It does not make sense to allow where you are\n>> to affect behaviour of the command, i.e. in these two invocations of\n>> ls-files:\n>>\n>>       git ls-files -X /var/tmp/exclude -i\n>>         cd example && git ls-files -X /var/tmp/exclude -i\n>>\n>> if the same line in /var/tmp/exclude meant completely different\n>> things, it would be crazy.\n>\n> To put it another way, think of --exclude-from as a way to specify a\n> replacement for .git/info/excludes, and --exclude-per-directory as a\n> way to specify a replacement for the in-tree .gitignore files.\n>\n> Historically, we did not have the --exclude-standard option from the\n> beginning, and only after we gained experience with --exclude-from\n> and --exclude-per-directory in our scripts, the --exclude-standard\n> was added to codify the (then-) best-current-practice after the fact,\n> and we used --exclude-from for exactly that purpose before then.\n>\n> cf. 8e7b07c8 (git-ls-files: add --exclude-standard, 2007-11-15)\n"},{"id":"256094","messageId":"xmqqy4o1lbbx.fsf@gitster.dls.corp.google.com","threadId":"38566","inReplyTo":"CAG4vEKP760_sq1fsJD_1jjz0_G+T8NosSXDqx0bvQy4tPVz5JQ@mail.gmail.com","subject":"Re: git ls-files -X option is relative to repo root","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-02-13T22:02:10Z","receivedAt":"2015-02-13T22:02:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Daniel Finnie <dan@danfinnie.com> writes:\n\n> Do you have any comments on why the path in --exclude-from=<path> is\n> relative to the project root?\n\nNot really.\n\nBecause ls-files was designed to be used by Porcelain scripts, and\nbecause the first thing Porcelain scripts are expected to do is to\nlearn the prefix and then cd to the root level of the working tree\nbefore doing anything else, <path> that is relative to the root\nlevel of the working tree ends up to be not so unnatural thing to be\nused with --exclude-from=<path> (e.g. \".git/info/exclude\").\n\nIf it were relative to whatever subdirectory the invoker of the\nPorcelain script happened to be, Porcelain would have to do a lot\nmore (e.g. in \"cd x/y && myPorcelain ../../.git/info/exclude\", the\nmyPorcelain script would first have to learn the prefix is x/y, go\nup two levels, and then strip two ../ from ../../.git/info/exclude\nto turn it into .git/info/exclude when it runs ls-files).\n\nSo that is a convenience explanation in retrospect, but \"Why\" is\noften a futile question to ask when talking about evolution, in\nwhich whatever works gets picked.\n"}]}