{"thread":{"id":"26838","subject":"Relative ls-files","startedAt":"2011-03-23T10:33:25Z","lastAt":"2011-03-25T09:34:20Z","messageCount":28,"participants":["John Tapsell","Michael J Gruber","demerphq","Martin Langhoff","Junio C Hamano","Nguyen Thai Ngoc Duy","Nguyễn Thái Ngọc Duy"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"164125","messageId":"AANLkTi=fP+jBpLuxst2rv02pYRmj4HOkv8Yenc-dR-N_@mail.gmail.com","threadId":"26838","inReplyTo":null,"subject":"Relative ls-files","fromName":"John Tapsell","fromEmail":"johnflux@gmail.com","sentAt":"2011-03-23T10:33:25Z","receivedAt":"2011-03-23T10:33:25Z","isPatch":false,"sender":{"key":"johnflux@gmail.com","avatar":"https://gravatar.com/avatar/25f70d4c0f96396b84a2e34bcd9bdc233462c7b4be29b5fdca8266fc53f30b0c?d=mp&s=160"},"body":"Hi,\n\n  Could someone add a feature to  ls-files  to list all the files in\nthe repository, but relative to the current path?  It would be useful\nfor many different aliases, such as \"git locate\".\n\nThanks,\n\nJohn\n"},{"id":"164127","messageId":"4D89D052.5030801@drmicha.warpmail.net","threadId":"26838","inReplyTo":"AANLkTi=fP+jBpLuxst2rv02pYRmj4HOkv8Yenc-dR-N_@mail.gmail.com","subject":"Re: Relative ls-files","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-23T10:49:54Z","receivedAt":"2011-03-23T10:49:54Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"John Tapsell venit, vidit, dixit 23.03.2011 11:33:\n> Hi,\n> \n>   Could someone add a feature to  ls-files  to list all the files in\n> the repository, but relative to the current path?  It would be useful\n> for many different aliases, such as \"git locate\".\n\nThat is in the works, we just have to decide between two suggested\nnotations:\n\ngit ls-files :\ngit ls-files :/\n\nMichael\n"},{"id":"164129","messageId":"AANLkTimc7gNKbh3C2hyMtFK6D1OWNALD+GvzmhG5cZrn@mail.gmail.com","threadId":"26838","inReplyTo":"4D89D052.5030801@drmicha.warpmail.net","subject":"Re: Relative ls-files","fromName":"John Tapsell","fromEmail":"johnflux@gmail.com","sentAt":"2011-03-23T11:27:05Z","receivedAt":"2011-03-23T11:27:05Z","isPatch":false,"sender":{"key":"johnflux@gmail.com","avatar":"https://gravatar.com/avatar/25f70d4c0f96396b84a2e34bcd9bdc233462c7b4be29b5fdca8266fc53f30b0c?d=mp&s=160"},"body":"On 23 March 2011 10:49, Michael J Gruber <git@drmicha.warpmail.net> wrote:\n> John Tapsell venit, vidit, dixit 23.03.2011 11:33:\n>> Hi,\n>>\n>>   Could someone add a feature to  ls-files  to list all the files in\n>> the repository, but relative to the current path?  It would be useful\n>> for many different aliases, such as \"git locate\".\n>\n> That is in the works, we just have to decide between two suggested\n> notations:\n>\n> git ls-files :\n> git ls-files :/\n\n\nWhat's wrong with --relative  or something?\n\nI've never liked magical strange notations.  \":\" already has a meaning.\n\nJohn\n"},{"id":"164130","messageId":"AANLkTimdLGgGXGRNVH5+X-cnhK2NWfWx9k0apt-6rr1Z@mail.gmail.com","threadId":"26838","inReplyTo":"AANLkTimc7gNKbh3C2hyMtFK6D1OWNALD+GvzmhG5cZrn@mail.gmail.com","subject":"Re: Relative ls-files","fromName":"demerphq","fromEmail":"demerphq@gmail.com","sentAt":"2011-03-23T11:28:39Z","receivedAt":"2011-03-23T11:28:39Z","isPatch":false,"sender":{"key":"demerphq@gmail.com","avatar":null},"body":"On 23 March 2011 12:27, John Tapsell <johnflux@gmail.com> wrote:\n> On 23 March 2011 10:49, Michael J Gruber <git@drmicha.warpmail.net> wrote:\n>> John Tapsell venit, vidit, dixit 23.03.2011 11:33:\n>>> Hi,\n>>>\n>>>   Could someone add a feature to  ls-files  to list all the files in\n>>> the repository, but relative to the current path?  It would be useful\n>>> for many different aliases, such as \"git locate\".\n>>\n>> That is in the works, we just have to decide between two suggested\n>> notations:\n>>\n>> git ls-files :\n>> git ls-files :/\n>\n>\n> What's wrong with --relative  or something?\n>\n> I've never liked magical strange notations.  \":\" already has a meaning.\n\n+1\n\nyves\n\n-- \nperl -Mre=debug -e \"/just|another|perl|hacker/\"\n"},{"id":"164131","messageId":"4D89DCBE.3060400@drmicha.warpmail.net","threadId":"26838","inReplyTo":"AANLkTimdLGgGXGRNVH5+X-cnhK2NWfWx9k0apt-6rr1Z@mail.gmail.com","subject":"Re: Relative ls-files","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-23T11:42:54Z","receivedAt":"2011-03-23T11:42:54Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"demerphq venit, vidit, dixit 23.03.2011 12:28:\n> On 23 March 2011 12:27, John Tapsell <johnflux@gmail.com> wrote:\n>> On 23 March 2011 10:49, Michael J Gruber <git@drmicha.warpmail.net> wrote:\n>>> John Tapsell venit, vidit, dixit 23.03.2011 11:33:\n>>>> Hi,\n>>>>\n>>>>   Could someone add a feature to  ls-files  to list all the files in\n>>>> the repository, but relative to the current path?  It would be useful\n>>>> for many different aliases, such as \"git locate\".\n>>>\n>>> That is in the works, we just have to decide between two suggested\n>>> notations:\n>>>\n>>> git ls-files :\n>>> git ls-files :/\n>>\n>>\n>> What's wrong with --relative  or something?\n\n??\n\nls-files already lists files relative to cwd. What you need is a way to\nspecify that you want all files, not just those beneath cwd.\n\n>>\n>> I've never liked magical strange notations.  \":\" already has a meaning.\n> \n> +1\n\nI think you've both been missing out on the discussions about\n--full-tree and refspec notation for that...\n\nOf course \":\" has a meaning. \"git show HEAD:\" lists all files at the\ntop-level of the tree at HEAD. That is exactly why \":\" has been\nsuggested to denote the top-level for pathspecs also. Note that this is\nmuch more general than just an option for ls-files.\n\nMichael\n"},{"id":"164142","messageId":"AANLkTi=BrgZe47Bt5evr_qFzKBL=MY-6NmH22gsRurVV@mail.gmail.com","threadId":"26838","inReplyTo":"4D89DCBE.3060400@drmicha.warpmail.net","subject":"Re: Relative ls-files","fromName":"Martin Langhoff","fromEmail":"martin.langhoff@gmail.com","sentAt":"2011-03-23T13:54:45Z","receivedAt":"2011-03-23T13:54:45Z","isPatch":false,"sender":{"key":"martin.langhoff@gmail.com","avatar":"https://gravatar.com/avatar/1e3f311b6c4c15836501901ca58f8c0b0667246488084ba524d8bc9867e22fd9?d=mp&s=160"},"body":"On Wed, Mar 23, 2011 at 7:42 AM, Michael J Gruber\n<git@drmicha.warpmail.net> wrote:\n> Of course \":\" has a meaning. \"git show HEAD:\" lists all files at the\n> top-level of the tree at HEAD.\n\nI got excited for a moment... now tested it and there isn't a recursive flag :-(\n\nI've been pining for something easy and intuitive like git ls-files\n<treeish>. You can do git ls-files --with-tree=<treeish> but I find it\nvery counter-intuitive.\n\nContext: in some projects, I need to ask\n\n - is this file in branch foo?\n - has this file moved in branch foo?\n - what files with extension .zoo exist in branch foo?\n\nand the answer is git ls-files --with-tree=<treeish> | grep <regex> .\nBut the --with-tree param is so counterintuitive to me that I read the\nmanpage, everytime.\n\nNot sure whether the bug is in me or in git, but it sure hits some\ncognitive dissonance.\n\n\nm\n-- \n martin.langhoff@gmail.com\n martin@laptop.org -- Software Architect - OLPC\n - ask interesting questions\n - don't get distracted with shiny stuff  - working code first\n - http://wiki.laptop.org/go/User:Martinlanghoff\n"},{"id":"164145","messageId":"7v7hbqgc7g.fsf@alter.siamese.dyndns.org","threadId":"26838","inReplyTo":"AANLkTi=BrgZe47Bt5evr_qFzKBL=MY-6NmH22gsRurVV@mail.gmail.com","subject":"Re: Relative ls-files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-23T14:09:55Z","receivedAt":"2011-03-23T14:09:55Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Martin Langhoff <martin.langhoff@gmail.com> writes:\n\n> and the answer is git ls-files --with-tree=<treeish> | grep <regex> .\n> But the --with-tree param is so counterintuitive to me that I read the\n> manpage, everytime.\n\nBecause --with-tree nor ls-files is the tool that was designed for.\n\nIf you want to find out about a branch, why aren't you using \"ls-tree -r\"?\n"},{"id":"164146","messageId":"AANLkTi=OJ_o2WQ2W6d30HXQZrg7=W70+fZWrbQPrAs=s@mail.gmail.com","threadId":"26838","inReplyTo":"7v7hbqgc7g.fsf@alter.siamese.dyndns.org","subject":"Re: Relative ls-files","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-23T14:14:08Z","receivedAt":"2011-03-23T14:14:08Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Mar 23, 2011 at 9:09 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Martin Langhoff <martin.langhoff@gmail.com> writes:\n>\n>> and the answer is git ls-files --with-tree=<treeish> | grep <regex> .\n>> But the --with-tree param is so counterintuitive to me that I read the\n>> manpage, everytime.\n>\n> Because --with-tree nor ls-files is the tool that was designed for.\n>\n> If you want to find out about a branch, why aren't you using \"ls-tree -r\"?\n\n(off topic?)\n\n\"ls-tree -r\" does not understand wildcards. Maybe it should not, but I\nthink read_tree_recursive() should use tree_entry_interesting(). The\nfunction it uses for matching, match_tree_entry, looks like another\nvariant of t_e_interesting.\n-- \nDuy\n"},{"id":"164148","messageId":"AANLkTinGedXLX_rZTtx6CeDonQ0dbsN2BBSqPcs258Yg@mail.gmail.com","threadId":"26838","inReplyTo":"7v7hbqgc7g.fsf@alter.siamese.dyndns.org","subject":"Re: Relative ls-files","fromName":"Martin Langhoff","fromEmail":"martin.langhoff@gmail.com","sentAt":"2011-03-23T14:46:41Z","receivedAt":"2011-03-23T14:46:41Z","isPatch":false,"sender":{"key":"martin.langhoff@gmail.com","avatar":"https://gravatar.com/avatar/1e3f311b6c4c15836501901ca58f8c0b0667246488084ba524d8bc9867e22fd9?d=mp&s=160"},"body":"On Wed, Mar 23, 2011 at 10:09 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Because --with-tree nor ls-files is the tool that was designed for.\n>\n> If you want to find out about a branch, why aren't you using \"ls-tree -r\"?\n\nThanks! Tab-completion wasn't showing it, so I never saw it.\n\nhappy happy\n\n\n\nm\n-- \n martin.langhoff@gmail.com\n martin@laptop.org -- Software Architect - OLPC\n - ask interesting questions\n - don't get distracted with shiny stuff  - working code first\n - http://wiki.laptop.org/go/User:Martinlanghoff\n"},{"id":"164151","messageId":"7v39mdhni3.fsf@alter.siamese.dyndns.org","threadId":"26838","inReplyTo":"AANLkTi=OJ_o2WQ2W6d30HXQZrg7=W70+fZWrbQPrAs=s@mail.gmail.com","subject":"Re: Relative ls-files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-23T15:20:36Z","receivedAt":"2011-03-23T15:20:36Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n\n> (off topic?)\n>\n> \"ls-tree -r\" does not understand wildcards. Maybe it should not, but I\n> think read_tree_recursive() should use tree_entry_interesting(). The\n> function it uses for matching, match_tree_entry, looks like another\n> variant of t_e_interesting.\n\nI thought that you already did that within the scope of your earlier\ntopic.\n\n\"ls-tree\" is quite a low-level plumbing, and until we absolutely know that\nall the old scripts people wrote relying on its original behaviour are\nextinct, we shouldn't touch it without a reasonable breakage protection.\n\nIt is Ok to give it a command line option to make it in line with other\npathspec users, namely, that causes the command to missing pathspec should\nautomatically mean the whole tree and to honor globs.  No existing script\nwould be using that option, so that is a safe thing to do.\n"},{"id":"164152","messageId":"7vy645g8qk.fsf@alter.siamese.dyndns.org","threadId":"26838","inReplyTo":"AANLkTinGedXLX_rZTtx6CeDonQ0dbsN2BBSqPcs258Yg@mail.gmail.com","subject":"Re: Relative ls-files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-23T15:24:51Z","receivedAt":"2011-03-23T15:24:51Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Martin Langhoff <martin.langhoff@gmail.com> writes:\n\n> On Wed, Mar 23, 2011 at 10:09 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Because --with-tree nor ls-files is the tool that was designed for.\n>>\n>> If you want to find out about a branch, why aren't you using \"ls-tree -r\"?\n>\n> Thanks! Tab-completion wasn't showing it, so I never saw it.\n\nGoing back to your original (which I suspect may be different from John\nTapsell's original):\n\n - is this file in branch foo?\n - has this file moved in branch foo?\n - what files with extension .zoo exist in branch foo?\n\nI am not sure what the difference between the first two question, but the\nmost direct way the scripted Porcelains do to answer these questions is:\n\n\tgit rev-parse --verify \"foo:$the_path\"\n\nThe third question can be answered by listing paths in branch 'foo' and\nlooking for .zoo, like so:\n\n\tgit ls-tree -r --name-only --full-tree foo | grep '\\.zoo$'\n"},{"id":"164154","messageId":"AANLkTin=y=THaQEzgMhyBVLBriJBCa-pVvONXDnzUmew@mail.gmail.com","threadId":"26838","inReplyTo":"7v39mdhni3.fsf@alter.siamese.dyndns.org","subject":"Re: Relative ls-files","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-23T15:41:47Z","receivedAt":"2011-03-23T15:41:47Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Mar 23, 2011 at 10:20 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n>\n>> (off topic?)\n>>\n>> \"ls-tree -r\" does not understand wildcards. Maybe it should not, but I\n>> think read_tree_recursive() should use tree_entry_interesting(). The\n>> function it uses for matching, match_tree_entry, looks like another\n>> variant of t_e_interesting.\n>\n> I thought that you already did that within the scope of your earlier\n> topic.\n>\n> \"ls-tree\" is quite a low-level plumbing, and until we absolutely know that\n> all the old scripts people wrote relying on its original behaviour are\n> extinct, we shouldn't touch it without a reasonable breakage protection.\n>\n> It is Ok to give it a command line option to make it in line with other\n> pathspec users, namely, that causes the command to missing pathspec should\n> automatically mean the whole tree and to honor globs.  No existing script\n> would be using that option, so that is a safe thing to do.\n\nThis read_tree_recursive() affects 'archive' and 'checkout -- paths'\n(ie. no wildcard awareness). I will probably move match_tree_entry()\nto ls-tree.c to preserve its behavior, then change\nread_tree_recursive() to use tree_entry_interesting().\n-- \nDuy\n"},{"id":"164155","messageId":"7voc51g7xo.fsf@alter.siamese.dyndns.org","threadId":"26838","inReplyTo":"4D89DCBE.3060400@drmicha.warpmail.net","subject":"Re: Relative ls-files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-23T15:42:11Z","receivedAt":"2011-03-23T15:42:11Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n>>> What's wrong with --relative  or something?\n>\n> ??\n>\n> ls-files already lists files relative to cwd. What you need is a way to\n> specify that you want all files, not just those beneath cwd.\n\nExactly.\n\n>>> I've never liked magical strange notations.  \":\" already has a meaning.\n>> \n>> +1\n>\n> I think you've both been missing out on the discussions about\n> --full-tree and refspec notation for that...\n\nI like this answer.  Don't pay any much attention +1/-1 from people who\nare clueless to the topic, but do pay attention to them as persons by\nshowing that there are things for them to read and learn if they want to\ndiscuss the topic.  A URL or two to the recent thread may have been nicer.\n\n> Of course \":\" has a meaning. \"git show HEAD:\" lists all files at the\n> top-level of the tree at HEAD. That is exactly why \":\" has been\n> suggested to denote the top-level for pathspecs also. Note that this is\n> much more general than just an option for ls-files.\n\nTalking about the \"pathspec magic\", I think in addition to \"this is\nrelative to root\", we at least would need \"this is literal, don't apply\nglobbing\" magic.  I am afraid that using ':' as the sole \"magic for\nfrom-root\" as you advocate may turn out to be too short-sighted and would\nhurt us in the future.\n\nIt may be more extensible if we used a common \"magic introducer\" at the\nbeginning, an character unlikely to collide with any pathspec existing\nscripts and people use, and then have additional \"what magic I want\"\nsignature immediately following that introducer letter in these magic\nfilespecs.\n\nOff the to of my head, \"/\" may be a perfect choice for \"here is a magic\"\nintroducer, as we never give absolute paths on the fiesystem from the root\nto git [*1*].\n\nThen, even when you are in a subdirectory somewhere, this:\n\n    $ git ls-tree pu -- '/:*.h' \"/!$path\"\n\nwould list paths in the pu branch, limiting its output to any \"*.h\" header\nfile, and a path that matches exactly with whatever is in $path variable\nwithout globbing within the current level.  The above uses ':' as \"this is\nrelative to root\" (your favorite, whose rationale being that HEAD:Makefile\nnames Makefile at the top) and '!' (randombly chosen without any rationale\nother than being \"NOT\" and without any association with \"glob\", which make\nit a bad choice of the letter) as \"this is NOT a glob\".\n\nIf we use ':' as the magic introducer, '::*.h\" may be more logical if you\nfollow your \"HEAD:Makefile names Makefile at the top\" analogy; ':/' breaks\nthe analogy (the first colon is a general introducer and does not talk\nanything about what kind of magic; the second letter should be what magic\nit is about, and should use ':' from HEAD:Makefile analogy).\n\nI personally think \"//*.h\" looks a lot more natural than either ':*.h' or\n':/*.h' that have been suggested on the command line, so I am tempted to\nsuggest using '/' (the first slash in the example) as the magic introducer\nand using '/' (the second) as the 'from-root' magic signature.\n\n\n[Footnote]\n\n*1* I am ignoring \"--no-index\" variants that are not strictly part of git\nhere, but I suspect this might also affect \"git add /path/from/root\" which\nI think we should deal with somehow.\n"},{"id":"164159","messageId":"4D8A1883.1030606@drmicha.warpmail.net","threadId":"26838","inReplyTo":"7voc51g7xo.fsf@alter.siamese.dyndns.org","subject":"Re: Relative ls-files","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-23T15:57:55Z","receivedAt":"2011-03-23T15:57:55Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Junio C Hamano venit, vidit, dixit 23.03.2011 16:42:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n> \n>>>> What's wrong with --relative  or something?\n>>\n>> ??\n>>\n>> ls-files already lists files relative to cwd. What you need is a way to\n>> specify that you want all files, not just those beneath cwd.\n> \n> Exactly.\n> \n>>>> I've never liked magical strange notations.  \":\" already has a meaning.\n>>>\n>>> +1\n>>\n>> I think you've both been missing out on the discussions about\n>> --full-tree and refspec notation for that...\n> \n> I like this answer.  Don't pay any much attention +1/-1 from people who\n> are clueless to the topic, but do pay attention to them as persons by\n> showing that there are things for them to read and learn if they want to\n> discuss the topic.  A URL or two to the recent thread may have been nicer.\n> \n>> Of course \":\" has a meaning. \"git show HEAD:\" lists all files at the\n>> top-level of the tree at HEAD. That is exactly why \":\" has been\n>> suggested to denote the top-level for pathspecs also. Note that this is\n>> much more general than just an option for ls-files.\n> \n> Talking about the \"pathspec magic\", I think in addition to \"this is\n> relative to root\", we at least would need \"this is literal, don't apply\n> globbing\" magic.  I am afraid that using ':' as the sole \"magic for\n> from-root\" as you advocate may turn out to be too short-sighted and would\n> hurt us in the future.\n\nI admit I haven't thought much about globbing. Does my current POC patch\naffect globbing in the way you want to avoid?\n\n> \n> It may be more extensible if we used a common \"magic introducer\" at the\n> beginning, an character unlikely to collide with any pathspec existing\n> scripts and people use, and then have additional \"what magic I want\"\n> signature immediately following that introducer letter in these magic\n> filespecs.\n> \n> Off the to of my head, \"/\" may be a perfect choice for \"here is a magic\"\n> introducer, as we never give absolute paths on the fiesystem from the root\n> to git [*1*].\n> \n> Then, even when you are in a subdirectory somewhere, this:\n> \n>     $ git ls-tree pu -- '/:*.h' \"/!$path\"\n> \n> would list paths in the pu branch, limiting its output to any \"*.h\" header\n> file, and a path that matches exactly with whatever is in $path variable\n> without globbing within the current level.  The above uses ':' as \"this is\n> relative to root\" (your favorite, whose rationale being that HEAD:Makefile\n> names Makefile at the top) and '!' (randombly chosen without any rationale\n> other than being \"NOT\" and without any association with \"glob\", which make\n> it a bad choice of the letter) as \"this is NOT a glob\".\n> \n> If we use ':' as the magic introducer, '::*.h\" may be more logical if you\n> follow your \"HEAD:Makefile names Makefile at the top\" analogy; ':/' breaks\n> the analogy (the first colon is a general introducer and does not talk\n> anything about what kind of magic; the second letter should be what magic\n> it is about, and should use ':' from HEAD:Makefile analogy).\n\nMainly I want \"few characters\" (up to 2) and \"good analogy\". \"/\" and\n\"//\" have obvious good analogies to file system usage.\n\n> \n> I personally think \"//*.h\" looks a lot more natural than either ':*.h' or\n\nWith current git:\n\n(cd Documentation && git show :Makefile)\n\nWhich Makefile do you get? That is why I call the \":\" proposal natural.\nI know, \"git show Makefile\" does not give the local one, but\n\ngit show :./Makefile\n\ndoes. Given this, I would find \":/Makefile\" very natural as well.\n\n> ':/*.h' that have been suggested on the command line, so I am tempted to\n> suggest using '/' (the first slash in the example) as the magic introducer\n> and using '/' (the second) as the 'from-root' magic signature.\n\nI'm afraid (but not sure) that leading \"/\" would create problems for Git\non Win! \":/\" is fine according to the experts.\n\nMichael\n"},{"id":"164160","messageId":"AANLkTin=7FzjrJ1q3_AgO9erWEsm=DSoHMUPDiwFAqr2@mail.gmail.com","threadId":"26838","inReplyTo":"4D8A1883.1030606@drmicha.warpmail.net","subject":"Re: Relative ls-files","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-23T16:10:23Z","receivedAt":"2011-03-23T16:10:23Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Mar 23, 2011 at 10:57 PM, Michael J Gruber\n<git@drmicha.warpmail.net> wrote:\n>> ':/*.h' that have been suggested on the command line, so I am tempted to\n>> suggest using '/' (the first slash in the example) as the magic introducer\n>> and using '/' (the second) as the 'from-root' magic signature.\n>\n> I'm afraid (but not sure) that leading \"/\" would create problems for Git\n> on Win! \":/\" is fine according to the experts.\n\n'/' is treated more or less just like '\\' on Windows so it would not\nbe a big deal. The 'git add /foo/bar' issue is more interesting, imo.\n-- \nDuy\n"},{"id":"164170","messageId":"7vzkoleo45.fsf@alter.siamese.dyndns.org","threadId":"26838","inReplyTo":"7v7hbqgc7g.fsf@alter.siamese.dyndns.org","subject":"Re: Relative ls-files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-23T17:35:38Z","receivedAt":"2011-03-23T17:35:38Z","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> Martin Langhoff <martin.langhoff@gmail.com> writes:\n>\n>> and the answer is git ls-files --with-tree=<treeish> | grep <regex> .\n>> But the --with-tree param is so counterintuitive to me that I read the\n>> manpage, everytime.\n>\n> Because --with-tree nor ls-files is the tool that was designed for.\n>\n> If you want to find out about a branch, why aren't you using \"ls-tree -r\"?\n\nIt obviously needs a side note to answer \"what is 'ls-files --with-tree'\nfor, then?\", so here is such a note.\n\nThe --with-tree option was invented for the sole purpose of helping \"git\ncommit -- $paths\" back when \"commit\" was still a scripted Porcelain.  We\nwanted to make sure that the $paths given from the command line made sense\n(we wanted to diagnose e.g. \"git commit Mkaefile\" as a typo).\n\nThe obvious plumbing to check if the given pathspec matches what are known\nto git (i.e. in the index) is:\n\n\tgit ls-files --error-unmatch -- $paths\n\nbut there is a catch.  If you are about to commit a removal of a path,\ni.e.\n\n\t$ rm -f generated-file.c\n\t$ git update-index --remove generated-file.c\n        $ git commit -m \"Do not keep a generated file in SCM\" generated-file.c\n\nthe above ls-files would report that the pathspec \"generated-file.c\" does\nnot match, as that path is no longer in the index.\n\nTo make the \"ls-files --error-unmatch\" useful for this check, we use:\n\n\tgit ls-files --error-unmatch --with-tree=HEAD -- $paths\n\nto overlay the contents of the tree on top of what is already in the index\nand then determine what paths are \"known\" to git at that point.\n\nSo your use of \"git ls-files --with-tree=<unrelated branch>\" has been\ngiving results that you didn't want to see, as the set of paths in your\nindex that is based on your current branch most likely are different from\nwhat is in that unrelated branch.\n\nI don't think there is any in-tree users of --with-tree option anymore,\nother than the tests, so it probably is not even worth thinking about\nremoving it and replacing it with a --with-head-tree (as using any commit\nother than HEAD makes little sense) option.\n"},{"id":"164189","messageId":"7vaaglcv9f.fsf@alter.siamese.dyndns.org","threadId":"26838","inReplyTo":"AANLkTin=y=THaQEzgMhyBVLBriJBCa-pVvONXDnzUmew@mail.gmail.com","subject":"Re: Relative ls-files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-23T22:44:12Z","receivedAt":"2011-03-23T22:44:12Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n\n> This read_tree_recursive() affects 'archive' and 'checkout -- paths'\n> (ie. no wildcard awareness). I will probably move match_tree_entry()\n> to ls-tree.c to preserve its behavior, then change\n> read_tree_recursive() to use tree_entry_interesting().\n\n[jc: culled people other than those in the \"magic pathspec\" discussion\nfrom CC list]\n\nWouldn't it be more sensible to add a bit (\"is this a glob or are we\nexpected to match it literally\") to each element in the pathspec array,\nand pass a pathspec whose elements are all marked as \"literal\" down from\nls-tree?\n\nThe internal matcher (and traversal optimizer) would need to become aware\nof \"not a glob\" match (and possibly different kinds of matches like \"**/\"\nsupport) sooner or later, and when that happens you would need something\nlike the above on the caller side in ls-tree.\n"},{"id":"164226","messageId":"AANLkTinYB=ZUTe29Y9ibLVL5z3KhiYmnCpCGcHx=18RJ@mail.gmail.com","threadId":"26838","inReplyTo":"7vaaglcv9f.fsf@alter.siamese.dyndns.org","subject":"Re: Relative ls-files","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-24T13:26:45Z","receivedAt":"2011-03-24T13:26:45Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 24, 2011 at 5:44 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Wouldn't it be more sensible to add a bit (\"is this a glob or are we\n> expected to match it literally\") to each element in the pathspec array,\n> and pass a pathspec whose elements are all marked as \"literal\" down from\n> ls-tree?\n>\n> The internal matcher (and traversal optimizer) would need to become aware\n> of \"not a glob\" match (and possibly different kinds of matches like \"**/\"\n> support) sooner or later, and when that happens you would need something\n> like the above on the caller side in ls-tree.\n\nI think it's possible even now. fnmatch() is only used if\npathspec_item.has_wildcard is true. So ls-tree.c only needs to clear\nthis field for all pathspecs and they will be treated literally. Let\nme try..\n-- \nDuy\n"},{"id":"164228","messageId":"1300977675-6243-1-git-send-email-pclouds@gmail.com","threadId":"26838","inReplyTo":"AANLkTinYB=ZUTe29Y9ibLVL5z3KhiYmnCpCGcHx=18RJ@mail.gmail.com","subject":"[PATCH 1/2] Reimplement read_tree_recursive() using tree_entry_interesting()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-24T14:41:14Z","receivedAt":"2011-03-24T14:41:14Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"read_tree_recursive() uses a very similar function, match_tree_entry, to\ntree_entry_interesting() to do its path matching. This patch kills\nmatch_tree_entry() in favor of tree_entry_interesting().\n\nmatch_tree_entry(), like older version of tree_entry_interesting(), does\nnot support wildcard matching. New read_tree_recursive() retains this\nbehavior by forcing all pathspecs literal.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n tree.c |  156 +++++++++++++++++++++++++--------------------------------------\n 1 files changed, 62 insertions(+), 94 deletions(-)\n\ndiff --git a/tree.c b/tree.c\nindex 5ab90af..2b23381 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -45,62 +45,14 @@ static int read_one_entry_quick(const unsigned char *sha1, const char *base, int\n \t\t\t\t  ADD_CACHE_JUST_APPEND);\n }\n \n-static int match_tree_entry(const char *base, int baselen, const char *path, unsigned int mode, const char **paths)\n-{\n-\tconst char *match;\n-\tint pathlen;\n-\n-\tif (!paths)\n-\t\treturn 1;\n-\tpathlen = strlen(path);\n-\twhile ((match = *paths++) != NULL) {\n-\t\tint matchlen = strlen(match);\n-\n-\t\tif (baselen >= matchlen) {\n-\t\t\t/* If it doesn't match, move along... */\n-\t\t\tif (strncmp(base, match, matchlen))\n-\t\t\t\tcontinue;\n-\t\t\t/* pathspecs match only at the directory boundaries */\n-\t\t\tif (!matchlen ||\n-\t\t\t    baselen == matchlen ||\n-\t\t\t    base[matchlen] == '/' ||\n-\t\t\t    match[matchlen - 1] == '/')\n-\t\t\t\treturn 1;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\t/* Does the base match? */\n-\t\tif (strncmp(base, match, baselen))\n-\t\t\tcontinue;\n-\n-\t\tmatch += baselen;\n-\t\tmatchlen -= baselen;\n-\n-\t\tif (pathlen > matchlen)\n-\t\t\tcontinue;\n-\n-\t\tif (matchlen > pathlen) {\n-\t\t\tif (match[pathlen] != '/')\n-\t\t\t\tcontinue;\n-\t\t\tif (!S_ISDIR(mode))\n-\t\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (strncmp(path, match, pathlen))\n-\t\t\tcontinue;\n-\n-\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-int read_tree_recursive(struct tree *tree,\n-\t\t\tconst char *base, int baselen,\n-\t\t\tint stage, const char **match,\n-\t\t\tread_tree_fn_t fn, void *context)\n+static int read_tree_1(struct tree *tree, struct strbuf *base,\n+\t\t       int stage, struct pathspec *pathspecs,\n+\t\t       read_tree_fn_t fn, void *context)\n {\n \tstruct tree_desc desc;\n \tstruct name_entry entry;\n+\tunsigned char sha1[20];\n+\tint len, retval, all_interesting = 0, oldlen = base->len;\n \n \tif (parse_tree(tree))\n \t\treturn -1;\n@@ -108,10 +60,22 @@ int read_tree_recursive(struct tree *tree,\n \tinit_tree_desc(&desc, tree->buffer, tree->size);\n \n \twhile (tree_entry(&desc, &entry)) {\n-\t\tif (!match_tree_entry(base, baselen, entry.path, entry.mode, match))\n+\t\tif (all_interesting)\n+\t\t\tretval = all_interesting > 0;\n+\t\telse {\n+\t\t\tretval = tree_entry_interesting(&entry, base, 0, pathspecs);\n+\t\t\tif (retval == 2)\n+\t\t\t\tall_interesting = 1;\n+\t\t\telse if (retval == -1) {\n+\t\t\t\tall_interesting = -1;\n+\t\t\t\tretval = 0;\n+\t\t\t}\n+\t\t}\n+\t\tif (!retval)\n \t\t\tcontinue;\n \n-\t\tswitch (fn(entry.sha1, base, baselen, entry.path, entry.mode, stage, context)) {\n+\t\tswitch (fn(entry.sha1, base->buf, base->len,\n+\t\t\t   entry.path, entry.mode, stage, context)) {\n \t\tcase 0:\n \t\t\tcontinue;\n \t\tcase READ_TREE_RECURSIVE:\n@@ -119,56 +83,60 @@ int read_tree_recursive(struct tree *tree,\n \t\tdefault:\n \t\t\treturn -1;\n \t\t}\n-\t\tif (S_ISDIR(entry.mode)) {\n-\t\t\tint retval;\n-\t\t\tchar *newbase;\n-\t\t\tunsigned int pathlen = tree_entry_len(entry.path, entry.sha1);\n-\n-\t\t\tnewbase = xmalloc(baselen + 1 + pathlen);\n-\t\t\tmemcpy(newbase, base, baselen);\n-\t\t\tmemcpy(newbase + baselen, entry.path, pathlen);\n-\t\t\tnewbase[baselen + pathlen] = '/';\n-\t\t\tretval = read_tree_recursive(lookup_tree(entry.sha1),\n-\t\t\t\t\t\t     newbase,\n-\t\t\t\t\t\t     baselen + pathlen + 1,\n-\t\t\t\t\t\t     stage, match, fn, context);\n-\t\t\tfree(newbase);\n-\t\t\tif (retval)\n-\t\t\t\treturn -1;\n-\t\t\tcontinue;\n-\t\t} else if (S_ISGITLINK(entry.mode)) {\n-\t\t\tint retval;\n-\t\t\tstruct strbuf path;\n-\t\t\tunsigned int entrylen;\n-\t\t\tstruct commit *commit;\n \n-\t\t\tentrylen = tree_entry_len(entry.path, entry.sha1);\n-\t\t\tstrbuf_init(&path, baselen + entrylen + 1);\n-\t\t\tstrbuf_add(&path, base, baselen);\n-\t\t\tstrbuf_add(&path, entry.path, entrylen);\n-\t\t\tstrbuf_addch(&path, '/');\n+\t\tif (S_ISDIR(entry.mode))\n+\t\t\thashcpy(sha1, entry.sha1);\n+\t\telse if (S_ISGITLINK(entry.mode)) {\n+\t\t\tstruct commit *commit;\n \n \t\t\tcommit = lookup_commit(entry.sha1);\n \t\t\tif (!commit)\n-\t\t\t\tdie(\"Commit %s in submodule path %s not found\",\n-\t\t\t\t    sha1_to_hex(entry.sha1), path.buf);\n+\t\t\t\tdie(\"Commit %s in submodule path %s%s not found\",\n+\t\t\t\t    sha1_to_hex(entry.sha1),\n+\t\t\t\t    base->buf, entry.path);\n \n \t\t\tif (parse_commit(commit))\n-\t\t\t\tdie(\"Invalid commit %s in submodule path %s\",\n-\t\t\t\t    sha1_to_hex(entry.sha1), path.buf);\n-\n-\t\t\tretval = read_tree_recursive(commit->tree,\n-\t\t\t\t\t\t     path.buf, path.len,\n-\t\t\t\t\t\t     stage, match, fn, context);\n-\t\t\tstrbuf_release(&path);\n-\t\t\tif (retval)\n-\t\t\t\treturn -1;\n-\t\t\tcontinue;\n+\t\t\t\tdie(\"Invalid commit %s in submodule path %s%s\",\n+\t\t\t\t    sha1_to_hex(entry.sha1),\n+\t\t\t\t    base->buf, entry.path);\n+\n+\t\t\thashcpy(sha1, commit->tree->object.sha1);\n \t\t}\n+\t\telse\n+\t\t\tcontinue;\n+\n+\t\tlen = tree_entry_len(entry.path, entry.sha1);\n+\t\tstrbuf_add(base, entry.path, len);\n+\t\tstrbuf_addch(base, '/');\n+\t\tretval = read_tree_1(lookup_tree(sha1),\n+\t\t\t\t     base, stage, pathspecs,\n+\t\t\t\t     fn, context);\n+\t\tstrbuf_setlen(base, oldlen);\n+\t\tif (retval)\n+\t\t\treturn -1;\n \t}\n \treturn 0;\n }\n \n+int read_tree_recursive(struct tree *tree,\n+\t\t\tconst char *base, int baselen,\n+\t\t\tint stage, const char **match,\n+\t\t\tread_tree_fn_t fn, void *context)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstruct pathspec pathspecs;\n+\tint i, ret;\n+\n+\tinit_pathspec(&pathspecs, match);\n+\tfor (i = 0; i < pathspecs.nr; i++)\n+\t\tpathspecs.items[i].has_wildcard = 0;\n+\tstrbuf_add(&sb, base, baselen);\n+\tret = read_tree_1(tree, &sb, stage, &pathspecs, fn, context);\n+\tstrbuf_release(&sb);\n+\tfree_pathspec(&pathspecs);\n+\treturn ret;\n+}\n+\n static int cmp_cache_name_compare(const void *a_, const void *b_)\n {\n \tconst struct cache_entry *ce1, *ce2;\n-- \n1.7.4.74.g639db\n"},{"id":"164229","messageId":"1300977675-6243-2-git-send-email-pclouds@gmail.com","threadId":"26838","inReplyTo":"1300977675-6243-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 2/2] Convert read_tree{,_recursive} to support struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-24T14:41:15Z","receivedAt":"2011-03-24T14:41:15Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This patch changes behavior of the two functions. Previously it does\nprefix matching only. Now it can also do wildcard matching.\n\nAll callers are updated. Some gain wildcard matching (archive,\ncheckout), others reset pathspec_item.has_wildcard to retain old\nbehavior (ls-files, ls-tree as they are plumbing).\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n I should add a few more tests for other touched commands too. Later..\n\n archive.c                    |   14 ++++++++++----\n builtin/checkout.c           |    5 ++++-\n builtin/ls-files.c           |    9 +++++----\n builtin/ls-tree.c            |   12 +++++++-----\n merge-recursive.c            |    4 +++-\n t/t3102-ls-tree-wildcards.sh |   22 ++++++++++++++++++++++\n tree.c                       |   13 ++++---------\n tree.h                       |    4 ++--\n 8 files changed, 57 insertions(+), 26 deletions(-)\n create mode 100755 t/t3102-ls-tree-wildcards.sh\n\ndiff --git a/archive.c b/archive.c\nindex 1944ed4..6eb5837 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -157,6 +157,7 @@ int write_archive_entries(struct archiver_args *args,\n \tstruct archiver_context context;\n \tstruct unpack_trees_options opts;\n \tstruct tree_desc t;\n+\tstruct pathspec pathspecs;\n \tint err;\n \n \tif (args->baselen > 0 && args->base[args->baselen - 1] == '/') {\n@@ -191,8 +192,10 @@ int write_archive_entries(struct archiver_args *args,\n \t\tgit_attr_set_direction(GIT_ATTR_INDEX, &the_index);\n \t}\n \n-\terr = read_tree_recursive(args->tree, \"\", 0, 0, args->pathspec,\n+\tinit_pathspec(&pathspecs, args->pathspec);\n+\terr = read_tree_recursive(args->tree, \"\", 0, 0, &pathspecs,\n \t\t\t\t  write_archive_entry, &context);\n+\tfree_pathspec(&pathspecs);\n \tif (err == READ_TREE_RECURSIVE)\n \t\terr = 0;\n \treturn err;\n@@ -222,10 +225,13 @@ static int reject_entry(const unsigned char *sha1, const char *base,\n static int path_exists(struct tree *tree, const char *path)\n {\n \tconst char *pathspec[] = { path, NULL };\n+\tstruct pathspec pathspecs;\n+\tint ret;\n \n-\tif (read_tree_recursive(tree, \"\", 0, 0, pathspec, reject_entry, NULL))\n-\t\treturn 1;\n-\treturn 0;\n+\tinit_pathspec(&pathspecs, pathspec);\n+\tret = read_tree_recursive(tree, \"\", 0, 0, &pathspecs, reject_entry, NULL);\n+\tfree_pathspec(&pathspecs);\n+\treturn ret != 0;\n }\n \n static void parse_pathspec_arg(const char **pathspec,\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2bf02f2..1558910 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -79,7 +79,10 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,\n \n static int read_tree_some(struct tree *tree, const char **pathspec)\n {\n-\tread_tree_recursive(tree, \"\", 0, 0, pathspec, update_some, NULL);\n+\tstruct pathspec pathspecs;\n+\tinit_pathspec(&pathspecs, pathspec);\n+\tread_tree_recursive(tree, \"\", 0, 0, &pathspecs, update_some, NULL);\n+\tfree_pathspec(&pathspecs);\n \n \t/* update the index with the given tree's info\n \t * for all args, expanding wildcards, and exit\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex fb2d5f4..2e001e1 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -338,7 +338,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n {\n \tstruct tree *tree;\n \tunsigned char sha1[20];\n-\tconst char **match;\n+\tstruct pathspec pathspecs;\n \tstruct cache_entry *last_stage0 = NULL;\n \tint i;\n \n@@ -360,10 +360,11 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\tstatic const char *(matchbuf[2]);\n \t\tmatchbuf[0] = prefix;\n \t\tmatchbuf[1] = NULL;\n-\t\tmatch = matchbuf;\n+\t\tinit_pathspec(&pathspecs, matchbuf);\n+\t\tpathspecs.items[0].has_wildcard = 0;\n \t} else\n-\t\tmatch = NULL;\n-\tif (read_tree(tree, 1, match))\n+\t\tinit_pathspec(&pathspecs, NULL);\n+\tif (read_tree(tree, 1, &pathspecs))\n \t\tdie(\"unable to read tree entries %s\", tree_name);\n \n \tfor (i = 0; i < active_nr; i++) {\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex f73e6bd..9c074de 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -19,7 +19,7 @@ static int line_termination = '\\n';\n #define LS_SHOW_SIZE 16\n static int abbrev;\n static int ls_options;\n-static const char **pathspec;\n+static struct pathspec pathspecs;\n static int chomp_prefix;\n static const char *ls_tree_prefix;\n \n@@ -35,7 +35,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n \tif (ls_options & LS_RECURSIVE)\n \t\treturn 1;\n \n-\ts = pathspec;\n+\ts = pathspecs.raw;\n \tif (!s)\n \t\treturn 0;\n \n@@ -120,7 +120,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n {\n \tunsigned char sha1[20];\n \tstruct tree *tree;\n-\tint full_tree = 0;\n+\tint i, full_tree = 0;\n \tconst struct option ls_tree_options[] = {\n \t\tOPT_BIT('d', NULL, &ls_options, \"only show trees\",\n \t\t\tLS_TREE_ONLY),\n@@ -166,11 +166,13 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \tif (get_sha1(argv[0], sha1))\n \t\tdie(\"Not a valid object name %s\", argv[0]);\n \n-\tpathspec = get_pathspec(prefix, argv + 1);\n+\tinit_pathspec(&pathspecs, get_pathspec(prefix, argv + 1));\n+\tfor (i = 0; i < pathspecs.nr; i++)\n+\t\tpathspecs.items[i].has_wildcard = 0;\n \ttree = parse_tree_indirect(sha1);\n \tif (!tree)\n \t\tdie(\"not a tree object\");\n-\tread_tree_recursive(tree, \"\", 0, 0, pathspec, show_tree, NULL);\n+\tread_tree_recursive(tree, \"\", 0, 0, &pathspecs, show_tree, NULL);\n \n \treturn 0;\n }\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 8e82a8b..89887de 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -278,7 +278,9 @@ static int save_files_dirs(const unsigned char *sha1,\n static int get_files_dirs(struct merge_options *o, struct tree *tree)\n {\n \tint n;\n-\tif (read_tree_recursive(tree, \"\", 0, 0, NULL, save_files_dirs, o))\n+\tstruct pathspec match_all;\n+\tinit_pathspec(&match_all, NULL);\n+\tif (read_tree_recursive(tree, \"\", 0, 0, &match_all, save_files_dirs, o))\n \t\treturn 0;\n \tn = o->current_file_set.nr + o->current_directory_set.nr;\n \treturn n;\ndiff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh\nnew file mode 100755\nindex 0000000..f2b2a52\n--- /dev/null\n+++ b/t/t3102-ls-tree-wildcards.sh\n@@ -0,0 +1,22 @@\n+#!/bin/sh\n+\n+test_description='ls-tree with(out) wildcards'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\tmkdir a aa \"a*\" &&\n+\ttouch a/one aa/two \"a*/three\" &&\n+\tgit add a/one aa/two \"a*/three\" &&\n+\tgit commit -m test\n+'\n+\n+test_expect_success 'ls-tree a* matches literally' '\n+\tcat >expected <<EOF &&\n+100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\ta*/three\n+EOF\n+\tgit ls-tree -r HEAD \"a*\" >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_done\ndiff --git a/tree.c b/tree.c\nindex 2b23381..9261b9e 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -120,20 +120,15 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,\n \n int read_tree_recursive(struct tree *tree,\n \t\t\tconst char *base, int baselen,\n-\t\t\tint stage, const char **match,\n+\t\t\tint stage, struct pathspec *pathspecs,\n \t\t\tread_tree_fn_t fn, void *context)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct pathspec pathspecs;\n-\tint i, ret;\n+\tint ret;\n \n-\tinit_pathspec(&pathspecs, match);\n-\tfor (i = 0; i < pathspecs.nr; i++)\n-\t\tpathspecs.items[i].has_wildcard = 0;\n \tstrbuf_add(&sb, base, baselen);\n-\tret = read_tree_1(tree, &sb, stage, &pathspecs, fn, context);\n+\tret = read_tree_1(tree, &sb, stage, pathspecs, fn, context);\n \tstrbuf_release(&sb);\n-\tfree_pathspec(&pathspecs);\n \treturn ret;\n }\n \n@@ -147,7 +142,7 @@ static int cmp_cache_name_compare(const void *a_, const void *b_)\n \t\t\t\t  ce2->name, ce2->ce_flags);\n }\n \n-int read_tree(struct tree *tree, int stage, const char **match)\n+int read_tree(struct tree *tree, int stage, struct pathspec *match)\n {\n \tread_tree_fn_t fn = NULL;\n \tint i, err;\ndiff --git a/tree.h b/tree.h\nindex 2ff01a4..6e5f195 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -25,9 +25,9 @@ typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const ch\n \n extern int read_tree_recursive(struct tree *tree,\n \t\t\t       const char *base, int baselen,\n-\t\t\t       int stage, const char **match,\n+\t\t\t       int stage, struct pathspec *pathspecs,\n \t\t\t       read_tree_fn_t fn, void *context);\n \n-extern int read_tree(struct tree *tree, int stage, const char **paths);\n+extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspecs);\n \n #endif /* TREE_H */\n-- \n1.7.4.74.g639db\n"},{"id":"164231","messageId":"7v7hboa83x.fsf@alter.siamese.dyndns.org","threadId":"26838","inReplyTo":"AANLkTinYB=ZUTe29Y9ibLVL5z3KhiYmnCpCGcHx=18RJ@mail.gmail.com","subject":"Re: Relative ls-files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-24T14:47:14Z","receivedAt":"2011-03-24T14:47:14Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n\n> On Thu, Mar 24, 2011 at 5:44 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Wouldn't it be more sensible to add a bit (\"is this a glob or are we\n>> expected to match it literally\") to each element in the pathspec array,\n>> and pass a pathspec whose elements are all marked as \"literal\" down from\n>> ls-tree?\n>>\n>> The internal matcher (and traversal optimizer) would need to become aware\n>> of \"not a glob\" match (and possibly different kinds of matches like \"**/\"\n>> support) sooner or later, and when that happens you would need something\n>> like the above on the caller side in ls-tree.\n>\n> I think it's possible even now. fnmatch() is only used if\n> pathspec_item.has_wildcard is true. So ls-tree.c only needs to clear\n> this field for all pathspecs and they will be treated literally. Let\n> me try..\n\nThanks, that would be good.\n"},{"id":"164232","messageId":"20110324144952.GA24388@do","threadId":"26838","inReplyTo":"1300977675-6243-2-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 2/2] Convert read_tree{,_recursive} to support struct pathspec","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-24T14:49:52Z","receivedAt":"2011-03-24T14:49:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 24, 2011 at 09:41:15PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> All callers are updated.\n\nJeez.. I made last minute changes and it broke something. This should\nbe squashed in, because tree_entry_interesting() does not like struct\npathspec* == NULL.\n\n--8<--\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 796e9e5..cff39cf 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -396,6 +396,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \tstruct rev_info rev;\n \tstruct object_array_entry *objects;\n \tstruct setup_revision_opt opt;\n+\tstruct pathspec match_all;\n \tint i, count, ret = 0;\n \n \tgit_config(git_log_config, NULL);\n@@ -403,6 +404,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \tif (diff_use_color_default == -1)\n \t\tdiff_use_color_default = git_use_color_default;\n \n+\tinit_pathspec(&match_all, NULL);\n \tinit_revisions(&rev, prefix);\n \trev.diff = 1;\n \trev.always_show_header = 1;\n@@ -449,7 +451,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \t\t\t\t\tdiff_get_color_opt(&rev.diffopt, DIFF_COMMIT),\n \t\t\t\t\tname,\n \t\t\t\t\tdiff_get_color_opt(&rev.diffopt, DIFF_RESET));\n-\t\t\tread_tree_recursive((struct tree *)o, \"\", 0, 0, NULL,\n+\t\t\tread_tree_recursive((struct tree *)o, \"\", 0, 0, &match_all,\n \t\t\t\t\tshow_tree_object, NULL);\n \t\t\trev.shown_one = 1;\n \t\t\tbreak;\n--8<--\n-- \nDuy\n"},{"id":"164249","messageId":"7vpqpg8hht.fsf@alter.siamese.dyndns.org","threadId":"26838","inReplyTo":"1300977675-6243-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 1/2] Reimplement read_tree_recursive() using tree_entry_interesting()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-24T19:07:26Z","receivedAt":"2011-03-24T19:07:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> read_tree_recursive() uses a very similar function, match_tree_entry, to\n> tree_entry_interesting() to do its path matching. This patch kills\n> match_tree_entry() in favor of tree_entry_interesting().\n> ...\n> +int read_tree_recursive(struct tree *tree,\n> +\t\t\tconst char *base, int baselen,\n> +\t\t\tint stage, const char **match,\n> +\t\t\tread_tree_fn_t fn, void *context)\n> +{\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tstruct pathspec pathspecs;\n> +\tint i, ret;\n> +\n> +\tinit_pathspec(&pathspecs, match);\n> +\tfor (i = 0; i < pathspecs.nr; i++)\n> +\t\tpathspecs.items[i].has_wildcard = 0;\n\nI think this is going in the right direction, but I have been hoping that\nwe would eventually stop passing \"const char **\" pointers around when the\ncaller specifies what are the set of paths that are to be affected.\n\nWe still retain \"const char **raw\" field in \"struct pathspec\" even after\nyour previous series, but I think that is because there still are too many\ncallers that already have a \"struct pathspec *pathspec\" but pass only that\nfield (i.e. \"pathspec->raw\") down the callchain, and converting all the\ncallees was a bit too much to chew on during the previous series (which I\nconsider is fine and sane).  The eventual goal should be for such callers\nto pass the \"pathspec\" itself, so that the callees can learn wildcarding\nand all the \"magic\" fun stuff later.\n\nAs read_tree_recursive() has only 6 external callers, it may be a good\nplace to start that conversion.  Another offender is fill_directory() in\ndir.c that are used in 6 places.\n\nThanks.\n"},{"id":"164250","messageId":"7vlj048f97.fsf@alter.siamese.dyndns.org","threadId":"26838","inReplyTo":"1300977675-6243-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 1/2] Reimplement read_tree_recursive() using tree_entry_interesting()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-24T19:55:48Z","receivedAt":"2011-03-24T19:55:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> +static int read_tree_1(struct tree *tree, struct strbuf *base,\n> +\t\t       int stage, struct pathspec *pathspecs,\n> +\t\t       read_tree_fn_t fn, void *context)\n\nMicronit: call the variable pathspec, not pathspecs.\n\nAn instance of the structure contains a specification to limit the set of\npaths to operate on as a set of pathspec elements, and this single set is\ncollectively called a \"struct pathspec\"; you are not passing an array that\nhas one or more pathspecs in it here (i.e. pathspecs[2] in this function\ndoes not make sense).\n\nIt looks like the result is easier to follow, perhaps mostly thanks to the\n(re)use of strbuf instead of allocating a new path when going deeper.\n\n> @@ -108,10 +60,22 @@ int read_tree_recursive(struct tree *tree,\n>  \tinit_tree_desc(&desc, tree->buffer, tree->size);\n>  \n>  \twhile (tree_entry(&desc, &entry)) {\n> -\t\tif (!match_tree_entry(base, baselen, entry.path, entry.mode, match))\n> +\t\tif (all_interesting)\n> +\t\t\tretval = all_interesting > 0;\n> +\t\telse {\n> +\t\t\tretval = tree_entry_interesting(&entry, base, 0, pathspecs);\n> +\t\t\tif (retval == 2)\n> +\t\t\t\tall_interesting = 1;\n> +\t\t\telse if (retval == -1) {\n> +\t\t\t\tall_interesting = -1;\n> +\t\t\t\tretval = 0;\n> +\t\t\t}\n> +\t\t}\n> +\t\tif (!retval)\n>  \t\t\tcontinue;\n\nThis \"if all-interesting then avoid calling into an expensive matcher\"\nlogic looks familiar but is not something that came from the parts deleted\nby this patch.  Where did I see it? Is that something we can share in a\ncommon helper function? Is such a sharing worth pursuing, considering that\nthe above is a reasonably trivial logic in a tight loop?\n\n\"That's how the return value of tree-entry-interesting is designed to be\nused, and it is unsurprising that all the callers will fall into that\npattern\" is a perfectly acceptable answer, I guess.\n\nThanks.\n"},{"id":"164251","messageId":"7vhbas8f4z.fsf@alter.siamese.dyndns.org","threadId":"26838","inReplyTo":"1300977675-6243-2-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 2/2] Convert read_tree{,_recursive} to support struct pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-24T19:58:20Z","receivedAt":"2011-03-24T19:58:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> This patch changes behavior of the two functions. Previously it does\n> prefix matching only. Now it can also do wildcard matching.\n\nThe most important in this change is that it finally starts passing\npathspec, not \"char **\", down the callchain.\n\nExcept that variables should be called pathspec not pathspecs, I think\nthis is basically in very good shape.\n\nThanks.\n"},{"id":"164281","messageId":"1301045660-25053-1-git-send-email-pclouds@gmail.com","threadId":"26838","inReplyTo":"7vlj048f97.fsf@alter.siamese.dyndns.org","subject":"[PATCH 1/3] Reimplement read_tree_recursive() using tree_entry_interesting()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-25T09:34:18Z","receivedAt":"2011-03-25T09:34:18Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"read_tree_recursive() uses a very similar function, match_tree_entry, to\ntree_entry_interesting() to do its path matching. This patch kills\nmatch_tree_entry() in favor of tree_entry_interesting().\n\nmatch_tree_entry(), like older version of tree_entry_interesting(), does\nnot support wildcard matching. New read_tree_recursive() retains this\nbehavior by forcing all pathspecs literal.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n 2011/3/25 Junio C Hamano <gitster@pobox.com>:\n > Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n >\n >> +static int read_tree_1(struct tree *tree, struct strbuf *base,\n >> +                    int stage, struct pathspec *pathspecs,\n >> +                    read_tree_fn_t fn, void *context)\n >\n > Micronit: call the variable pathspec, not pathspecs.\n\n Fixed (also in the second patch)\n\n > This \"if all-interesting then avoid calling into an expensive matcher\"\n > logic looks familiar but is not something that came from the parts deleted\n > by this patch.  Where did I see it? Is that something we can share in a\n > common helper function? Is such a sharing worth pursuing, considering that\n > the above is a reasonably trivial logic in a tight loop?\n >\n > \"That's how the return value of tree-entry-interesting is designed to be\n > used, and it is unsurprising that all the callers will fall into that\n > pattern\" is a perfectly acceptable answer, I guess.\n\n Actually the surrounding code could be improved so that helper function\n is not needed. I also update other t_e_i() callsites in the third patch.\n\n tree.c |  152 ++++++++++++++++++++++++----------------------------------------\n 1 files changed, 57 insertions(+), 95 deletions(-)\n\ndiff --git a/tree.c b/tree.c\nindex 5ab90af..db3a5c3 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -45,62 +45,14 @@ static int read_one_entry_quick(const unsigned char *sha1, const char *base, int\n \t\t\t\t  ADD_CACHE_JUST_APPEND);\n }\n \n-static int match_tree_entry(const char *base, int baselen, const char *path, unsigned int mode, const char **paths)\n-{\n-\tconst char *match;\n-\tint pathlen;\n-\n-\tif (!paths)\n-\t\treturn 1;\n-\tpathlen = strlen(path);\n-\twhile ((match = *paths++) != NULL) {\n-\t\tint matchlen = strlen(match);\n-\n-\t\tif (baselen >= matchlen) {\n-\t\t\t/* If it doesn't match, move along... */\n-\t\t\tif (strncmp(base, match, matchlen))\n-\t\t\t\tcontinue;\n-\t\t\t/* pathspecs match only at the directory boundaries */\n-\t\t\tif (!matchlen ||\n-\t\t\t    baselen == matchlen ||\n-\t\t\t    base[matchlen] == '/' ||\n-\t\t\t    match[matchlen - 1] == '/')\n-\t\t\t\treturn 1;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\t/* Does the base match? */\n-\t\tif (strncmp(base, match, baselen))\n-\t\t\tcontinue;\n-\n-\t\tmatch += baselen;\n-\t\tmatchlen -= baselen;\n-\n-\t\tif (pathlen > matchlen)\n-\t\t\tcontinue;\n-\n-\t\tif (matchlen > pathlen) {\n-\t\t\tif (match[pathlen] != '/')\n-\t\t\t\tcontinue;\n-\t\t\tif (!S_ISDIR(mode))\n-\t\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (strncmp(path, match, pathlen))\n-\t\t\tcontinue;\n-\n-\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-int read_tree_recursive(struct tree *tree,\n-\t\t\tconst char *base, int baselen,\n-\t\t\tint stage, const char **match,\n-\t\t\tread_tree_fn_t fn, void *context)\n+static int read_tree_1(struct tree *tree, struct strbuf *base,\n+\t\t       int stage, struct pathspec *pathspec,\n+\t\t       read_tree_fn_t fn, void *context)\n {\n \tstruct tree_desc desc;\n \tstruct name_entry entry;\n+\tunsigned char sha1[20];\n+\tint len, retval = 0, oldlen = base->len;\n \n \tif (parse_tree(tree))\n \t\treturn -1;\n@@ -108,10 +60,16 @@ int read_tree_recursive(struct tree *tree,\n \tinit_tree_desc(&desc, tree->buffer, tree->size);\n \n \twhile (tree_entry(&desc, &entry)) {\n-\t\tif (!match_tree_entry(base, baselen, entry.path, entry.mode, match))\n-\t\t\tcontinue;\n+\t\tif (retval != 2) {\n+\t\t\tretval = tree_entry_interesting(&entry, base, 0, pathspec);\n+\t\t\tif (retval < 0)\n+\t\t\t\tbreak;\n+\t\t\tif (retval == 0)\n+\t\t\t\tcontinue;\n+\t\t}\n \n-\t\tswitch (fn(entry.sha1, base, baselen, entry.path, entry.mode, stage, context)) {\n+\t\tswitch (fn(entry.sha1, base->buf, base->len,\n+\t\t\t   entry.path, entry.mode, stage, context)) {\n \t\tcase 0:\n \t\t\tcontinue;\n \t\tcase READ_TREE_RECURSIVE:\n@@ -119,56 +77,60 @@ int read_tree_recursive(struct tree *tree,\n \t\tdefault:\n \t\t\treturn -1;\n \t\t}\n-\t\tif (S_ISDIR(entry.mode)) {\n-\t\t\tint retval;\n-\t\t\tchar *newbase;\n-\t\t\tunsigned int pathlen = tree_entry_len(entry.path, entry.sha1);\n-\n-\t\t\tnewbase = xmalloc(baselen + 1 + pathlen);\n-\t\t\tmemcpy(newbase, base, baselen);\n-\t\t\tmemcpy(newbase + baselen, entry.path, pathlen);\n-\t\t\tnewbase[baselen + pathlen] = '/';\n-\t\t\tretval = read_tree_recursive(lookup_tree(entry.sha1),\n-\t\t\t\t\t\t     newbase,\n-\t\t\t\t\t\t     baselen + pathlen + 1,\n-\t\t\t\t\t\t     stage, match, fn, context);\n-\t\t\tfree(newbase);\n-\t\t\tif (retval)\n-\t\t\t\treturn -1;\n-\t\t\tcontinue;\n-\t\t} else if (S_ISGITLINK(entry.mode)) {\n-\t\t\tint retval;\n-\t\t\tstruct strbuf path;\n-\t\t\tunsigned int entrylen;\n-\t\t\tstruct commit *commit;\n \n-\t\t\tentrylen = tree_entry_len(entry.path, entry.sha1);\n-\t\t\tstrbuf_init(&path, baselen + entrylen + 1);\n-\t\t\tstrbuf_add(&path, base, baselen);\n-\t\t\tstrbuf_add(&path, entry.path, entrylen);\n-\t\t\tstrbuf_addch(&path, '/');\n+\t\tif (S_ISDIR(entry.mode))\n+\t\t\thashcpy(sha1, entry.sha1);\n+\t\telse if (S_ISGITLINK(entry.mode)) {\n+\t\t\tstruct commit *commit;\n \n \t\t\tcommit = lookup_commit(entry.sha1);\n \t\t\tif (!commit)\n-\t\t\t\tdie(\"Commit %s in submodule path %s not found\",\n-\t\t\t\t    sha1_to_hex(entry.sha1), path.buf);\n+\t\t\t\tdie(\"Commit %s in submodule path %s%s not found\",\n+\t\t\t\t    sha1_to_hex(entry.sha1),\n+\t\t\t\t    base->buf, entry.path);\n \n \t\t\tif (parse_commit(commit))\n-\t\t\t\tdie(\"Invalid commit %s in submodule path %s\",\n-\t\t\t\t    sha1_to_hex(entry.sha1), path.buf);\n-\n-\t\t\tretval = read_tree_recursive(commit->tree,\n-\t\t\t\t\t\t     path.buf, path.len,\n-\t\t\t\t\t\t     stage, match, fn, context);\n-\t\t\tstrbuf_release(&path);\n-\t\t\tif (retval)\n-\t\t\t\treturn -1;\n-\t\t\tcontinue;\n+\t\t\t\tdie(\"Invalid commit %s in submodule path %s%s\",\n+\t\t\t\t    sha1_to_hex(entry.sha1),\n+\t\t\t\t    base->buf, entry.path);\n+\n+\t\t\thashcpy(sha1, commit->tree->object.sha1);\n \t\t}\n+\t\telse\n+\t\t\tcontinue;\n+\n+\t\tlen = tree_entry_len(entry.path, entry.sha1);\n+\t\tstrbuf_add(base, entry.path, len);\n+\t\tstrbuf_addch(base, '/');\n+\t\tretval = read_tree_1(lookup_tree(sha1),\n+\t\t\t\t     base, stage, pathspec,\n+\t\t\t\t     fn, context);\n+\t\tstrbuf_setlen(base, oldlen);\n+\t\tif (retval)\n+\t\t\treturn -1;\n \t}\n \treturn 0;\n }\n \n+int read_tree_recursive(struct tree *tree,\n+\t\t\tconst char *base, int baselen,\n+\t\t\tint stage, const char **match,\n+\t\t\tread_tree_fn_t fn, void *context)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstruct pathspec pathspec;\n+\tint i, ret;\n+\n+\tinit_pathspec(&pathspec, match);\n+\tfor (i = 0; i < pathspec.nr; i++)\n+\t\tpathspec.items[i].has_wildcard = 0;\n+\tstrbuf_add(&sb, base, baselen);\n+\tret = read_tree_1(tree, &sb, stage, &pathspec, fn, context);\n+\tstrbuf_release(&sb);\n+\tfree_pathspec(&pathspec);\n+\treturn ret;\n+}\n+\n static int cmp_cache_name_compare(const void *a_, const void *b_)\n {\n \tconst struct cache_entry *ce1, *ce2;\n-- \n1.7.4.74.g639db\n"},{"id":"164282","messageId":"1301045660-25053-2-git-send-email-pclouds@gmail.com","threadId":"26838","inReplyTo":"1301045660-25053-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 2/3] Convert read_tree{,_recursive} to support struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-25T09:34:19Z","receivedAt":"2011-03-25T09:34:19Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This patch changes behavior of the two functions. Previously it does\nprefix matching only. Now it can also do wildcard matching.\n\nAll callers are updated. Some gain wildcard matching (archive,\ncheckout), others reset pathspec_item.has_wildcard to retain old\nbehavior (ls-files, ls-tree as they are plumbing).\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n archive.c                    |   18 ++++++++++++------\n builtin/checkout.c           |    5 ++++-\n builtin/log.c                |    4 +++-\n builtin/ls-files.c           |    9 +++++----\n builtin/ls-tree.c            |   12 +++++++-----\n merge-recursive.c            |    4 +++-\n t/t3102-ls-tree-wildcards.sh |   22 ++++++++++++++++++++++\n tree.c                       |   13 ++++---------\n tree.h                       |    4 ++--\n 9 files changed, 62 insertions(+), 29 deletions(-)\n create mode 100755 t/t3102-ls-tree-wildcards.sh\n\ndiff --git a/archive.c b/archive.c\nindex 1944ed4..42f2d2f 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -157,6 +157,7 @@ int write_archive_entries(struct archiver_args *args,\n \tstruct archiver_context context;\n \tstruct unpack_trees_options opts;\n \tstruct tree_desc t;\n+\tstruct pathspec pathspec;\n \tint err;\n \n \tif (args->baselen > 0 && args->base[args->baselen - 1] == '/') {\n@@ -191,8 +192,10 @@ int write_archive_entries(struct archiver_args *args,\n \t\tgit_attr_set_direction(GIT_ATTR_INDEX, &the_index);\n \t}\n \n-\terr = read_tree_recursive(args->tree, \"\", 0, 0, args->pathspec,\n+\tinit_pathspec(&pathspec, args->pathspec);\n+\terr = read_tree_recursive(args->tree, \"\", 0, 0, &pathspec,\n \t\t\t\t  write_archive_entry, &context);\n+\tfree_pathspec(&pathspec);\n \tif (err == READ_TREE_RECURSIVE)\n \t\terr = 0;\n \treturn err;\n@@ -221,11 +224,14 @@ static int reject_entry(const unsigned char *sha1, const char *base,\n \n static int path_exists(struct tree *tree, const char *path)\n {\n-\tconst char *pathspec[] = { path, NULL };\n-\n-\tif (read_tree_recursive(tree, \"\", 0, 0, pathspec, reject_entry, NULL))\n-\t\treturn 1;\n-\treturn 0;\n+\tconst char *paths[] = { path, NULL };\n+\tstruct pathspec pathspec;\n+\tint ret;\n+\n+\tinit_pathspec(&pathspec, paths);\n+\tret = read_tree_recursive(tree, \"\", 0, 0, &pathspec, reject_entry, NULL);\n+\tfree_pathspec(&pathspec);\n+\treturn ret != 0;\n }\n \n static void parse_pathspec_arg(const char **pathspec,\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 2bf02f2..dc3eedf 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -79,7 +79,10 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,\n \n static int read_tree_some(struct tree *tree, const char **pathspec)\n {\n-\tread_tree_recursive(tree, \"\", 0, 0, pathspec, update_some, NULL);\n+\tstruct pathspec ps;\n+\tinit_pathspec(&ps, pathspec);\n+\tread_tree_recursive(tree, \"\", 0, 0, &ps, update_some, NULL);\n+\tfree_pathspec(&ps);\n \n \t/* update the index with the given tree's info\n \t * for all args, expanding wildcards, and exit\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 796e9e5..cff39cf 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -396,6 +396,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \tstruct rev_info rev;\n \tstruct object_array_entry *objects;\n \tstruct setup_revision_opt opt;\n+\tstruct pathspec match_all;\n \tint i, count, ret = 0;\n \n \tgit_config(git_log_config, NULL);\n@@ -403,6 +404,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \tif (diff_use_color_default == -1)\n \t\tdiff_use_color_default = git_use_color_default;\n \n+\tinit_pathspec(&match_all, NULL);\n \tinit_revisions(&rev, prefix);\n \trev.diff = 1;\n \trev.always_show_header = 1;\n@@ -449,7 +451,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \t\t\t\t\tdiff_get_color_opt(&rev.diffopt, DIFF_COMMIT),\n \t\t\t\t\tname,\n \t\t\t\t\tdiff_get_color_opt(&rev.diffopt, DIFF_RESET));\n-\t\t\tread_tree_recursive((struct tree *)o, \"\", 0, 0, NULL,\n+\t\t\tread_tree_recursive((struct tree *)o, \"\", 0, 0, &match_all,\n \t\t\t\t\tshow_tree_object, NULL);\n \t\t\trev.shown_one = 1;\n \t\t\tbreak;\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex fb2d5f4..199af46 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -338,7 +338,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n {\n \tstruct tree *tree;\n \tunsigned char sha1[20];\n-\tconst char **match;\n+\tstruct pathspec pathspec;\n \tstruct cache_entry *last_stage0 = NULL;\n \tint i;\n \n@@ -360,10 +360,11 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)\n \t\tstatic const char *(matchbuf[2]);\n \t\tmatchbuf[0] = prefix;\n \t\tmatchbuf[1] = NULL;\n-\t\tmatch = matchbuf;\n+\t\tinit_pathspec(&pathspec, matchbuf);\n+\t\tpathspec.items[0].has_wildcard = 0;\n \t} else\n-\t\tmatch = NULL;\n-\tif (read_tree(tree, 1, match))\n+\t\tinit_pathspec(&pathspec, NULL);\n+\tif (read_tree(tree, 1, &pathspec))\n \t\tdie(\"unable to read tree entries %s\", tree_name);\n \n \tfor (i = 0; i < active_nr; i++) {\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex f73e6bd..4290723 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -19,7 +19,7 @@ static int line_termination = '\\n';\n #define LS_SHOW_SIZE 16\n static int abbrev;\n static int ls_options;\n-static const char **pathspec;\n+static struct pathspec pathspec;\n static int chomp_prefix;\n static const char *ls_tree_prefix;\n \n@@ -35,7 +35,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)\n \tif (ls_options & LS_RECURSIVE)\n \t\treturn 1;\n \n-\ts = pathspec;\n+\ts = pathspec.raw;\n \tif (!s)\n \t\treturn 0;\n \n@@ -120,7 +120,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n {\n \tunsigned char sha1[20];\n \tstruct tree *tree;\n-\tint full_tree = 0;\n+\tint i, full_tree = 0;\n \tconst struct option ls_tree_options[] = {\n \t\tOPT_BIT('d', NULL, &ls_options, \"only show trees\",\n \t\t\tLS_TREE_ONLY),\n@@ -166,11 +166,13 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \tif (get_sha1(argv[0], sha1))\n \t\tdie(\"Not a valid object name %s\", argv[0]);\n \n-\tpathspec = get_pathspec(prefix, argv + 1);\n+\tinit_pathspec(&pathspec, get_pathspec(prefix, argv + 1));\n+\tfor (i = 0; i < pathspec.nr; i++)\n+\t\tpathspec.items[i].has_wildcard = 0;\n \ttree = parse_tree_indirect(sha1);\n \tif (!tree)\n \t\tdie(\"not a tree object\");\n-\tread_tree_recursive(tree, \"\", 0, 0, pathspec, show_tree, NULL);\n+\tread_tree_recursive(tree, \"\", 0, 0, &pathspec, show_tree, NULL);\n \n \treturn 0;\n }\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 8e82a8b..89887de 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -278,7 +278,9 @@ static int save_files_dirs(const unsigned char *sha1,\n static int get_files_dirs(struct merge_options *o, struct tree *tree)\n {\n \tint n;\n-\tif (read_tree_recursive(tree, \"\", 0, 0, NULL, save_files_dirs, o))\n+\tstruct pathspec match_all;\n+\tinit_pathspec(&match_all, NULL);\n+\tif (read_tree_recursive(tree, \"\", 0, 0, &match_all, save_files_dirs, o))\n \t\treturn 0;\n \tn = o->current_file_set.nr + o->current_directory_set.nr;\n \treturn n;\ndiff --git a/t/t3102-ls-tree-wildcards.sh b/t/t3102-ls-tree-wildcards.sh\nnew file mode 100755\nindex 0000000..f2b2a52\n--- /dev/null\n+++ b/t/t3102-ls-tree-wildcards.sh\n@@ -0,0 +1,22 @@\n+#!/bin/sh\n+\n+test_description='ls-tree with(out) wildcards'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\tmkdir a aa \"a*\" &&\n+\ttouch a/one aa/two \"a*/three\" &&\n+\tgit add a/one aa/two \"a*/three\" &&\n+\tgit commit -m test\n+'\n+\n+test_expect_success 'ls-tree a* matches literally' '\n+\tcat >expected <<EOF &&\n+100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391\ta*/three\n+EOF\n+\tgit ls-tree -r HEAD \"a*\" >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_done\ndiff --git a/tree.c b/tree.c\nindex db3a5c3..698ecf7 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -114,20 +114,15 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,\n \n int read_tree_recursive(struct tree *tree,\n \t\t\tconst char *base, int baselen,\n-\t\t\tint stage, const char **match,\n+\t\t\tint stage, struct pathspec *pathspec,\n \t\t\tread_tree_fn_t fn, void *context)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstruct pathspec pathspec;\n-\tint i, ret;\n+\tint ret;\n \n-\tinit_pathspec(&pathspec, match);\n-\tfor (i = 0; i < pathspec.nr; i++)\n-\t\tpathspec.items[i].has_wildcard = 0;\n \tstrbuf_add(&sb, base, baselen);\n-\tret = read_tree_1(tree, &sb, stage, &pathspec, fn, context);\n+\tret = read_tree_1(tree, &sb, stage, pathspec, fn, context);\n \tstrbuf_release(&sb);\n-\tfree_pathspec(&pathspec);\n \treturn ret;\n }\n \n@@ -141,7 +136,7 @@ static int cmp_cache_name_compare(const void *a_, const void *b_)\n \t\t\t\t  ce2->name, ce2->ce_flags);\n }\n \n-int read_tree(struct tree *tree, int stage, const char **match)\n+int read_tree(struct tree *tree, int stage, struct pathspec *match)\n {\n \tread_tree_fn_t fn = NULL;\n \tint i, err;\ndiff --git a/tree.h b/tree.h\nindex 2ff01a4..69bcb5e 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -25,9 +25,9 @@ typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const ch\n \n extern int read_tree_recursive(struct tree *tree,\n \t\t\t       const char *base, int baselen,\n-\t\t\t       int stage, const char **match,\n+\t\t\t       int stage, struct pathspec *pathspec,\n \t\t\t       read_tree_fn_t fn, void *context);\n \n-extern int read_tree(struct tree *tree, int stage, const char **paths);\n+extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec);\n \n #endif /* TREE_H */\n-- \n1.7.4.74.g639db\n"},{"id":"164283","messageId":"1301045660-25053-3-git-send-email-pclouds@gmail.com","threadId":"26838","inReplyTo":"1301045660-25053-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 3/3] Improve tree_entry_interesting() handling code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-03-25T09:34:20Z","receivedAt":"2011-03-25T09:34:20Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"t_e_i() can return -1 or 2 to early shortcut a search. Current code\nmay use up to two variables to handle it. One for saving return value\nfrom t_e_i temporarily, one for saving return code 2.\n\nThe second variable is not needed. If we make sure the first variable\ndoes not change until the next t_e_i() call, then we can do something\nlike this:\n\nint ret = 0;\n\nwhile (...) {\n\tif (ret != 2) {\n\t\tret = t_e_i();\n\t\tif (ret < 0) /* no longer interesting */\n\t\t\tbreak;\n\t\tif (ret == 0) /* skip this round */\n\t\t\tcontinue;\n\t}\n\t/* ret > 0, interesting */\n}\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/grep.c |   12 ++++++------\n list-objects.c |   18 +++++++-----------\n tree-diff.c    |   53 ++++++++++++++++++++---------------------------------\n 3 files changed, 33 insertions(+), 50 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0bf8c01..9cb1f32 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -520,18 +520,18 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int\n static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t     struct tree_desc *tree, struct strbuf *base, int tn_len)\n {\n-\tint hit = 0, matched = 0;\n+\tint hit = 0, match = 0;\n \tstruct name_entry entry;\n \tint old_baselen = base->len;\n \n \twhile (tree_entry(tree, &entry)) {\n \t\tint te_len = tree_entry_len(entry.path, entry.sha1);\n \n-\t\tif (matched != 2) {\n-\t\t\tmatched = tree_entry_interesting(&entry, base, tn_len, pathspec);\n-\t\t\tif (matched == -1)\n-\t\t\t\tbreak; /* no more matches */\n-\t\t\tif (!matched)\n+\t\tif (match != 2) {\n+\t\t\tmatch = tree_entry_interesting(&entry, base, tn_len, pathspec);\n+\t\t\tif (match < 0)\n+\t\t\t\tbreak;\n+\t\t\tif (match == 0)\n \t\t\t\tcontinue;\n \t\t}\n \ndiff --git a/list-objects.c b/list-objects.c\nindex 838b6a7..0fb44e7 100644\n--- a/list-objects.c\n+++ b/list-objects.c\n@@ -68,7 +68,7 @@ static void process_tree(struct rev_info *revs,\n \tstruct tree_desc desc;\n \tstruct name_entry entry;\n \tstruct name_path me;\n-\tint all_interesting = (revs->diffopt.pathspec.nr == 0);\n+\tint match = revs->diffopt.pathspec.nr == 0 ? 2 : 0;\n \tint baselen = base->len;\n \n \tif (!revs->tree_objects)\n@@ -85,7 +85,7 @@ static void process_tree(struct rev_info *revs,\n \tme.elem = name;\n \tme.elem_len = strlen(name);\n \n-\tif (!all_interesting) {\n+\tif (!match) {\n \t\tstrbuf_addstr(base, name);\n \t\tif (base->len)\n \t\t\tstrbuf_addch(base, '/');\n@@ -94,17 +94,13 @@ static void process_tree(struct rev_info *revs,\n \tinit_tree_desc(&desc, tree->buffer, tree->size);\n \n \twhile (tree_entry(&desc, &entry)) {\n-\t\tif (!all_interesting) {\n-\t\t\tint showit = tree_entry_interesting(&entry,\n-\t\t\t\t\t\t\t    base, 0,\n-\t\t\t\t\t\t\t    &revs->diffopt.pathspec);\n-\n-\t\t\tif (showit < 0)\n+\t\tif (match != 2) {\n+\t\t\tmatch = tree_entry_interesting(&entry, base, 0,\n+\t\t\t\t\t\t       &revs->diffopt.pathspec);\n+\t\t\tif (match < 0)\n \t\t\t\tbreak;\n-\t\t\telse if (!showit)\n+\t\t\tif (match == 0)\n \t\t\t\tcontinue;\n-\t\t\telse if (showit == 2)\n-\t\t\t\tall_interesting = 1;\n \t\t}\n \n \t\tif (S_ISDIR(entry.mode))\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 3954281..f291069 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -65,23 +65,17 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,\n static void show_tree(struct diff_options *opt, const char *prefix,\n \t\t      struct tree_desc *desc, struct strbuf *base)\n {\n-\tint all_interesting = 0;\n-\twhile (desc->size) {\n-\t\tint show;\n-\n-\t\tif (all_interesting)\n-\t\t\tshow = 1;\n-\t\telse {\n-\t\t\tshow = tree_entry_interesting(&desc->entry, base, 0,\n-\t\t\t\t\t\t      &opt->pathspec);\n-\t\t\tif (show == 2)\n-\t\t\t\tall_interesting = 1;\n+\tint match = 0;\n+\tfor (; desc->size; update_tree_entry(desc)) {\n+\t\tif (match != 2) {\n+\t\t\tmatch = tree_entry_interesting(&desc->entry, base, 0,\n+\t\t\t\t\t\t       &opt->pathspec);\n+\t\t\tif (match < 0)\n+\t\t\t\tbreak;\n+\t\t\tif (match == 0)\n+\t\t\t\tcontinue;\n \t\t}\n-\t\tif (show < 0)\n-\t\t\tbreak;\n-\t\tif (show)\n-\t\t\tshow_entry(opt, prefix, desc, base);\n-\t\tupdate_tree_entry(desc);\n+\t\tshow_entry(opt, prefix, desc, base);\n \t}\n }\n \n@@ -121,20 +115,16 @@ static void show_entry(struct diff_options *opt, const char *prefix,\n }\n \n static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,\n-\t\t\t       struct diff_options *opt, int *all_interesting)\n+\t\t\t       struct diff_options *opt, int *match)\n {\n \twhile (t->size) {\n-\t\tint show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);\n-\t\tif (show == 2)\n-\t\t\t*all_interesting = 1;\n-\t\tif (!show) {\n-\t\t\tupdate_tree_entry(t);\n-\t\t\tcontinue;\n+\t\t*match = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);\n+\t\tif (*match) {\n+\t\t\tif (*match < 0)\n+\t\t\t\tt->size = 0;\n+\t\t\tbreak;\n \t\t}\n-\t\t/* Skip it all? */\n-\t\tif (show < 0)\n-\t\t\tt->size = 0;\n-\t\treturn;\n+\t\tupdate_tree_entry(t);\n \t}\n }\n \n@@ -143,8 +133,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,\n {\n \tstruct strbuf base;\n \tint baselen = strlen(base_str);\n-\tint all_t1_interesting = 0;\n-\tint all_t2_interesting = 0;\n+\tint t1_match = 0, t2_match = 0;\n \n \t/* Enable recursion indefinitely */\n \topt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);\n@@ -158,10 +147,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,\n \t\t    DIFF_OPT_TST(opt, HAS_CHANGES))\n \t\t\tbreak;\n \t\tif (opt->pathspec.nr) {\n-\t\t\tif (!all_t1_interesting)\n-\t\t\t\tskip_uninteresting(t1, &base, opt, &all_t1_interesting);\n-\t\t\tif (!all_t2_interesting)\n-\t\t\t\tskip_uninteresting(t2, &base, opt, &all_t2_interesting);\n+\t\t\tskip_uninteresting(t1, &base, opt, &t1_match);\n+\t\t\tskip_uninteresting(t2, &base, opt, &t2_match);\n \t\t}\n \t\tif (!t1->size) {\n \t\t\tif (!t2->size)\n-- \n1.7.4.74.g639db\n"}]}