{"thread":{"id":"32519","subject":"What's cooking in git.git (Jan 2013, #02; Thu, 3)","startedAt":"2013-01-03T19:17:23Z","lastAt":"2013-01-06T16:58:13Z","messageCount":16,"participants":["Junio C Hamano","Adam Spiers"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"205944","messageId":"7vmwwqvzy4.fsf@alter.siamese.dyndns.org","threadId":"32519","inReplyTo":null,"subject":"What's cooking in git.git (Jan 2013, #02; Thu, 3)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-03T19:17:23Z","receivedAt":"2013-01-03T19:17:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Here are the topics that have been cooking.  Commits prefixed with\n'-' are only in 'pu' (proposed updates) while commits prefixed with\n'+' are in 'next'.\n\nThe post 1.8.1 cycle has started, and about a dozen topics (mostly\nfixes) have graduated to the 'master' branch.  The second batch will\nfollow shortly.\n\nAs usual, this cycle is expected to last for 8 to 10 weeks.  To\nensure the quality of the end result, let's merge topics in flight\nearlier than previous cycles to 'next' and fix issues in-tree.\n\nYou can find the changes described here in the integration branches of the\nrepositories listed at\n\n    http://git-blame.blogspot.com/p/git-public-repositories.html\n\n--------------------------------------------------\n[New Topics]\n\n* jn/less-reconfigure (2013-01-02) 1 commit\n  (merged to 'next' on 2013-01-02 at e5cd6cf)\n + build: do not automatically reconfigure unless configure.ac changed\n\n When autoconf is used, any build on a different commit always ran\n \"config.status --recheck\" even when unnecessary.\n\n\n* ap/merge-stop-at-prepare-commit-msg-failure (2013-01-03) 1 commit\n - merge: Honor prepare-commit-msg return code\n\n \"git merge\" started calling prepare-commit-msg hook like \"git\n commit\" does some time ago, but forgot to pay attention to the exit\n status of the hook.  t7505 may want a general clean-up but that is\n a different topic.\n\n Will merge to 'next'.\n\n\n* tb/test-shell-lint (2013-01-02) 1 commit\n - test: Add check-non-portable-shell.pl\n\n Check for common mistakes in the test scripts, based on simple\n pattern-matching.\n\n Will merge to 'next'.\n\n\n* jk/enable-test-lint-by-default (2013-01-03) 1 commit\n - tests: turn on test-lint by default\n\n We had two simple and quick tests to catch common mistakes when\n writing test scripts, but they weren't run by default when running\n tests.\n\n Will merge to 'next'.\n\n--------------------------------------------------\n[Graduated to \"master\"]\n\n* as/test-tweaks (2012-12-20) 7 commits\n  (merged to 'next' on 2012-12-22 at 7312c6c)\n + tests: paint unexpectedly fixed known breakages in bold red\n + tests: test the test framework more thoroughly\n + tests: refactor mechanics of testing in a sub test-lib\n + tests: change info messages from yellow/brown to cyan\n + tests: paint skipped tests in blue\n + tests: paint known breakages in yellow\n + tests: test number comes first in 'not ok $count - $message'\n\n Output from the tests is coloured using \"green is okay, yellow is\n questionable, red is bad and blue is informative\" scheme.\n\n\n* da/p4merge-mktemp (2012-12-26) 1 commit\n  (merged to 'next' on 2012-12-26 at 036938a)\n + mergetools/p4merge: Honor $TMPDIR for the /dev/null placeholder\n\n Create an empty file in $TMPDIR instead of using an empty file in\n the local directory.\n\n\n* dm/port (2012-12-19) 4 commits\n  (merged to 'next' on 2012-12-22 at 8adc198)\n + git-compat-util.h: do not #include <sys/param.h> by default\n + Generalize the inclusion of strings.h\n + Detect when the passwd struct is missing pw_gecos\n + Support builds when sys/param.h is missing\n (this branch is used by mk/qnx.)\n\n Add a few more knobs for new platform ports can tweak.\n\n\n* jc/maint-fbsd-sh-ifs-workaround (2012-12-10) 1 commit\n  (merged to 'next' on 2012-12-11 at 6659fdc)\n + sh-setup: work around \"unset IFS\" bug in some shells\n\n Some shells do not behave correctly when IFS is unset; work it\n around by explicitly setting it to the default value.\n\n\n* jc/maint-fnmatch-old-style-definition (2012-12-19) 1 commit\n  (merged to 'next' on 2012-12-22 at 540df2c)\n + compat/fnmatch: update old-style definition to ANSI\n\n Update old-style function definition \"int foo(bar) int bar; {}\"\n to \"int foo(int bar) {}\".\n\n\n* jc/maint-test-portability (2012-12-19) 3 commits\n  (merged to 'next' on 2012-12-22 at daeed53)\n + t4014: fix arguments to grep\n + t9502: do not assume GNU tar\n + t0200: \"locale\" may not exist\n (this branch is used by jc/test-portability.)\n\n Minor test fixes noticed while running our tests on OpenBSD 5.2,\n applicable to 'maint'.\n\n\n* jc/mkstemp-more-careful-error-reporting (2012-12-18) 1 commit\n  (merged to 'next' on 2012-12-22 at 18cdaf0)\n + xmkstemp(): avoid showing truncated template more carefully\n\n After failing to create a temporary file using mkstemp(), failing\n pathname was not reported correctly on some platforms.\n\n\n* jc/same-encoding (2012-12-10) 1 commit\n  (merged to 'next' on 2012-12-17 at 86b41c7)\n + format_commit_message(): simplify calls to logmsg_reencode()\n\n Finishing touches to the series to unify \"Do we need to reencode\n between these two encodings?\" logic.\n\n\n* jc/test-cvs-no-init-in-existing-dir (2012-12-24) 1 commit\n  (merged to 'next' on 2012-12-26 at 3b93f37)\n + t9200: let \"cvs init\" create the test repository\n\n t9200 runs \"cvs init\" on a directory that already exists, but a\n platform can configure this fail for the current user (e.g. you\n need to be in the cvsadmin group on NetBSD 6.0).\n\n\n* jc/test-portability (2012-12-19) 3 commits\n  (merged to 'next' on 2012-12-22 at 123041b)\n + t9020: use configured Python to run the test helper\n + t3600: Avoid \"cp -a\", which is a GNUism\n + Merge branch 'jc/maint-test-portability' into 'jc/test-portability'\n (this branch uses jc/maint-test-portability.)\n\n The remainder of jc/maint-test-portability, applicable to 'master'.\n\n\n* jk/repack-ref-racefix (2012-12-21) 1 commit\n  (merged to 'next' on 2012-12-22 at 03e1ca9)\n + refs: do not use cached refs in repack_without_ref\n\n \"git pack-refs\" that ran in parallel to another process that\n created new refs had a nasty race.\n\n\n* md/gitweb-sort-by-age (2012-12-11) 1 commit\n  (merged to 'next' on 2012-12-13 at 9f39410)\n + gitweb: Sort projects with undefined ages last\n\n Gitweb showed repositories without any commit at the top in its\n age-sorted view, in which the users are interested in looking at\n active projects; sorting them at the bottom makes it more useful.\n\n\n* mh/ceiling (2012-10-29) 8 commits\n  (merged to 'next' on 2012-11-26 at d1ce76a)\n + string_list_longest_prefix(): remove function\n + setup_git_directory_gently_1(): resolve symlinks in ceiling paths\n + longest_ancestor_length(): require prefix list entries to be normalized\n + longest_ancestor_length(): take a string_list argument for prefixes\n + longest_ancestor_length(): use string_list_split()\n + Introduce new function real_path_if_valid()\n + real_path_internal(): add comment explaining use of cwd\n + Introduce new static function real_path_internal()\n\n Elements of GIT_CEILING_DIRECTORIES list may not match the real\n pathname we obtain from getcwd(), leading the GIT_DIR discovery\n logic to escape the ceilings the user thought to have specified.\n\n\n* mh/pthreads-autoconf (2012-11-27) 1 commit\n  (merged to 'next' on 2012-11-28 at 780600e)\n + configure.ac: fix pthreads detection on Mac OS X\n\n\n* mk/maint-graph-infinity-loop (2012-09-25) 1 commit\n  (merged to 'next' on 2012-12-26 at 2ff59ab)\n + graph.c: infinite loop in git whatchanged --graph -m\n\n The --graph code fell into infinite loop when asked to do what the\n code did not expect ;-)\n\n\n* mk/qnx (2012-12-19) 2 commits\n  (merged to 'next' on 2012-12-22 at 0473197)\n + Port to QNX\n + Make lock local to fetch_pack\n (this branch uses dm/port.)\n\n Port to QNX.\n\n\n* ms/subtree-fixlets (2012-12-22) 2 commits\n  (merged to 'next' on 2012-12-26 at 1cb26eb)\n + git-subtree: fix typo in manpage\n + git-subtree: ignore git-subtree executable\n\n\n* nd/invalidate-i-t-a-cache-tree (2012-12-15) 4 commits\n  (merged to 'next' on 2012-12-18 at 33e4488)\n + cache-tree: invalidate i-t-a paths after generating trees\n + cache-tree: fix writing cache-tree when CE_REMOVE is present\n + cache-tree: replace \"for\" loops in update_one with \"while\" loops\n + cache-tree: remove dead i-t-a code in verify_cache()\n\n Writing out a tree object when you still have intent-to-add entries\n in the index left an incorrect cache-tree data there.\n\n\n* pf/editor-ignore-sigint (2012-12-02) 5 commits\n  (merged to 'next' on 2012-12-07 at 6b04419)\n + launch_editor: propagate signals from editor to git\n + run-command: do not warn about child death from terminal\n + launch_editor: ignore terminal signals while editor has control\n + launch_editor: refactor to use start/finish_command\n + run-command: drop silent_exec_failure arg from wait_or_whine\n\n The behaviour visible to the end users was confusing, when they\n attempt to kill a process spawned in the editor that was in turn\n launched by Git with SIGINT (or SIGQUIT), as Git would catch that\n signal and die.  We ignore these signals now.\n\n\n* rb/http-cert-cred-no-username-prompt (2012-12-21) 1 commit\n  (merged to 'next' on 2012-12-22 at 9fc28ed)\n + http.c: Avoid username prompt for certifcate credentials\n\n It is wrong to ask for username if the authentication is done by\n certificate identity.\n\n\n* sp/shortlog-missing-lf (2012-12-11) 2 commits\n  (merged to 'next' on 2012-12-11 at 64b8429)\n + strbuf_add_wrapped*(): Remove unused return value\n + shortlog: fix wrapping lines of wraplen\n\n When a line to be wrapped has a solid run of non space characters\n whose length exactly is the wrap width, \"git shortlog -w\" failed to\n add a newline after such a line.\n\n\n* ss/nedmalloc-compilation (2012-12-11) 1 commit\n  (merged to 'next' on 2012-12-13 at c1f0d7f)\n + nedmalloc: Fix a compile warning (exposed as error) with GCC 4.7.2\n\n\n* ss/svn-prompt (2012-12-17) 3 commits\n  (merged to 'next' on 2012-12-26 at 1012ae2)\n + git-svn, perl/Git.pm: extend and use Git->prompt method for querying users\n + perl/Git.pm: Honor SSH_ASKPASS as fallback if GIT_ASKPASS is not set\n + git-svn, perl/Git.pm: add central method for prompting passwords\n\n Tweak the way \"git svn\" asks for password to be in line with the\n rest of the system, so that the same SSH/GIT_ASKPASS can be used.\n\n--------------------------------------------------\n[Stalled]\n\n* jl/submodule-deinit (2012-12-04) 1 commit\n  (merged to 'next' on 2012-12-07 at ea772f0)\n + submodule: add 'deinit' command\n\n There was no Porcelain way to say \"I no longer am interested in\n this submodule\", once you express your interest in a submodule with\n \"submodule init\".  \"submodule deinit\" is the way to do so.\n\n But this does not yet do so (does not remove the checkout of the\n submodule).  The design discussion petered out.\n\n http://thread.gmane.org/gmane.comp.version-control.git/210867/focus=211456\n\n Will kick back to 'pu'.\n\n\n* jc/doc-maintainer (2012-11-27) 1 commit\n - update \"howto maintain git\"\n\n An early draft that is still incomplete.\n\n\n* jk/lua-hackery (2012-10-07) 6 commits\n - pretty: fix up one-off format_commit_message calls\n - Minimum compilation fixup\n - Makefile: make \"lua\" a bit more configurable\n - add a \"lua\" pretty format\n - add basic lua infrastructure\n - pretty: make some commit-parsing helpers more public\n\n Interesting exercise. When we do this for real, we probably would want\n to wrap a commit to make it more like an \"object\" with methods like\n \"parents\", etc.\n\n\n* rc/maint-complete-git-p4 (2012-09-24) 1 commit\n  (merged to 'next' on 2012-10-29 at af52cef)\n + Teach git-completion about git p4\n\n Comment from Pete will need to be addressed ($gmane/206172).\n\n Will kick back to 'pu'.\n\n\n* jc/maint-name-rev (2012-09-17) 7 commits\n - describe --contains: use \"name-rev --algorithm=weight\"\n - name-rev --algorithm=weight: tests and documentation\n - name-rev --algorithm=weight: cache the computed weight in notes\n - name-rev --algorithm=weight: trivial optimization\n - name-rev: --algorithm option\n - name_rev: clarify the logic to assign a new tip-name to a commit\n - name-rev: lose unnecessary typedef\n\n \"git name-rev\" names the given revision based on a ref that can be\n reached in the smallest number of steps from the rev, but that is\n not useful when the caller wants to know which tag is the oldest one\n that contains the rev.  This teaches a new mode to the command that\n uses the oldest ref among those which contain the rev.\n\n I am not sure if this is worth it; for one thing, even with the help\n from notes-cache, it seems to make the \"describe --contains\" even\n slower. Also the command will be unusably slow for a user who does\n not have a write access (hence unable to create or update the\n notes-cache).\n\n Stalled mostly due to lack of responses.\n\n\n* jc/xprm-generation (2012-09-14) 1 commit\n - test-generation: compute generation numbers and clock skews\n\n A toy to analyze how bad the clock skews are in histories of real\n world projects.\n\n Stalled mostly due to lack of responses.\n\n\n* jc/blame-no-follow (2012-09-21) 2 commits\n - blame: pay attention to --no-follow\n - diff: accept --no-follow option\n\n Teaches \"--no-follow\" option to \"git blame\" to disable its\n whole-file rename detection.\n\n Stalled mostly due to lack of responses.\n\n\n* jc/add-delete-default (2012-08-13) 1 commit\n - git add: notice removal of tracked paths by default\n\n \"git add dir/\" updated modified files and added new files, but does\n not notice removed files, which may be \"Huh?\" to some users.  They\n can of course use \"git add -A dir/\", but why should they?\n\n Resurrected from graveyard, as I thought it was a worthwhile thing\n to do in the longer term.\n\n Waiting for comments.\n\n\n* mb/remote-default-nn-origin (2012-07-11) 6 commits\n - Teach get_default_remote to respect remote.default.\n - Test that plain \"git fetch\" uses remote.default when on a detached HEAD.\n - Teach clone to set remote.default.\n - Teach \"git remote\" about remote.default.\n - Teach remote.c about the remote.default configuration setting.\n - Rename remote.c's default_remote_name static variables.\n\n When the user does not specify what remote to interact with, we\n often attempt to use 'origin'.  This can now be customized via a\n configuration variable.\n\n Expecting a reroll.\n $gmane/210151\n\n \"The first remote becomes the default\" bit is better done as a\n separate step.\n\n--------------------------------------------------\n[Cooking]\n\n* jc/doc-default-format (2013-01-03) 2 commits\n - Allow installing a non-default set of documentation\n - Allow generating a non-default set of documentation\n\n Instead of the default of generating html/man and installing man,\n you can control what \"make doc\" and \"make install-doc\" do via two\n make variables.\n\n Will merge to 'next'.\n\n\n* fc/remote-testgit-feature-done (2012-10-29) 1 commit\n - remote-testgit: properly check for errors\n\n In the longer term, tightening rules is a good thing to do, and\n because nobody who has worked in the remote helper area seems to be\n interested in reviewing this, I would assume they do not think\n such a retroactive tightening will affect their remote helpers.  So\n let's advance this topic to see what happens.\n\n\n* fc/remote-bzr (2013-01-02) 9 commits\n - remote-bzr: detect local repositories\n - remote-bzr: add support for older versions of bzr\n - remote-bzr: add support to push special modes\n - remote-bzr: add support for fecthing special modes\n - remote-bzr: add simple tests\n - remote-bzr: update working tree upon pushing\n - remote-bzr: add support for remote repositories\n - remote-bzr: add support for pushing\n - Add new remote-bzr transport helper\n\n New remote helper for bzr, with minimum fix squashed in.\n\n Will merge to 'next'.\n\n\n* mo/cvs-server-updates (2012-12-09) 18 commits\n - t9402: Use TABs for indentation\n - t9402: Rename check.cvsCount and check.list\n - t9402: Simplify git ls-tree\n - t9402: Add missing &&; Code style\n - t9402: No space after IO-redirection\n - t9402: Dont use test_must_fail cvs\n - t9402: improve check_end_tree() and check_end_full_tree()\n - t9402: sed -i is not portable\n - cvsserver Documentation: new cvs ... -r support\n - cvsserver: add t9402 to test branch and tag refs\n - cvsserver: support -r and sticky tags for most operations\n - cvsserver: Add version awareness to argsfromdir\n - cvsserver: generalize getmeta() to recognize commit refs\n - cvsserver: implement req_Sticky and related utilities\n - cvsserver: add misc commit lookup, file meta data, and file listing functions\n - cvsserver: define a tag name character escape mechanism\n - cvsserver: cleanup extra slashes in filename arguments\n - cvsserver: factor out git-log parsing logic\n\n As nobody seems to be stepping up to review this, I am tempted to\n merge this to 'next and see who screams.\n\n\n* jc/submittingpatches (2013-01-02) 4 commits\n - SubmittingPatches: give list and maintainer addresses\n - SubmittingPatches: remove overlong checklist\n - SubmittingPatches: mention subsystems with dedicated repositories\n - SubmittingPatches: who am I and who cares?\n\n Will merge to 'next'.\n\n\n* kb/maint-bundle-doc (2013-01-01) 2 commits\n - Documentation: full-ness of a bundle is significant for cloning\n - Documentation: correct example restore from bundle\n\n Will merge to 'next'.\n\n\n* nd/maint-branch-desc-doc (2013-01-03) 5 commits\n - format-patch: pick up branch description when no ref is specified\n - format-patch: pick up correct branch name from symbolic ref\n - t4014: a few more tests on cover letter using branch description\n - branch: delete branch description if it's empty\n - config.txt: a few lines about branch.<name>.description\n\n Will merge to 'next'.\n\n\n* tb/test-t9020-no-which (2013-01-01) 1 commit\n - t9020: which is not portable\n\n Will merge to 'next'.\n\n\n* tb/test-t9810-no-sed-i (2013-01-01) 1 commit\n - t9810: Do not use sed -i\n\n Will merge to 'next'.\n\n\n* aw/rebase-am-failure-detection (2012-10-11) 1 commit\n  (merged to 'next' on 2013-01-02 at b9db3a2)\n + rebase: Handle cases where format-patch fails\n\n Save output from format-patch command in a temporary file, just in\n case it aborts, to give a better failure-case behaviour.\n\n\n* ap/status-ignored-in-ignored-directory (2013-01-01) 2 commits\n - git-status: Test --ignored behavior\n - dir.c: Make git-status --ignored more consistent\n\n Will merge to 'next'.\n\n\n* ta/remove-stale-translated-tut (2012-12-27) 1 commit\n  (merged to 'next' on 2013-01-02 at e70df8e)\n + Remove Documentation/pt_BR/gittutorial.txt\n\n Remove a translation of a document that was left stale.\n\n\n* er/stop-recommending-parsecvs (2012-12-28) 1 commit\n  (merged to 'next' on 2013-01-02 at fd816dd)\n + Remove the suggestion to use parsecvs, which is currently broken.\n\n Stop recommending a defunct third-party software.\n\n\n* as/test-name-alias-uniquely (2012-12-28) 1 commit\n  (merged to 'next' on 2013-01-02 at e297810)\n + Use longer alias names in subdirectory tests\n\n A few short-and-bland aliases used in the tests were interfering\n with git-custom command in user's $PATH.\n\n\n* jc/maint-fmt-merge-msg-no-edit-lose-credit (2012-12-28) 1 commit\n  (merged to 'next' on 2013-01-02 at 8795e87)\n + merge --no-edit: do not credit people involved in the side branch\n\n Stop spending cycles to compute information to be placed on\n commented lines in \"merge --no-edit\".\n\n\n* as/check-ignore (2012-12-28) 19 commits\n - Add git-check-ignore sub-command\n - setup.c: document get_pathspec()\n - pathspec.c: extract new validate_path() for reuse\n - pathspec.c: move reusable code from builtin/add.c\n - add.c: remove unused argument from validate_pathspec()\n - add.c: refactor treat_gitlinks()\n - dir.c: provide clear_directory() for reclaiming dir_struct memory\n - dir.c: keep track of where patterns came from\n - dir.c: use a single struct exclude_list per source of excludes\n - dir.c: rename free_excludes() to clear_exclude_list()\n - dir.c: refactor is_path_excluded()\n - dir.c: refactor is_excluded()\n - dir.c: refactor is_excluded_from_list()\n - dir.c: rename excluded() to is_excluded()\n - dir.c: rename excluded_from_list() to is_excluded_from_list()\n - dir.c: rename path_excluded() to is_path_excluded()\n - dir.c: rename cryptic 'which' variable to more consistent name\n - Improve documentation and comments regarding directory traversal API\n - api-directory-listing.txt: update to match code\n\n Rerolled.  The early parts looked mostly fine; we may want to split\n this into two topics and have the early half graduate sooner.\n\n\n* jc/format-patch-reroll (2013-01-02) 9 commits\n - format-patch: give --reroll-count a short synonym -v\n - format-patch: document and test --reroll-count\n - format-patch: add --reroll-count=$N option\n - get_patch_filename(): split into two functions\n - get_patch_filename(): drop \"just-numbers\" hack\n - get_patch_filename(): simplify function signature\n - builtin/log.c: stop using global patch_suffix\n - builtin/log.c: drop redundant \"numbered_files\" parameter from make_cover_letter()\n - builtin/log.c: drop unused \"numbered\" parameter from make_cover_letter()\n\n Teach \"format-patch\" to prefix v4- to its output files for the\n fourth iteration of a patch series, to make it easier for the\n submitter to keep separate copies for iterations.\n\n Will merge to 'next'.\n\n\n* mz/pick-unborn (2012-12-23) 2 commits\n  (merged to 'next' on 2013-01-02 at 22b9951)\n + learn to pick/revert into unborn branch\n + tests: move test_cmp_rev to test-lib-functions\n\n Allows \"git cherry-pick $commit\" when you do not have any history\n behind HEAD yet.\n\n\n* nd/retire-fnmatch (2013-01-01) 7 commits\n - Makefile: add USE_WILDMATCH to use wildmatch as fnmatch\n - wildmatch: advance faster in <asterisk> + <literal> patterns\n - wildmatch: make a special case for \"*/\" with FNM_PATHNAME\n - test-wildmatch: add \"perf\" command to compare wildmatch and fnmatch\n - wildmatch: support \"no FNM_PATHNAME\" mode\n - wildmatch: make dowild() take arbitrary flags\n - wildmatch: rename constants and update prototype\n (this branch uses nd/wildmatch.)\n\n Replace our use of fnmatch(3) with a more feature-rich wildmatch.\n A handful patches at the bottom have been moved to nd/wildmatch to\n graduate as part of that branch, before this series solidifies.\n\n Will merge to 'next'.\n\n\n* os/gitweb-highlight-uncaptured (2013-01-01) 1 commit\n - gitweb: fix error in sanitize when highlight is enabled\n\n Will merge to 'next'.\n\n\n* jc/merge-blobs (2012-12-26) 5 commits\n - merge-tree: fix d/f conflicts\n - merge-tree: add comments to clarify what these functions are doing\n - merge-tree: lose unused \"resolve_directories\"\n - merge-tree: lose unused \"flags\" from merge_list\n - Which merge_file() function do you mean?\n\n A beginning of a new merge strategy based on the disused merge-tree\n proof-of-concept code.\n\n\n* jk/pathspec-literal (2012-12-19) 1 commit\n  (merged to 'next' on 2012-12-22 at c794bd6)\n + add global --literal-pathspecs option\n\n Allow scripts to feed literal paths to commands that take\n pathspecs, by disabling wildcard globbing.\n\n Will merge to 'master'.\n\n\n* er/python-version-requirements (2012-12-28) 1 commit\n  (merged to 'next' on 2013-01-02 at 1023a3f)\n + Add checks to Python scripts for version dependencies.\n\n Some python scripts we ship cannot be run with old versions of the\n interpreter.\n\n\n* mb/gitweb-highlight-link-target (2012-12-20) 1 commit\n - Highlight the link target line in Gitweb using CSS\n\n Expecting a reroll.\n $gmane/211935\n\n\n* mz/oneway-merge-wo-u-no-lstat (2012-12-20) 1 commit\n  (merged to 'next' on 2012-12-22 at 87bd30e)\n + oneway_merge(): only lstat() when told to update worktree\n\n Optimize \"read-tree -m <tree-ish>\" without \"-u\".\n\n\n* wk/submodule-update-remote (2012-12-19) 3 commits\n  (merged to 'next' on 2012-12-22 at 7ddf897)\n + submodule add: If --branch is given, record it in .gitmodules\n + submodule update: add --remote for submodule's upstream changes\n + submodule: add get_submodule_config helper funtion\n\n The beginning of 'integrate with the tip of the remote branch, not\n the commit recorded in the superproject gitlink' support.\n\n Will merge to 'master'.\n\n\n* cc/no-gitk-build-dependency (2012-12-18) 3 commits\n  (merged to 'next' on 2012-12-22 at da7b2cf)\n + Makefile: replace \"echo 1>...\" with \"echo >...\"\n + Makefile: detect when PYTHON_PATH changes\n + Makefile: remove tracking of TCLTK_PATH\n\n Remove leftover bits from an earlier change to move gitk in its own\n subdirectory.  Reimplementing the dependency tracking rules needs\n to be done in gitk history separately.\n\n Will merge to 'master'.\n\n\n* jc/format-color-auto (2012-12-17) 2 commits\n  (merged to 'next' on 2012-12-18 at 5aaac94)\n + log --format: teach %C(auto,black) to respect color config\n + t6006: clean up whitespace\n\n Introduce \"log --format=%C(auto,blue)Foo%C(auto,reset)\" that does\n not color its output when writing to a non-terminal.\n\n Will merge to 'master'.\n\n\n* zk/clean-report-failure (2013-01-02) 2 commits\n - (SQUASH???) fix-up only the trivial bits\n - git-clean: Display more accurate delete messages\n\n \"git clean\" states what it is going to remove and then goes on to\n remove it, but sometimes it only discovers things that cannot be\n removed after recursing into a directory, which makes the output\n confusing and even wrong.\n\n Rerolled, and comments sent.\n\n\n* mp/complete-paths (2012-12-21) 1 commit\n - git-completion.bash: add support for path completion\n\n The completion script used to let the default completer to suggest\n pathnames, which gave too many irrelevant choices (e.g. \"git add\"\n would not want to add an unmodified path).  Teach it to use a more\n git-aware logic to enumerate only relevant ones.\n\n Waiting for area-experts' review.\n\n\n* ja/directory-attrs (2012-12-17) 1 commit\n  (merged to 'next' on 2012-12-17 at ced8e73)\n + Add directory pattern matching to attributes\n\n The attribute mechanism didn't allow limiting attributes to be\n applied to only a single directory itself with \"path/\" like the\n exclude mechanism does.\n\n Will merge to 'master'.\n\n\n* jk/mailmap-from-blob (2012-12-13) 5 commits\n  (merged to 'next' on 2012-12-17 at 14b7cdc)\n + mailmap: default mailmap.blob in bare repositories\n + mailmap: fix some documentation loose-ends for mailmap.blob\n + mailmap: clean up read_mailmap error handling\n + mailmap: support reading mailmap from blobs\n + mailmap: refactor mailmap parsing for non-file sources\n\n Allow us to read, and default to read, mailmap files from the tip\n of the history in bare repositories.  This will help running tools\n like shortlog in server settings.\n\n Will merge to 'master'.\n\n\n* jk/complete-commit-c (2012-12-15) 1 commit\n  (merged to 'next' on 2012-12-18 at 75b5f21)\n + completion: complete refs for \"git commit -c\"\n\n Complete \"git commmit -c foo<TAB>\" into a refname that begins with\n \"foo\".\n\n Will merge to 'master'.\n\n\n* jk/error-const-return (2012-12-15) 2 commits\n  (merged to 'next' on 2012-12-22 at bf2b1cd)\n + silence some -Wuninitialized false positives\n + make error()'s constant return value more visible\n\n Help compilers' flow analysis by making it more explicit that\n error() always returns -1, to reduce false \"variable used\n uninitialized\" warnings.  Looks somewhat ugly but not too much.\n\n Will merge to 'master'.\n\n\n* ap/log-mailmap (2012-12-27) 10 commits\n - log --use-mailmap: optimize for cases without --author/--committer search\n - log: add log.mailmap configuration option\n - log: grep author/committer using mailmap\n - test: Add test for --use-mailmap option\n - log: Add --use-mailmap option\n - pretty: Use mailmap to display username and email\n - mailmap: Add mailmap structure to rev_info and pp\n - mailmap: Simplify map_user() interface\n - mailmap: Remove buffer length limit in map_user\n - Use split_ident_line to parse author and committer\n (this branch is used by jc/mailmap.)\n\n Clean up various codepaths around mailmap and teach the \"log\"\n machinery to use it.\n\n Expecting a reroll.\n $gmane/212426\n\n\n* jc/fetch-ignore-symref (2012-12-11) 1 commit\n  (merged to 'next' on 2012-12-17 at 370e2c8)\n + fetch: ignore wildcarded refspecs that update local symbolic refs\n\n Avoid false error from an attempt to update local symbolic ref via\n fetch.\n\n Will merge to 'master'.\n\n\n* bc/append-signed-off-by (2013-01-01) 12 commits\n - t4014: do not use echo -n\n - Unify appending signoff in format-patch, commit and sequencer\n - format-patch: update append_signoff prototype\n - format-patch: stricter S-o-b detection\n - t4014: more tests about appending s-o-b lines\n - sequencer.c: teach append_signoff to avoid adding a duplicate newline\n - sequencer.c: teach append_signoff how to detect duplicate s-o-b\n - sequencer.c: always separate \"(cherry picked from\" from commit body\n - sequencer.c: recognize \"(cherry picked from ...\" as part of s-o-b footer\n - t/t3511: add some tests of 'cherry-pick -s' functionality\n - t/test-lib-functions.sh: allow to specify the tag name to test_commit\n - sequencer.c: remove broken support for rfc2822 continuation in footer\n\n Expecting a reroll.\n $gmane/212507\n\n\n* mh/unify-xml-in-imap-send-and-http-push (2012-12-02) 8 commits\n  (merged to 'next' on 2012-12-03 at d677090)\n + wrap_in_html(): process message in bulk rather than line-by-line\n + wrap_in_html(): use strbuf_addstr_xml_quoted()\n + imap-send: change msg_data from storing (ptr, len) to storing strbuf\n + imap-send: correctly report errors reading from stdin\n + imap-send: store all_msgs as a strbuf\n + lf_to_crlf(): NUL-terminate msg_data::data\n + xml_entities(): use function strbuf_addstr_xml_quoted()\n + Add new function strbuf_add_xml_quoted()\n\n Update imap-send to reuse xml quoting code from http-push codepath,\n clean up some code, and fix a small bug.\n\n Will merge to 'master'.\n\n\n* jk/fsck-dot-in-trees (2012-11-28) 2 commits\n  (merged to 'next' on 2012-11-28 at 519dabc)\n + fsck: warn about \".git\" in trees\n + fsck: warn about '.' and '..' in trees\n\n Will merge to 'master'.\n\n\n* jn/warn-on-inaccessible-loosen (2012-10-14) 4 commits\n  (merged to 'next' on 2012-11-28 at 43d51c2)\n + config: exit on error accessing any config file\n + doc: advertise GIT_CONFIG_NOSYSTEM\n + config: treat user and xdg config permission problems as errors\n + config, gitignore: failure to access with ENOTDIR is ok\n\n Deal with a situation where .config/git is a file and we notice\n .config/git/config is not readable due to ENOTDIR, not ENOENT.\n\n\n* fc/fast-export-fixes (2012-12-03) 15 commits\n  (merged to 'next' on 2012-12-03 at f9df523)\n + fast-export: make sure updated refs get updated\n + fast-export: don't handle uninteresting refs\n + fast-export: fix comparison in tests\n + fast-export: trivial cleanup\n + remote-testgit: implement the \"done\" feature manually\n + remote-testgit: report success after an import\n + remote-testgit: exercise more features\n + remote-testgit: cleanup tests\n + remote-testgit: remove irrelevant test\n + remote-testgit: remove non-local functionality\n + Add new simplified git-remote-testgit\n + Rename git-remote-testgit to git-remote-testpy\n + remote-helpers: fix failure message\n + remote-testgit: fix direction of marks\n + fast-export: avoid importing blob marks\n\n Will merge to 'master'.\n\n\n* jc/apply-trailing-blank-removal (2012-10-12) 1 commit\n  (merged to 'next' on 2012-11-26 at 3af69e7)\n + apply.c:update_pre_post_images(): the preimage can be truncated\n\n Fix to update_pre_post_images() that did not take into account the\n possibility that whitespace fix could shrink the preimage and\n change the number of lines in it.\n\n\n* nd/pathspec-wildcard (2012-11-26) 4 commits\n  (merged to 'next' on 2012-12-03 at eca0fcb)\n + tree_entry_interesting: do basedir compare on wildcard patterns when possible\n + pathspec: apply \"*.c\" optimization from exclude\n + pathspec: do exact comparison on the leading non-wildcard part\n + pathspec: save the non-wildcard length part\n\n Will merge to 'master'.\n\n\n* nd/wildmatch (2013-01-01) 18 commits\n  (merged to 'next' on 2013-01-01 at 8c633a5)\n + wildmatch: replace variable 'special' with better named ones\n + compat/fnmatch: respect NO_FNMATCH* even on glibc\n + wildmatch: fix \"**\" special case\n  (merged to 'next' on 2012-12-15 at c734714)\n + t3070: Disable some failing fnmatch tests\n  (merged to 'next' on 2012-11-21 at 151288f)\n + test-wildmatch: avoid Windows path mangling\n  (merged to 'next' on 2012-10-25 at 510e8df)\n + Support \"**\" wildcard in .gitignore and .gitattributes\n + wildmatch: make /**/ match zero or more directories\n + wildmatch: adjust \"**\" behavior\n + wildmatch: fix case-insensitive matching\n + wildmatch: remove static variable force_lower_case\n + wildmatch: make wildmatch's return value compatible with fnmatch\n + t3070: disable unreliable fnmatch tests\n + Integrate wildmatch to git\n + wildmatch: follow Git's coding convention\n + wildmatch: remove unnecessary functions\n + Import wildmatch from rsync\n + ctype: support iscntrl, ispunct, isxdigit and isprint\n + ctype: make sane_ctype[] const array\n (this branch is used by nd/retire-fnmatch.)\n\n Allows pathname patterns in .gitignore and .gitattributes files\n with double-asterisks \"foo/**/bar\" to match any number of directory\n hierarchies.\n\n\n* cr/push-force-tag-update (2012-12-03) 10 commits\n  (merged to 'next' on 2012-12-04 at af2e3a9)\n + push: allow already-exists advice to be disabled\n + push: rename config variable for more general use\n + push: cleanup push rules comment\n + push: clarify rejection of update to non-commit-ish\n + push: require force for annotated tags\n + push: require force for refs under refs/tags/\n + push: flag updates that require force\n + push: keep track of \"update\" state separately\n + push: add advice for rejected tag reference\n + push: return reject reasons as a bitset\n\n Require \"-f\" for push to update a tag, even if it is a fast-forward.\n\n Will merge to 'master'.\n"},{"id":"205970","messageId":"CAOkDyE-f-8XZAzWrQgh_DG=fZctqBFXqpog-FSDU_yeXfwWTwA@mail.gmail.com","threadId":"32519","inReplyTo":"7vmwwqvzy4.fsf@alter.siamese.dyndns.org","subject":"Re: What's cooking in git.git (Jan 2013, #02; Thu, 3)","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-04T17:23:37Z","receivedAt":"2013-01-04T17:23:37Z","isPatch":false,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"On Thu, Jan 3, 2013 at 7:17 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> * as/check-ignore (2012-12-28) 19 commits\n>  - Add git-check-ignore sub-command\n>  - setup.c: document get_pathspec()\n>  - pathspec.c: extract new validate_path() for reuse\n>  - pathspec.c: move reusable code from builtin/add.c\n>  - add.c: remove unused argument from validate_pathspec()\n>  - add.c: refactor treat_gitlinks()\n>  - dir.c: provide clear_directory() for reclaiming dir_struct memory\n>  - dir.c: keep track of where patterns came from\n>  - dir.c: use a single struct exclude_list per source of excludes\n>  - dir.c: rename free_excludes() to clear_exclude_list()\n>  - dir.c: refactor is_path_excluded()\n>  - dir.c: refactor is_excluded()\n>  - dir.c: refactor is_excluded_from_list()\n>  - dir.c: rename excluded() to is_excluded()\n>  - dir.c: rename excluded_from_list() to is_excluded_from_list()\n>  - dir.c: rename path_excluded() to is_path_excluded()\n>  - dir.c: rename cryptic 'which' variable to more consistent name\n>  - Improve documentation and comments regarding directory traversal API\n>  - api-directory-listing.txt: update to match code\n>\n>  Rerolled.  The early parts looked mostly fine; we may want to split\n>  this into two topics and have the early half graduate sooner.\n\nSounds good to me.  As already mentioned, I have the v4 series ready\nand it addresses all issues already voiced in v3, but I have postponed\nsubmitting it as per your request.  Please let me know when and how to\nproceed, thanks!\n"},{"id":"205978","messageId":"7vobh4tzx3.fsf@alter.siamese.dyndns.org","threadId":"32519","inReplyTo":"CAOkDyE-f-8XZAzWrQgh_DG=fZctqBFXqpog-FSDU_yeXfwWTwA@mail.gmail.com","subject":"Re: as/check-ignore (was Re: What's cooking in git.git (Jan 2013, #02; Thu, 3))","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-04T21:13:12Z","receivedAt":"2013-01-04T21:13:12Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Adam Spiers <git@adamspiers.org> writes:\n\n> On Thu, Jan 3, 2013 at 7:17 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> * as/check-ignore (2012-12-28) 19 commits\n>>  - Add git-check-ignore sub-command\n>>  - setup.c: document get_pathspec()\n>>  - pathspec.c: extract new validate_path() for reuse\n>>  - pathspec.c: move reusable code from builtin/add.c\n>>  - add.c: remove unused argument from validate_pathspec()\n>>  - add.c: refactor treat_gitlinks()\n>>  - dir.c: provide clear_directory() for reclaiming dir_struct memory\n>>  - dir.c: keep track of where patterns came from\n>>  - dir.c: use a single struct exclude_list per source of excludes\n>>  - dir.c: rename free_excludes() to clear_exclude_list()\n>>  - dir.c: refactor is_path_excluded()\n>>  - dir.c: refactor is_excluded()\n>>  - dir.c: refactor is_excluded_from_list()\n>>  - dir.c: rename excluded() to is_excluded()\n>>  - dir.c: rename excluded_from_list() to is_excluded_from_list()\n>>  - dir.c: rename path_excluded() to is_path_excluded()\n>>  - dir.c: rename cryptic 'which' variable to more consistent name\n>>  - Improve documentation and comments regarding directory traversal API\n>>  - api-directory-listing.txt: update to match code\n>>\n>>  Rerolled.  The early parts looked mostly fine; we may want to split\n>>  this into two topics and have the early half graduate sooner.\n>\n> Sounds good to me.  As already mentioned, I have the v4 series ready\n> and it addresses all issues already voiced in v3, but I have postponed\n> submitting it as per your request.  Please let me know when and how to\n> proceed, thanks!\n\nI was planning to add a new \"as/dir-c-cleanup\" topic that leads to\nf619881 (dir.c: rename free_excludes() to clear_exclude_list(),\n2012-12-27), and leave the remainder in this series.  I think the\nearlier parts of this series up to that point should go 'next' now.\n"},{"id":"206143","messageId":"20130106161758.GC2396@pacific.linksys.moosehall","threadId":"32519","inReplyTo":"7vobh4tzx3.fsf@alter.siamese.dyndns.org","subject":"Re: as/check-ignore (was Re: What's cooking in git.git (Jan 2013, #02; Thu, 3))","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:17:58Z","receivedAt":"2013-01-06T16:17:58Z","isPatch":false,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"On Fri, Jan 04, 2013 at 01:13:12PM -0800, Junio C Hamano wrote:\n> Adam Spiers <git@adamspiers.org> writes:\n> > On Thu, Jan 3, 2013 at 7:17 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> >> * as/check-ignore (2012-12-28) 19 commits\n> >>  - Add git-check-ignore sub-command\n> >>  - setup.c: document get_pathspec()\n> >>  - pathspec.c: extract new validate_path() for reuse\n> >>  - pathspec.c: move reusable code from builtin/add.c\n> >>  - add.c: remove unused argument from validate_pathspec()\n> >>  - add.c: refactor treat_gitlinks()\n> >>  - dir.c: provide clear_directory() for reclaiming dir_struct memory\n> >>  - dir.c: keep track of where patterns came from\n> >>  - dir.c: use a single struct exclude_list per source of excludes\n> >>  - dir.c: rename free_excludes() to clear_exclude_list()\n> >>  - dir.c: refactor is_path_excluded()\n> >>  - dir.c: refactor is_excluded()\n> >>  - dir.c: refactor is_excluded_from_list()\n> >>  - dir.c: rename excluded() to is_excluded()\n> >>  - dir.c: rename excluded_from_list() to is_excluded_from_list()\n> >>  - dir.c: rename path_excluded() to is_path_excluded()\n> >>  - dir.c: rename cryptic 'which' variable to more consistent name\n> >>  - Improve documentation and comments regarding directory traversal API\n> >>  - api-directory-listing.txt: update to match code\n> >>\n> >>  Rerolled.  The early parts looked mostly fine; we may want to split\n> >>  this into two topics and have the early half graduate sooner.\n> >\n> > Sounds good to me.  As already mentioned, I have the v4 series ready\n> > and it addresses all issues already voiced in v3, but I have postponed\n> > submitting it as per your request.  Please let me know when and how to\n> > proceed, thanks!\n> \n> I was planning to add a new \"as/dir-c-cleanup\" topic that leads to\n> f619881 (dir.c: rename free_excludes() to clear_exclude_list(),\n> 2012-12-27), and leave the remainder in this series.  I think the\n> earlier parts of this series up to that point should go 'next' now.\n\nThat sounds perfect; thanks.  I'll rebase v4 on top of this and submit.\n"},{"id":"206146","messageId":"1357491493-11619-1-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"20130106161758.GC2396@pacific.linksys.moosehall","subject":"[PATCH v4 00/11] new git check-ignore sub-command","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:02Z","receivedAt":"2013-01-06T16:58:02Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"This is the v4 re-roll of the check-ignore series, which is based on\nJunio's as/dir-c-cleanup topic branch f6198812 (dir.c: rename\nfree_excludes() to clear_exclude_list(), 2012-12-27).  As previously\ndiscussed, the earlier parts of the v3 series seem to be complete and\nare progressing to 'next'.\n\nSince v3, I addressed the issue of newly public functions with\nunacceptably vague or generic names via the following steps:\n\n  - eliminated extraction from add.c to pathspec.c of two functions\n    which did not need to be public (validate_pathspec() and\n    treat_gitlinks())\n\n  - edited the series history to create separate commits for\n    extraction of reusable code from treat_gitlinks() and\n    validate_pathspec() into more carefully named public functions\n\nThis should make reviewing easier.\n\nI will summarise the changes in the revised patches since v3 in\nbetween the \"---\" divider and the diffstat of each individual patch.\n\nThis series is also available via the check-ignore-v4 tag in:\n\n    git://github.com/aspiers/git.git\n\nAdam Spiers (11):\n  dir.c: use a single struct exclude_list per source of excludes\n  dir.c: keep track of where patterns came from\n  dir.c: provide clear_directory() for reclaiming dir_struct memory\n  dir.c: improve docs for match_pathspec() and match_pathspec_depth()\n  add.c: remove unused argument from validate_pathspec()\n  add.c: move pathspec matchers into new pathspec.c for reuse\n  pathspec.c: rename newly public functions for clarity\n  add.c: extract check_path_for_gitlink() from treat_gitlinks() for\n    reuse\n  add.c: extract new die_if_path_beyond_symlink() for reuse\n  setup.c: document get_pathspec()\n  add git-check-ignore sub-command\n\n .gitignore                                        |   1 +\n Documentation/git-check-ignore.txt                |  89 +++\n Documentation/gitignore.txt                       |   6 +-\n Documentation/technical/api-directory-listing.txt |  14 +-\n Makefile                                          |   3 +\n builtin.h                                         |   1 +\n builtin/add.c                                     |  78 +--\n builtin/check-ignore.c                            | 173 ++++++\n builtin/clean.c                                   |   3 +-\n builtin/ls-files.c                                |   9 +-\n command-list.txt                                  |   1 +\n contrib/completion/git-completion.bash            |   1 +\n dir.c                                             | 152 ++++--\n dir.h                                             |  62 ++-\n git.c                                             |   1 +\n pathspec.c                                        | 101 ++++\n pathspec.h                                        |   9 +\n setup.c                                           |  19 +\n t/t0008-ignores.sh                                | 632 ++++++++++++++++++++++\n unpack-trees.c                                    |   2 +-\n 20 files changed, 1240 insertions(+), 117 deletions(-)\n create mode 100644 Documentation/git-check-ignore.txt\n create mode 100644 builtin/check-ignore.c\n create mode 100644 pathspec.c\n create mode 100644 pathspec.h\n create mode 100755 t/t0008-ignores.sh\n\n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206152","messageId":"1357491493-11619-2-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 01/11] dir.c: use a single struct exclude_list per source of excludes","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:03Z","receivedAt":"2013-01-06T16:58:03Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"Previously each exclude_list could potentially contain patterns\nfrom multiple sources.  For example dir->exclude_list[EXC_FILE]\nwould typically contain patterns from .git/info/exclude and\ncore.excludesfile, and dir->exclude_list[EXC_DIRS] could contain\npatterns from multiple per-directory .gitignore files during\ndirectory traversal (i.e. when dir->exclude_stack was more than\none item deep).\n\nWe split these composite exclude_lists up into three groups of\nexclude_lists (EXC_CMDL / EXC_DIRS / EXC_FILE as before), so that each\nexclude_list now contains patterns from a single source.  This will\nallow us to cleanly track the origin of each pattern simply by adding\na src field to struct exclude_list, rather than to struct exclude,\nwhich would make memory management of the source string tricky in the\nEXC_DIRS case where its contents are dynamically generated.\n\nSimilarly, by moving the filebuf member from struct exclude_stack to\nstruct exclude_list, it allows us to track and subsequently free\nmemory buffers allocated during the parsing of all exclude files,\nrather than only tracking buffers allocated for files in the EXC_DIRS\ngroup.\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\n Documentation/technical/api-directory-listing.txt | 12 +++--\n builtin/clean.c                                   |  3 +-\n builtin/ls-files.c                                |  8 +--\n dir.c                                             | 64 ++++++++++++++++-------\n dir.h                                             | 36 +++++++++----\n unpack-trees.c                                    |  2 +-\n 6 files changed, 86 insertions(+), 39 deletions(-)\n\ndiff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt\nindex 944fc39..fa9c8ae 100644\n--- a/Documentation/technical/api-directory-listing.txt\n+++ b/Documentation/technical/api-directory-listing.txt\n@@ -67,11 +67,13 @@ marked. If you to exclude files, make sure you have loaded index first.\n * Prepare `struct dir_struct dir` and clear it with `memset(&dir, 0,\n   sizeof(dir))`.\n \n-* Call `add_exclude()` to add single exclude pattern,\n-  `add_excludes_from_file()` to add patterns from a file\n-  (e.g. `.git/info/exclude`), and/or set `dir.exclude_per_dir`.  A\n-  short-hand function `setup_standard_excludes()` can be used to set up\n-  the standard set of exclude settings.\n+* To add single exclude pattern, call `add_exclude_list()` and then\n+  `add_exclude()`.\n+\n+* To add patterns from a file (e.g. `.git/info/exclude`), call\n+  `add_excludes_from_file()` , and/or set `dir.exclude_per_dir`.  A\n+  short-hand function `setup_standard_excludes()` can be used to set\n+  up the standard set of exclude settings.\n \n * Set options described in the Data Structure section above.\n \ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex 0c7b3d0..dd89737 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -97,9 +97,10 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \tif (!ignored)\n \t\tsetup_standard_excludes(&dir);\n \n+\tadd_exclude_list(&dir, EXC_CMDL);\n \tfor (i = 0; i < exclude_list.nr; i++)\n \t\tadd_exclude(exclude_list.items[i].string, \"\", 0,\n-\t\t\t    &dir.exclude_list[EXC_CMDL]);\n+\t\t\t    &dir.exclude_list_group[EXC_CMDL].el[0]);\n \n \tpathspec = get_pathspec(prefix, argv);\n \ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex ef7f99a..0ca9d8e 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -420,10 +420,10 @@ static int option_parse_z(const struct option *opt,\n static int option_parse_exclude(const struct option *opt,\n \t\t\t\tconst char *arg, int unset)\n {\n-\tstruct exclude_list *list = opt->value;\n+\tstruct exclude_list_group *group = opt->value;\n \n \texc_given = 1;\n-\tadd_exclude(arg, \"\", 0, list);\n+\tadd_exclude(arg, \"\", 0, &group->el[0]);\n \n \treturn 0;\n }\n@@ -488,7 +488,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\t\"show unmerged files in the output\"),\n \t\tOPT_BOOLEAN(0, \"resolve-undo\", &show_resolve_undo,\n \t\t\t    \"show resolve-undo information\"),\n-\t\t{ OPTION_CALLBACK, 'x', \"exclude\", &dir.exclude_list[EXC_CMDL], \"pattern\",\n+\t\t{ OPTION_CALLBACK, 'x', \"exclude\",\n+\t\t\t&dir.exclude_list_group[EXC_CMDL], \"pattern\",\n \t\t\t\"skip files matching pattern\",\n \t\t\t0, option_parse_exclude },\n \t\t{ OPTION_CALLBACK, 'X', \"exclude-from\", &dir, \"file\",\n@@ -523,6 +524,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (read_cache() < 0)\n \t\tdie(\"index file corrupt\");\n \n+\tadd_exclude_list(&dir, EXC_CMDL);\n \targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n \t\t\tls_files_usage, 0);\n \tif (show_tag || show_valid_bit) {\ndiff --git a/dir.c b/dir.c\nindex 41f141c..3a15cb9 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -411,15 +411,16 @@ void clear_exclude_list(struct exclude_list *el)\n \tfor (i = 0; i < el->nr; i++)\n \t\tfree(el->excludes[i]);\n \tfree(el->excludes);\n+\tfree(el->filebuf);\n \n \tel->nr = 0;\n \tel->excludes = NULL;\n+\tel->filebuf = NULL;\n }\n \n int add_excludes_from_file_to_list(const char *fname,\n \t\t\t\t   const char *base,\n \t\t\t\t   int baselen,\n-\t\t\t\t   char **buf_p,\n \t\t\t\t   struct exclude_list *el,\n \t\t\t\t   int check_index)\n {\n@@ -460,8 +461,7 @@ int add_excludes_from_file_to_list(const char *fname,\n \t\tclose(fd);\n \t}\n \n-\tif (buf_p)\n-\t\t*buf_p = buf;\n+\tel->filebuf = buf;\n \tentry = buf;\n \tfor (i = 0; i < size; i++) {\n \t\tif (buf[i] == '\\n') {\n@@ -475,10 +475,26 @@ int add_excludes_from_file_to_list(const char *fname,\n \treturn 0;\n }\n \n+struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type)\n+{\n+\tstruct exclude_list *el;\n+\tstruct exclude_list_group *group;\n+\n+\tgroup = &dir->exclude_list_group[group_type];\n+\tALLOC_GROW(group->el, group->nr + 1, group->alloc);\n+\tel = &group->el[group->nr++];\n+\tmemset(el, 0, sizeof(*el));\n+\treturn el;\n+}\n+\n+/*\n+ * Used to set up core.excludesfile and .git/info/exclude lists.\n+ */\n void add_excludes_from_file(struct dir_struct *dir, const char *fname)\n {\n-\tif (add_excludes_from_file_to_list(fname, \"\", 0, NULL,\n-\t\t\t\t\t   &dir->exclude_list[EXC_FILE], 0) < 0)\n+\tstruct exclude_list *el;\n+\tel = add_exclude_list(dir, EXC_FILE);\n+\tif (add_excludes_from_file_to_list(fname, \"\", 0, el, 0) < 0)\n \t\tdie(\"cannot use %s as an exclude file\", fname);\n }\n \n@@ -488,6 +504,7 @@ void add_excludes_from_file(struct dir_struct *dir, const char *fname)\n  */\n static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n {\n+\tstruct exclude_list_group *group;\n \tstruct exclude_list *el;\n \tstruct exclude_stack *stk = NULL;\n \tint current;\n@@ -496,17 +513,20 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n \t    (baselen + strlen(dir->exclude_per_dir) >= PATH_MAX))\n \t\treturn; /* too long a path -- ignore */\n \n-\t/* Pop the directories that are not the prefix of the path being checked. */\n-\tel = &dir->exclude_list[EXC_DIRS];\n+\tgroup = &dir->exclude_list_group[EXC_DIRS];\n+\n+\t/* Pop the exclude lists from the EXCL_DIRS exclude_list_group\n+\t * which originate from directories not in the prefix of the\n+\t * path being checked. */\n \twhile ((stk = dir->exclude_stack) != NULL) {\n \t\tif (stk->baselen <= baselen &&\n \t\t    !strncmp(dir->basebuf, base, stk->baselen))\n \t\t\tbreak;\n+\t\tel = &group->el[dir->exclude_stack->exclude_ix];\n \t\tdir->exclude_stack = stk->prev;\n-\t\twhile (stk->exclude_ix < el->nr)\n-\t\t\tfree(el->excludes[--el->nr]);\n-\t\tfree(stk->filebuf);\n+\t\tclear_exclude_list(el);\n \t\tfree(stk);\n+\t\tgroup->nr--;\n \t}\n \n \t/* Read from the parent directories and push them down. */\n@@ -527,13 +547,14 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n \t\t}\n \t\tstk->prev = dir->exclude_stack;\n \t\tstk->baselen = cp - base;\n-\t\tstk->exclude_ix = el->nr;\n \t\tmemcpy(dir->basebuf + current, base + current,\n \t\t       stk->baselen - current);\n \t\tstrcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);\n+\t\tel = add_exclude_list(dir, EXC_DIRS);\n+\t\tstk->exclude_ix = group->nr - 1;\n \t\tadd_excludes_from_file_to_list(dir->basebuf,\n \t\t\t\t\t       dir->basebuf, stk->baselen,\n-\t\t\t\t\t       &stk->filebuf, el, 1);\n+\t\t\t\t\t       el, 1);\n \t\tdir->exclude_stack = stk;\n \t\tcurrent = stk->baselen;\n \t}\n@@ -679,18 +700,23 @@ static struct exclude *last_exclude_matching(struct dir_struct *dir,\n \t\t\t\t\t     int *dtype_p)\n {\n \tint pathlen = strlen(pathname);\n-\tint st;\n+\tint i, j;\n+\tstruct exclude_list_group *group;\n \tstruct exclude *exclude;\n \tconst char *basename = strrchr(pathname, '/');\n \tbasename = (basename) ? basename+1 : pathname;\n \n \tprep_exclude(dir, pathname, basename-pathname);\n-\tfor (st = EXC_CMDL; st <= EXC_FILE; st++) {\n-\t\texclude = last_exclude_matching_from_list(\n-\t\t\tpathname, pathlen, basename, dtype_p,\n-\t\t\t&dir->exclude_list[st]);\n-\t\tif (exclude)\n-\t\t\treturn exclude;\n+\n+\tfor (i = EXC_CMDL; i <= EXC_FILE; i++) {\n+\t\tgroup = &dir->exclude_list_group[i];\n+\t\tfor (j = group->nr - 1; j >= 0; j--) {\n+\t\t\texclude = last_exclude_matching_from_list(\n+\t\t\t\tpathname, pathlen, basename, dtype_p,\n+\t\t\t\t&group->el[j]);\n+\t\t\tif (exclude)\n+\t\t\t\treturn exclude;\n+\t\t}\n \t}\n \treturn NULL;\n }\ndiff --git a/dir.h b/dir.h\nindex 5664ba8..c4d88db 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -16,14 +16,18 @@ struct dir_entry {\n #define EXC_FLAG_NEGATIVE 16\n \n /*\n- * Each .gitignore file will be parsed into patterns which are then\n- * appended to the relevant exclude_list (either EXC_DIRS or\n- * EXC_FILE).  exclude_lists are also used to represent the list of\n- * --exclude values passed via CLI args (EXC_CMDL).\n+ * Each excludes file will be parsed into a fresh exclude_list which\n+ * is appended to the relevant exclude_list_group (either EXC_DIRS or\n+ * EXC_FILE).  An exclude_list within the EXC_CMDL exclude_list_group\n+ * can also be used to represent the list of --exclude values passed\n+ * via CLI args.\n  */\n struct exclude_list {\n \tint nr;\n \tint alloc;\n+\t/* remember pointer to exclude file contents so we can free() */\n+\tchar *filebuf;\n+\n \tstruct exclude {\n \t\tconst char *pattern;\n \t\tint patternlen;\n@@ -42,9 +46,13 @@ struct exclude_list {\n  */\n struct exclude_stack {\n \tstruct exclude_stack *prev; /* the struct exclude_stack for the parent directory */\n-\tchar *filebuf; /* remember pointer to per-directory exclude file contents so we can free() */\n \tint baselen;\n-\tint exclude_ix;\n+\tint exclude_ix; /* index of exclude_list within EXC_DIRS exclude_list_group */\n+};\n+\n+struct exclude_list_group {\n+\tint nr, alloc;\n+\tstruct exclude_list *el;\n };\n \n struct dir_struct {\n@@ -62,16 +70,23 @@ struct dir_struct {\n \n \t/* Exclude info */\n \tconst char *exclude_per_dir;\n-\tstruct exclude_list exclude_list[3];\n+\n \t/*\n-\t * We maintain three exclude pattern lists:\n+\t * We maintain three groups of exclude pattern lists:\n+\t *\n \t * EXC_CMDL lists patterns explicitly given on the command line.\n \t * EXC_DIRS lists patterns obtained from per-directory ignore files.\n-\t * EXC_FILE lists patterns from fallback ignore files.\n+\t * EXC_FILE lists patterns from fallback ignore files, e.g.\n+\t *   - .git/info/exclude\n+\t *   - core.excludesfile\n+\t *\n+\t * Each group contains multiple exclude lists, a single list\n+\t * per source.\n \t */\n #define EXC_CMDL 0\n #define EXC_DIRS 1\n #define EXC_FILE 2\n+\tstruct exclude_list_group exclude_list_group[3];\n \n \t/*\n \t * Temporary variables which are used during loading of the\n@@ -129,8 +144,9 @@ extern struct exclude *last_exclude_matching_path(struct path_exclude_check *, c\n extern int is_path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype);\n \n \n+extern struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type);\n extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,\n-\t\t\t\t\t  char **buf_p, struct exclude_list *el, int check_index);\n+\t\t\t\t\t  struct exclude_list *el, int check_index);\n extern void add_excludes_from_file(struct dir_struct *, const char *fname);\n extern void parse_exclude_pattern(const char **string, int *patternlen, int *flags, int *nowildcardlen);\n extern void add_exclude(const char *string, const char *base,\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex ad621d9..de8da46 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1019,7 +1019,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options\n \tif (!core_apply_sparse_checkout || !o->update)\n \t\to->skip_sparse_checkout = 1;\n \tif (!o->skip_sparse_checkout) {\n-\t\tif (add_excludes_from_file_to_list(git_path(\"info/sparse-checkout\"), \"\", 0, NULL, &el, 0) < 0)\n+\t\tif (add_excludes_from_file_to_list(git_path(\"info/sparse-checkout\"), \"\", 0, &el, 0) < 0)\n \t\t\to->skip_sparse_checkout = 1;\n \t\telse\n \t\t\to->el = &el;\n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206148","messageId":"1357491493-11619-3-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 02/11] dir.c: keep track of where patterns came from","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:04Z","receivedAt":"2013-01-06T16:58:04Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"For exclude patterns read in from files, the filename is stored in the\nexclude list, and the originating line number is stored in the\nindividual exclude (counting starting at 1).\n\nFor exclude patterns provided on the command line, a string describing\nthe source of the patterns is stored in the exclude list, and the\nsequence number assigned to each exclude pattern is negative, with\ncounting starting at -1.  So for example the 2nd pattern provided via\n--exclude would be numbered -2.  This allows any future consumers of\nthat data to easily distinguish between exclude patterns from files\nvs. from the CLI.\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\n builtin/clean.c    |  4 ++--\n builtin/ls-files.c |  5 +++--\n dir.c              | 26 ++++++++++++++++++++------\n dir.h              | 21 +++++++++++++++++++--\n 4 files changed, 44 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex dd89737..b098288 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -97,10 +97,10 @@ int cmd_clean(int argc, const char **argv, const char *prefix)\n \tif (!ignored)\n \t\tsetup_standard_excludes(&dir);\n \n-\tadd_exclude_list(&dir, EXC_CMDL);\n+\tadd_exclude_list(&dir, EXC_CMDL, \"--exclude option\");\n \tfor (i = 0; i < exclude_list.nr; i++)\n \t\tadd_exclude(exclude_list.items[i].string, \"\", 0,\n-\t\t\t    &dir.exclude_list_group[EXC_CMDL].el[0]);\n+\t\t\t    &dir.exclude_list_group[EXC_CMDL].el[0], -(i+1));\n \n \tpathspec = get_pathspec(prefix, argv);\n \ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 0ca9d8e..fa9ccb8 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -35,6 +35,7 @@ static int error_unmatch;\n static char *ps_matched;\n static const char *with_tree;\n static int exc_given;\n+static int exclude_args;\n \n static const char *tag_cached = \"\";\n static const char *tag_unmerged = \"\";\n@@ -423,7 +424,7 @@ static int option_parse_exclude(const struct option *opt,\n \tstruct exclude_list_group *group = opt->value;\n \n \texc_given = 1;\n-\tadd_exclude(arg, \"\", 0, &group->el[0]);\n+\tadd_exclude(arg, \"\", 0, &group->el[0], --exclude_args);\n \n \treturn 0;\n }\n@@ -524,7 +525,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (read_cache() < 0)\n \t\tdie(\"index file corrupt\");\n \n-\tadd_exclude_list(&dir, EXC_CMDL);\n+\tadd_exclude_list(&dir, EXC_CMDL, \"--exclude option\");\n \targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n \t\t\tls_files_usage, 0);\n \tif (show_tag || show_valid_bit) {\ndiff --git a/dir.c b/dir.c\nindex 3a15cb9..d3f462b 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -349,7 +349,7 @@ void parse_exclude_pattern(const char **pattern,\n }\n \n void add_exclude(const char *string, const char *base,\n-\t\t int baselen, struct exclude_list *el)\n+\t\t int baselen, struct exclude_list *el, int srcpos)\n {\n \tstruct exclude *x;\n \tint patternlen;\n@@ -373,8 +373,10 @@ void add_exclude(const char *string, const char *base,\n \tx->base = base;\n \tx->baselen = baselen;\n \tx->flags = flags;\n+\tx->srcpos = srcpos;\n \tALLOC_GROW(el->excludes, el->nr + 1, el->alloc);\n \tel->excludes[el->nr++] = x;\n+\tx->el = el;\n }\n \n static void *read_skip_worktree_file_from_index(const char *path, size_t *size)\n@@ -425,7 +427,7 @@ int add_excludes_from_file_to_list(const char *fname,\n \t\t\t\t   int check_index)\n {\n \tstruct stat st;\n-\tint fd, i;\n+\tint fd, i, lineno = 1;\n \tsize_t size = 0;\n \tchar *buf, *entry;\n \n@@ -467,15 +469,17 @@ int add_excludes_from_file_to_list(const char *fname,\n \t\tif (buf[i] == '\\n') {\n \t\t\tif (entry != buf + i && entry[0] != '#') {\n \t\t\t\tbuf[i - (i && buf[i-1] == '\\r')] = 0;\n-\t\t\t\tadd_exclude(entry, base, baselen, el);\n+\t\t\t\tadd_exclude(entry, base, baselen, el, lineno);\n \t\t\t}\n+\t\t\tlineno++;\n \t\t\tentry = buf + i + 1;\n \t\t}\n \t}\n \treturn 0;\n }\n \n-struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type)\n+struct exclude_list *add_exclude_list(struct dir_struct *dir,\n+\t\t\t\t      int group_type, const char *src)\n {\n \tstruct exclude_list *el;\n \tstruct exclude_list_group *group;\n@@ -484,6 +488,7 @@ struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type)\n \tALLOC_GROW(group->el, group->nr + 1, group->alloc);\n \tel = &group->el[group->nr++];\n \tmemset(el, 0, sizeof(*el));\n+\tel->src = src;\n \treturn el;\n }\n \n@@ -493,7 +498,7 @@ struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type)\n void add_excludes_from_file(struct dir_struct *dir, const char *fname)\n {\n \tstruct exclude_list *el;\n-\tel = add_exclude_list(dir, EXC_FILE);\n+\tel = add_exclude_list(dir, EXC_FILE, fname);\n \tif (add_excludes_from_file_to_list(fname, \"\", 0, el, 0) < 0)\n \t\tdie(\"cannot use %s as an exclude file\", fname);\n }\n@@ -524,6 +529,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n \t\t\tbreak;\n \t\tel = &group->el[dir->exclude_stack->exclude_ix];\n \t\tdir->exclude_stack = stk->prev;\n+\t\tfree((char *)el->src); /* see strdup() below */\n \t\tclear_exclude_list(el);\n \t\tfree(stk);\n \t\tgroup->nr--;\n@@ -550,7 +556,15 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)\n \t\tmemcpy(dir->basebuf + current, base + current,\n \t\t       stk->baselen - current);\n \t\tstrcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);\n-\t\tel = add_exclude_list(dir, EXC_DIRS);\n+\t\t/*\n+\t\t * dir->basebuf gets reused by the traversal, but we\n+\t\t * need fname to remain unchanged to ensure the src\n+\t\t * member of each struct exclude correctly\n+\t\t * back-references its source file.  Other invocations\n+\t\t * of add_exclude_list provide stable strings, so we\n+\t\t * strdup() and free() here in the caller.\n+\t\t */\n+\t\tel = add_exclude_list(dir, EXC_DIRS, strdup(dir->basebuf));\n \t\tstk->exclude_ix = group->nr - 1;\n \t\tadd_excludes_from_file_to_list(dir->basebuf,\n \t\t\t\t\t       dir->basebuf, stk->baselen,\ndiff --git a/dir.h b/dir.h\nindex c4d88db..64c410e 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -25,16 +25,32 @@ struct dir_entry {\n struct exclude_list {\n \tint nr;\n \tint alloc;\n+\n \t/* remember pointer to exclude file contents so we can free() */\n \tchar *filebuf;\n \n+\t/* origin of list, e.g. path to filename, or descriptive string */\n+\tconst char *src;\n+\n \tstruct exclude {\n+\t\t/*\n+\t\t * This allows callers of last_exclude_matching() etc.\n+\t\t * to determine the origin of the matching pattern.\n+\t\t */\n+\t\tstruct exclude_list *el;\n+\n \t\tconst char *pattern;\n \t\tint patternlen;\n \t\tint nowildcardlen;\n \t\tconst char *base;\n \t\tint baselen;\n \t\tint flags;\n+\n+\t\t/*\n+\t\t * Counting starts from 1 for line numbers in ignore files,\n+\t\t * and from -1 decrementing for patterns from CLI args.\n+\t\t */\n+\t\tint srcpos;\n \t} **excludes;\n };\n \n@@ -144,13 +160,14 @@ extern struct exclude *last_exclude_matching_path(struct path_exclude_check *, c\n extern int is_path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype);\n \n \n-extern struct exclude_list *add_exclude_list(struct dir_struct *dir, int group_type);\n+extern struct exclude_list *add_exclude_list(struct dir_struct *dir,\n+\t\t\t\t\t     int group_type, const char *src);\n extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,\n \t\t\t\t\t  struct exclude_list *el, int check_index);\n extern void add_excludes_from_file(struct dir_struct *, const char *fname);\n extern void parse_exclude_pattern(const char **string, int *patternlen, int *flags, int *nowildcardlen);\n extern void add_exclude(const char *string, const char *base,\n-\t\t\tint baselen, struct exclude_list *el);\n+\t\t\tint baselen, struct exclude_list *el, int srcpos);\n extern void clear_exclude_list(struct exclude_list *el);\n extern int file_exists(const char *);\n \n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206149","messageId":"1357491493-11619-4-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 03/11] dir.c: provide clear_directory() for reclaiming dir_struct memory","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:05Z","receivedAt":"2013-01-06T16:58:05Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"By the end of a directory traversal, a dir_struct instance will\ntypically contains pointers to various data structures on the heap.\nclear_directory() provides a convenient way to reclaim that memory.\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\n Documentation/technical/api-directory-listing.txt |  2 ++\n dir.c                                             | 30 +++++++++++++++++++++++\n dir.h                                             |  1 +\n 3 files changed, 33 insertions(+)\n\ndiff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt\nindex fa9c8ae..fbceb62 100644\n--- a/Documentation/technical/api-directory-listing.txt\n+++ b/Documentation/technical/api-directory-listing.txt\n@@ -81,4 +81,6 @@ marked. If you to exclude files, make sure you have loaded index first.\n \n * Use `dir.entries[]`.\n \n+* Call `free_directory()` when none of the contained elements are no longer in use.\n+\n (JC)\ndiff --git a/dir.c b/dir.c\nindex d3f462b..46f362e 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1557,3 +1557,33 @@ void free_pathspec(struct pathspec *pathspec)\n \tfree(pathspec->items);\n \tpathspec->items = NULL;\n }\n+\n+/*\n+ * Frees memory within dir which was allocated for exclude lists and\n+ * the exclude_stack.  Does not free dir itself.\n+ */\n+void clear_directory(struct dir_struct *dir)\n+{\n+\tint i, j;\n+\tstruct exclude_list_group *group;\n+\tstruct exclude_list *el;\n+\tstruct exclude_stack *stk;\n+\n+\tfor (i = EXC_CMDL; i <= EXC_FILE; i++) {\n+\t\tgroup = &dir->exclude_list_group[i];\n+\t\tfor (j = 0; j < group->nr; j++) {\n+\t\t\tel = &group->el[j];\n+\t\t\tif (i == EXC_DIRS)\n+\t\t\t\tfree((char *)el->src);\n+\t\t\tclear_exclude_list(el);\n+\t\t}\n+\t\tfree(group->el);\n+\t}\n+\n+\tstk = dir->exclude_stack;\n+\twhile (stk) {\n+\t\tstruct exclude_stack *prev = stk->prev;\n+\t\tfree(stk);\n+\t\tstk = prev;\n+\t}\n+}\ndiff --git a/dir.h b/dir.h\nindex 64c410e..dd42a3a 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -169,6 +169,7 @@ extern void parse_exclude_pattern(const char **string, int *patternlen, int *fla\n extern void add_exclude(const char *string, const char *base,\n \t\t\tint baselen, struct exclude_list *el, int srcpos);\n extern void clear_exclude_list(struct exclude_list *el);\n+extern void clear_directory(struct dir_struct *dir);\n extern int file_exists(const char *);\n \n extern int is_inside_dir(const char *dir);\n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206147","messageId":"1357491493-11619-5-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 04/11] dir.c: improve docs for match_pathspec() and match_pathspec_depth()","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:06Z","receivedAt":"2013-01-06T16:58:06Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"Fix a grammatical issue in the description of these functions, and\nmake it more obvious how and why seen[] can be reused across multiple\ninvocations.\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\n dir.c | 38 ++++++++++++++++++++++++++------------\n dir.h |  6 ++++++\n 2 files changed, 32 insertions(+), 12 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 46f362e..547b83f 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -167,12 +167,19 @@ static int match_one(const char *match, const char *name, int namelen)\n }\n \n /*\n- * Given a name and a list of pathspecs, see if the name matches\n- * any of the pathspecs.  The caller is also interested in seeing\n- * all pathspec matches some names it calls this function with\n- * (otherwise the user could have mistyped the unmatched pathspec),\n- * and a mark is left in seen[] array for pathspec element that\n- * actually matched anything.\n+ * Given a name and a list of pathspecs, returns the nature of the\n+ * closest (i.e. most specific) match of the name to any of the\n+ * pathspecs.\n+ *\n+ * The caller typically calls this multiple times with the same\n+ * pathspec and seen[] array but with different name/namelen\n+ * (e.g. entries from the index) and is interested in seeing if and\n+ * how each pathspec matches all the names it calls this function\n+ * with.  A mark is left in the seen[] array for each pathspec element\n+ * indicating the closest type of match that element achieved, so if\n+ * seen[n] remains zero after multiple invocations, that means the nth\n+ * pathspec did not match any names, which could indicate that the\n+ * user mistyped the nth pathspec.\n  */\n int match_pathspec(const char **pathspec, const char *name, int namelen,\n \t\tint prefix, char *seen)\n@@ -239,12 +246,19 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,\n }\n \n /*\n- * Given a name and a list of pathspecs, see if the name matches\n- * any of the pathspecs.  The caller is also interested in seeing\n- * all pathspec matches some names it calls this function with\n- * (otherwise the user could have mistyped the unmatched pathspec),\n- * and a mark is left in seen[] array for pathspec element that\n- * actually matched anything.\n+ * Given a name and a list of pathspecs, returns the nature of the\n+ * closest (i.e. most specific) match of the name to any of the\n+ * pathspecs.\n+ *\n+ * The caller typically calls this multiple times with the same\n+ * pathspec and seen[] array but with different name/namelen\n+ * (e.g. entries from the index) and is interested in seeing if and\n+ * how each pathspec matches all the names it calls this function\n+ * with.  A mark is left in the seen[] array for each pathspec element\n+ * indicating the closest type of match that element achieved, so if\n+ * seen[n] remains zero after multiple invocations, that means the nth\n+ * pathspec did not match any names, which could indicate that the\n+ * user mistyped the nth pathspec.\n  */\n int match_pathspec_depth(const struct pathspec *ps,\n \t\t\t const char *name, int namelen,\ndiff --git a/dir.h b/dir.h\nindex dd42a3a..136e838 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -116,6 +116,12 @@ struct dir_struct {\n \tchar basebuf[PATH_MAX];\n };\n \n+/*\n+ * The ordering of these constants is significant, with\n+ * higher-numbered match types signifying \"closer\" (i.e. more\n+ * specific) matches which will override lower-numbered match types\n+ * when populating the seen[] array.\n+ */\n #define MATCHED_RECURSIVELY 1\n #define MATCHED_FNMATCH 2\n #define MATCHED_EXACTLY 3\n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206151","messageId":"1357491493-11619-6-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 05/11] add.c: remove unused argument from validate_pathspec()","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:07Z","receivedAt":"2013-01-06T16:58:07Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"The 'argc' argument passed to validate_pathspec() was never used.\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\n builtin/add.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex c689f37..1f62ba3 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -197,7 +197,7 @@ static void refresh(int verbose, const char **pathspec)\n         free(seen);\n }\n \n-static const char **validate_pathspec(int argc, const char **argv, const char *prefix)\n+static const char **validate_pathspec(const char **argv, const char *prefix)\n {\n \tconst char **pathspec = get_pathspec(prefix, argv);\n \n@@ -248,7 +248,7 @@ int interactive_add(int argc, const char **argv, const char *prefix, int patch)\n \tconst char **pathspec = NULL;\n \n \tif (argc) {\n-\t\tpathspec = validate_pathspec(argc, argv, prefix);\n+\t\tpathspec = validate_pathspec(argv, prefix);\n \t\tif (!pathspec)\n \t\t\treturn -1;\n \t}\n@@ -414,7 +414,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t\tfprintf(stderr, _(\"Maybe you wanted to say 'git add .'?\\n\"));\n \t\treturn 0;\n \t}\n-\tpathspec = validate_pathspec(argc, argv, prefix);\n+\tpathspec = validate_pathspec(argv, prefix);\n \n \tif (read_cache() < 0)\n \t\tdie(_(\"index file corrupt\"));\n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206153","messageId":"1357491493-11619-7-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 06/11] add.c: move pathspec matchers into new pathspec.c for reuse","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:08Z","receivedAt":"2013-01-06T16:58:08Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"Extract the following functions from builtin/add.c to pathspec.c, in\npreparation for reuse by a new git check-ignore command:\n\n  - fill_pathspec_matches()\n  - find_used_pathspec()\n\nThe functions being extracted are not changed in any way, except\nremoval of the 'static' qualifier.\n\nAlso add comments documenting these newly public functions,\nincluding clarifications that they operate on the index.\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\nThe v3 version of this patch extracted 5 functions from add.c to\npathspec.c, two of which did not need to be extracted.  Here we\nuse more fine-grained commits for extraction, and also wrap pathspec.h\nin a PATHSPEC_H gate to avoid duplication.\n\n Makefile      |  2 ++\n builtin/add.c | 34 +---------------------------------\n pathspec.c    | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n pathspec.h    |  7 +++++++\n 4 files changed, 67 insertions(+), 33 deletions(-)\n create mode 100644 pathspec.c\n create mode 100644 pathspec.h\n\ndiff --git a/Makefile b/Makefile\nindex 13293d3..48facad 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -645,6 +645,7 @@ LIB_H += pack-refs.h\n LIB_H += pack-revindex.h\n LIB_H += parse-options.h\n LIB_H += patch-ids.h\n+LIB_H += pathspec.h\n LIB_H += pkt-line.h\n LIB_H += progress.h\n LIB_H += prompt.h\n@@ -758,6 +759,7 @@ LIB_OBJS += parse-options-cb.o\n LIB_OBJS += patch-delta.o\n LIB_OBJS += patch-ids.o\n LIB_OBJS += path.o\n+LIB_OBJS += pathspec.o\n LIB_OBJS += pkt-line.o\n LIB_OBJS += preload-index.o\n LIB_OBJS += pretty.o\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 1f62ba3..e51ba44 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -6,6 +6,7 @@\n #include \"cache.h\"\n #include \"builtin.h\"\n #include \"dir.h\"\n+#include \"pathspec.h\"\n #include \"exec_cmd.h\"\n #include \"cache-tree.h\"\n #include \"run-command.h\"\n@@ -97,39 +98,6 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags)\n \treturn !!data.add_errors;\n }\n \n-static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)\n-{\n-\tint num_unmatched = 0, i;\n-\n-\t/*\n-\t * Since we are walking the index as if we were walking the directory,\n-\t * we have to mark the matched pathspec as seen; otherwise we will\n-\t * mistakenly think that the user gave a pathspec that did not match\n-\t * anything.\n-\t */\n-\tfor (i = 0; i < specs; i++)\n-\t\tif (!seen[i])\n-\t\t\tnum_unmatched++;\n-\tif (!num_unmatched)\n-\t\treturn;\n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n-\t\tmatch_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen);\n-\t}\n-}\n-\n-static char *find_used_pathspec(const char **pathspec)\n-{\n-\tchar *seen;\n-\tint i;\n-\n-\tfor (i = 0; pathspec[i];  i++)\n-\t\t; /* just counting */\n-\tseen = xcalloc(i, 1);\n-\tfill_pathspec_matches(pathspec, seen, i);\n-\treturn seen;\n-}\n-\n static char *prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)\n {\n \tchar *seen;\ndiff --git a/pathspec.c b/pathspec.c\nnew file mode 100644\nindex 0000000..1472af8\n--- /dev/null\n+++ b/pathspec.c\n@@ -0,0 +1,57 @@\n+#include \"cache.h\"\n+#include \"dir.h\"\n+#include \"pathspec.h\"\n+\n+/*\n+ * Finds which of the given pathspecs match items in the index.\n+ *\n+ * For each pathspec, sets the corresponding entry in the seen[] array\n+ * (which should be specs items long, i.e. the same size as pathspec)\n+ * to the nature of the \"closest\" (i.e. most specific) match found for\n+ * that pathspec in the index, if it was a closer type of match than\n+ * the existing entry.  As an optimization, matching is skipped\n+ * altogether if seen[] already only contains non-zero entries.\n+ *\n+ * If seen[] has not already been written to, it may make sense\n+ * to use find_used_pathspec() instead.\n+ */\n+void fill_pathspec_matches(const char **pathspec, char *seen, int specs)\n+{\n+\tint num_unmatched = 0, i;\n+\n+\t/*\n+\t * Since we are walking the index as if we were walking the directory,\n+\t * we have to mark the matched pathspec as seen; otherwise we will\n+\t * mistakenly think that the user gave a pathspec that did not match\n+\t * anything.\n+\t */\n+\tfor (i = 0; i < specs; i++)\n+\t\tif (!seen[i])\n+\t\t\tnum_unmatched++;\n+\tif (!num_unmatched)\n+\t\treturn;\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\t\tmatch_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen);\n+\t}\n+}\n+\n+/*\n+ * Finds which of the given pathspecs match items in the index.\n+ *\n+ * This is a one-shot wrapper around fill_pathspec_matches() which\n+ * allocates, populates, and returns a seen[] array indicating the\n+ * nature of the \"closest\" (i.e. most specific) matches which each of\n+ * the given pathspecs achieves against all items in the index.\n+ */\n+char *find_used_pathspec(const char **pathspec)\n+{\n+\tchar *seen;\n+\tint i;\n+\n+\tfor (i = 0; pathspec[i];  i++)\n+\t\t; /* just counting */\n+\tseen = xcalloc(i, 1);\n+\tfill_pathspec_matches(pathspec, seen, i);\n+\treturn seen;\n+}\ndiff --git a/pathspec.h b/pathspec.h\nnew file mode 100644\nindex 0000000..1cb1909\n--- /dev/null\n+++ b/pathspec.h\n@@ -0,0 +1,7 @@\n+#ifndef PATHSPEC_H\n+#define PATHSPEC_H\n+\n+extern char *find_used_pathspec(const char **pathspec);\n+extern void fill_pathspec_matches(const char **pathspec, char *seen, int specs);\n+\n+#endif /* PATHSPEC_H */\n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206154","messageId":"1357491493-11619-8-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 07/11] pathspec.c: rename newly public functions for clarity","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:09Z","receivedAt":"2013-01-06T16:58:09Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"Perform the following function renames to make it explicit that these\npathspec handling functions are for matching against the index, rather\nthan against a tree or the working directory.\n\n- fill_pathspec_matches() -> add_pathspec_matches_against_index()\n- find_used_pathspec() -> find_pathspecs_matching_against_index()\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\n builtin/add.c |  4 ++--\n pathspec.c    | 17 +++++++++--------\n pathspec.h    |  4 ++--\n 3 files changed, 13 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex e51ba44..8c3fdf9 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -117,7 +117,7 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec, int\n \t\t\t*dst++ = entry;\n \t}\n \tdir->nr = dst - dir->entries;\n-\tfill_pathspec_matches(pathspec, seen, specs);\n+\tadd_pathspec_matches_against_index(pathspec, seen, specs);\n \treturn seen;\n }\n \n@@ -415,7 +415,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \n \t\tpath_exclude_check_init(&check, &dir);\n \t\tif (!seen)\n-\t\t\tseen = find_used_pathspec(pathspec);\n+\t\t\tseen = find_pathspecs_matching_against_index(pathspec);\n \t\tfor (i = 0; pathspec[i]; i++) {\n \t\t\tif (!seen[i] && pathspec[i][0]\n \t\t\t    && !file_exists(pathspec[i])) {\ndiff --git a/pathspec.c b/pathspec.c\nindex 1472af8..b73b15c 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -13,9 +13,10 @@\n  * altogether if seen[] already only contains non-zero entries.\n  *\n  * If seen[] has not already been written to, it may make sense\n- * to use find_used_pathspec() instead.\n+ * to use find_pathspecs_matching_against_index() instead.\n  */\n-void fill_pathspec_matches(const char **pathspec, char *seen, int specs)\n+void add_pathspec_matches_against_index(const char **pathspec,\n+\t\t\t\t\tchar *seen, int specs)\n {\n \tint num_unmatched = 0, i;\n \n@@ -39,12 +40,12 @@ void fill_pathspec_matches(const char **pathspec, char *seen, int specs)\n /*\n  * Finds which of the given pathspecs match items in the index.\n  *\n- * This is a one-shot wrapper around fill_pathspec_matches() which\n- * allocates, populates, and returns a seen[] array indicating the\n- * nature of the \"closest\" (i.e. most specific) matches which each of\n- * the given pathspecs achieves against all items in the index.\n+ * This is a one-shot wrapper around add_pathspec_matches_against_index()\n+ * which allocates, populates, and returns a seen[] array indicating the\n+ * nature of the \"closest\" (i.e. most specific) matches which each of the\n+ * given pathspecs achieves against all items in the index.\n  */\n-char *find_used_pathspec(const char **pathspec)\n+char *find_pathspecs_matching_against_index(const char **pathspec)\n {\n \tchar *seen;\n \tint i;\n@@ -52,6 +53,6 @@ char *find_used_pathspec(const char **pathspec)\n \tfor (i = 0; pathspec[i];  i++)\n \t\t; /* just counting */\n \tseen = xcalloc(i, 1);\n-\tfill_pathspec_matches(pathspec, seen, i);\n+\tadd_pathspec_matches_against_index(pathspec, seen, i);\n \treturn seen;\n }\ndiff --git a/pathspec.h b/pathspec.h\nindex 1cb1909..3852bc0 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -1,7 +1,7 @@\n #ifndef PATHSPEC_H\n #define PATHSPEC_H\n \n-extern char *find_used_pathspec(const char **pathspec);\n-extern void fill_pathspec_matches(const char **pathspec, char *seen, int specs);\n+extern char *find_pathspecs_matching_against_index(const char **pathspec);\n+extern void add_pathspec_matches_against_index(const char **pathspec, char *seen, int specs);\n \n #endif /* PATHSPEC_H */\n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206156","messageId":"1357491493-11619-9-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 08/11] add.c: extract check_path_for_gitlink() from treat_gitlinks() for reuse","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:10Z","receivedAt":"2013-01-06T16:58:10Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"Extract the body of the for loop in treat_gitlinks() into a separate\ncheck_path_for_gitlink() function so that it can be reused elsewhere.\nThis paves the way for a new check-ignore sub-command.\n\nAlso document treat_gitlinks().\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\nUnlike v3, this series doesn't make treat_gitlinks() public.\n\n builtin/add.c | 24 ++++++------------------\n pathspec.c    | 31 +++++++++++++++++++++++++++++++\n pathspec.h    |  1 +\n 3 files changed, 38 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 8c3fdf9..f95ded2 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -121,6 +121,10 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec, int\n \treturn seen;\n }\n \n+/*\n+ * Checks the index to see whether any path in pathspec refers to\n+ * something inside a submodule.  If so, dies with an error message.\n+ */\n static void treat_gitlinks(const char **pathspec)\n {\n \tint i;\n@@ -128,24 +132,8 @@ static void treat_gitlinks(const char **pathspec)\n \tif (!pathspec || !*pathspec)\n \t\treturn;\n \n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n-\t\tif (S_ISGITLINK(ce->ce_mode)) {\n-\t\t\tint len = ce_namelen(ce), j;\n-\t\t\tfor (j = 0; pathspec[j]; j++) {\n-\t\t\t\tint len2 = strlen(pathspec[j]);\n-\t\t\t\tif (len2 <= len || pathspec[j][len] != '/' ||\n-\t\t\t\t    memcmp(ce->name, pathspec[j], len))\n-\t\t\t\t\tcontinue;\n-\t\t\t\tif (len2 == len + 1)\n-\t\t\t\t\t/* strip trailing slash */\n-\t\t\t\t\tpathspec[j] = xstrndup(ce->name, len);\n-\t\t\t\telse\n-\t\t\t\t\tdie (_(\"Path '%s' is in submodule '%.*s'\"),\n-\t\t\t\t\t\tpathspec[j], len, ce->name);\n-\t\t\t}\n-\t\t}\n-\t}\n+\tfor (i = 0; pathspec[i]; i++)\n+\t\tpathspec[i] = check_path_for_gitlink(pathspec[i]);\n }\n \n static void refresh(int verbose, const char **pathspec)\ndiff --git a/pathspec.c b/pathspec.c\nindex b73b15c..02d3344 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -56,3 +56,34 @@ char *find_pathspecs_matching_against_index(const char **pathspec)\n \tadd_pathspec_matches_against_index(pathspec, seen, i);\n \treturn seen;\n }\n+\n+/*\n+ * Check the index to see whether path refers to a submodule, or\n+ * something inside a submodule.  If the former, returns the path with\n+ * any trailing slash stripped.  If the latter, dies with an error\n+ * message.\n+ */\n+const char *check_path_for_gitlink(const char *path)\n+{\n+\tint i, path_len = strlen(path);\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\t\tif (S_ISGITLINK(ce->ce_mode)) {\n+\t\t\tint ce_len = ce_namelen(ce);\n+\t\t\tif (path_len <= ce_len || path[ce_len] != '/' ||\n+\t\t\t    memcmp(ce->name, path, ce_len))\n+\t\t\t\t/* path does not refer to this\n+\t\t\t\t * submodule or anything inside it */\n+\t\t\t\tcontinue;\n+\t\t\tif (path_len == ce_len + 1) {\n+\t\t\t\t/* path refers to submodule;\n+\t\t\t\t * strip trailing slash */\n+\t\t\t\treturn xstrndup(ce->name, ce_len);\n+\t\t\t} else {\n+\t\t\t\tdie (_(\"Path '%s' is in submodule '%.*s'\"),\n+\t\t\t\t     path, ce_len, ce->name);\n+\t\t\t}\n+\t\t}\n+\t}\n+\treturn path;\n+}\ndiff --git a/pathspec.h b/pathspec.h\nindex 3852bc0..bf8eb96 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -3,5 +3,6 @@\n \n extern char *find_pathspecs_matching_against_index(const char **pathspec);\n extern void add_pathspec_matches_against_index(const char **pathspec, char *seen, int specs);\n+extern const char *check_path_for_gitlink(const char *path);\n \n #endif /* PATHSPEC_H */\n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206155","messageId":"1357491493-11619-10-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 09/11] add.c: extract new die_if_path_beyond_symlink() for reuse","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:11Z","receivedAt":"2013-01-06T16:58:11Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"This will be reused by a new git check-ignore command.\n\nAlso document validate_pathspec().\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\nUnlike v3, this series doesn't make validate_pathspec() public.\n\n builtin/add.c | 10 ++++++----\n pathspec.c    | 12 ++++++++++++\n pathspec.h    |  1 +\n 3 files changed, 19 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex f95ded2..3716617 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -153,6 +153,11 @@ static void refresh(int verbose, const char **pathspec)\n         free(seen);\n }\n \n+/*\n+ * Normalizes argv relative to prefix, via get_pathspec(), and then\n+ * runs die_if_path_beyond_symlink() on each path in the normalized\n+ * list.\n+ */\n static const char **validate_pathspec(const char **argv, const char *prefix)\n {\n \tconst char **pathspec = get_pathspec(prefix, argv);\n@@ -160,10 +165,7 @@ static const char **validate_pathspec(const char **argv, const char *prefix)\n \tif (pathspec) {\n \t\tconst char **p;\n \t\tfor (p = pathspec; *p; p++) {\n-\t\t\tif (has_symlink_leading_path(*p, strlen(*p))) {\n-\t\t\t\tint len = prefix ? strlen(prefix) : 0;\n-\t\t\t\tdie(_(\"'%s' is beyond a symbolic link\"), *p + len);\n-\t\t\t}\n+\t\t\tdie_if_path_beyond_symlink(*p, prefix);\n \t\t}\n \t}\n \ndiff --git a/pathspec.c b/pathspec.c\nindex 02d3344..284f397 100644\n--- a/pathspec.c\n+++ b/pathspec.c\n@@ -87,3 +87,15 @@ const char *check_path_for_gitlink(const char *path)\n \t}\n \treturn path;\n }\n+\n+/*\n+ * Dies if the given path refers to a file inside a symlinked\n+ * directory in the index.\n+ */\n+void die_if_path_beyond_symlink(const char *path, const char *prefix)\n+{\n+\tif (has_symlink_leading_path(path, strlen(path))) {\n+\t\tint len = prefix ? strlen(prefix) : 0;\n+\t\tdie(_(\"'%s' is beyond a symbolic link\"), path + len);\n+\t}\n+}\ndiff --git a/pathspec.h b/pathspec.h\nindex bf8eb96..db0184a 100644\n--- a/pathspec.h\n+++ b/pathspec.h\n@@ -4,5 +4,6 @@\n extern char *find_pathspecs_matching_against_index(const char **pathspec);\n extern void add_pathspec_matches_against_index(const char **pathspec, char *seen, int specs);\n extern const char *check_path_for_gitlink(const char *path);\n+extern void die_if_path_beyond_symlink(const char *path, const char *prefix);\n \n #endif /* PATHSPEC_H */\n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206150","messageId":"1357491493-11619-11-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 10/11] setup.c: document get_pathspec()","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:12Z","receivedAt":"2013-01-06T16:58:12Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"Since we have just created a new pathspec-handling library, now is a\ngood time to add some comments explaining get_pathspec().\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\nThe deprecation warning is new since v3.\n\n setup.c | 19 +++++++++++++++++++\n 1 file changed, 19 insertions(+)\n\ndiff --git a/setup.c b/setup.c\nindex 7663a4c..9570147 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -249,6 +249,25 @@ static const char *prefix_pathspec(const char *prefix, int prefixlen, const char\n \t\treturn prefix_path(prefix, prefixlen, copyfrom);\n }\n \n+/*\n+ * N.B. get_pathspec() is deprecated in favor of the \"struct pathspec\"\n+ * based interface - see pathspec_magic above.\n+ *\n+ * Arguments:\n+ *  - prefix - a path relative to the root of the working tree\n+ *  - pathspec - a list of paths underneath the prefix path\n+ *\n+ * Iterates over pathspec, prepending each path with prefix,\n+ * and return the resulting list.\n+ *\n+ * If pathspec is empty, return a singleton list containing prefix.\n+ *\n+ * If pathspec and prefix are both empty, return an empty list.\n+ *\n+ * This is typically used by built-in commands such as add.c, in order\n+ * to normalize argv arguments provided to the built-in into a list of\n+ * paths to process, all relative to the root of the working tree.\n+ */\n const char **get_pathspec(const char *prefix, const char **pathspec)\n {\n \tconst char *entry = *pathspec;\n-- \n1.7.11.7.33.gb8feba5\n"},{"id":"206157","messageId":"1357491493-11619-12-git-send-email-git@adamspiers.org","threadId":"32519","inReplyTo":"1357491493-11619-1-git-send-email-git@adamspiers.org","subject":"[PATCH v4 11/11] add git-check-ignore sub-command","fromName":"Adam Spiers","fromEmail":"git@adamspiers.org","sentAt":"2013-01-06T16:58:13Z","receivedAt":"2013-01-06T16:58:13Z","isPatch":true,"sender":{"key":"git@adamspiers.org","avatar":"https://avatars.githubusercontent.com/u/100738?v=4"},"body":"This works in a similar manner to git-check-attr.\n\nThanks to Jeff King and Junio C Hamano for the idea:\nhttp://thread.gmane.org/gmane.comp.version-control.git/108671/focus=108815\n\nSigned-off-by: Adam Spiers <git@adamspiers.org>\n---\nSeveral minor improvements since v3:\n\n  - rename char *dir to slash\n  - fix some declaration-after-statement violations\n  - correctly handle and test the case where --stdin is used\n    but STDIN is empty\n  - test that files in the index are not listed as ignored\n  - test that the presence of a file in the working directory\n    doesn't impact the result of running check-ignore on that file\n  - stylistic tweaks\n  - drop the -q option to grep in the test suite\n  - fix potential brittleness with future tests which could call\n    test_expect_success_multi with parameters containing double-quotes\n\n .gitignore                                        |   1 +\n Documentation/git-check-ignore.txt                |  89 +++\n Documentation/gitignore.txt                       |   6 +-\n Documentation/technical/api-directory-listing.txt |   2 +-\n Makefile                                          |   1 +\n builtin.h                                         |   1 +\n builtin/check-ignore.c                            | 173 ++++++\n command-list.txt                                  |   1 +\n contrib/completion/git-completion.bash            |   1 +\n git.c                                             |   1 +\n t/t0008-ignores.sh                                | 632 ++++++++++++++++++++++\n 11 files changed, 905 insertions(+), 3 deletions(-)\n create mode 100644 Documentation/git-check-ignore.txt\n create mode 100644 builtin/check-ignore.c\n create mode 100755 t/t0008-ignores.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex f1acd3e..20ef4e8 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -19,6 +19,7 @@\n /git-bundle\n /git-cat-file\n /git-check-attr\n+/git-check-ignore\n /git-check-ref-format\n /git-checkout\n /git-checkout-index\ndiff --git a/Documentation/git-check-ignore.txt b/Documentation/git-check-ignore.txt\nnew file mode 100644\nindex 0000000..854e4d0\n--- /dev/null\n+++ b/Documentation/git-check-ignore.txt\n@@ -0,0 +1,89 @@\n+git-check-ignore(1)\n+===================\n+\n+NAME\n+----\n+git-check-ignore - Debug gitignore / exclude files\n+\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git check-ignore' [options] pathname...\n+'git check-ignore' [options] --stdin < <list-of-paths>\n+\n+DESCRIPTION\n+-----------\n+\n+For each pathname given via the command-line or from a file via\n+`--stdin`, show the pattern from .gitignore (or other input files to\n+the exclude mechanism) that decides if the pathname is excluded or\n+included.  Later patterns within a file take precedence over earlier\n+ones.\n+\n+OPTIONS\n+-------\n+-q, --quiet::\n+\tDon't output anything, just set exit status.  This is only\n+\tvalid with a single pathname.\n+\n+-v, --verbose::\n+\tAlso output details about the matching pattern (if any)\n+\tfor each given pathname.\n+\n+--stdin::\n+\tRead file names from stdin instead of from the command-line.\n+\n+-z::\n+\tThe output format is modified to be machine-parseable (see\n+\tbelow).  If `--stdin` is also given, input paths are separated\n+\twith a NUL character instead of a linefeed character.\n+\n+OUTPUT\n+------\n+\n+By default, any of the given pathnames which match an ignore pattern\n+will be output, one per line.  If no pattern matches a given path,\n+nothing will be output for that path; this means that path will not be\n+ignored.\n+\n+If `--verbose` is specified, the output is a series of lines of the form:\n+\n+<source> <COLON> <linenum> <COLON> <pattern> <HT> <pathname>\n+\n+<pathname> is the path of a file being queried, <pattern> is the\n+matching pattern, <source> is the pattern's source file, and <linenum>\n+is the line number of the pattern within that source.  If the pattern\n+contained a `!` prefix or `/` suffix, it will be preserved in the\n+output.  <source> will be an absolute path when referring to the file\n+configured by `core.excludesfile`, or relative to the repository root\n+when referring to `.git/info/exclude` or a per-directory exclude file.\n+\n+If `-z` is specified, the pathnames in the output are delimited by the\n+null character; if `--verbose` is also specified then null characters\n+are also used instead of colons and hard tabs:\n+\n+<source> <NULL> <linenum> <NULL> <pattern> <NULL> <pathname> <NULL>\n+\n+\n+EXIT STATUS\n+-----------\n+\n+0::\n+\tOne or more of the provided paths is ignored.\n+\n+1::\n+\tNone of the provided paths are ignored.\n+\n+128::\n+\tA fatal error was encountered.\n+\n+SEE ALSO\n+--------\n+linkgit:gitignore[5]\n+linkgit:gitconfig[5]\n+linkgit:git-ls-files[5]\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt\nindex 2e7328b..f401b8c 100644\n--- a/Documentation/gitignore.txt\n+++ b/Documentation/gitignore.txt\n@@ -153,8 +153,10 @@ The second .gitignore prevents git from ignoring\n \n SEE ALSO\n --------\n-linkgit:git-rm[1], linkgit:git-update-index[1],\n-linkgit:gitrepository-layout[5]\n+linkgit:git-rm[1],\n+linkgit:git-update-index[1],\n+linkgit:gitrepository-layout[5],\n+linkgit:git-check-ignore[1]\n \n GIT\n ---\ndiff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt\nindex fbceb62..9d3e352 100644\n--- a/Documentation/technical/api-directory-listing.txt\n+++ b/Documentation/technical/api-directory-listing.txt\n@@ -81,6 +81,6 @@ marked. If you to exclude files, make sure you have loaded index first.\n \n * Use `dir.entries[]`.\n \n-* Call `free_directory()` when none of the contained elements are no longer in use.\n+* Call `clear_directory()` when none of the contained elements are no longer in use.\n \n (JC)\ndiff --git a/Makefile b/Makefile\nindex 48facad..8476fc8 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -822,6 +822,7 @@ BUILTIN_OBJS += builtin/branch.o\n BUILTIN_OBJS += builtin/bundle.o\n BUILTIN_OBJS += builtin/cat-file.o\n BUILTIN_OBJS += builtin/check-attr.o\n+BUILTIN_OBJS += builtin/check-ignore.o\n BUILTIN_OBJS += builtin/check-ref-format.o\n BUILTIN_OBJS += builtin/checkout-index.o\n BUILTIN_OBJS += builtin/checkout.o\ndiff --git a/builtin.h b/builtin.h\nindex dffb34e..d57faf4 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -58,6 +58,7 @@ extern int cmd_cat_file(int argc, const char **argv, const char *prefix);\n extern int cmd_checkout(int argc, const char **argv, const char *prefix);\n extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);\n extern int cmd_check_attr(int argc, const char **argv, const char *prefix);\n+extern int cmd_check_ignore(int argc, const char **argv, const char *prefix);\n extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);\n extern int cmd_cherry(int argc, const char **argv, const char *prefix);\n extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nnew file mode 100644\nindex 0000000..709535c\n--- /dev/null\n+++ b/builtin/check-ignore.c\n@@ -0,0 +1,173 @@\n+#include \"builtin.h\"\n+#include \"cache.h\"\n+#include \"dir.h\"\n+#include \"quote.h\"\n+#include \"pathspec.h\"\n+#include \"parse-options.h\"\n+\n+static int quiet, verbose, stdin_paths;\n+static const char * const check_ignore_usage[] = {\n+\"git check-ignore [options] pathname...\",\n+\"git check-ignore [options] --stdin < <list-of-paths>\",\n+NULL\n+};\n+\n+static int null_term_line;\n+\n+static const struct option check_ignore_options[] = {\n+\tOPT__QUIET(&quiet, N_(\"suppress progress reporting\")),\n+\tOPT__VERBOSE(&verbose, N_(\"be verbose\")),\n+\tOPT_GROUP(\"\"),\n+\tOPT_BOOLEAN(0, \"stdin\", &stdin_paths,\n+\t\t    N_(\"read file names from stdin\")),\n+\tOPT_BOOLEAN('z', NULL, &null_term_line,\n+\t\t    N_(\"input paths are terminated by a null character\")),\n+\tOPT_END()\n+};\n+\n+static void output_exclude(const char *path, struct exclude *exclude)\n+{\n+\tchar *bang  = exclude->flags & EXC_FLAG_NEGATIVE  ? \"!\" : \"\";\n+\tchar *slash = exclude->flags & EXC_FLAG_MUSTBEDIR ? \"/\" : \"\";\n+\tif (!null_term_line) {\n+\t\tif (!verbose) {\n+\t\t\twrite_name_quoted(path, stdout, '\\n');\n+\t\t} else {\n+\t\t\tquote_c_style(exclude->el->src, NULL, stdout, 0);\n+\t\t\tprintf(\":%d:%s%s%s\\t\",\n+\t\t\t       exclude->srcpos,\n+\t\t\t       bang, exclude->pattern, slash);\n+\t\t\tquote_c_style(path, NULL, stdout, 0);\n+\t\t\tfputc('\\n', stdout);\n+\t\t}\n+\t} else {\n+\t\tif (!verbose) {\n+\t\t\tprintf(\"%s%c\", path, '\\0');\n+\t\t} else {\n+\t\t\tprintf(\"%s%c%d%c%s%s%s%c%s%c\",\n+\t\t\t       exclude->el->src, '\\0',\n+\t\t\t       exclude->srcpos, '\\0',\n+\t\t\t       bang, exclude->pattern, slash, '\\0',\n+\t\t\t       path, '\\0');\n+\t\t}\n+\t}\n+}\n+\n+static int check_ignore(const char *prefix, const char **pathspec)\n+{\n+\tstruct dir_struct dir;\n+\tconst char *path, *full_path;\n+\tchar *seen;\n+\tint num_ignored = 0, dtype = DT_UNKNOWN, i;\n+\tstruct path_exclude_check check;\n+\tstruct exclude *exclude;\n+\n+\t/* read_cache() is only necessary so we can watch out for submodules. */\n+\tif (read_cache() < 0)\n+\t\tdie(_(\"index file corrupt\"));\n+\n+\tmemset(&dir, 0, sizeof(dir));\n+\tdir.flags |= DIR_COLLECT_IGNORED;\n+\tsetup_standard_excludes(&dir);\n+\n+\tif (!pathspec || !*pathspec) {\n+\t\tif (!quiet)\n+\t\t\tfprintf(stderr, \"no pathspec given.\\n\");\n+\t\treturn 0;\n+\t}\n+\n+\tpath_exclude_check_init(&check, &dir);\n+\t/*\n+\t * look for pathspecs matching entries in the index, since these\n+\t * should not be ignored, in order to be consistent with\n+\t * 'git status', 'git add' etc.\n+\t */\n+\tseen = find_pathspecs_matching_against_index(pathspec);\n+\tfor (i = 0; pathspec[i]; i++) {\n+\t\tpath = pathspec[i];\n+\t\tfull_path = prefix_path(prefix, prefix\n+\t\t\t\t\t? strlen(prefix) : 0, path);\n+\t\tfull_path = check_path_for_gitlink(full_path);\n+\t\tdie_if_path_beyond_symlink(full_path, prefix);\n+\t\tif (!seen[i] && path[0]) {\n+\t\t\texclude = last_exclude_matching_path(&check, full_path,\n+\t\t\t\t\t\t\t     -1, &dtype);\n+\t\t\tif (exclude) {\n+\t\t\t\tif (!quiet)\n+\t\t\t\t\toutput_exclude(path, exclude);\n+\t\t\t\tnum_ignored++;\n+\t\t\t}\n+\t\t}\n+\t}\n+\tfree(seen);\n+\tclear_directory(&dir);\n+\tpath_exclude_check_clear(&check);\n+\n+\treturn num_ignored;\n+}\n+\n+static int check_ignore_stdin_paths(const char *prefix)\n+{\n+\tstruct strbuf buf, nbuf;\n+\tchar **pathspec = NULL;\n+\tsize_t nr = 0, alloc = 0;\n+\tint line_termination = null_term_line ? 0 : '\\n';\n+\tint num_ignored;\n+\n+\tstrbuf_init(&buf, 0);\n+\tstrbuf_init(&nbuf, 0);\n+\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\t\tif (line_termination && buf.buf[0] == '\"') {\n+\t\t\tstrbuf_reset(&nbuf);\n+\t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n+\t\t\t\tdie(\"line is badly quoted\");\n+\t\t\tstrbuf_swap(&buf, &nbuf);\n+\t\t}\n+\t\tALLOC_GROW(pathspec, nr + 1, alloc);\n+\t\tpathspec[nr] = xcalloc(strlen(buf.buf) + 1, sizeof(*buf.buf));\n+\t\tstrcpy(pathspec[nr++], buf.buf);\n+\t}\n+\tALLOC_GROW(pathspec, nr + 1, alloc);\n+\tpathspec[nr] = NULL;\n+\tnum_ignored = check_ignore(prefix, (const char **)pathspec);\n+\tmaybe_flush_or_die(stdout, \"attribute to stdout\");\n+\tstrbuf_release(&buf);\n+\tstrbuf_release(&nbuf);\n+\tfree(pathspec);\n+\treturn num_ignored;\n+}\n+\n+int cmd_check_ignore(int argc, const char **argv, const char *prefix)\n+{\n+\tint num_ignored;\n+\n+\tgit_config(git_default_config, NULL);\n+\n+\targc = parse_options(argc, argv, prefix, check_ignore_options,\n+\t\t\t     check_ignore_usage, 0);\n+\n+\tif (stdin_paths) {\n+\t\tif (argc > 0)\n+\t\t\tdie(_(\"cannot specify pathnames with --stdin\"));\n+\t} else {\n+\t\tif (null_term_line)\n+\t\t\tdie(_(\"-z only makes sense with --stdin\"));\n+\t\tif (argc == 0)\n+\t\t\tdie(_(\"no path specified\"));\n+\t}\n+\tif (quiet) {\n+\t\tif (argc > 1)\n+\t\t\tdie(_(\"--quiet is only valid with a single pathname\"));\n+\t\tif (verbose)\n+\t\t\tdie(_(\"cannot have both --quiet and --verbose\"));\n+\t}\n+\n+\tif (stdin_paths) {\n+\t\tnum_ignored = check_ignore_stdin_paths(prefix);\n+\t} else {\n+\t\tnum_ignored = check_ignore(prefix, argv);\n+\t\tmaybe_flush_or_die(stdout, \"ignore to stdout\");\n+\t}\n+\n+\treturn !num_ignored;\n+}\ndiff --git a/command-list.txt b/command-list.txt\nindex 14ea67a..ef7f39c 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -12,6 +12,7 @@ git-branch                              mainporcelain common\n git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n git-check-attr                          purehelpers\n+git-check-ignore                        purehelpers\n git-checkout                            mainporcelain common\n git-checkout-index                      plumbingmanipulators\n git-check-ref-format                    purehelpers\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 2e1b5e1..1fb896b 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -842,6 +842,7 @@ __git_list_porcelain_commands ()\n \t\tarchimport)       : import;;\n \t\tcat-file)         : plumbing;;\n \t\tcheck-attr)       : plumbing;;\n+\t\tcheck-ignore)     : plumbing;;\n \t\tcheck-ref-format) : plumbing;;\n \t\tcheckout-index)   : plumbing;;\n \t\tcommit-tree)      : plumbing;;\ndiff --git a/git.c b/git.c\nindex d232de9..0b31e66 100644\n--- a/git.c\n+++ b/git.c\n@@ -340,6 +340,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"bundle\", cmd_bundle, RUN_SETUP_GENTLY },\n \t\t{ \"cat-file\", cmd_cat_file, RUN_SETUP },\n \t\t{ \"check-attr\", cmd_check_attr, RUN_SETUP },\n+\t\t{ \"check-ignore\", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"check-ref-format\", cmd_check_ref_format },\n \t\t{ \"checkout\", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"checkout-index\", cmd_checkout_index,\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nnew file mode 100755\nindex 0000000..9b0fcd6\n--- /dev/null\n+++ b/t/t0008-ignores.sh\n@@ -0,0 +1,632 @@\n+#!/bin/sh\n+\n+test_description=check-ignore\n+\n+. ./test-lib.sh\n+\n+init_vars () {\n+\tglobal_excludes=\"$(pwd)/global-excludes\"\n+}\n+\n+enable_global_excludes () {\n+\tinit_vars &&\n+\tgit config core.excludesfile \"$global_excludes\"\n+}\n+\n+expect_in () {\n+\tdest=\"$HOME/expected-$1\" text=\"$2\"\n+\tif test -z \"$text\"\n+\tthen\n+\t\t>\"$dest\" # avoid newline\n+\telse\n+\t\techo \"$text\" >\"$dest\"\n+\tfi\n+}\n+\n+expect () {\n+\texpect_in stdout \"$1\"\n+}\n+\n+expect_from_stdin () {\n+\tcat >\"$HOME/expected-stdout\"\n+}\n+\n+test_stderr () {\n+\texpected=\"$1\"\n+\texpect_in stderr \"$1\" &&\n+\ttest_cmp \"$HOME/expected-stderr\" \"$HOME/stderr\"\n+}\n+\n+stderr_contains () {\n+\tregexp=\"$1\"\n+\tif grep \"$regexp\" \"$HOME/stderr\"\n+\tthen\n+\t\treturn 0\n+\telse\n+\t\techo \"didn't find /$regexp/ in $HOME/stderr\"\n+\t\tcat \"$HOME/stderr\"\n+\t\treturn 1\n+\tfi\n+}\n+\n+stderr_empty_on_success () {\n+\texpect_code=\"$1\"\n+\tif test $expect_code = 0\n+\tthen\n+\t\ttest_stderr \"\"\n+\telse\n+\t\t# If we expect failure then stderr might or might not be empty\n+\t\t# due to --quiet - the caller can check its contents\n+\t\treturn 0\n+\tfi\n+}\n+\n+test_check_ignore () {\n+\targs=\"$1\" expect_code=\"${2:-0}\" global_args=\"$3\"\n+\n+\tinit_vars &&\n+\trm -f \"$HOME/stdout\" \"$HOME/stderr\" \"$HOME/cmd\" &&\n+\techo git $global_args check-ignore $quiet_opt $verbose_opt $args \\\n+\t\t>\"$HOME/cmd\" &&\n+\ttest_expect_code \"$expect_code\" \\\n+\t\tgit $global_args check-ignore $quiet_opt $verbose_opt $args \\\n+\t\t>\"$HOME/stdout\" 2>\"$HOME/stderr\" &&\n+\ttest_cmp \"$HOME/expected-stdout\" \"$HOME/stdout\" &&\n+\tstderr_empty_on_success \"$expect_code\"\n+}\n+\n+test_expect_success_multi () {\n+\tprereq=\n+\tif test $# -eq 4\n+\tthen\n+\t\tprereq=$1\n+\t\tshift\n+\tfi\n+\ttestname=\"$1\" expect_verbose=\"$2\" code=\"$3\"\n+\n+\texpect=$( echo \"$expect_verbose\" | sed -e 's/.*\t//' )\n+\n+\ttest_expect_success $prereq \"$testname\" '\n+\t\texpect \"$expect\" &&\n+\t\teval \"$code\"\n+\t'\n+\n+\tfor quiet_opt in '-q' '--quiet'\n+\tdo\n+\t\ttest_expect_success $prereq \"$testname${quiet_opt:+ with $quiet_opt}\" \"\n+\t\t\texpect '' &&\n+\t\t\t$code\n+\t\t\"\n+\tdone\n+\tquiet_opt=\n+\n+\tfor verbose_opt in '-v' '--verbose'\n+\tdo\n+\t\ttest_expect_success $prereq \"$testname${verbose_opt:+ with $verbose_opt}\" \"\n+\t\t\texpect '$expect_verbose' &&\n+\t\t\t$code\n+\t\t\"\n+\tdone\n+\tverbose_opt=\n+}\n+\n+test_expect_success 'setup' '\n+\tinit_vars &&\n+\tmkdir -p a/b/ignored-dir a/submodule b &&\n+\tif test_have_prereq SYMLINKS\n+\tthen\n+\t\tln -s b a/symlink\n+\tfi &&\n+\t(\n+\t\tcd a/submodule &&\n+\t\tgit init &&\n+\t\techo a >a &&\n+\t\tgit add a &&\n+\t\tgit commit -m\"commit in submodule\"\n+\t) &&\n+\tgit add a/submodule &&\n+\tcat <<-\\EOF >.gitignore &&\n+\t\tone\n+\t\tignored-*\n+\tEOF\n+\ttouch {,a/}{not-ignored,ignored-{and-untracked,but-in-index}} &&\n+\tgit add -f {,a/}ignored-but-in-index\n+\tcat <<-\\EOF >a/.gitignore &&\n+\t\ttwo*\n+\t\t*three\n+\tEOF\n+\tcat <<-\\EOF >a/b/.gitignore &&\n+\t\tfour\n+\t\tfive\n+\t\t# this comment should affect the line numbers\n+\t\tsix\n+\t\tignored-dir/\n+\t\t# and so should this blank line:\n+\n+\t\t!on*\n+\t\t!two\n+\tEOF\n+\techo \"seven\" >a/b/ignored-dir/.gitignore &&\n+\ttest -n \"$HOME\" &&\n+\tcat <<-\\EOF >\"$global_excludes\" &&\n+\t\tglobalone\n+\t\t!globaltwo\n+\t\tglobalthree\n+\tEOF\n+\tcat <<-\\EOF >>.git/info/exclude\n+\t\tper-repo\n+\tEOF\n+'\n+\n+############################################################################\n+#\n+# test invalid inputs\n+\n+test_expect_success_multi 'empty command line' '' '\n+\ttest_check_ignore \"\" 128 &&\n+\tstderr_contains \"fatal: no path specified\"\n+'\n+\n+test_expect_success_multi '--stdin with empty STDIN' '' '\n+\ttest_check_ignore \"--stdin\" 1 </dev/null &&\n+\tif test -n \"$quiet_opt\"; then\n+\t\ttest_stderr \"\"\n+\telse\n+\t\ttest_stderr \"no pathspec given.\"\n+\tfi\n+'\n+\n+test_expect_success '-q with multiple args' '\n+\texpect \"\" &&\n+\ttest_check_ignore \"-q one two\" 128 &&\n+\tstderr_contains \"fatal: --quiet is only valid with a single pathname\"\n+'\n+\n+test_expect_success '--quiet with multiple args' '\n+\texpect \"\" &&\n+\ttest_check_ignore \"--quiet one two\" 128 &&\n+\tstderr_contains \"fatal: --quiet is only valid with a single pathname\"\n+'\n+\n+for verbose_opt in '-v' '--verbose'\n+do\n+\tfor quiet_opt in '-q' '--quiet'\n+\tdo\n+\t\ttest_expect_success \"$quiet_opt $verbose_opt\" \"\n+\t\t\texpect '' &&\n+\t\t\ttest_check_ignore '$quiet_opt $verbose_opt foo' 128 &&\n+\t\t\tstderr_contains 'fatal: cannot have both --quiet and --verbose'\n+\t\t\"\n+\tdone\n+done\n+\n+test_expect_success '--quiet with multiple args' '\n+\texpect \"\" &&\n+\ttest_check_ignore \"--quiet one two\" 128 &&\n+\tstderr_contains \"fatal: --quiet is only valid with a single pathname\"\n+'\n+\n+test_expect_success_multi 'erroneous use of --' '' '\n+\ttest_check_ignore \"--\" 128 &&\n+\tstderr_contains \"fatal: no path specified\"\n+'\n+\n+test_expect_success_multi '--stdin with superfluous arg' '' '\n+\ttest_check_ignore \"--stdin foo\" 128 &&\n+\tstderr_contains \"fatal: cannot specify pathnames with --stdin\"\n+'\n+\n+test_expect_success_multi '--stdin -z with superfluous arg' '' '\n+\ttest_check_ignore \"--stdin -z foo\" 128 &&\n+\tstderr_contains \"fatal: cannot specify pathnames with --stdin\"\n+'\n+\n+test_expect_success_multi '-z without --stdin' '' '\n+\ttest_check_ignore \"-z\" 128 &&\n+\tstderr_contains \"fatal: -z only makes sense with --stdin\"\n+'\n+\n+test_expect_success_multi '-z without --stdin and superfluous arg' '' '\n+\ttest_check_ignore \"-z foo\" 128 &&\n+\tstderr_contains \"fatal: -z only makes sense with --stdin\"\n+'\n+\n+test_expect_success_multi 'needs work tree' '' '\n+\t(\n+\t\tcd .git &&\n+\t\ttest_check_ignore \"foo\" 128\n+\t) &&\n+\tstderr_contains \"fatal: This operation must be run in a work tree\"\n+'\n+\n+############################################################################\n+#\n+# test standard ignores\n+\n+# First make sure that the presence of a file in the working tree\n+# does not impact results, but that the presence of a file in the\n+# index does.\n+\n+for subdir in '' 'a/'\n+do\n+\tif test -z \"$subdir\"\n+\tthen\n+\t\twhere=\"at top-level\"\n+\telse\n+\t\twhere=\"in subdir $subdir\"\n+\tfi\n+\n+\ttest_expect_success_multi \"non-existent file $where not ignored\" '' \"\n+\t\ttest_check_ignore '${subdir}non-existent' 1\n+\t\"\n+\n+\ttest_expect_success_multi \"non-existent file $where ignored\" \\\n+\t\t\".gitignore:1:one\t${subdir}one\" \"\n+\t\ttest_check_ignore '${subdir}one'\n+\t\"\n+\n+\ttest_expect_success_multi \"existing untracked file $where not ignored\" '' \"\n+\t\ttest_check_ignore '${subdir}not-ignored' 1\n+\t\"\n+\n+\ttest_expect_success_multi \"existing tracked file $where not ignored\" '' \"\n+\t\ttest_check_ignore '${subdir}ignored-but-in-index' 1\n+\t\"\n+\n+\ttest_expect_success_multi \"existing untracked file $where ignored\" \\\n+\t\t\".gitignore:2:ignored-*\t${subdir}ignored-and-untracked\" \"\n+\t\ttest_check_ignore '${subdir}ignored-and-untracked'\n+\t\"\n+done\n+\n+# Having established the above, from now on we mostly test against\n+# files which do not exist in the working tree or index.\n+\n+test_expect_success 'sub-directory local ignore' '\n+\texpect \"a/3-three\" &&\n+\ttest_check_ignore \"a/3-three a/three-not-this-one\"\n+'\n+\n+test_expect_success 'sub-directory local ignore with --verbose'  '\n+\texpect \"a/.gitignore:2:*three\ta/3-three\" &&\n+\ttest_check_ignore \"--verbose a/3-three a/three-not-this-one\"\n+'\n+\n+test_expect_success 'local ignore inside a sub-directory' '\n+\texpect \"3-three\" &&\n+\t(\n+\t\tcd a &&\n+\t\ttest_check_ignore \"3-three three-not-this-one\"\n+\t)\n+'\n+test_expect_success 'local ignore inside a sub-directory with --verbose' '\n+\texpect \"a/.gitignore:2:*three\t3-three\" &&\n+\t(\n+\t\tcd a &&\n+\t\ttest_check_ignore \"--verbose 3-three three-not-this-one\"\n+\t)\n+'\n+\n+test_expect_success_multi 'nested include' \\\n+\t'a/b/.gitignore:8:!on*\ta/b/one' '\n+\ttest_check_ignore \"a/b/one\"\n+'\n+\n+############################################################################\n+#\n+# test ignored sub-directories\n+\n+test_expect_success_multi 'ignored sub-directory' \\\n+\t'a/b/.gitignore:5:ignored-dir/\ta/b/ignored-dir' '\n+\ttest_check_ignore \"a/b/ignored-dir\"\n+'\n+\n+test_expect_success 'multiple files inside ignored sub-directory' '\n+\texpect_from_stdin <<-\\EOF &&\n+\t\ta/b/ignored-dir/foo\n+\t\ta/b/ignored-dir/twoooo\n+\t\ta/b/ignored-dir/seven\n+\tEOF\n+\ttest_check_ignore \"a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven\"\n+'\n+\n+test_expect_success 'multiple files inside ignored sub-directory with -v' '\n+\texpect_from_stdin <<-\\EOF &&\n+\t\ta/b/.gitignore:5:ignored-dir/\ta/b/ignored-dir/foo\n+\t\ta/b/.gitignore:5:ignored-dir/\ta/b/ignored-dir/twoooo\n+\t\ta/b/.gitignore:5:ignored-dir/\ta/b/ignored-dir/seven\n+\tEOF\n+\ttest_check_ignore \"-v a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven\"\n+'\n+\n+test_expect_success 'cd to ignored sub-directory' '\n+\texpect_from_stdin <<-\\EOF &&\n+\t\tfoo\n+\t\ttwoooo\n+\t\t../one\n+\t\tseven\n+\t\t../../one\n+\tEOF\n+\t(\n+\t\tcd a/b/ignored-dir &&\n+\t\ttest_check_ignore \"foo twoooo ../one seven ../../one\"\n+\t)\n+'\n+\n+test_expect_success 'cd to ignored sub-directory with -v' '\n+\texpect_from_stdin <<-\\EOF &&\n+\t\ta/b/.gitignore:5:ignored-dir/\tfoo\n+\t\ta/b/.gitignore:5:ignored-dir/\ttwoooo\n+\t\ta/b/.gitignore:8:!on*\t../one\n+\t\ta/b/.gitignore:5:ignored-dir/\tseven\n+\t\t.gitignore:1:one\t../../one\n+\tEOF\n+\t(\n+\t\tcd a/b/ignored-dir &&\n+\t\ttest_check_ignore \"-v foo twoooo ../one seven ../../one\"\n+\t)\n+'\n+\n+############################################################################\n+#\n+# test handling of symlinks\n+\n+test_expect_success_multi SYMLINKS 'symlink' '' '\n+\ttest_check_ignore \"a/symlink\" 1\n+'\n+\n+test_expect_success_multi SYMLINKS 'beyond a symlink' '' '\n+\ttest_check_ignore \"a/symlink/foo\" 128 &&\n+\ttest_stderr \"fatal: '\\''a/symlink/foo'\\'' is beyond a symbolic link\"\n+'\n+\n+test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '\n+\t(\n+\t\tcd a &&\n+\t\ttest_check_ignore \"symlink/foo\" 128\n+\t) &&\n+\ttest_stderr \"fatal: '\\''symlink/foo'\\'' is beyond a symbolic link\"\n+'\n+\n+############################################################################\n+#\n+# test handling of submodules\n+\n+test_expect_success_multi 'submodule' '' '\n+\ttest_check_ignore \"a/submodule/one\" 128 &&\n+\ttest_stderr \"fatal: Path '\\''a/submodule/one'\\'' is in submodule '\\''a/submodule'\\''\"\n+'\n+\n+test_expect_success_multi 'submodule from subdirectory' '' '\n+\t(\n+\t\tcd a &&\n+\t\ttest_check_ignore \"submodule/one\" 128\n+\t) &&\n+\ttest_stderr \"fatal: Path '\\''a/submodule/one'\\'' is in submodule '\\''a/submodule'\\''\"\n+'\n+\n+############################################################################\n+#\n+# test handling of global ignore files\n+\n+test_expect_success 'global ignore not yet enabled' '\n+\texpect_from_stdin <<-\\EOF &&\n+\t\t.git/info/exclude:7:per-repo\tper-repo\n+\t\ta/.gitignore:2:*three\ta/globalthree\n+\t\t.git/info/exclude:7:per-repo\ta/per-repo\n+\tEOF\n+\ttest_check_ignore \"-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo\"\n+'\n+\n+test_expect_success 'global ignore' '\n+\tenable_global_excludes &&\n+\texpect_from_stdin <<-\\EOF &&\n+\t\tglobalone\n+\t\tper-repo\n+\t\tglobalthree\n+\t\ta/globalthree\n+\t\ta/per-repo\n+\t\tglobaltwo\n+\tEOF\n+\ttest_check_ignore \"globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo\"\n+'\n+\n+test_expect_success 'global ignore with -v' '\n+\tenable_global_excludes &&\n+\texpect_from_stdin <<-EOF &&\n+\t\t$global_excludes:1:globalone\tglobalone\n+\t\t.git/info/exclude:7:per-repo\tper-repo\n+\t\t$global_excludes:3:globalthree\tglobalthree\n+\t\ta/.gitignore:2:*three\ta/globalthree\n+\t\t.git/info/exclude:7:per-repo\ta/per-repo\n+\t\t$global_excludes:2:!globaltwo\tglobaltwo\n+\tEOF\n+\ttest_check_ignore \"-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo\"\n+'\n+\n+############################################################################\n+#\n+# test --stdin\n+\n+cat <<-\\EOF >stdin\n+\tone\n+\tnot-ignored\n+\ta/one\n+\ta/not-ignored\n+\ta/b/on\n+\ta/b/one\n+\ta/b/one one\n+\t\"a/b/one two\"\n+\t\"a/b/one\\\"three\"\n+\ta/b/not-ignored\n+\ta/b/two\n+\ta/b/twooo\n+\tglobaltwo\n+\ta/globaltwo\n+\ta/b/globaltwo\n+\tb/globaltwo\n+EOF\n+cat <<-\\EOF >expected-default\n+\tone\n+\ta/one\n+\ta/b/on\n+\ta/b/one\n+\ta/b/one one\n+\ta/b/one two\n+\t\"a/b/one\\\"three\"\n+\ta/b/two\n+\ta/b/twooo\n+\tglobaltwo\n+\ta/globaltwo\n+\ta/b/globaltwo\n+\tb/globaltwo\n+EOF\n+cat <<-EOF >expected-verbose\n+\t.gitignore:1:one\tone\n+\t.gitignore:1:one\ta/one\n+\ta/b/.gitignore:8:!on*\ta/b/on\n+\ta/b/.gitignore:8:!on*\ta/b/one\n+\ta/b/.gitignore:8:!on*\ta/b/one one\n+\ta/b/.gitignore:8:!on*\ta/b/one two\n+\ta/b/.gitignore:8:!on*\t\"a/b/one\\\"three\"\n+\ta/b/.gitignore:9:!two\ta/b/two\n+\ta/.gitignore:1:two*\ta/b/twooo\n+\t$global_excludes:2:!globaltwo\tglobaltwo\n+\t$global_excludes:2:!globaltwo\ta/globaltwo\n+\t$global_excludes:2:!globaltwo\ta/b/globaltwo\n+\t$global_excludes:2:!globaltwo\tb/globaltwo\n+EOF\n+\n+sed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' stdin | \\\n+\ttr \"\\n\" \"\\0\" >stdin0\n+sed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' expected-default | \\\n+\ttr \"\\n\" \"\\0\" >expected-default0\n+sed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' expected-verbose | \\\n+\ttr \":\\t\\n\" \"\\0\" >expected-verbose0\n+\n+test_expect_success '--stdin' '\n+\texpect_from_stdin <expected-default &&\n+\ttest_check_ignore \"--stdin\" <stdin\n+'\n+\n+test_expect_success '--stdin -q' '\n+\texpect \"\" &&\n+\ttest_check_ignore \"-q --stdin\" <stdin\n+'\n+\n+test_expect_success '--stdin -v' '\n+\texpect_from_stdin <expected-verbose &&\n+\ttest_check_ignore \"-v --stdin\" <stdin\n+'\n+\n+for opts in '--stdin -z' '-z --stdin'\n+do\n+\ttest_expect_success \"$opts\" \"\n+\t\texpect_from_stdin <expected-default0 &&\n+\t\ttest_check_ignore '$opts' <stdin0\n+\t\"\n+\n+\ttest_expect_success \"$opts -q\" \"\n+\t\texpect \"\" &&\n+\t\ttest_check_ignore '-q $opts' <stdin0\n+\t\"\n+\n+\ttest_expect_success \"$opts -v\" \"\n+\t\texpect_from_stdin <expected-verbose0 &&\n+\t\ttest_check_ignore '-v $opts' <stdin0\n+\t\"\n+done\n+\n+cat <<-\\EOF >stdin\n+\t../one\n+\t../not-ignored\n+\tone\n+\tnot-ignored\n+\tb/on\n+\tb/one\n+\tb/one one\n+\t\"b/one two\"\n+\t\"b/one\\\"three\"\n+\tb/two\n+\tb/not-ignored\n+\tb/twooo\n+\t../globaltwo\n+\tglobaltwo\n+\tb/globaltwo\n+\t../b/globaltwo\n+EOF\n+cat <<-\\EOF >expected-default\n+\t../one\n+\tone\n+\tb/on\n+\tb/one\n+\tb/one one\n+\tb/one two\n+\t\"b/one\\\"three\"\n+\tb/two\n+\tb/twooo\n+\t../globaltwo\n+\tglobaltwo\n+\tb/globaltwo\n+\t../b/globaltwo\n+EOF\n+cat <<-EOF >expected-verbose\n+\t.gitignore:1:one\t../one\n+\t.gitignore:1:one\tone\n+\ta/b/.gitignore:8:!on*\tb/on\n+\ta/b/.gitignore:8:!on*\tb/one\n+\ta/b/.gitignore:8:!on*\tb/one one\n+\ta/b/.gitignore:8:!on*\tb/one two\n+\ta/b/.gitignore:8:!on*\t\"b/one\\\"three\"\n+\ta/b/.gitignore:9:!two\tb/two\n+\ta/.gitignore:1:two*\tb/twooo\n+\t$global_excludes:2:!globaltwo\t../globaltwo\n+\t$global_excludes:2:!globaltwo\tglobaltwo\n+\t$global_excludes:2:!globaltwo\tb/globaltwo\n+\t$global_excludes:2:!globaltwo\t../b/globaltwo\n+EOF\n+\n+sed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' stdin | \\\n+\ttr \"\\n\" \"\\0\" >stdin0\n+sed -e 's/^\"//' -e 's/\\\\//' -e 's/\"$//' expected-default | \\\n+\ttr \"\\n\" \"\\0\" >expected-default0\n+sed -e 's/\t\"/\t/' -e 's/\\\\//' -e 's/\"$//' expected-verbose | \\\n+\ttr \":\\t\\n\" \"\\0\" >expected-verbose0\n+\n+test_expect_success '--stdin from subdirectory' '\n+\texpect_from_stdin <expected-default &&\n+\t(\n+\t\tcd a &&\n+\t\ttest_check_ignore \"--stdin\" <../stdin\n+\t)\n+'\n+\n+test_expect_success '--stdin from subdirectory with -v' '\n+\texpect_from_stdin <expected-verbose &&\n+\t(\n+\t\tcd a &&\n+\t\ttest_check_ignore \"--stdin -v\" <../stdin\n+\t)\n+'\n+\n+for opts in '--stdin -z' '-z --stdin'\n+do\n+\ttest_expect_success \"$opts from subdirectory\" '\n+\t\texpect_from_stdin <expected-default0 &&\n+\t\t(\n+\t\t\tcd a &&\n+\t\t\ttest_check_ignore \"'\"$opts\"'\" <../stdin0\n+\t\t)\n+\t'\n+\n+\ttest_expect_success \"$opts from subdirectory with -v\" '\n+\t\texpect_from_stdin <expected-verbose0 &&\n+\t\t(\n+\t\t\tcd a &&\n+\t\t\ttest_check_ignore \"'\"$opts\"' -v\" <../stdin0\n+\t\t)\n+\t'\n+done\n+\n+\n+test_done\n-- \n1.7.11.7.33.gb8feba5\n"}]}