Merge branch 'as/check-ignore'
authorJunio C Hamano <gitster@pobox.com>
Thu, 24 Jan 2013 05:19:10 +0000 (21:19 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 24 Jan 2013 05:19:10 +0000 (21:19 -0800)
Add a new command "git check-ignore" for debugging .gitignore
files.

The variable names may want to get cleaned up but that can be done
in-tree.

* as/check-ignore:
clean.c, ls-files.c: respect encapsulation of exclude_list_groups
t0008: avoid brace expansion
add git-check-ignore sub-command
setup.c: document get_pathspec()
add.c: extract new die_if_path_beyond_symlink() for reuse
add.c: extract check_path_for_gitlink() from treat_gitlinks() for reuse
pathspec.c: rename newly public functions for clarity
add.c: move pathspec matchers into new pathspec.c for reuse
add.c: remove unused argument from validate_pathspec()
dir.c: improve docs for match_pathspec() and match_pathspec_depth()
dir.c: provide clear_directory() for reclaiming dir_struct memory
dir.c: keep track of where patterns came from
dir.c: use a single struct exclude_list per source of excludes

Conflicts:
builtin/ls-files.c
dir.c

14 files changed:
1  2 
.gitignore
Documentation/gitignore.txt
Makefile
builtin.h
builtin/add.c
builtin/clean.c
builtin/ls-files.c
command-list.txt
contrib/completion/git-completion.bash
dir.c
dir.h
git.c
setup.c
unpack-trees.c
diff --combined .gitignore
index aa258a6bcfe105cdb872c6d77cd9bd19c84e8dc5,20ef4e8d383eed0c87e5b26329a1d5947b66cd72..6669bf0c6c9a0b42f74e2ed189350a6a9f11f17d
@@@ -1,10 -1,7 +1,10 @@@
  /GIT-BUILD-OPTIONS
  /GIT-CFLAGS
  /GIT-LDFLAGS
 -/GIT-GUI-VARS
 +/GIT-PREFIX
 +/GIT-PYTHON-VARS
 +/GIT-SCRIPT-DEFINES
 +/GIT-USER-AGENT
  /GIT-VERSION-FILE
  /bin-wrappers/
  /git
@@@ -22,6 -19,7 +22,7 @@@
  /git-bundle
  /git-cat-file
  /git-check-attr
+ /git-check-ignore
  /git-check-ref-format
  /git-checkout
  /git-checkout-index
@@@ -34,7 -32,6 +35,7 @@@
  /git-commit-tree
  /git-config
  /git-count-objects
 +/git-credential
  /git-credential-cache
  /git-credential-cache--daemon
  /git-credential-store
  /git-remote-ftps
  /git-remote-fd
  /git-remote-ext
 -/git-remote-testgit
 +/git-remote-testpy
 +/git-remote-testsvn
  /git-repack
  /git-replace
  /git-repo-config
  /git-whatchanged
  /git-write-tree
  /git-core-*/?*
 -/gitk-git/gitk-wish
  /gitweb/GITWEB-BUILD-OPTIONS
  /gitweb/gitweb.cgi
  /gitweb/static/gitweb.js
  /gitweb/static/gitweb.min.*
  /test-chmtime
 -/test-credential
  /test-ctype
  /test-date
  /test-delta
  /test-run-command
  /test-sha1
  /test-sigchain
 +/test-string-list
  /test-subprocess
  /test-svn-fe
 +/test-wildmatch
  /common-cmds.h
  *.tar.gz
  *.dsc
index 91a6438031949d83600abc791676bbf0397a0ddc,f401b8cc6a831e291d4e0026b27355bb12a74967..0da205fd97a8b3bf35ec4f920d555e24a75ad768
@@@ -41,24 -41,16 +41,24 @@@ precedence, the last matching pattern d
     variable 'core.excludesfile'.
  
  Which file to place a pattern in depends on how the pattern is meant to
 -be used. Patterns which should be version-controlled and distributed to
 -other repositories via clone (i.e., files that all developers will want
 -to ignore) should go into a `.gitignore` file. Patterns which are
 -specific to a particular repository but which do not need to be shared
 -with other related repositories (e.g., auxiliary files that live inside
 -the repository but are specific to one user's workflow) should go into
 -the `$GIT_DIR/info/exclude` file.  Patterns which a user wants git to
 -ignore in all situations (e.g., backup or temporary files generated by
 -the user's editor of choice) generally go into a file specified by
 -`core.excludesfile` in the user's `~/.gitconfig`.
 +be used.
 +
 + * Patterns which should be version-controlled and distributed to
 +   other repositories via clone (i.e., files that all developers will want
 +   to ignore) should go into a `.gitignore` file.
 +
 + * Patterns which are
 +   specific to a particular repository but which do not need to be shared
 +   with other related repositories (e.g., auxiliary files that live inside
 +   the repository but are specific to one user's workflow) should go into
 +   the `$GIT_DIR/info/exclude` file.
 +
 + * Patterns which a user wants git to
 +   ignore in all situations (e.g., backup or temporary files generated by
 +   the user's editor of choice) generally go into a file specified by
 +   `core.excludesfile` in the user's `~/.gitconfig`. Its default value is
 +   $XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or
 +   empty, $HOME/.config/git/ignore is used instead.
  
  The underlying git plumbing tools, such as
  'git ls-files' and 'git read-tree', read
@@@ -74,15 -66,11 +74,15 @@@ PATTERN FORMA
     for readability.
  
   - A line starting with # serves as a comment.
 +   Put a backslash ("`\`") in front of the first hash for patterns
 +   that begin with a hash.
  
 - - An optional prefix '!' which negates the pattern; any
 + - An optional prefix "`!`" which negates the pattern; any
     matching file excluded by a previous pattern will become
     included again.  If a negated pattern matches, this will
     override lower precedence patterns sources.
 +   Put a backslash ("`\`") in front of the first "`!`" for patterns
 +   that begin with a literal "`!`", for example, "`\!important!.txt`".
  
   - If the pattern ends with a slash, it is removed for the
     purpose of the following description, but it would only find
     For example, "/{asterisk}.c" matches "cat-file.c" but not
     "mozilla-sha1/sha1.c".
  
 +Two consecutive asterisks ("`**`") in patterns matched against
 +full pathname may have special meaning:
 +
 + - A leading "`**`" followed by a slash means match in all
 +   directories. For example, "`**/foo`" matches file or directory
 +   "`foo`" anywhere, the same as pattern "`foo`". "**/foo/bar"
 +   matches file or directory "`bar`" anywhere that is directly
 +   under directory "`foo`".
 +
 + - A trailing "/**" matches everything inside. For example,
 +   "abc/**" matches all files inside directory "abc", relative
 +   to the location of the `.gitignore` file, with infinite depth.
 +
 + - A slash followed by two consecutive asterisks then a slash
 +   matches zero or more directories. For example, "`a/**/b`"
 +   matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on.
 +
 + - Other consecutive asterisks are considered invalid.
 +
  NOTES
  -----
  
@@@ -184,8 -153,10 +184,10 @@@ The second .gitignore prevents git fro
  
  SEE ALSO
  --------
- linkgit:git-rm[1], linkgit:git-update-index[1],
- linkgit:gitrepository-layout[5]
+ linkgit:git-rm[1],
+ linkgit:git-update-index[1],
+ linkgit:gitrepository-layout[5],
+ linkgit:git-check-ignore[1]
  
  GIT
  ---
diff --combined Makefile
index fd635acb2e4f05672e899129ae483ee421a59e2d,8476fc87ef23dff4cc4c0b79b5e573d006be63b7..11e85a639652f8b47aaad8113fcc2776eae982e5
+++ b/Makefile
@@@ -74,14 -74,10 +74,14 @@@ all:
  # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
  # d_type in struct dirent (Cygwin 1.5, fixed in Cygwin 1.7).
  #
 +# Define HAVE_STRINGS_H if you have strings.h and need it for strcasecmp.
 +#
  # Define NO_STRCASESTR if you don't have strcasestr.
  #
  # Define NO_MEMMEM if you don't have memmem.
  #
 +# Define NO_GETPAGESIZE if you don't have getpagesize.
 +#
  # Define NO_STRLCPY if you don't have strlcpy.
  #
  # Define NO_STRTOUMAX if you don't have both strtoimax and strtoumax in the
@@@ -94,8 -90,6 +94,8 @@@
  #
  # Define NO_MKDTEMP if you don't have mkdtemp in the C library.
  #
 +# Define MKDIR_WO_TRAILING_SLASH if your mkdir() can't deal with trailing slash.
 +#
  # Define NO_MKSTEMPS if you don't have mkstemps in the C library.
  #
  # Define NO_STRTOK_R if you don't have strtok_r in the C library.
  #
  # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
  #
 +# Define NEEDS_LIBINTL_BEFORE_LIBICONV if you need libintl before libiconv.
 +#
 +# Define NO_INTPTR_T if you don't have intptr_t nor uintptr_t.
 +#
 +# Define NO_UINTMAX_T if you don't have uintmax_t.
 +#
  # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
  # Patrick Mauritz).
  #
  #
  # Define NO_MMAP if you want to avoid mmap.
  #
 +# Define NO_SYS_POLL_H if you don't have sys/poll.h.
 +#
 +# Define NO_POLL if you do not have or don't want to use poll().
 +# This also implies NO_SYS_POLL_H.
 +#
 +# Define NEEDS_SYS_PARAM_H if you need to include sys/param.h to compile,
 +# *PLEASE* REPORT to git@vger.kernel.org if your platform needs this;
 +# we want to know more about the issue.
 +#
  # Define NO_PTHREADS if you do not have or do not want to use Pthreads.
  #
  # Define NO_PREAD if you have a problem with pread() system call (e.g.
  # cygwin1.dll before v1.5.22).
  #
 +# Define NO_SETITIMER if you don't have setitimer()
 +#
 +# Define NO_STRUCT_ITIMERVAL if you don't have struct itimerval
 +# This also implies NO_SETITIMER
 +#
  # Define NO_THREAD_SAFE_PREAD if your pread() implementation is not
  # thread-safe. (e.g. compat/pread.c or cygwin)
  #
  # Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
  # field that counts the on-disk footprint in 512-byte blocks.
  #
 -# Define ASCIIDOC7 if you want to format documentation with AsciiDoc 7
 -#
  # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72
  # (not v1.73 or v1.71).
  #
  # apostrophes to be ASCII so that cut&pasting examples to the shell
  # will work.
  #
 +# Define PERL_PATH to the path of your Perl binary (usually /usr/bin/perl).
 +#
  # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
  # MakeMaker (e.g. using ActiveState under Cygwin).
  #
  # Define NO_PERL if you do not want Perl scripts or libraries at all.
  #
 +# Define PYTHON_PATH to the path of your Python binary (often /usr/bin/python
 +# but /usr/bin/python2.7 on some platforms).
 +#
  # Define NO_PYTHON if you do not want Python scripts or libraries at all.
  #
  # Define NO_TCLTK if you do not want Tcl/Tk GUI.
  #
  # Define NO_REGEX if you have no or inferior regex support in your C library.
  #
 +# Define CYGWIN_V15_WIN32API if you are using Cygwin v1.7.x but are not
 +# using the current w32api packages. The recommended approach, however,
 +# is to update your installation if compilation errors occur.
 +#
  # Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the
  # user.
  #
  # the diff algorithm.  It gives a nice speedup if your processor has
  # fast unaligned word loads.  Does NOT work on big-endian systems!
  # Enabled by default on x86_64.
 +#
 +# Define GIT_USER_AGENT if you want to change how git identifies itself during
 +# network interactions.  The default is "git/$(GIT_VERSION)".
 +#
 +# Define DEFAULT_HELP_FORMAT to "man", "info" or "html"
 +# (defaults to "man") if you want to have a different default when
 +# "git help" is called without a parameter specifying the format.
  
  GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
  -include GIT-VERSION-FILE
  
 -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
 -uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
 -uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
 -uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
 -uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
 -uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
 -
 -ifdef MSVC
 -      # avoid the MingW and Cygwin configuration sections
 -      uname_S := Windows
 -      uname_O := Windows
 -endif
 -
  # CFLAGS and LDFLAGS are for the users to override from the command line.
  
  CFLAGS = -g -O2 -Wall
@@@ -378,7 -351,7 +378,7 @@@ htmldir = share/doc/git-do
  ETC_GITCONFIG = $(sysconfdir)/gitconfig
  ETC_GITATTRIBUTES = $(sysconfdir)/gitattributes
  lib = lib
 -# DESTDIR=
 +# DESTDIR =
  pathsep = :
  
  export prefix bindir sharedir sysconfdir gitwebdir localedir
@@@ -418,9 -391,12 +418,9 @@@ BUILTIN_OBJS 
  BUILT_INS =
  COMPAT_CFLAGS =
  COMPAT_OBJS =
 -XDIFF_H =
  XDIFF_OBJS =
 -VCSSVN_H =
  VCSSVN_OBJS =
 -VCSSVN_TEST_OBJS =
 -MISC_H =
 +GENERATED_H =
  EXTRA_CPPFLAGS =
  LIB_H =
  LIB_OBJS =
@@@ -474,7 -450,7 +474,7 @@@ SCRIPT_PERL += git-relink.per
  SCRIPT_PERL += git-send-email.perl
  SCRIPT_PERL += git-svn.perl
  
 -SCRIPT_PYTHON += git-remote-testgit.py
 +SCRIPT_PYTHON += git-remote-testpy.py
  SCRIPT_PYTHON += git-p4.py
  
  SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
@@@ -499,7 -475,6 +499,7 @@@ PROGRAM_OBJS += sh-i18n--envsubst.
  PROGRAM_OBJS += shell.o
  PROGRAM_OBJS += show-index.o
  PROGRAM_OBJS += upload-pack.o
 +PROGRAM_OBJS += remote-testsvn.o
  
  # Binary suffix, set to .exe for Windows builds
  X =
  PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
  
  TEST_PROGRAMS_NEED_X += test-chmtime
 -TEST_PROGRAMS_NEED_X += test-credential
  TEST_PROGRAMS_NEED_X += test-ctype
  TEST_PROGRAMS_NEED_X += test-date
  TEST_PROGRAMS_NEED_X += test-delta
@@@ -525,10 -501,8 +525,10 @@@ TEST_PROGRAMS_NEED_X += test-run-comman
  TEST_PROGRAMS_NEED_X += test-scrap-cache-tree
  TEST_PROGRAMS_NEED_X += test-sha1
  TEST_PROGRAMS_NEED_X += test-sigchain
 +TEST_PROGRAMS_NEED_X += test-string-list
  TEST_PROGRAMS_NEED_X += test-subprocess
  TEST_PROGRAMS_NEED_X += test-svn-fe
 +TEST_PROGRAMS_NEED_X += test-wildmatch
  
  TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
  
@@@ -580,51 -554,58 +580,51 @@@ endi
  export PERL_PATH
  export PYTHON_PATH
  
 -LIB_FILE=libgit.a
 -XDIFF_LIB=xdiff/lib.a
 -VCSSVN_LIB=vcs-svn/lib.a
 -
 -XDIFF_H += xdiff/xinclude.h
 -XDIFF_H += xdiff/xmacros.h
 -XDIFF_H += xdiff/xdiff.h
 -XDIFF_H += xdiff/xtypes.h
 -XDIFF_H += xdiff/xutils.h
 -XDIFF_H += xdiff/xprepare.h
 -XDIFF_H += xdiff/xdiffi.h
 -XDIFF_H += xdiff/xemit.h
 -
 -VCSSVN_H += vcs-svn/line_buffer.h
 -VCSSVN_H += vcs-svn/sliding_window.h
 -VCSSVN_H += vcs-svn/repo_tree.h
 -VCSSVN_H += vcs-svn/fast_export.h
 -VCSSVN_H += vcs-svn/svndiff.h
 -VCSSVN_H += vcs-svn/svndump.h
 -
 -MISC_H += bisect.h
 -MISC_H += branch.h
 -MISC_H += bundle.h
 -MISC_H += common-cmds.h
 -MISC_H += fetch-pack.h
 -MISC_H += reachable.h
 -MISC_H += send-pack.h
 -MISC_H += shortlog.h
 -MISC_H += tar.h
 -MISC_H += thread-utils.h
 -MISC_H += url.h
 -MISC_H += walker.h
 -MISC_H += wt-status.h
 +LIB_FILE = libgit.a
 +XDIFF_LIB = xdiff/lib.a
 +VCSSVN_LIB = vcs-svn/lib.a
 +
 +LIB_H += xdiff/xinclude.h
 +LIB_H += xdiff/xmacros.h
 +LIB_H += xdiff/xdiff.h
 +LIB_H += xdiff/xtypes.h
 +LIB_H += xdiff/xutils.h
 +LIB_H += xdiff/xprepare.h
 +LIB_H += xdiff/xdiffi.h
 +LIB_H += xdiff/xemit.h
 +
 +LIB_H += vcs-svn/line_buffer.h
 +LIB_H += vcs-svn/sliding_window.h
 +LIB_H += vcs-svn/repo_tree.h
 +LIB_H += vcs-svn/fast_export.h
 +LIB_H += vcs-svn/svndiff.h
 +LIB_H += vcs-svn/svndump.h
 +
 +GENERATED_H += common-cmds.h
  
  LIB_H += advice.h
  LIB_H += archive.h
  LIB_H += argv-array.h
  LIB_H += attr.h
 +LIB_H += bisect.h
  LIB_H += blob.h
 +LIB_H += branch.h
  LIB_H += builtin.h
  LIB_H += bulk-checkin.h
 -LIB_H += cache.h
 +LIB_H += bundle.h
  LIB_H += cache-tree.h
 +LIB_H += cache.h
  LIB_H += color.h
 +LIB_H += column.h
  LIB_H += commit.h
  LIB_H += compat/bswap.h
  LIB_H += compat/cygwin.h
  LIB_H += compat/mingw.h
  LIB_H += compat/obstack.h
 +LIB_H += compat/poll/poll.h
 +LIB_H += compat/precompose_utf8.h
  LIB_H += compat/terminal.h
  LIB_H += compat/win32/dirent.h
 -LIB_H += compat/win32/poll.h
  LIB_H += compat/win32/pthread.h
  LIB_H += compat/win32/syslog.h
  LIB_H += connected.h
@@@ -637,7 -618,6 +637,7 @@@ LIB_H += diff.
  LIB_H += diffcore.h
  LIB_H += dir.h
  LIB_H += exec_cmd.h
 +LIB_H += fetch-pack.h
  LIB_H += fmt-merge-msg.h
  LIB_H += fsck.h
  LIB_H += gettext.h
@@@ -647,30 -627,29 +647,31 @@@ LIB_H += graph.
  LIB_H += grep.h
  LIB_H += hash.h
  LIB_H += help.h
 +LIB_H += http.h
  LIB_H += kwset.h
  LIB_H += levenshtein.h
  LIB_H += list-objects.h
  LIB_H += ll-merge.h
  LIB_H += log-tree.h
  LIB_H += mailmap.h
 -LIB_H += merge-file.h
 +LIB_H += merge-blobs.h
  LIB_H += merge-recursive.h
  LIB_H += mergesort.h
 -LIB_H += notes.h
  LIB_H += notes-cache.h
  LIB_H += notes-merge.h
 +LIB_H += notes.h
  LIB_H += object.h
 -LIB_H += pack.h
  LIB_H += pack-refs.h
  LIB_H += pack-revindex.h
 +LIB_H += pack.h
  LIB_H += parse-options.h
  LIB_H += patch-ids.h
+ LIB_H += pathspec.h
  LIB_H += pkt-line.h
  LIB_H += progress.h
  LIB_H += prompt.h
  LIB_H += quote.h
 +LIB_H += reachable.h
  LIB_H += reflog-walk.h
  LIB_H += refs.h
  LIB_H += remote.h
@@@ -678,11 -657,9 +679,11 @@@ LIB_H += rerere.
  LIB_H += resolve-undo.h
  LIB_H += revision.h
  LIB_H += run-command.h
 +LIB_H += send-pack.h
  LIB_H += sequencer.h
  LIB_H += sha1-array.h
  LIB_H += sha1-lookup.h
 +LIB_H += shortlog.h
  LIB_H += sideband.h
  LIB_H += sigchain.h
  LIB_H += strbuf.h
@@@ -690,19 -667,14 +691,19 @@@ LIB_H += streaming.
  LIB_H += string-list.h
  LIB_H += submodule.h
  LIB_H += tag.h
 +LIB_H += tar.h
  LIB_H += thread-utils.h
  LIB_H += transport.h
 -LIB_H += tree.h
  LIB_H += tree-walk.h
 +LIB_H += tree.h
  LIB_H += unpack-trees.h
 +LIB_H += url.h
  LIB_H += userdiff.h
  LIB_H += utf8.h
  LIB_H += varint.h
 +LIB_H += walker.h
 +LIB_H += wildmatch.h
 +LIB_H += wt-status.h
  LIB_H += xdiff-interface.h
  LIB_H += xdiff/xdiff.h
  
@@@ -752,7 -724,6 +753,7 @@@ LIB_OBJS += editor.
  LIB_OBJS += entry.o
  LIB_OBJS += environment.o
  LIB_OBJS += exec_cmd.o
 +LIB_OBJS += fetch-pack.o
  LIB_OBJS += fsck.o
  LIB_OBJS += gettext.o
  LIB_OBJS += gpg-interface.o
@@@ -770,8 -741,7 +771,8 @@@ LIB_OBJS += lockfile.
  LIB_OBJS += log-tree.o
  LIB_OBJS += mailmap.o
  LIB_OBJS += match-trees.o
 -LIB_OBJS += merge-file.o
 +LIB_OBJS += merge.o
 +LIB_OBJS += merge-blobs.o
  LIB_OBJS += merge-recursive.o
  LIB_OBJS += mergesort.o
  LIB_OBJS += name-hash.o
@@@ -789,6 -759,7 +790,7 @@@ LIB_OBJS += parse-options-cb.
  LIB_OBJS += patch-delta.o
  LIB_OBJS += patch-ids.o
  LIB_OBJS += path.o
+ LIB_OBJS += pathspec.o
  LIB_OBJS += pkt-line.o
  LIB_OBJS += preload-index.o
  LIB_OBJS += pretty.o
@@@ -805,7 -776,6 +807,7 @@@ LIB_OBJS += rerere.
  LIB_OBJS += resolve-undo.o
  LIB_OBJS += revision.o
  LIB_OBJS += run-command.o
 +LIB_OBJS += send-pack.o
  LIB_OBJS += sequencer.o
  LIB_OBJS += server-info.o
  LIB_OBJS += setup.o
@@@ -834,9 -804,7 +836,9 @@@ LIB_OBJS += usage.
  LIB_OBJS += userdiff.o
  LIB_OBJS += utf8.o
  LIB_OBJS += varint.o
 +LIB_OBJS += version.o
  LIB_OBJS += walker.o
 +LIB_OBJS += wildmatch.o
  LIB_OBJS += wrapper.o
  LIB_OBJS += write_or_die.o
  LIB_OBJS += ws.o
@@@ -854,6 -822,7 +856,7 @@@ BUILTIN_OBJS += builtin/branch.
  BUILTIN_OBJS += builtin/bundle.o
  BUILTIN_OBJS += builtin/cat-file.o
  BUILTIN_OBJS += builtin/check-attr.o
+ BUILTIN_OBJS += builtin/check-ignore.o
  BUILTIN_OBJS += builtin/check-ref-format.o
  BUILTIN_OBJS += builtin/checkout-index.o
  BUILTIN_OBJS += builtin/checkout.o
@@@ -864,7 -833,6 +867,7 @@@ BUILTIN_OBJS += builtin/commit-tree.
  BUILTIN_OBJS += builtin/commit.o
  BUILTIN_OBJS += builtin/config.o
  BUILTIN_OBJS += builtin/count-objects.o
 +BUILTIN_OBJS += builtin/credential.o
  BUILTIN_OBJS += builtin/describe.o
  BUILTIN_OBJS += builtin/diff-files.o
  BUILTIN_OBJS += builtin/diff-index.o
@@@ -942,9 -910,455 +945,9 @@@ BUILTIN_OBJS += builtin/write-tree.
  GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
  EXTLIBS =
  
 -#
 -# Platform specific tweaks
 -#
 -
 -# We choose to avoid "if .. else if .. else .. endif endif"
 -# because maintaining the nesting to match is a pain.  If
 -# we had "elif" things would have been much nicer...
 -
 -ifeq ($(uname_M),x86_64)
 -      XDL_FAST_HASH = YesPlease
 -endif
 -ifeq ($(uname_S),OSF1)
 -      # Need this for u_short definitions et al
 -      BASIC_CFLAGS += -D_OSF_SOURCE
 -      SOCKLEN_T = int
 -      NO_STRTOULL = YesPlease
 -      NO_NSEC = YesPlease
 -endif
 -ifeq ($(uname_S),Linux)
 -      NO_STRLCPY = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      HAVE_PATHS_H = YesPlease
 -      LIBC_CONTAINS_LIBINTL = YesPlease
 -      HAVE_DEV_TTY = YesPlease
 -endif
 -ifeq ($(uname_S),GNU/kFreeBSD)
 -      NO_STRLCPY = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      HAVE_PATHS_H = YesPlease
 -      DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
 -      LIBC_CONTAINS_LIBINTL = YesPlease
 -endif
 -ifeq ($(uname_S),UnixWare)
 -      CC = cc
 -      NEEDS_SOCKET = YesPlease
 -      NEEDS_NSL = YesPlease
 -      NEEDS_SSL_WITH_CRYPTO = YesPlease
 -      NEEDS_LIBICONV = YesPlease
 -      SHELL_PATH = /usr/local/bin/bash
 -      NO_IPV6 = YesPlease
 -      NO_HSTRERROR = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      BASIC_CFLAGS += -Kthread
 -      BASIC_CFLAGS += -I/usr/local/include
 -      BASIC_LDFLAGS += -L/usr/local/lib
 -      INSTALL = ginstall
 -      TAR = gtar
 -      NO_STRCASESTR = YesPlease
 -      NO_MEMMEM = YesPlease
 -endif
 -ifeq ($(uname_S),SCO_SV)
 -      ifeq ($(uname_R),3.2)
 -              CFLAGS = -O2
 -      endif
 -      ifeq ($(uname_R),5)
 -              CC = cc
 -              BASIC_CFLAGS += -Kthread
 -      endif
 -      NEEDS_SOCKET = YesPlease
 -      NEEDS_NSL = YesPlease
 -      NEEDS_SSL_WITH_CRYPTO = YesPlease
 -      NEEDS_LIBICONV = YesPlease
 -      SHELL_PATH = /usr/bin/bash
 -      NO_IPV6 = YesPlease
 -      NO_HSTRERROR = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      BASIC_CFLAGS += -I/usr/local/include
 -      BASIC_LDFLAGS += -L/usr/local/lib
 -      NO_STRCASESTR = YesPlease
 -      NO_MEMMEM = YesPlease
 -      INSTALL = ginstall
 -      TAR = gtar
 -endif
 -ifeq ($(uname_S),Darwin)
 -      NEEDS_CRYPTO_WITH_SSL = YesPlease
 -      NEEDS_SSL_WITH_CRYPTO = YesPlease
 -      NEEDS_LIBICONV = YesPlease
 -      ifeq ($(shell expr "$(uname_R)" : '[15678]\.'),2)
 -              OLD_ICONV = UnfortunatelyYes
 -      endif
 -      ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2)
 -              NO_STRLCPY = YesPlease
 -      endif
 -      NO_MEMMEM = YesPlease
 -      USE_ST_TIMESPEC = YesPlease
 -      HAVE_DEV_TTY = YesPlease
 -endif
 -ifeq ($(uname_S),SunOS)
 -      NEEDS_SOCKET = YesPlease
 -      NEEDS_NSL = YesPlease
 -      SHELL_PATH = /bin/bash
 -      SANE_TOOL_PATH = /usr/xpg6/bin:/usr/xpg4/bin
 -      NO_STRCASESTR = YesPlease
 -      NO_MEMMEM = YesPlease
 -      NO_MKDTEMP = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      NO_REGEX = YesPlease
 -      NO_FNMATCH_CASEFOLD = YesPlease
 -      NO_MSGFMT_EXTENDED_OPTIONS = YesPlease
 -      HAVE_DEV_TTY = YesPlease
 -      ifeq ($(uname_R),5.6)
 -              SOCKLEN_T = int
 -              NO_HSTRERROR = YesPlease
 -              NO_IPV6 = YesPlease
 -              NO_SOCKADDR_STORAGE = YesPlease
 -              NO_UNSETENV = YesPlease
 -              NO_SETENV = YesPlease
 -              NO_STRLCPY = YesPlease
 -              NO_STRTOUMAX = YesPlease
 -              GIT_TEST_CMP = cmp
 -      endif
 -      ifeq ($(uname_R),5.7)
 -              NEEDS_RESOLV = YesPlease
 -              NO_IPV6 = YesPlease
 -              NO_SOCKADDR_STORAGE = YesPlease
 -              NO_UNSETENV = YesPlease
 -              NO_SETENV = YesPlease
 -              NO_STRLCPY = YesPlease
 -              NO_STRTOUMAX = YesPlease
 -              GIT_TEST_CMP = cmp
 -      endif
 -      ifeq ($(uname_R),5.8)
 -              NO_UNSETENV = YesPlease
 -              NO_SETENV = YesPlease
 -              NO_STRTOUMAX = YesPlease
 -              GIT_TEST_CMP = cmp
 -      endif
 -      ifeq ($(uname_R),5.9)
 -              NO_UNSETENV = YesPlease
 -              NO_SETENV = YesPlease
 -              NO_STRTOUMAX = YesPlease
 -              GIT_TEST_CMP = cmp
 -      endif
 -      INSTALL = /usr/ucb/install
 -      TAR = gtar
 -      BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H
 -endif
 -ifeq ($(uname_O),Cygwin)
 -      ifeq ($(shell expr "$(uname_R)" : '1\.[1-6]\.'),4)
 -              NO_D_TYPE_IN_DIRENT = YesPlease
 -              NO_D_INO_IN_DIRENT = YesPlease
 -              NO_STRCASESTR = YesPlease
 -              NO_MEMMEM = YesPlease
 -              NO_MKSTEMPS = YesPlease
 -              NO_SYMLINK_HEAD = YesPlease
 -              NO_IPV6 = YesPlease
 -              OLD_ICONV = UnfortunatelyYes
 -      endif
 -      NO_THREAD_SAFE_PREAD = YesPlease
 -      NEEDS_LIBICONV = YesPlease
 -      NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
 -      NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
 -      NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
 -      # There are conflicting reports about this.
 -      # On some boxes NO_MMAP is needed, and not so elsewhere.
 -      # Try commenting this out if you suspect MMAP is more efficient
 -      NO_MMAP = YesPlease
 -      X = .exe
 -      COMPAT_OBJS += compat/cygwin.o
 -      UNRELIABLE_FSTAT = UnfortunatelyYes
 -      SPARSE_FLAGS = -isystem /usr/include/w32api -Wno-one-bit-signed-bitfield
 -endif
 -ifeq ($(uname_S),FreeBSD)
 -      NEEDS_LIBICONV = YesPlease
 -      OLD_ICONV = YesPlease
 -      NO_MEMMEM = YesPlease
 -      BASIC_CFLAGS += -I/usr/local/include
 -      BASIC_LDFLAGS += -L/usr/local/lib
 -      DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
 -      USE_ST_TIMESPEC = YesPlease
 -      ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
 -              PTHREAD_LIBS = -pthread
 -              NO_UINTMAX_T = YesPlease
 -              NO_STRTOUMAX = YesPlease
 -      endif
 -      PYTHON_PATH = /usr/local/bin/python
 -      HAVE_PATHS_H = YesPlease
 -endif
 -ifeq ($(uname_S),OpenBSD)
 -      NO_STRCASESTR = YesPlease
 -      NO_MEMMEM = YesPlease
 -      USE_ST_TIMESPEC = YesPlease
 -      NEEDS_LIBICONV = YesPlease
 -      BASIC_CFLAGS += -I/usr/local/include
 -      BASIC_LDFLAGS += -L/usr/local/lib
 -      HAVE_PATHS_H = YesPlease
 -endif
 -ifeq ($(uname_S),NetBSD)
 -      ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
 -              NEEDS_LIBICONV = YesPlease
 -      endif
 -      BASIC_CFLAGS += -I/usr/pkg/include
 -      BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
 -      USE_ST_TIMESPEC = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      HAVE_PATHS_H = YesPlease
 -endif
 -ifeq ($(uname_S),AIX)
 -      DEFAULT_PAGER = more
 -      NO_STRCASESTR=YesPlease
 -      NO_MEMMEM = YesPlease
 -      NO_MKDTEMP = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      NO_STRLCPY = YesPlease
 -      NO_NSEC = YesPlease
 -      FREAD_READS_DIRECTORIES = UnfortunatelyYes
 -      INTERNAL_QSORT = UnfortunatelyYes
 -      NEEDS_LIBICONV=YesPlease
 -      BASIC_CFLAGS += -D_LARGE_FILES
 -      ifeq ($(shell expr "$(uname_V)" : '[1234]'),1)
 -              NO_PTHREADS = YesPlease
 -      else
 -              PTHREAD_LIBS = -lpthread
 -      endif
 -      ifeq ($(shell expr "$(uname_V).$(uname_R)" : '5\.1'),3)
 -              INLINE=''
 -      endif
 -      GIT_TEST_CMP = cmp
 -endif
 -ifeq ($(uname_S),GNU)
 -      # GNU/Hurd
 -      NO_STRLCPY=YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      HAVE_PATHS_H = YesPlease
 -      LIBC_CONTAINS_LIBINTL = YesPlease
 -endif
 -ifeq ($(uname_S),IRIX)
 -      NO_SETENV = YesPlease
 -      NO_UNSETENV = YesPlease
 -      NO_STRCASESTR = YesPlease
 -      NO_MEMMEM = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      NO_MKDTEMP = YesPlease
 -      # When compiled with the MIPSpro 7.4.4m compiler, and without pthreads
 -      # (i.e. NO_PTHREADS is set), and _with_ MMAP (i.e. NO_MMAP is not set),
 -      # git dies with a segmentation fault when trying to access the first
 -      # entry of a reflog.  The conservative choice is made to always set
 -      # NO_MMAP.  If you suspect that your compiler is not affected by this
 -      # issue, comment out the NO_MMAP statement.
 -      NO_MMAP = YesPlease
 -      NO_REGEX = YesPlease
 -      NO_FNMATCH_CASEFOLD = YesPlease
 -      SNPRINTF_RETURNS_BOGUS = YesPlease
 -      SHELL_PATH = /usr/gnu/bin/bash
 -      NEEDS_LIBGEN = YesPlease
 -endif
 -ifeq ($(uname_S),IRIX64)
 -      NO_SETENV=YesPlease
 -      NO_UNSETENV = YesPlease
 -      NO_STRCASESTR=YesPlease
 -      NO_MEMMEM = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      NO_MKDTEMP = YesPlease
 -      # When compiled with the MIPSpro 7.4.4m compiler, and without pthreads
 -      # (i.e. NO_PTHREADS is set), and _with_ MMAP (i.e. NO_MMAP is not set),
 -      # git dies with a segmentation fault when trying to access the first
 -      # entry of a reflog.  The conservative choice is made to always set
 -      # NO_MMAP.  If you suspect that your compiler is not affected by this
 -      # issue, comment out the NO_MMAP statement.
 -      NO_MMAP = YesPlease
 -      NO_REGEX = YesPlease
 -      NO_FNMATCH_CASEFOLD = YesPlease
 -      SNPRINTF_RETURNS_BOGUS = YesPlease
 -      SHELL_PATH=/usr/gnu/bin/bash
 -      NEEDS_LIBGEN = YesPlease
 -endif
 -ifeq ($(uname_S),HP-UX)
 -      INLINE = __inline
 -      NO_IPV6=YesPlease
 -      NO_SETENV=YesPlease
 -      NO_STRCASESTR=YesPlease
 -      NO_MEMMEM = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      NO_STRLCPY = YesPlease
 -      NO_MKDTEMP = YesPlease
 -      NO_UNSETENV = YesPlease
 -      NO_HSTRERROR = YesPlease
 -      NO_SYS_SELECT_H = YesPlease
 -      NO_FNMATCH_CASEFOLD = YesPlease
 -      SNPRINTF_RETURNS_BOGUS = YesPlease
 -      NO_NSEC = YesPlease
 -      ifeq ($(uname_R),B.11.00)
 -              NO_INET_NTOP = YesPlease
 -              NO_INET_PTON = YesPlease
 -      endif
 -      ifeq ($(uname_R),B.10.20)
 -              # Override HP-UX 11.x setting:
 -              INLINE =
 -              SOCKLEN_T = size_t
 -              NO_PREAD = YesPlease
 -              NO_INET_NTOP = YesPlease
 -              NO_INET_PTON = YesPlease
 -      endif
 -      GIT_TEST_CMP = cmp
 -endif
 -ifeq ($(uname_S),Windows)
 -      GIT_VERSION := $(GIT_VERSION).MSVC
 -      pathsep = ;
 -      NO_PREAD = YesPlease
 -      NEEDS_CRYPTO_WITH_SSL = YesPlease
 -      NO_LIBGEN_H = YesPlease
 -      NO_SYS_POLL_H = YesPlease
 -      NO_SYMLINK_HEAD = YesPlease
 -      NO_IPV6 = YesPlease
 -      NO_UNIX_SOCKETS = YesPlease
 -      NO_SETENV = YesPlease
 -      NO_UNSETENV = YesPlease
 -      NO_STRCASESTR = YesPlease
 -      NO_STRLCPY = YesPlease
 -      NO_STRTOK_R = YesPlease
 -      NO_FNMATCH = YesPlease
 -      NO_MEMMEM = YesPlease
 -      # NEEDS_LIBICONV = YesPlease
 -      NO_ICONV = YesPlease
 -      NO_STRTOUMAX = YesPlease
 -      NO_STRTOULL = YesPlease
 -      NO_MKDTEMP = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      SNPRINTF_RETURNS_BOGUS = YesPlease
 -      NO_SVN_TESTS = YesPlease
 -      NO_PERL_MAKEMAKER = YesPlease
 -      RUNTIME_PREFIX = YesPlease
 -      NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
 -      NO_NSEC = YesPlease
 -      USE_WIN32_MMAP = YesPlease
 -      # USE_NED_ALLOCATOR = YesPlease
 -      UNRELIABLE_FSTAT = UnfortunatelyYes
 -      OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
 -      NO_REGEX = YesPlease
 -      NO_CURL = YesPlease
 -      NO_PYTHON = YesPlease
 -      BLK_SHA1 = YesPlease
 -      NO_POSIX_GOODIES = UnfortunatelyYes
 -      NATIVE_CRLF = YesPlease
 -
 -      CC = compat/vcbuild/scripts/clink.pl
 -      AR = compat/vcbuild/scripts/lib.pl
 -      CFLAGS =
 -      BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
 -      COMPAT_OBJS = compat/msvc.o compat/winansi.o \
 -              compat/win32/pthread.o compat/win32/syslog.o \
 -              compat/win32/poll.o compat/win32/dirent.o
 -      COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
 -      BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
 -      EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
 -      PTHREAD_LIBS =
 -      lib =
 -ifndef DEBUG
 -      BASIC_CFLAGS += -GL -Os -MT
 -      BASIC_LDFLAGS += -LTCG
 -      AR += -LTCG
 -else
 -      BASIC_CFLAGS += -Zi -MTd
 -endif
 -      X = .exe
 -endif
 -ifeq ($(uname_S),Interix)
 -      NO_INITGROUPS = YesPlease
 -      NO_IPV6 = YesPlease
 -      NO_MEMMEM = YesPlease
 -      NO_MKDTEMP = YesPlease
 -      NO_STRTOUMAX = YesPlease
 -      NO_NSEC = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      ifeq ($(uname_R),3.5)
 -              NO_INET_NTOP = YesPlease
 -              NO_INET_PTON = YesPlease
 -              NO_SOCKADDR_STORAGE = YesPlease
 -              NO_FNMATCH_CASEFOLD = YesPlease
 -      endif
 -      ifeq ($(uname_R),5.2)
 -              NO_INET_NTOP = YesPlease
 -              NO_INET_PTON = YesPlease
 -              NO_SOCKADDR_STORAGE = YesPlease
 -              NO_FNMATCH_CASEFOLD = YesPlease
 -      endif
 -endif
 -ifeq ($(uname_S),Minix)
 -      NO_IPV6 = YesPlease
 -      NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
 -      NO_NSEC = YesPlease
 -      NEEDS_LIBGEN =
 -      NEEDS_CRYPTO_WITH_SSL = YesPlease
 -      NEEDS_IDN_WITH_CURL = YesPlease
 -      NEEDS_SSL_WITH_CURL = YesPlease
 -      NEEDS_RESOLV =
 -      NO_HSTRERROR = YesPlease
 -      NO_MMAP = YesPlease
 -      NO_CURL =
 -      NO_EXPAT =
 -endif
 -ifneq (,$(findstring MINGW,$(uname_S)))
 -      pathsep = ;
 -      NO_PREAD = YesPlease
 -      NEEDS_CRYPTO_WITH_SSL = YesPlease
 -      NO_LIBGEN_H = YesPlease
 -      NO_SYS_POLL_H = YesPlease
 -      NO_SYMLINK_HEAD = YesPlease
 -      NO_UNIX_SOCKETS = YesPlease
 -      NO_SETENV = YesPlease
 -      NO_UNSETENV = YesPlease
 -      NO_STRCASESTR = YesPlease
 -      NO_STRLCPY = YesPlease
 -      NO_STRTOK_R = YesPlease
 -      NO_FNMATCH = YesPlease
 -      NO_MEMMEM = YesPlease
 -      NEEDS_LIBICONV = YesPlease
 -      OLD_ICONV = YesPlease
 -      NO_STRTOUMAX = YesPlease
 -      NO_MKDTEMP = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -      NO_SVN_TESTS = YesPlease
 -      NO_PERL_MAKEMAKER = YesPlease
 -      RUNTIME_PREFIX = YesPlease
 -      NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
 -      NO_NSEC = YesPlease
 -      USE_WIN32_MMAP = YesPlease
 -      USE_NED_ALLOCATOR = YesPlease
 -      UNRELIABLE_FSTAT = UnfortunatelyYes
 -      OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
 -      NO_REGEX = YesPlease
 -      NO_PYTHON = YesPlease
 -      BLK_SHA1 = YesPlease
 -      ETAGS_TARGET = ETAGS
 -      NO_INET_PTON = YesPlease
 -      NO_INET_NTOP = YesPlease
 -      NO_POSIX_GOODIES = UnfortunatelyYes
 -      COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
 -      COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 -      COMPAT_OBJS += compat/mingw.o compat/winansi.o \
 -              compat/win32/pthread.o compat/win32/syslog.o \
 -              compat/win32/poll.o compat/win32/dirent.o
 -      EXTLIBS += -lws2_32
 -      PTHREAD_LIBS =
 -      X = .exe
 -      SPARSE_FLAGS = -Wno-one-bit-signed-bitfield
 -ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
 -      htmldir=doc/git/html/
 -      prefix =
 -      INSTALL = /bin/install
 -      EXTLIBS += /mingw/lib/libz.a
 -      NO_R_TO_GCC_LINKER = YesPlease
 -      INTERNAL_QSORT = YesPlease
 -      HAVE_LIBCHARSET_H = YesPlease
 -else
 -      NO_CURL = YesPlease
 -endif
 -endif
 +GIT_USER_AGENT = git/$(GIT_VERSION)
  
 +include config.mak.uname
  -include config.mak.autogen
  -include config.mak
  
@@@ -1055,7 -1469,7 +1058,7 @@@ els
                CURL_LIBCURL = -lcurl
        endif
        ifdef NEEDS_SSL_WITH_CURL
 -              CURL_LIBCURL += -lssl
 +              CURL_LIBCURL += -lssl
                ifdef NEEDS_CRYPTO_WITH_SSL
                        CURL_LIBCURL += -lcrypto
                endif
        REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
        PROGRAM_OBJS += http-fetch.o
        PROGRAMS += $(REMOTE_CURL_NAMES)
 -      curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p)
 +      curl_check := $(shell (echo 070908; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)
        ifeq "$(curl_check)" "070908"
                ifndef NO_EXPAT
                        PROGRAM_OBJS += http-push.o
@@@ -1123,9 -1537,6 +1126,9 @@@ ifdef NEEDS_LIBICON
        else
                ICONV_LINK =
        endif
 +      ifdef NEEDS_LIBINTL_BEFORE_LIBICONV
 +              ICONV_LINK += -lintl
 +      endif
        EXTLIBS += $(ICONV_LINK) -liconv
  endif
  ifdef NEEDS_LIBGEN
@@@ -1151,9 -1562,6 +1154,9 @@@ endi
  ifdef NO_D_INO_IN_DIRENT
        BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
  endif
 +ifdef NO_GECOS_IN_PWENT
 +      BASIC_CFLAGS += -DNO_GECOS_IN_PWENT
 +endif
  ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
        BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
  endif
@@@ -1187,11 -1595,6 +1190,11 @@@ ifdef NO_GETTEX
        BASIC_CFLAGS += -DNO_GETTEXT
        USE_GETTEXT_SCHEME ?= fallthrough
  endif
 +ifdef NO_POLL
 +      NO_SYS_POLL_H = YesPlease
 +      COMPAT_CFLAGS += -DNO_POLL -Icompat/poll
 +      COMPAT_OBJS += compat/poll/poll.o
 +endif
  ifdef NO_STRCASESTR
        COMPAT_CFLAGS += -DNO_STRCASESTR
        COMPAT_OBJS += compat/strcasestr.o
@@@ -1230,10 -1633,6 +1233,10 @@@ ifdef NO_MKDTEM
        COMPAT_CFLAGS += -DNO_MKDTEMP
        COMPAT_OBJS += compat/mkdtemp.o
  endif
 +ifdef MKDIR_WO_TRAILING_SLASH
 +      COMPAT_CFLAGS += -DMKDIR_WO_TRAILING_SLASH
 +      COMPAT_OBJS += compat/mkdir.o
 +endif
  ifdef NO_MKSTEMPS
        COMPAT_CFLAGS += -DNO_MKSTEMPS
  endif
@@@ -1247,9 -1646,6 +1250,9 @@@ endi
  ifdef NO_SYS_POLL_H
        BASIC_CFLAGS += -DNO_SYS_POLL_H
  endif
 +ifdef NEEDS_SYS_PARAM_H
 +      BASIC_CFLAGS += -DNEEDS_SYS_PARAM_H
 +endif
  ifdef NO_INTTYPES_H
        BASIC_CFLAGS += -DNO_INTTYPES_H
  endif
@@@ -1268,13 -1664,6 +1271,13 @@@ endi
  ifdef OBJECT_CREATION_USES_RENAMES
        COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1
  endif
 +ifdef NO_STRUCT_ITIMERVAL
 +      COMPAT_CFLAGS += -DNO_STRUCT_ITIMERVAL
 +      NO_SETITIMER = YesPlease
 +endif
 +ifdef NO_SETITIMER
 +      COMPAT_CFLAGS += -DNO_SETITIMER
 +endif
  ifdef NO_PREAD
        COMPAT_CFLAGS += -DNO_PREAD
        COMPAT_OBJS += compat/pread.o
@@@ -1292,9 -1681,6 +1295,9 @@@ endi
  ifdef NO_IPV6
        BASIC_CFLAGS += -DNO_IPV6
  endif
 +ifdef NO_INTPTR_T
 +      COMPAT_CFLAGS += -DNO_INTPTR_T
 +endif
  ifdef NO_UINTMAX_T
        BASIC_CFLAGS += -Duintmax_t=uint32_t
  endif
@@@ -1361,9 -1747,6 +1364,9 @@@ ifdef NO_MEMME
        COMPAT_CFLAGS += -DNO_MEMMEM
        COMPAT_OBJS += compat/memmem.o
  endif
 +ifdef NO_GETPAGESIZE
 +      COMPAT_CFLAGS += -DNO_GETPAGESIZE
 +endif
  ifdef INTERNAL_QSORT
        COMPAT_CFLAGS += -DINTERNAL_QSORT
        COMPAT_OBJS += compat/qsort.o
@@@ -1389,10 -1772,6 +1392,10 @@@ ifdef HAVE_LIBCHARSET_
        EXTLIBS += $(CHARSET_LIB)
  endif
  
 +ifdef HAVE_STRINGS_H
 +      BASIC_CFLAGS += -DHAVE_STRINGS_H
 +endif
 +
  ifdef HAVE_DEV_TTY
        BASIC_CFLAGS += -DHAVE_DEV_TTY
  endif
@@@ -1407,9 -1786,6 +1410,9 @@@ ifdef NO_REGE
        COMPAT_CFLAGS += -Icompat/regex
        COMPAT_OBJS += compat/regex/regex.o
  endif
 +ifdef CYGWIN_V15_WIN32API
 +      COMPAT_CFLAGS += -DCYGWIN_V15_WIN32API
 +endif
  
  ifdef USE_NED_ALLOCATOR
         COMPAT_CFLAGS += -Icompat/nedmalloc
@@@ -1429,15 -1805,15 +1432,15 @@@ ifneq (,$(XDL_FAST_HASH)
  endif
  
  ifeq ($(TCLTK_PATH),)
 -NO_TCLTK=NoThanks
 +NO_TCLTK = NoThanks
  endif
  
  ifeq ($(PERL_PATH),)
 -NO_PERL=NoThanks
 +NO_PERL = NoThanks
  endif
  
  ifeq ($(PYTHON_PATH),)
 -NO_PYTHON=NoThanks
 +NO_PYTHON = NoThanks
  endif
  
  QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir
@@@ -1470,6 -1846,10 +1473,6 @@@ ifndef 
  endif
  endif
  
 -ifdef ASCIIDOC7
 -      export ASCIIDOC7
 -endif
 -
  ifdef NO_INSTALL_HARDLINKS
        export NO_INSTALL_HARDLINKS
  endif
@@@ -1484,13 -1864,13 +1487,13 @@@ PROFILE_DIR := $(CURDIR
  ifeq ("$(PROFILE)","GEN")
        CFLAGS += -fprofile-generate=$(PROFILE_DIR) -DNO_NORETURN=1
        EXTLIBS += -lgcov
 -      export CCACHE_DISABLE=t
 -      V=1
 +      export CCACHE_DISABLE = t
 +      V = 1
  else
  ifneq ("$(PROFILE)","")
        CFLAGS += -fprofile-use=$(PROFILE_DIR) -fprofile-correction -DNO_NORETURN=1
 -      export CCACHE_DISABLE=t
 -      V=1
 +      export CCACHE_DISABLE = t
 +      V = 1
  endif
  endif
  
@@@ -1547,18 -1927,6 +1550,18 @@@ SHELL_PATH_CQ_SQ = $(subst ','\'',$(SHE
  BASIC_CFLAGS += -DSHELL_PATH='$(SHELL_PATH_CQ_SQ)'
  endif
  
 +GIT_USER_AGENT_SQ = $(subst ','\'',$(GIT_USER_AGENT))
 +GIT_USER_AGENT_CQ = "$(subst ",\",$(subst \,\\,$(GIT_USER_AGENT)))"
 +GIT_USER_AGENT_CQ_SQ = $(subst ','\'',$(GIT_USER_AGENT_CQ))
 +GIT-USER-AGENT: FORCE
 +      @if test x'$(GIT_USER_AGENT_SQ)' != x"`cat GIT-USER-AGENT 2>/dev/null`"; then \
 +              echo '$(GIT_USER_AGENT_SQ)' >GIT-USER-AGENT; \
 +      fi
 +
 +ifdef DEFAULT_HELP_FORMAT
 +BASIC_CFLAGS += -DDEFAULT_HELP_FORMAT='"$(DEFAULT_HELP_FORMAT)"'
 +endif
 +
  ALL_CFLAGS += $(BASIC_CFLAGS)
  ALL_LDFLAGS += $(BASIC_LDFLAGS)
  
@@@ -1605,41 -1973,8 +1608,41 @@@ shell_compatibility_test: please_set_SH
  strip: $(PROGRAMS) git$X
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
  
 -git.o: common-cmds.h
 -git.sp git.s git.o: EXTRA_CPPFLAGS = -DGIT_VERSION='"$(GIT_VERSION)"' \
 +### Target-specific flags and dependencies
 +
 +# The generic compilation pattern rule and automatically
 +# computed header dependencies (falling back to a dependency on
 +# LIB_H) are enough to describe how most targets should be built,
 +# but some targets are special enough to need something a little
 +# different.
 +#
 +# - When a source file "foo.c" #includes a generated header file,
 +#   we need to list that dependency for the "foo.o" target.
 +#
 +#   We also list it from other targets that are built from foo.c
 +#   like "foo.sp" and "foo.s", even though that is easy to forget
 +#   to do because the generated header is already present around
 +#   after a regular build attempt.
 +#
 +# - Some code depends on configuration kept in makefile
 +#   variables. The target-specific variable EXTRA_CPPFLAGS can
 +#   be used to convey that information to the C preprocessor
 +#   using -D options.
 +#
 +#   The "foo.o" target should have a corresponding dependency on
 +#   a file that changes when the value of the makefile variable
 +#   changes.  For example, targets making use of the
 +#   $(GIT_VERSION) variable depend on GIT-VERSION-FILE.
 +#
 +#   Technically the ".sp" and ".s" targets do not need this
 +#   dependency because they are force-built, but they get the
 +#   same dependency for consistency. This way, you do not have to
 +#   know how each target is implemented. And it means the
 +#   dependencies here will not need to change if the force-build
 +#   details change some day.
 +
 +git.sp git.s git.o: GIT-PREFIX
 +git.sp git.s git.o: EXTRA_CPPFLAGS = \
        '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
        '-DGIT_MAN_PATH="$(mandir_SQ)"' \
        '-DGIT_INFO_PATH="$(infodir_SQ)"'
@@@ -1648,19 -1983,14 +1651,19 @@@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
  
 -help.sp help.o: common-cmds.h
 +help.sp help.s help.o: common-cmds.h
  
 -builtin/help.sp builtin/help.o: common-cmds.h
 +builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX
  builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
        '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
        '-DGIT_MAN_PATH="$(mandir_SQ)"' \
        '-DGIT_INFO_PATH="$(infodir_SQ)"'
  
 +version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT
 +version.sp version.s version.o: EXTRA_CPPFLAGS = \
 +      '-DGIT_VERSION="$(GIT_VERSION)"' \
 +      '-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)'
 +
  $(BUILT_INS): git$X
        $(QUIET_BUILT_IN)$(RM) $@ && \
        ln git$X $@ 2>/dev/null || \
@@@ -1672,54 -2002,35 +1675,54 @@@ common-cmds.h: ./generate-cmdlist.sh co
  common-cmds.h: $(wildcard Documentation/git-*.txt)
        $(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
  
 +SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\
 +      $(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\
 +      $(gitwebdir_SQ):$(PERL_PATH_SQ)
  define cmd_munge_script
  $(RM) $@ $@+ && \
  sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
      -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
      -e 's|@@DIFF@@|$(DIFF_SQ)|' \
 -    -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
      -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \
      -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
      -e 's/@@USE_GETTEXT_SCHEME@@/$(USE_GETTEXT_SCHEME)/g' \
      -e $(BROKEN_PATH_FIX) \
 +    -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
 +    -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
      $@.sh >$@+
  endef
  
 -$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
 +GIT-SCRIPT-DEFINES: FORCE
 +      @FLAGS='$(SCRIPT_DEFINES)'; \
 +          if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
 +              echo >&2 "    * new script parameters"; \
 +              echo "$$FLAGS" >$@; \
 +            fi
 +
 +
 +$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh GIT-SCRIPT-DEFINES
        $(QUIET_GEN)$(cmd_munge_script) && \
        chmod +x $@+ && \
        mv $@+ $@
  
 -$(SCRIPT_LIB) : % : %.sh
 +$(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES
        $(QUIET_GEN)$(cmd_munge_script) && \
        mv $@+ $@
  
  ifndef NO_PERL
  $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
  
 -perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL
 +perl/perl.mak: perl/PM.stamp
 +
 +perl/PM.stamp: FORCE
 +      $(QUIET_GEN)$(FIND) perl -type f -name '*.pm' | sort >$@+ && \
 +      { cmp $@+ $@ >/dev/null 2>/dev/null || mv $@+ $@; } && \
 +      $(RM) $@+
 +
 +perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL
        $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
  
 -$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
 +$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
        $(QUIET_GEN)$(RM) $@ $@+ && \
        INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \
        sed -e '1{' \
  gitweb:
        $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all
  
 -git-instaweb: git-instaweb.sh gitweb
 -      $(QUIET_GEN)$(RM) $@ $@+ && \
 -      sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
 -          -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
 -          -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
 -          -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \
 -          -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
 -          $@.sh > $@+ && \
 +git-instaweb: git-instaweb.sh gitweb GIT-SCRIPT-DEFINES
 +      $(QUIET_GEN)$(cmd_munge_script) && \
        chmod +x $@+ && \
        mv $@+ $@
  else # NO_PERL
@@@ -1754,7 -2071,7 +1757,7 @@@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git
  endif # NO_PERL
  
  ifndef NO_PYTHON
 -$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS
 +$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS
  $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
        $(QUIET_GEN)$(RM) $@ $@+ && \
        INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
@@@ -1776,29 -2093,24 +1779,29 @@@ $(patsubst %.py,%,$(SCRIPT_PYTHON)): % 
        mv $@+ $@
  endif # NO_PYTHON
  
 -configure: configure.ac
 +configure: configure.ac GIT-VERSION-FILE
        $(QUIET_GEN)$(RM) $@ $<+ && \
        sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
            $< > $<+ && \
        autoconf -o $@ $<+ && \
        $(RM) $<+
  
 -# These can record GIT_VERSION
 -git.o git.spec http.o \
 -      $(patsubst %.sh,%,$(SCRIPT_SH)) \
 -      $(patsubst %.perl,%,$(SCRIPT_PERL)) \
 -      : GIT-VERSION-FILE
 -
 -TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
 -GIT_OBJS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
 -      git.o
 -ifndef NO_CURL
 -      GIT_OBJS += http.o http-walker.o remote-curl.o
 +ifdef AUTOCONFIGURED
 +# We avoid depending on 'configure' here, because it gets rebuilt
 +# every time GIT-VERSION-FILE is modified, only to update the embedded
 +# version number string, which config.status does not care about.  We
 +# do want to recheck when the platform/environment detection logic
 +# changes, hence this depends on configure.ac.
 +config.status: configure.ac
 +      $(QUIET_GEN)$(MAKE) configure && \
 +      if test -f config.status; then \
 +        ./config.status --recheck; \
 +      else \
 +        ./configure; \
 +      fi
 +reconfigure config.mak.autogen: config.status
 +      $(QUIET_GEN)./config.status
 +.PHONY: reconfigure # This is a convenience target.
  endif
  
  XDIFF_OBJS += xdiff/xdiffi.o
@@@ -1816,14 -2128,9 +1819,14 @@@ VCSSVN_OBJS += vcs-svn/fast_export.
  VCSSVN_OBJS += vcs-svn/svndiff.o
  VCSSVN_OBJS += vcs-svn/svndump.o
  
 -VCSSVN_TEST_OBJS += test-line-buffer.o
 -
 -OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)
 +TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
 +OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
 +      $(XDIFF_OBJS) \
 +      $(VCSSVN_OBJS) \
 +      git.o
 +ifndef NO_CURL
 +      OBJECTS += http.o http-walker.o remote-curl.o
 +endif
  
  dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
  dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS))))
  # Dependencies on automatically generated headers such as common-cmds.h
  # should _not_ be included here, since they are necessary even when
  # building an object for the first time.
 -#
 -# XXX. Please check occasionally that these include all dependencies
 -# gcc detects!
 -
 -$(GIT_OBJS): $(LIB_H)
 -builtin/branch.o builtin/checkout.o builtin/clone.o builtin/reset.o branch.o transport.o: branch.h
 -builtin/bundle.o bundle.o transport.o: bundle.h
 -builtin/bisect--helper.o builtin/rev-list.o bisect.o: bisect.h
 -builtin/clone.o builtin/fetch-pack.o transport.o: fetch-pack.h
 -builtin/index-pack.o builtin/grep.o builtin/pack-objects.o transport-helper.o thread-utils.o: thread-utils.h
 -builtin/send-pack.o transport.o: send-pack.h
 -builtin/log.o builtin/shortlog.o: shortlog.h
 -builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 -builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 -builtin/tar-tree.o archive-tar.o: tar.h
 -connect.o transport.o url.o http-backend.o: url.h
 -builtin/branch.o builtin/commit.o builtin/tag.o column.o help.o pager.o: column.h
 -http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 -http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
  
 -xdiff-interface.o $(XDIFF_OBJS): $(XDIFF_H)
 -
 -$(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) $(VCSSVN_H)
 +$(OBJECTS): $(LIB_H)
  endif
  
 +exec_cmd.sp exec_cmd.s exec_cmd.o: GIT-PREFIX
  exec_cmd.sp exec_cmd.s exec_cmd.o: EXTRA_CPPFLAGS = \
        '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
        '-DBINDIR="$(bindir_relative_SQ)"' \
        '-DPREFIX="$(prefix_SQ)"'
  
 +builtin/init-db.sp builtin/init-db.s builtin/init-db.o: GIT-PREFIX
  builtin/init-db.sp builtin/init-db.s builtin/init-db.o: EXTRA_CPPFLAGS = \
        -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
  
 +config.sp config.s config.o: GIT-PREFIX
  config.sp config.s config.o: EXTRA_CPPFLAGS = \
        -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
  
 +attr.sp attr.s attr.o: GIT-PREFIX
  attr.sp attr.s attr.o: EXTRA_CPPFLAGS = \
        -DETC_GITATTRIBUTES='"$(ETC_GITATTRIBUTES_SQ)"'
  
 +gettext.sp gettext.s gettext.o: GIT-PREFIX
  gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
        -DGIT_LOCALE_PATH='"$(localedir_SQ)"'
  
 -http.sp http.s http.o: EXTRA_CPPFLAGS = \
 -      -DGIT_HTTP_USER_AGENT='"git/$(GIT_VERSION)"'
 -
  ifdef NO_EXPAT
  http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
  endif
@@@ -1976,10 -2302,6 +1979,10 @@@ git-http-push$X: revision.o http.o http
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
  
 +git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB)
 +      $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) \
 +      $(VCSSVN_LIB)
 +
  $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
        $(QUIET_LNCP)$(RM) $@ && \
        ln $< $@ 2>/dev/null || \
@@@ -2023,10 -2345,9 +2026,10 @@@ XGETTEXT_FLAGS = 
        --from-code=UTF-8
  XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \
        --keyword=_ --keyword=N_ --keyword="Q_:1,2"
 -XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell
 +XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
 +      --keyword=gettextln --keyword=eval_gettextln
  XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
 -LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(XDIFF_H) $(VCSSVN_H) $(MISC_H)
 +LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
  LOCALIZED_SH := $(SCRIPT_SH)
  LOCALIZED_PERL := $(SCRIPT_PERL)
  
@@@ -2073,22 -2394,14 +2076,22 @@@ cscope
        $(FIND_SOURCE_FILES) | xargs cscope -b
  
  ### Detect prefix changes
 -TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):\
 -             $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
 -             $(localedir_SQ):$(USE_GETTEXT_SCHEME)
 +TRACK_PREFIX = $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
 +              $(localedir_SQ)
 +
 +GIT-PREFIX: FORCE
 +      @FLAGS='$(TRACK_PREFIX)'; \
 +      if test x"$$FLAGS" != x"`cat GIT-PREFIX 2>/dev/null`" ; then \
 +              echo >&2 "    * new prefix flags"; \
 +              echo "$$FLAGS" >GIT-PREFIX; \
 +      fi
 +
 +TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):$(USE_GETTEXT_SCHEME)
  
  GIT-CFLAGS: FORCE
        @FLAGS='$(TRACK_CFLAGS)'; \
            if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \
 -              echo 1>&2 "    * new build flags or prefix"; \
 +              echo >&2 "    * new build flags"; \
                echo "$$FLAGS" >GIT-CFLAGS; \
              fi
  
@@@ -2097,7 -2410,7 +2100,7 @@@ TRACK_LDFLAGS = $(subst ','\'',$(ALL_LD
  GIT-LDFLAGS: FORCE
        @FLAGS='$(TRACK_LDFLAGS)'; \
            if test x"$$FLAGS" != x"`cat GIT-LDFLAGS 2>/dev/null`" ; then \
 -              echo 1>&2 "    * new link flags"; \
 +              echo >&2 "    * new link flags"; \
                echo "$$FLAGS" >GIT-LDFLAGS; \
              fi
  
@@@ -2139,14 -2452,14 +2142,14 @@@ ifdef GIT_PERF_MAKE_OPT
        @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@
  endif
  
 -### Detect Tck/Tk interpreter path changes
 -ifndef NO_TCLTK
 -TRACK_VARS = $(subst ','\'',-DTCLTK_PATH='$(TCLTK_PATH_SQ)')
 +### Detect Python interpreter path changes
 +ifndef NO_PYTHON
 +TRACK_PYTHON = $(subst ','\'',-DPYTHON_PATH='$(PYTHON_PATH_SQ)')
  
 -GIT-GUI-VARS: FORCE
 -      @VARS='$(TRACK_VARS)'; \
 +GIT-PYTHON-VARS: FORCE
 +      @VARS='$(TRACK_PYTHON)'; \
            if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \
 -              echo 1>&2 "    * new Tcl/Tk interpreter location"; \
 +              echo >&2 "    * new Python interpreter location"; \
                echo "$$VARS" >$@; \
              fi
  endif
@@@ -2167,7 -2480,6 +2170,7 @@@ bin-wrappers/%: wrap-for-bin.s
  # with that.
  
  export NO_SVN_TESTS
 +export TEST_NO_MALLOC_CHECK
  
  ### Testing rules
  
@@@ -2341,11 -2653,11 +2344,11 @@@ quick-install-html
  
  ### Maintainer's dist rules
  
 -git.spec: git.spec.in
 +git.spec: git.spec.in GIT-VERSION-FILE
        sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@+
        mv $@+ $@
  
 -GIT_TARNAME=git-$(GIT_VERSION)
 +GIT_TARNAME = git-$(GIT_VERSION)
  dist: git.spec git-archive$(X) configure
        ./git-archive --format=tar \
                --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
@@@ -2391,9 -2703,6 +2394,9 @@@ dist-doc
  
  distclean: clean
        $(RM) configure
 +      $(RM) config.log config.status config.cache
 +      $(RM) config.mak.autogen config.mak.append
 +      $(RM) -r autom4te.cache
  
  profile-clean:
        $(RM) $(addsuffix *.gcda,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
@@@ -2408,6 -2717,8 +2411,6 @@@ clean: profile-clea
        $(RM) -r $(dep_dirs)
        $(RM) -r po/build/
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*
 -      $(RM) -r autom4te.cache
 -      $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
        $(RM) -r $(GIT_TARNAME) .doc-tmp-dir
        $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
        $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
@@@ -2425,8 -2736,7 +2428,8 @@@ ifndef NO_TCLT
        $(MAKE) -C gitk-git clean
        $(MAKE) -C git-gui clean
  endif
 -      $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
 +      $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-BUILD-OPTIONS
 +      $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES GIT-PYTHON-VARS
  
  .PHONY: all install profile-clean clean strip
  .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
  
  ### Check documentation
  #
 +ALL_COMMANDS = $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS)
 +ALL_COMMANDS += git
 +ALL_COMMANDS += gitk
 +ALL_COMMANDS += gitweb
 +ALL_COMMANDS += git-gui git-citool
  check-docs::
 -      @(for v in $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk; \
 +      @(for v in $(ALL_COMMANDS); \
        do \
                case "$$v" in \
                git-merge-octopus | git-merge-ours | git-merge-recursive | \
                sed -e '/^#/d' \
                    -e 's/[     ].*//' \
                    -e 's/^/listed /' command-list.txt; \
 -              ls -1 Documentation/git*txt | \
 +              $(MAKE) -C Documentation print-man1 | \
 +              grep '\.txt$$' | \
                sed -e 's|Documentation/|documented |' \
                    -e 's/\.txt//'; \
        ) | while read how cmd; \
        do \
 -              case "$$how,$$cmd" in \
 -              *,git-citool | \
 -              *,git-gui | \
 -              *,git-help | \
 -              documented,gitattributes | \
 -              documented,gitignore | \
 -              documented,gitmodules | \
 -              documented,gitcli | \
 -              documented,git-tools | \
 -              documented,gitcore-tutorial | \
 -              documented,gitcvs-migration | \
 -              documented,gitdiffcore | \
 -              documented,gitglossary | \
 -              documented,githooks | \
 -              documented,gitrepository-layout | \
 -              documented,gitrevisions | \
 -              documented,gittutorial | \
 -              documented,gittutorial-2 | \
 -              documented,git-bisect-lk2009 | \
 -              documented,git-remote-helpers | \
 -              documented,gitworkflows | \
 -              sentinel,not,matching,is,ok ) continue ;; \
 -              esac; \
 -              case " $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk " in \
 +              case " $(ALL_COMMANDS) " in \
                *" $$cmd "*)    ;; \
                *) echo "removed but $$how: $$cmd" ;; \
                esac; \
diff --combined builtin.h
index 7e7bbd665a905b0fdf9ce5351f6f09dfd3dd7e8a,d57faf49874364115041b8f08942542f3ceb0c2c..faef55913634a21a757b4814f855ed834c32915e
+++ b/builtin.h
@@@ -9,19 -9,20 +9,19 @@@
  
  #define DEFAULT_MERGE_LOG_LEN 20
  
 -extern const char git_version_string[];
  extern const char git_usage_string[];
  extern const char git_more_info_string[];
  
  extern void prune_packed_objects(int);
  
  struct fmt_merge_msg_opts {
 -      unsigned add_title:1;
 +      unsigned add_title:1,
 +              credit_people:1;
        int shortlog_len;
  };
  
  extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
                         struct fmt_merge_msg_opts *);
 -extern void commit_notes(struct notes_tree *t, const char *msg);
  
  struct notes_rewrite_cfg {
        struct notes_tree **trees;
        int mode_from_env;
  };
  
 -combine_notes_fn parse_combine_notes_fn(const char *v);
  struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd);
  int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
                          const unsigned char *from_obj, const unsigned char *to_obj);
  void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);
  
 -extern int check_pager_config(const char *cmd);
 -struct diff_options;
 -extern void setup_diff_pager(struct diff_options *);
 -
  extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);
  
  extern int cmd_add(int argc, const char **argv, const char *prefix);
@@@ -52,6 -58,7 +52,7 @@@ extern int cmd_cat_file(int argc, cons
  extern int cmd_checkout(int argc, const char **argv, const char *prefix);
  extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
  extern int cmd_check_attr(int argc, const char **argv, const char *prefix);
+ extern int cmd_check_ignore(int argc, const char **argv, const char *prefix);
  extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
  extern int cmd_cherry(int argc, const char **argv, const char *prefix);
  extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
@@@ -62,7 -69,6 +63,7 @@@ extern int cmd_commit(int argc, const c
  extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
  extern int cmd_config(int argc, const char **argv, const char *prefix);
  extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
 +extern int cmd_credential(int argc, const char **argv, const char *prefix);
  extern int cmd_describe(int argc, const char **argv, const char *prefix);
  extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
  extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
diff --combined builtin/add.c
index 075312afcd8813c3a7dbf08f6be519a37498fe4f,3716617e221932d00c34e5b0eed80beb18791785..7cb6cca56dc58d02d075bf6042115f00265a9b68
@@@ -6,6 -6,7 +6,7 @@@
  #include "cache.h"
  #include "builtin.h"
  #include "dir.h"
+ #include "pathspec.h"
  #include "exec_cmd.h"
  #include "cache-tree.h"
  #include "run-command.h"
@@@ -16,7 -17,7 +17,7 @@@
  #include "bulk-checkin.h"
  
  static const char * const builtin_add_usage[] = {
 -      "git add [options] [--] <filepattern>...",
 +      N_("git add [options] [--] <filepattern>..."),
        NULL
  };
  static int patch_interactive, add_interactive, edit_interactive;
@@@ -97,39 -98,6 +98,6 @@@ int add_files_to_cache(const char *pref
        return !!data.add_errors;
  }
  
- static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
- {
-       int num_unmatched = 0, i;
-       /*
-        * Since we are walking the index as if we were walking the directory,
-        * we have to mark the matched pathspec as seen; otherwise we will
-        * mistakenly think that the user gave a pathspec that did not match
-        * anything.
-        */
-       for (i = 0; i < specs; i++)
-               if (!seen[i])
-                       num_unmatched++;
-       if (!num_unmatched)
-               return;
-       for (i = 0; i < active_nr; i++) {
-               struct cache_entry *ce = active_cache[i];
-               match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen);
-       }
- }
- static char *find_used_pathspec(const char **pathspec)
- {
-       char *seen;
-       int i;
-       for (i = 0; pathspec[i];  i++)
-               ; /* just counting */
-       seen = xcalloc(i, 1);
-       fill_pathspec_matches(pathspec, seen, i);
-       return seen;
- }
  static char *prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
  {
        char *seen;
                        *dst++ = entry;
        }
        dir->nr = dst - dir->entries;
-       fill_pathspec_matches(pathspec, seen, specs);
+       add_pathspec_matches_against_index(pathspec, seen, specs);
        return seen;
  }
  
+ /*
+  * Checks the index to see whether any path in pathspec refers to
+  * something inside a submodule.  If so, dies with an error message.
+  */
  static void treat_gitlinks(const char **pathspec)
  {
        int i;
        if (!pathspec || !*pathspec)
                return;
  
-       for (i = 0; i < active_nr; i++) {
-               struct cache_entry *ce = active_cache[i];
-               if (S_ISGITLINK(ce->ce_mode)) {
-                       int len = ce_namelen(ce), j;
-                       for (j = 0; pathspec[j]; j++) {
-                               int len2 = strlen(pathspec[j]);
-                               if (len2 <= len || pathspec[j][len] != '/' ||
-                                   memcmp(ce->name, pathspec[j], len))
-                                       continue;
-                               if (len2 == len + 1)
-                                       /* strip trailing slash */
-                                       pathspec[j] = xstrndup(ce->name, len);
-                               else
-                                       die (_("Path '%s' is in submodule '%.*s'"),
-                                               pathspec[j], len, ce->name);
-                       }
-               }
-       }
+       for (i = 0; pathspec[i]; i++)
+               pathspec[i] = check_path_for_gitlink(pathspec[i]);
  }
  
  static void refresh(int verbose, const char **pathspec)
          free(seen);
  }
  
- static const char **validate_pathspec(int argc, const char **argv, const char *prefix)
+ /*
+  * Normalizes argv relative to prefix, via get_pathspec(), and then
+  * runs die_if_path_beyond_symlink() on each path in the normalized
+  * list.
+  */
+ static const char **validate_pathspec(const char **argv, const char *prefix)
  {
        const char **pathspec = get_pathspec(prefix, argv);
  
        if (pathspec) {
                const char **p;
                for (p = pathspec; *p; p++) {
-                       if (has_symlink_leading_path(*p, strlen(*p))) {
-                               int len = prefix ? strlen(prefix) : 0;
-                               die(_("'%s' is beyond a symbolic link"), *p + len);
-                       }
+                       die_if_path_beyond_symlink(*p, prefix);
                }
        }
  
@@@ -248,7 -206,7 +206,7 @@@ int interactive_add(int argc, const cha
        const char **pathspec = NULL;
  
        if (argc) {
-               pathspec = validate_pathspec(argc, argv, prefix);
+               pathspec = validate_pathspec(argv, prefix);
                if (!pathspec)
                        return -1;
        }
  
  static int edit_patch(int argc, const char **argv, const char *prefix)
  {
 -      char *file = xstrdup(git_path("ADD_EDIT.patch"));
 +      char *file = git_pathdup("ADD_EDIT.patch");
        const char *apply_argv[] = { "apply", "--recount", "--cached",
                NULL, NULL };
        struct child_process child;
                die (_("Could not apply '%s'"), file);
  
        unlink(file);
 +      free(file);
        return 0;
  }
  
@@@ -316,19 -273,19 +274,19 @@@ static int verbose = 0, show_only = 0, 
  static int ignore_add_errors, addremove, intent_to_add, ignore_missing = 0;
  
  static struct option builtin_add_options[] = {
 -      OPT__DRY_RUN(&show_only, "dry run"),
 -      OPT__VERBOSE(&verbose, "be verbose"),
 +      OPT__DRY_RUN(&show_only, N_("dry run")),
 +      OPT__VERBOSE(&verbose, N_("be verbose")),
        OPT_GROUP(""),
 -      OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
 -      OPT_BOOLEAN('p', "patch", &patch_interactive, "select hunks interactively"),
 -      OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
 -      OPT__FORCE(&ignored_too, "allow adding otherwise ignored files"),
 -      OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
 -      OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
 -      OPT_BOOLEAN('A', "all", &addremove, "add changes from all tracked and untracked files"),
 -      OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
 -      OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
 -      OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, "check if - even missing - files are ignored in dry run"),
 +      OPT_BOOLEAN('i', "interactive", &add_interactive, N_("interactive picking")),
 +      OPT_BOOLEAN('p', "patch", &patch_interactive, N_("select hunks interactively")),
 +      OPT_BOOLEAN('e', "edit", &edit_interactive, N_("edit current diff and apply")),
 +      OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
 +      OPT_BOOLEAN('u', "update", &take_worktree_changes, N_("update tracked files")),
 +      OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
 +      OPT_BOOLEAN('A', "all", &addremove, N_("add changes from all tracked and untracked files")),
 +      OPT_BOOLEAN( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
 +      OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
 +      OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
        OPT_END(),
  };
  
@@@ -415,7 -372,7 +373,7 @@@ int cmd_add(int argc, const char **argv
                fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
                return 0;
        }
-       pathspec = validate_pathspec(argc, argv, prefix);
+       pathspec = validate_pathspec(argv, prefix);
  
        if (read_cache() < 0)
                die(_("index file corrupt"));
  
                path_exclude_check_init(&check, &dir);
                if (!seen)
-                       seen = find_used_pathspec(pathspec);
+                       seen = find_pathspecs_matching_against_index(pathspec);
                for (i = 0; pathspec[i]; i++) {
                        if (!seen[i] && pathspec[i][0]
                            && !file_exists(pathspec[i])) {
diff --combined builtin/clean.c
index f4b760bf3dcb2371da6ae9d77f2f8fb1c0fa9eb9,b9cb7ad4e088257fd0900816f883a92b7a3a5b43..04e396b17acc2443a663dd085ef812c3c2746d27
  #include "cache.h"
  #include "dir.h"
  #include "parse-options.h"
 +#include "refs.h"
  #include "string-list.h"
  #include "quote.h"
  
  static int force = -1; /* unset */
  
  static const char *const builtin_clean_usage[] = {
 -      "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>...",
 +      N_("git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
        NULL
  };
  
 +static const char *msg_remove = N_("Removing %s\n");
 +static const char *msg_would_remove = N_("Would remove %s\n");
 +static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
 +static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
 +static const char *msg_warn_remove_failed = N_("failed to remove %s");
 +
  static int git_clean_config(const char *var, const char *value, void *cb)
  {
        if (!strcmp(var, "clean.requireforce"))
@@@ -41,131 -34,31 +41,132 @@@ static int exclude_cb(const struct opti
        return 0;
  }
  
 +static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 +              int dry_run, int quiet, int *dir_gone)
 +{
 +      DIR *dir;
 +      struct strbuf quoted = STRBUF_INIT;
 +      struct dirent *e;
 +      int res = 0, ret = 0, gone = 1, original_len = path->len, len, i;
 +      unsigned char submodule_head[20];
 +      struct string_list dels = STRING_LIST_INIT_DUP;
 +
 +      *dir_gone = 1;
 +
 +      if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
 +                      !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
 +              if (!quiet) {
 +                      quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
 +                      printf(dry_run ?  _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
 +                                      quoted.buf);
 +              }
 +
 +              *dir_gone = 0;
 +              return 0;
 +      }
 +
 +      dir = opendir(path->buf);
 +      if (!dir) {
 +              /* an empty dir could be removed even if it is unreadble */
 +              res = dry_run ? 0 : rmdir(path->buf);
 +              if (res) {
 +                      quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
 +                      warning(_(msg_warn_remove_failed), quoted.buf);
 +                      *dir_gone = 0;
 +              }
 +              return res;
 +      }
 +
 +      if (path->buf[original_len - 1] != '/')
 +              strbuf_addch(path, '/');
 +
 +      len = path->len;
 +      while ((e = readdir(dir)) != NULL) {
 +              struct stat st;
 +              if (is_dot_or_dotdot(e->d_name))
 +                      continue;
 +
 +              strbuf_setlen(path, len);
 +              strbuf_addstr(path, e->d_name);
 +              if (lstat(path->buf, &st))
 +                      ; /* fall thru */
 +              else if (S_ISDIR(st.st_mode)) {
 +                      if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
 +                              ret = 1;
 +                      if (gone) {
 +                              quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
 +                              string_list_append(&dels, quoted.buf);
 +                      } else
 +                              *dir_gone = 0;
 +                      continue;
 +              } else {
 +                      res = dry_run ? 0 : unlink(path->buf);
 +                      if (!res) {
 +                              quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
 +                              string_list_append(&dels, quoted.buf);
 +                      } else {
 +                              quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
 +                              warning(_(msg_warn_remove_failed), quoted.buf);
 +                              *dir_gone = 0;
 +                              ret = 1;
 +                      }
 +                      continue;
 +              }
 +
 +              /* path too long, stat fails, or non-directory still exists */
 +              *dir_gone = 0;
 +              ret = 1;
 +              break;
 +      }
 +      closedir(dir);
 +
 +      strbuf_setlen(path, original_len);
 +
 +      if (*dir_gone) {
 +              res = dry_run ? 0 : rmdir(path->buf);
 +              if (!res)
 +                      *dir_gone = 1;
 +              else {
 +                      quote_path_relative(path->buf, strlen(path->buf), &quoted, prefix);
 +                      warning(_(msg_warn_remove_failed), quoted.buf);
 +                      *dir_gone = 0;
 +                      ret = 1;
 +              }
 +      }
 +
 +      if (!*dir_gone && !quiet) {
 +              for (i = 0; i < dels.nr; i++)
 +                      printf(dry_run ?  _(msg_would_remove) : _(msg_remove), dels.items[i].string);
 +      }
 +      string_list_clear(&dels, 0);
 +      return ret;
 +}
 +
  int cmd_clean(int argc, const char **argv, const char *prefix)
  {
 -      int i;
 -      int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
 -      int ignored_only = 0, config_set = 0, errors = 0;
 +      int i, res;
 +      int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
 +      int ignored_only = 0, config_set = 0, errors = 0, gone = 1;
        int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
        struct strbuf directory = STRBUF_INIT;
        struct dir_struct dir;
        static const char **pathspec;
        struct strbuf buf = STRBUF_INIT;
        struct string_list exclude_list = STRING_LIST_INIT_NODUP;
+       struct exclude_list *el;
        const char *qname;
        char *seen = NULL;
        struct option options[] = {
 -              OPT__QUIET(&quiet, "do not print names of files removed"),
 -              OPT__DRY_RUN(&show_only, "dry run"),
 -              OPT__FORCE(&force, "force"),
 +              OPT__QUIET(&quiet, N_("do not print names of files removed")),
 +              OPT__DRY_RUN(&dry_run, N_("dry run")),
 +              OPT__FORCE(&force, N_("force")),
                OPT_BOOLEAN('d', NULL, &remove_directories,
 -                              "remove whole directories"),
 -              { OPTION_CALLBACK, 'e', "exclude", &exclude_list, "pattern",
 -                "add <pattern> to ignore rules", PARSE_OPT_NONEG, exclude_cb },
 -              OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
 +                              N_("remove whole directories")),
 +              { OPTION_CALLBACK, 'e', "exclude", &exclude_list, N_("pattern"),
 +                N_("add <pattern> to ignore rules"), PARSE_OPT_NONEG, exclude_cb },
 +              OPT_BOOLEAN('x', NULL, &ignored, N_("remove ignored files, too")),
                OPT_BOOLEAN('X', NULL, &ignored_only,
 -                              "remove only ignored files"),
 +                              N_("remove only ignored files")),
                OPT_END()
        };
  
        if (ignored && ignored_only)
                die(_("-x and -X cannot be used together"));
  
 -      if (!show_only && !force) {
 +      if (!dry_run && !force) {
                if (config_set)
                        die(_("clean.requireForce set to true and neither -n nor -f given; "
                                  "refusing to clean"));
        if (!ignored)
                setup_standard_excludes(&dir);
  
+       el = add_exclude_list(&dir, EXC_CMDL, "--exclude option");
        for (i = 0; i < exclude_list.nr; i++)
-               add_exclude(exclude_list.items[i].string, "", 0,
-                           &dir.exclude_list[EXC_CMDL]);
+               add_exclude(exclude_list.items[i].string, "", 0, el, -(i+1));
  
        pathspec = get_pathspec(prefix, argv);
  
  
                if (S_ISDIR(st.st_mode)) {
                        strbuf_addstr(&directory, ent->name);
 -                      qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
 -                      if (show_only && (remove_directories ||
 -                          (matches == MATCHED_EXACTLY))) {
 -                              printf(_("Would remove %s\n"), qname);
 -                      } else if (remove_directories ||
 -                                 (matches == MATCHED_EXACTLY)) {
 -                              if (!quiet)
 -                                      printf(_("Removing %s\n"), qname);
 -                              if (remove_dir_recursively(&directory,
 -                                                         rm_flags) != 0) {
 -                                      warning(_("failed to remove %s"), qname);
 +                      if (remove_directories || (matches == MATCHED_EXACTLY)) {
 +                              if (remove_dirs(&directory, prefix, rm_flags, dry_run, quiet, &gone))
                                        errors++;
 +                              if (gone && !quiet) {
 +                                      qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
 +                                      printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
                                }
 -                      } else if (show_only) {
 -                              printf(_("Would not remove %s\n"), qname);
 -                      } else {
 -                              printf(_("Not removing %s\n"), qname);
                        }
                        strbuf_reset(&directory);
                } else {
                        if (pathspec && !matches)
                                continue;
 -                      qname = quote_path_relative(ent->name, -1, &buf, prefix);
 -                      if (show_only) {
 -                              printf(_("Would remove %s\n"), qname);
 -                              continue;
 -                      } else if (!quiet) {
 -                              printf(_("Removing %s\n"), qname);
 -                      }
 -                      if (unlink(ent->name) != 0) {
 -                              warning(_("failed to remove %s"), qname);
 +                      res = dry_run ? 0 : unlink(ent->name);
 +                      if (res) {
 +                              qname = quote_path_relative(ent->name, -1, &buf, prefix);
 +                              warning(_(msg_warn_remove_failed), qname);
                                errors++;
 +                      } else if (!quiet) {
 +                              qname = quote_path_relative(ent->name, -1, &buf, prefix);
 +                              printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
                        }
                }
        }
diff --combined builtin/ls-files.c
index 373c573449b5771f9b56d7d4ce04e4c0b3957cd9,b4d8b017a835c0f2911306c0f1c445d4584e913d..175e6e3e72003387bfa4f78dbd0ed10c02c4e318
@@@ -35,6 -35,7 +35,7 @@@ static int error_unmatch
  static char *ps_matched;
  static const char *with_tree;
  static int exc_given;
+ static int exclude_args;
  
  static const char *tag_cached = "";
  static const char *tag_unmerged = "";
@@@ -337,7 -338,7 +338,7 @@@ void overlay_tree_on_cache(const char *
                matchbuf[0] = prefix;
                matchbuf[1] = NULL;
                init_pathspec(&pathspec, matchbuf);
 -              pathspec.items[0].use_wildcard = 0;
 +              pathspec.items[0].nowildcard_len = pathspec.items[0].len;
        } else
                init_pathspec(&pathspec, NULL);
        if (read_tree(tree, 1, &pathspec))
@@@ -405,7 -406,7 +406,7 @@@ int report_path_error(const char *ps_ma
  }
  
  static const char * const ls_files_usage[] = {
 -      "git ls-files [options] [<file>...]",
 +      N_("git ls-files [options] [<file>...]"),
        NULL
  };
  
@@@ -420,10 -421,10 +421,10 @@@ static int option_parse_z(const struct 
  static int option_parse_exclude(const struct option *opt,
                                const char *arg, int unset)
  {
-       struct exclude_list *list = opt->value;
+       struct string_list *exclude_list = opt->value;
  
        exc_given = 1;
-       add_exclude(arg, "", 0, list);
+       string_list_append(exclude_list, arg);
  
        return 0;
  }
@@@ -452,62 -453,65 +453,64 @@@ static int option_parse_exclude_standar
  
  int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
  {
-       int require_work_tree = 0, show_tag = 0;
+       int require_work_tree = 0, show_tag = 0, i;
        const char *max_prefix;
        struct dir_struct dir;
+       struct exclude_list *el;
+       struct string_list exclude_list = STRING_LIST_INIT_NODUP;
        struct option builtin_ls_files_options[] = {
                { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
 -                      "paths are separated with NUL character",
 +                      N_("paths are separated with NUL character"),
                        PARSE_OPT_NOARG, option_parse_z },
                OPT_BOOLEAN('t', NULL, &show_tag,
 -                      "identify the file status with tags"),
 +                      N_("identify the file status with tags")),
                OPT_BOOLEAN('v', NULL, &show_valid_bit,
 -                      "use lowercase letters for 'assume unchanged' files"),
 +                      N_("use lowercase letters for 'assume unchanged' files")),
                OPT_BOOLEAN('c', "cached", &show_cached,
 -                      "show cached files in the output (default)"),
 +                      N_("show cached files in the output (default)")),
                OPT_BOOLEAN('d', "deleted", &show_deleted,
 -                      "show deleted files in the output"),
 +                      N_("show deleted files in the output")),
                OPT_BOOLEAN('m', "modified", &show_modified,
 -                      "show modified files in the output"),
 +                      N_("show modified files in the output")),
                OPT_BOOLEAN('o', "others", &show_others,
 -                      "show other files in the output"),
 +                      N_("show other files in the output")),
                OPT_BIT('i', "ignored", &dir.flags,
 -                      "show ignored files in the output",
 +                      N_("show ignored files in the output"),
                        DIR_SHOW_IGNORED),
                OPT_BOOLEAN('s', "stage", &show_stage,
 -                      "show staged contents' object name in the output"),
 +                      N_("show staged contents' object name in the output")),
                OPT_BOOLEAN('k', "killed", &show_killed,
 -                      "show files on the filesystem that need to be removed"),
 +                      N_("show files on the filesystem that need to be removed")),
                OPT_BIT(0, "directory", &dir.flags,
 -                      "show 'other' directories' name only",
 +                      N_("show 'other' directories' name only"),
                        DIR_SHOW_OTHER_DIRECTORIES),
                OPT_NEGBIT(0, "empty-directory", &dir.flags,
 -                      "don't show empty directories",
 +                      N_("don't show empty directories"),
                        DIR_HIDE_EMPTY_DIRECTORIES),
                OPT_BOOLEAN('u', "unmerged", &show_unmerged,
 -                      "show unmerged files in the output"),
 +                      N_("show unmerged files in the output")),
                OPT_BOOLEAN(0, "resolve-undo", &show_resolve_undo,
 -                          "show resolve-undo information"),
 -              { OPTION_CALLBACK, 'x', "exclude",
 -                      &exclude_list, "pattern",
 -                      "skip files matching pattern",
 +                          N_("show resolve-undo information")),
-               { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], N_("pattern"),
++              { OPTION_CALLBACK, 'x', "exclude", &exclude_list, N_("pattern"),
 +                      N_("skip files matching pattern"),
                        0, option_parse_exclude },
 -              { OPTION_CALLBACK, 'X', "exclude-from", &dir, "file",
 -                      "exclude patterns are read from <file>",
 +              { OPTION_CALLBACK, 'X', "exclude-from", &dir, N_("file"),
 +                      N_("exclude patterns are read from <file>"),
                        0, option_parse_exclude_from },
 -              OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file",
 -                      "read additional per-directory exclude patterns in <file>"),
 +              OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, N_("file"),
 +                      N_("read additional per-directory exclude patterns in <file>")),
                { OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL,
 -                      "add the standard git exclusions",
 +                      N_("add the standard git exclusions"),
                        PARSE_OPT_NOARG, option_parse_exclude_standard },
                { OPTION_SET_INT, 0, "full-name", &prefix_len, NULL,
 -                      "make the output relative to the project top directory",
 +                      N_("make the output relative to the project top directory"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
                OPT_BOOLEAN(0, "error-unmatch", &error_unmatch,
 -                      "if any <file> is not in the index, treat this as an error"),
 -              OPT_STRING(0, "with-tree", &with_tree, "tree-ish",
 -                      "pretend that paths removed since <tree-ish> are still present"),
 +                      N_("if any <file> is not in the index, treat this as an error")),
 +              OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
 +                      N_("pretend that paths removed since <tree-ish> are still present")),
                OPT__ABBREV(&abbrev),
 -              OPT_BOOLEAN(0, "debug", &debug_mode, "show debugging data"),
 +              OPT_BOOLEAN(0, "debug", &debug_mode, N_("show debugging data")),
                OPT_END()
        };
  
  
        argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
                        ls_files_usage, 0);
+       el = add_exclude_list(&dir, EXC_CMDL, "--exclude option");
+       for (i = 0; i < exclude_list.nr; i++) {
+               add_exclude(exclude_list.items[i].string, "", 0, el, --exclude_args);
+       }
        if (show_tag || show_valid_bit) {
                tag_cached = "H ";
                tag_unmerged = "M ";
diff --combined command-list.txt
index 7e8cfec29d9e00cd6dfb26bca1f1295f64ae53fd,ef7f39c8b07bf6fa4057701d5bc7a46fec9fd40a..bf83303c48dc5cfbccfc4a31b347dcdec197d7d4
@@@ -12,6 -12,7 +12,7 @@@ git-branc
  git-bundle                              mainporcelain
  git-cat-file                            plumbinginterrogators
  git-check-attr                          purehelpers
+ git-check-ignore                        purehelpers
  git-checkout                            mainporcelain common
  git-checkout-index                      plumbingmanipulators
  git-check-ref-format                    purehelpers
@@@ -25,9 -26,6 +26,9 @@@ git-commi
  git-commit-tree                         plumbingmanipulators
  git-config                              ancillarymanipulators
  git-count-objects                       ancillaryinterrogators
 +git-credential                          purehelpers
 +git-credential-cache                    purehelpers
 +git-credential-store                    purehelpers
  git-cvsexportcommit                     foreignscminterface
  git-cvsimport                           foreignscminterface
  git-cvsserver                           foreignscminterface
@@@ -116,7 -114,6 +117,7 @@@ git-sho
  git-show-branch                         ancillaryinterrogators
  git-show-index                          plumbinginterrogators
  git-show-ref                            plumbinginterrogators
 +git-sh-i18n                             purehelpers
  git-sh-setup                            purehelpers
  git-stash                               mainporcelain
  git-status                              mainporcelain common
index 14dd5e7ca272350b3fa13d6fc8da3ccb46e12227,1fb896b8c53a30f42c14e6bd9c947b1ff07bed75..7147d64af20f8db8daa65958d68adb0802605303
mode 100644,100755..100644
  #    1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
  #    2) Add the following line to your .bashrc/.zshrc:
  #        source ~/.git-completion.sh
 -#
 -#    3) Consider changing your PS1 to also show the current branch:
 -#         Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
 -#         ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
 -#
 -#       The argument to __git_ps1 will be displayed only if you
 -#       are currently in a git repository.  The %s token will be
 -#       the name of the current branch.
 -#
 -#       In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
 -#       value, unstaged (*) and staged (+) changes will be shown next
 -#       to the branch name.  You can configure this per-repository
 -#       with the bash.showDirtyState variable, which defaults to true
 -#       once GIT_PS1_SHOWDIRTYSTATE is enabled.
 -#
 -#       You can also see if currently something is stashed, by setting
 -#       GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
 -#       then a '$' will be shown next to the branch name.
 -#
 -#       If you would like to see if there're untracked files, then you can
 -#       set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're
 -#       untracked files, then a '%' will be shown next to the branch name.
 -#
 -#       If you would like to see the difference between HEAD and its
 -#       upstream, set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates
 -#       you are behind, ">" indicates you are ahead, and "<>"
 -#       indicates you have diverged.  You can further control
 -#       behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated
 -#       list of values:
 -#           verbose       show number of commits ahead/behind (+/-) upstream
 -#           legacy        don't use the '--count' option available in recent
 -#                         versions of git-rev-list
 -#           git           always compare HEAD to @{upstream}
 -#           svn           always compare HEAD to your SVN upstream
 -#       By default, __git_ps1 will compare HEAD to your SVN upstream
 -#       if it can find one, or @{upstream} otherwise.  Once you have
 -#       set GIT_PS1_SHOWUPSTREAM, you can override it on a
 -#       per-repository basis by setting the bash.showUpstream config
 -#       variable.
 -#
 -
 -if [[ -n ${ZSH_VERSION-} ]]; then
 -      autoload -U +X bashcompinit && bashcompinit
 -fi
 +#    3) Consider changing your PS1 to also show the current branch,
 +#       see git-prompt.sh for details.
  
  case "$COMP_WORDBREAKS" in
  *:*) : great ;;
@@@ -32,14 -74,9 +32,14 @@@ esa
  # returns location of .git repo
  __gitdir ()
  {
 +      # Note: this function is duplicated in git-prompt.sh
 +      # When updating it, make sure you update the other one to match.
        if [ -z "${1-}" ]; then
                if [ -n "${__git_dir-}" ]; then
                        echo "$__git_dir"
 +              elif [ -n "${GIT_DIR-}" ]; then
 +                      test -d "${GIT_DIR-}" || return 1
 +                      echo "$GIT_DIR"
                elif [ -d .git ]; then
                        echo .git
                else
        fi
  }
  
 -# stores the divergence from upstream in $p
 -# used by GIT_PS1_SHOWUPSTREAM
 -__git_ps1_show_upstream ()
 -{
 -      local key value
 -      local svn_remote svn_url_pattern count n
 -      local upstream=git legacy="" verbose=""
 -
 -      svn_remote=()
 -      # get some config options from git-config
 -      local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
 -      while read -r key value; do
 -              case "$key" in
 -              bash.showupstream)
 -                      GIT_PS1_SHOWUPSTREAM="$value"
 -                      if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
 -                              p=""
 -                              return
 -                      fi
 -                      ;;
 -              svn-remote.*.url)
 -                      svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
 -                      svn_url_pattern+="\\|$value"
 -                      upstream=svn+git # default upstream is SVN if available, else git
 -                      ;;
 -              esac
 -      done <<< "$output"
 -
 -      # parse configuration values
 -      for option in ${GIT_PS1_SHOWUPSTREAM}; do
 -              case "$option" in
 -              git|svn) upstream="$option" ;;
 -              verbose) verbose=1 ;;
 -              legacy)  legacy=1  ;;
 -              esac
 -      done
 -
 -      # Find our upstream
 -      case "$upstream" in
 -      git)    upstream="@{upstream}" ;;
 -      svn*)
 -              # get the upstream from the "git-svn-id: ..." in a commit message
 -              # (git-svn uses essentially the same procedure internally)
 -              local svn_upstream=($(git log --first-parent -1 \
 -                                      --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
 -              if [[ 0 -ne ${#svn_upstream[@]} ]]; then
 -                      svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
 -                      svn_upstream=${svn_upstream%@*}
 -                      local n_stop="${#svn_remote[@]}"
 -                      for ((n=1; n <= n_stop; n++)); do
 -                              svn_upstream=${svn_upstream#${svn_remote[$n]}}
 -                      done
 -
 -                      if [[ -z "$svn_upstream" ]]; then
 -                              # default branch name for checkouts with no layout:
 -                              upstream=${GIT_SVN_ID:-git-svn}
 -                      else
 -                              upstream=${svn_upstream#/}
 -                      fi
 -              elif [[ "svn+git" = "$upstream" ]]; then
 -                      upstream="@{upstream}"
 -              fi
 -              ;;
 -      esac
 -
 -      # Find how many commits we are ahead/behind our upstream
 -      if [[ -z "$legacy" ]]; then
 -              count="$(git rev-list --count --left-right \
 -                              "$upstream"...HEAD 2>/dev/null)"
 -      else
 -              # produce equivalent output to --count for older versions of git
 -              local commits
 -              if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
 -              then
 -                      local commit behind=0 ahead=0
 -                      for commit in $commits
 -                      do
 -                              case "$commit" in
 -                              "<"*) ((behind++)) ;;
 -                              *)    ((ahead++))  ;;
 -                              esac
 -                      done
 -                      count="$behind  $ahead"
 -              else
 -                      count=""
 -              fi
 -      fi
 -
 -      # calculate the result
 -      if [[ -z "$verbose" ]]; then
 -              case "$count" in
 -              "") # no upstream
 -                      p="" ;;
 -              "0      0") # equal to upstream
 -                      p="=" ;;
 -              "0      "*) # ahead of upstream
 -                      p=">" ;;
 -              *"      0") # behind upstream
 -                      p="<" ;;
 -              *)          # diverged from upstream
 -                      p="<>" ;;
 -              esac
 -      else
 -              case "$count" in
 -              "") # no upstream
 -                      p="" ;;
 -              "0      0") # equal to upstream
 -                      p=" u=" ;;
 -              "0      "*) # ahead of upstream
 -                      p=" u+${count#0 }" ;;
 -              *"      0") # behind upstream
 -                      p=" u-${count%  0}" ;;
 -              *)          # diverged from upstream
 -                      p=" u+${count#* }-${count%      *}" ;;
 -              esac
 -      fi
 -
 -}
 -
 -
 -# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
 -# returns text to add to bash PS1 prompt (includes branch name)
 -__git_ps1 ()
 -{
 -      local g="$(__gitdir)"
 -      if [ -n "$g" ]; then
 -              local r=""
 -              local b=""
 -              if [ -f "$g/rebase-merge/interactive" ]; then
 -                      r="|REBASE-i"
 -                      b="$(cat "$g/rebase-merge/head-name")"
 -              elif [ -d "$g/rebase-merge" ]; then
 -                      r="|REBASE-m"
 -                      b="$(cat "$g/rebase-merge/head-name")"
 -              else
 -                      if [ -d "$g/rebase-apply" ]; then
 -                              if [ -f "$g/rebase-apply/rebasing" ]; then
 -                                      r="|REBASE"
 -                              elif [ -f "$g/rebase-apply/applying" ]; then
 -                                      r="|AM"
 -                              else
 -                                      r="|AM/REBASE"
 -                              fi
 -                      elif [ -f "$g/MERGE_HEAD" ]; then
 -                              r="|MERGING"
 -                      elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
 -                              r="|CHERRY-PICKING"
 -                      elif [ -f "$g/BISECT_LOG" ]; then
 -                              r="|BISECTING"
 -                      fi
 -
 -                      b="$(git symbolic-ref HEAD 2>/dev/null)" || {
 -
 -                              b="$(
 -                              case "${GIT_PS1_DESCRIBE_STYLE-}" in
 -                              (contains)
 -                                      git describe --contains HEAD ;;
 -                              (branch)
 -                                      git describe --contains --all HEAD ;;
 -                              (describe)
 -                                      git describe HEAD ;;
 -                              (* | default)
 -                                      git describe --tags --exact-match HEAD ;;
 -                              esac 2>/dev/null)" ||
 -
 -                              b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
 -                              b="unknown"
 -                              b="($b)"
 -                      }
 -              fi
 -
 -              local w=""
 -              local i=""
 -              local s=""
 -              local u=""
 -              local c=""
 -              local p=""
 -
 -              if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
 -                      if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
 -                              c="BARE:"
 -                      else
 -                              b="GIT_DIR!"
 -                      fi
 -              elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
 -                      if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
 -                              if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
 -                                      git diff --no-ext-diff --quiet --exit-code || w="*"
 -                                      if git rev-parse --quiet --verify HEAD >/dev/null; then
 -                                              git diff-index --cached --quiet HEAD -- || i="+"
 -                                      else
 -                                              i="#"
 -                                      fi
 -                              fi
 -                      fi
 -                      if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
 -                              git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
 -                      fi
 -
 -                      if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
 -                              if [ -n "$(git ls-files --others --exclude-standard)" ]; then
 -                                      u="%"
 -                              fi
 -                      fi
 -
 -                      if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
 -                              __git_ps1_show_upstream
 -                      fi
 -              fi
 -
 -              local f="$w$i$s$u"
 -              printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
 -      fi
 -}
 -
  __gitcomp_1 ()
  {
        local c IFS=$' \t\n'
@@@ -165,6 -417,7 +165,6 @@@ __git_reassemble_comp_words_by_ref(
  }
  
  if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
 -if [[ -z ${ZSH_VERSION:+set} ]]; then
  _get_comp_words_by_ref ()
  {
        local exclude cur_ words_ cword_
                shift
        done
  }
 -else
 -_get_comp_words_by_ref ()
 -{
 -      while [ $# -gt 0 ]; do
 -              case "$1" in
 -              cur)
 -                      cur=${COMP_WORDS[COMP_CWORD]}
 -                      ;;
 -              prev)
 -                      prev=${COMP_WORDS[COMP_CWORD-1]}
 -                      ;;
 -              words)
 -                      words=("${COMP_WORDS[@]}")
 -                      ;;
 -              cword)
 -                      cword=$COMP_CWORD
 -                      ;;
 -              -n)
 -                      # assume COMP_WORDBREAKS is already set sanely
 -                      shift
 -                      ;;
 -              esac
 -              shift
 -      done
 -}
 -fi
  fi
  
  # Generates completion reply with compgen, appending a space to possible
@@@ -290,7 -569,7 +290,7 @@@ __git_refs (
                                if [[ "$ref" == "$cur"* ]]; then
                                        echo "$ref"
                                fi
 -                      done | uniq -u
 +                      done | sort | uniq -u
                fi
                return
        fi
@@@ -397,7 -676,7 +397,7 @@@ __git_complete_revlist_file (
                *)   pfx="$ref:$pfx" ;;
                esac
  
 -              __gitcomp_nl "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
 +              __gitcomp_nl "$(git --git-dir="$(__gitdir)" ls-tree "$ls" 2>/dev/null \
                                | sed '/^100... blob /{
                                           s,^.*        ,,
                                           s,$, ,
@@@ -554,7 -833,7 +554,7 @@@ __git_list_porcelain_commands (
  {
        local i IFS=" "$'\n'
        __git_compute_all_commands
 -      for i in "help" $__git_all_commands
 +      for i in $__git_all_commands
        do
                case $i in
                *--*)             : helper pattern;;
                archimport)       : import;;
                cat-file)         : plumbing;;
                check-attr)       : plumbing;;
+               check-ignore)     : plumbing;;
                check-ref-format) : plumbing;;
                checkout-index)   : plumbing;;
                commit-tree)      : plumbing;;
@@@ -844,15 -1124,11 +845,15 @@@ _git_branch (
        done
  
        case "$cur" in
 +      --set-upstream-to=*)
 +              __gitcomp "$(__git_refs)" "" "${cur##--set-upstream-to=}"
 +              ;;
        --*)
                __gitcomp "
                        --color --no-color --verbose --abbrev= --no-abbrev
                        --track --no-track --contains --merged --no-merged
 -                      --set-upstream --edit-description --list
 +                      --set-upstream-to= --edit-description --list
 +                      --unset-upstream
                        "
                ;;
        *)
@@@ -958,8 -1234,6 +959,8 @@@ _git_clone (
                        --upload-pack
                        --template=
                        --depth
 +                      --single-branch
 +                      --branch
                        "
                return
                ;;
@@@ -971,13 -1245,6 +972,13 @@@ _git_commit (
  {
        __git_has_doubledash && return
  
 +      case "$prev" in
 +      -c|-C)
 +              __gitcomp_nl "$(__git_refs)" "" "${cur}"
 +              return
 +              ;;
 +      esac
 +
        case "$cur" in
        --cleanup=*)
                __gitcomp "default strip verbatim whitespace
        --*)
                __gitcomp "
                        --all --author= --signoff --verify --no-verify
 -                      --edit --amend --include --only --interactive
 +                      --edit --no-edit
 +                      --amend --include --only --interactive
                        --dry-run --reuse-message= --reedit-message=
                        --reset-author --file= --message= --template=
                        --cleanup= --untracked-files --untracked-files=
@@@ -1054,7 -1320,7 +1055,7 @@@ _git_diff (
  }
  
  __git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
 -                      tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3
 +                      tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare
  "
  
  _git_difftool ()
@@@ -1094,14 -1360,6 +1095,14 @@@ _git_fetch (
        __git_complete_remote_or_refspec
  }
  
 +__git_format_patch_options="
 +      --stdout --attach --no-attach --thread --thread= --output-directory
 +      --numbered --start-number --numbered-files --keep-subject --signoff
 +      --signature --no-signature --in-reply-to= --cc= --full-index --binary
 +      --not --all --cover-letter --no-prefix --src-prefix= --dst-prefix=
 +      --inline --suffix= --ignore-if-in-upstream --subject-prefix=
 +"
 +
  _git_format_patch ()
  {
        case "$cur" in
                return
                ;;
        --*)
 -              __gitcomp "
 -                      --stdout --attach --no-attach --thread --thread=
 -                      --output-directory
 -                      --numbered --start-number
 -                      --numbered-files
 -                      --keep-subject
 -                      --signoff --signature --no-signature
 -                      --in-reply-to= --cc=
 -                      --full-index --binary
 -                      --not --all
 -                      --cover-letter
 -                      --no-prefix --src-prefix= --dst-prefix=
 -                      --inline --suffix= --ignore-if-in-upstream
 -                      --subject-prefix=
 -                      "
 +              __gitcomp "$__git_format_patch_options"
                return
                ;;
        esac
@@@ -1526,12 -1798,6 +1527,12 @@@ _git_send_email (
                __gitcomp "ssl tls" "" "${cur##--smtp-encryption=}"
                return
                ;;
 +      --thread=*)
 +              __gitcomp "
 +                      deep shallow
 +                      " "" "${cur##--thread=}"
 +              return
 +              ;;
        --*)
                __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to
                        --compose --confirm= --dry-run --envelope-sender
                        --signed-off-by-cc --smtp-pass --smtp-server
                        --smtp-server-port --smtp-encryption= --smtp-user
                        --subject --suppress-cc= --suppress-from --thread --to
 -                      --validate --no-validate"
 +                      --validate --no-validate
 +                      $__git_format_patch_options"
                return
                ;;
        esac
 -      COMPREPLY=()
 +      __git_complete_revlist
  }
  
  _git_stage ()
@@@ -2016,7 -2281,7 +2017,7 @@@ _git_config (
  
  _git_remote ()
  {
 -      local subcommands="add rename rm set-head set-branches set-url show prune update"
 +      local subcommands="add rename remove set-head set-branches set-url show prune update"
        local subcommand="$(__git_find_on_cmdline "$subcommands")"
        if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
        fi
  
        case "$subcommand" in
 -      rename|rm|set-url|show|prune)
 +      rename|remove|set-url|show|prune)
                __gitcomp_nl "$(__git_remotes)"
                ;;
        set-head|set-branches)
@@@ -2408,71 -2673,20 +2409,71 @@@ __gitk_main (
        __git_complete_revlist
  }
  
 -__git_func_wrap ()
 -{
 -      if [[ -n ${ZSH_VERSION-} ]]; then
 -              emulate -L bash
 -              setopt KSH_TYPESET
 +if [[ -n ${ZSH_VERSION-} ]]; then
 +      echo "WARNING: this script is deprecated, please see git-completion.zsh" 1>&2
  
 -              # workaround zsh's bug that leaves 'words' as a special
 -              # variable in versions < 4.3.12
 -              typeset -h words
 +      autoload -U +X compinit && compinit
  
 -              # workaround zsh's bug that quotes spaces in the COMPREPLY
 -              # array if IFS doesn't contain spaces.
 -              typeset -h IFS
 -      fi
 +      __gitcomp ()
 +      {
 +              emulate -L zsh
 +
 +              local cur_="${3-$cur}"
 +
 +              case "$cur_" in
 +              --*=)
 +                      ;;
 +              *)
 +                      local c IFS=$' \t\n'
 +                      local -a array
 +                      for c in ${=1}; do
 +                              c="$c${4-}"
 +                              case $c in
 +                              --*=*|*.) ;;
 +                              *) c="$c " ;;
 +                              esac
 +                              array+=("$c")
 +                      done
 +                      compset -P '*[=:]'
 +                      compadd -Q -S '' -p "${2-}" -a -- array && _ret=0
 +                      ;;
 +              esac
 +      }
 +
 +      __gitcomp_nl ()
 +      {
 +              emulate -L zsh
 +
 +              local IFS=$'\n'
 +              compset -P '*[=:]'
 +              compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0
 +      }
 +
 +      __git_zsh_helper ()
 +      {
 +              emulate -L ksh
 +              local cur cword prev
 +              cur=${words[CURRENT-1]}
 +              prev=${words[CURRENT-2]}
 +              let cword=CURRENT-1
 +              __${service}_main
 +      }
 +
 +      _git ()
 +      {
 +              emulate -L zsh
 +              local _ret=1
 +              __git_zsh_helper
 +              let _ret && _default -S '' && _ret=0
 +              return _ret
 +      }
 +
 +      compdef _git git gitk
 +      return
 +fi
 +
 +__git_func_wrap ()
 +{
        local cur words cword prev
        _get_comp_words_by_ref -n =: cur words cword prev
        $1
diff --combined dir.c
index 9dde68a2f3a1a325d2c5b90fa4d20dbf7670652c,547b83f210e0907eaa2ae424bf417636b24de982..cf1e6b0082381670809a4293c4a49cfef681d756
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -10,7 -10,6 +10,7 @@@
  #include "cache.h"
  #include "dir.h"
  #include "refs.h"
 +#include "wildmatch.h"
  
  struct path_simplify {
        int len;
@@@ -37,33 -36,10 +37,33 @@@ int fnmatch_icase(const char *pattern, 
        return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0));
  }
  
 +inline int git_fnmatch(const char *pattern, const char *string,
 +                     int flags, int prefix)
 +{
 +      int fnm_flags = 0;
 +      if (flags & GFNM_PATHNAME)
 +              fnm_flags |= FNM_PATHNAME;
 +      if (prefix > 0) {
 +              if (strncmp(pattern, string, prefix))
 +                      return FNM_NOMATCH;
 +              pattern += prefix;
 +              string += prefix;
 +      }
 +      if (flags & GFNM_ONESTAR) {
 +              int pattern_len = strlen(++pattern);
 +              int string_len = strlen(string);
 +              return string_len < pattern_len ||
 +                     strcmp(pattern,
 +                            string + string_len - pattern_len);
 +      }
 +      return fnmatch(pattern, string, fnm_flags);
 +}
 +
  static size_t common_prefix_len(const char **pathspec)
  {
        const char *n, *first;
        size_t max = 0;
 +      int literal = limit_pathspec_to_literal();
  
        if (!pathspec)
                return max;
@@@ -73,7 -49,7 +73,7 @@@
                size_t i, len = 0;
                for (i = 0; first == n || i < max; i++) {
                        char c = n[i];
 -                      if (!c || c != first[i] || is_glob_special(c))
 +                      if (!c || c != first[i] || (!literal && is_glob_special(c)))
                                break;
                        if (c == '/')
                                len = i + 1;
@@@ -143,7 -119,6 +143,7 @@@ int within_depth(const char *name, int 
  static int match_one(const char *match, const char *name, int namelen)
  {
        int matchlen;
 +      int literal = limit_pathspec_to_literal();
  
        /* If the match was just the prefix, we matched */
        if (!*match)
                for (;;) {
                        unsigned char c1 = tolower(*match);
                        unsigned char c2 = tolower(*name);
 -                      if (c1 == '\0' || is_glob_special(c1))
 +                      if (c1 == '\0' || (!literal && is_glob_special(c1)))
                                break;
                        if (c1 != c2)
                                return 0;
                for (;;) {
                        unsigned char c1 = *match;
                        unsigned char c2 = *name;
 -                      if (c1 == '\0' || is_glob_special(c1))
 +                      if (c1 == '\0' || (!literal && is_glob_special(c1)))
                                break;
                        if (c1 != c2)
                                return 0;
                }
        }
  
 -
        /*
         * If we don't match the matchstring exactly,
         * we need to match by fnmatch
         */
        matchlen = strlen(match);
 -      if (strncmp_icase(match, name, matchlen))
 +      if (strncmp_icase(match, name, matchlen)) {
 +              if (literal)
 +                      return 0;
                return !fnmatch_icase(match, name, 0) ? MATCHED_FNMATCH : 0;
 +      }
  
        if (namelen == matchlen)
                return MATCHED_EXACTLY;
  }
  
  /*
-  * Given a name and a list of pathspecs, see if the name matches
-  * any of the pathspecs.  The caller is also interested in seeing
-  * all pathspec matches some names it calls this function with
-  * (otherwise the user could have mistyped the unmatched pathspec),
-  * and a mark is left in seen[] array for pathspec element that
-  * actually matched anything.
+  * Given a name and a list of pathspecs, returns the nature of the
+  * closest (i.e. most specific) match of the name to any of the
+  * pathspecs.
+  *
+  * The caller typically calls this multiple times with the same
+  * pathspec and seen[] array but with different name/namelen
+  * (e.g. entries from the index) and is interested in seeing if and
+  * how each pathspec matches all the names it calls this function
+  * with.  A mark is left in the seen[] array for each pathspec element
+  * indicating the closest type of match that element achieved, so if
+  * seen[n] remains zero after multiple invocations, that means the nth
+  * pathspec did not match any names, which could indicate that the
+  * user mistyped the nth pathspec.
   */
  int match_pathspec(const char **pathspec, const char *name, int namelen,
                int prefix, char *seen)
@@@ -259,22 -239,26 +266,29 @@@ static int match_pathspec_item(const st
                        return MATCHED_RECURSIVELY;
        }
  
 -      if (item->use_wildcard && !fnmatch(match, name, 0))
 +      if (item->nowildcard_len < item->len &&
 +          !git_fnmatch(match, name,
 +                       item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,
 +                       item->nowildcard_len - prefix))
                return MATCHED_FNMATCH;
  
        return 0;
  }
  
  /*
-  * Given a name and a list of pathspecs, see if the name matches
-  * any of the pathspecs.  The caller is also interested in seeing
-  * all pathspec matches some names it calls this function with
-  * (otherwise the user could have mistyped the unmatched pathspec),
-  * and a mark is left in seen[] array for pathspec element that
-  * actually matched anything.
+  * Given a name and a list of pathspecs, returns the nature of the
+  * closest (i.e. most specific) match of the name to any of the
+  * pathspecs.
+  *
+  * The caller typically calls this multiple times with the same
+  * pathspec and seen[] array but with different name/namelen
+  * (e.g. entries from the index) and is interested in seeing if and
+  * how each pathspec matches all the names it calls this function
+  * with.  A mark is left in the seen[] array for each pathspec element
+  * indicating the closest type of match that element achieved, so if
+  * seen[n] remains zero after multiple invocations, that means the nth
+  * pathspec did not match any names, which could indicate that the
+  * user mistyped the nth pathspec.
   */
  int match_pathspec_depth(const struct pathspec *ps,
                         const char *name, int namelen,
@@@ -379,7 -363,7 +393,7 @@@ void parse_exclude_pattern(const char *
  }
  
  void add_exclude(const char *string, const char *base,
-                int baselen, struct exclude_list *el)
+                int baselen, struct exclude_list *el, int srcpos)
  {
        struct exclude *x;
        int patternlen;
        x->base = base;
        x->baselen = baselen;
        x->flags = flags;
+       x->srcpos = srcpos;
        ALLOC_GROW(el->excludes, el->nr + 1, el->alloc);
        el->excludes[el->nr++] = x;
+       x->el = el;
  }
  
  static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
@@@ -441,27 -427,26 +457,28 @@@ void clear_exclude_list(struct exclude_
        for (i = 0; i < el->nr; i++)
                free(el->excludes[i]);
        free(el->excludes);
+       free(el->filebuf);
  
        el->nr = 0;
        el->excludes = NULL;
+       el->filebuf = NULL;
  }
  
  int add_excludes_from_file_to_list(const char *fname,
                                   const char *base,
                                   int baselen,
-                                  char **buf_p,
                                   struct exclude_list *el,
                                   int check_index)
  {
        struct stat st;
-       int fd, i;
+       int fd, i, lineno = 1;
        size_t size = 0;
        char *buf, *entry;
  
        fd = open(fname, O_RDONLY);
        if (fd < 0 || fstat(fd, &st) < 0) {
 +              if (errno != ENOENT)
 +                      warn_on_inaccessible(fname);
                if (0 <= fd)
                        close(fd);
                if (!check_index ||
                close(fd);
        }
  
-       if (buf_p)
-               *buf_p = buf;
+       el->filebuf = buf;
        entry = buf;
        for (i = 0; i < size; i++) {
                if (buf[i] == '\n') {
                        if (entry != buf + i && entry[0] != '#') {
                                buf[i - (i && buf[i-1] == '\r')] = 0;
-                               add_exclude(entry, base, baselen, el);
+                               add_exclude(entry, base, baselen, el, lineno);
                        }
+                       lineno++;
                        entry = buf + i + 1;
                }
        }
        return 0;
  }
  
+ struct exclude_list *add_exclude_list(struct dir_struct *dir,
+                                     int group_type, const char *src)
+ {
+       struct exclude_list *el;
+       struct exclude_list_group *group;
+       group = &dir->exclude_list_group[group_type];
+       ALLOC_GROW(group->el, group->nr + 1, group->alloc);
+       el = &group->el[group->nr++];
+       memset(el, 0, sizeof(*el));
+       el->src = src;
+       return el;
+ }
+ /*
+  * Used to set up core.excludesfile and .git/info/exclude lists.
+  */
  void add_excludes_from_file(struct dir_struct *dir, const char *fname)
  {
-       if (add_excludes_from_file_to_list(fname, "", 0, NULL,
-                                          &dir->exclude_list[EXC_FILE], 0) < 0)
+       struct exclude_list *el;
+       el = add_exclude_list(dir, EXC_FILE, fname);
+       if (add_excludes_from_file_to_list(fname, "", 0, el, 0) < 0)
                die("cannot use %s as an exclude file", fname);
  }
  
   */
  static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
  {
+       struct exclude_list_group *group;
        struct exclude_list *el;
        struct exclude_stack *stk = NULL;
        int current;
            (baselen + strlen(dir->exclude_per_dir) >= PATH_MAX))
                return; /* too long a path -- ignore */
  
-       /* Pop the directories that are not the prefix of the path being checked. */
-       el = &dir->exclude_list[EXC_DIRS];
+       group = &dir->exclude_list_group[EXC_DIRS];
+       /* Pop the exclude lists from the EXCL_DIRS exclude_list_group
+        * which originate from directories not in the prefix of the
+        * path being checked. */
        while ((stk = dir->exclude_stack) != NULL) {
                if (stk->baselen <= baselen &&
                    !strncmp(dir->basebuf, base, stk->baselen))
                        break;
+               el = &group->el[dir->exclude_stack->exclude_ix];
                dir->exclude_stack = stk->prev;
-               while (stk->exclude_ix < el->nr)
-                       free(el->excludes[--el->nr]);
-               free(stk->filebuf);
+               free((char *)el->src); /* see strdup() below */
+               clear_exclude_list(el);
                free(stk);
+               group->nr--;
        }
  
        /* Read from the parent directories and push them down. */
                }
                stk->prev = dir->exclude_stack;
                stk->baselen = cp - base;
-               stk->exclude_ix = el->nr;
                memcpy(dir->basebuf + current, base + current,
                       stk->baselen - current);
                strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
+               /*
+                * dir->basebuf gets reused by the traversal, but we
+                * need fname to remain unchanged to ensure the src
+                * member of each struct exclude correctly
+                * back-references its source file.  Other invocations
+                * of add_exclude_list provide stable strings, so we
+                * strdup() and free() here in the caller.
+                */
+               el = add_exclude_list(dir, EXC_DIRS, strdup(dir->basebuf));
+               stk->exclude_ix = group->nr - 1;
                add_excludes_from_file_to_list(dir->basebuf,
                                               dir->basebuf, stk->baselen,
-                                              &stk->filebuf, el, 1);
+                                              el, 1);
                dir->exclude_stack = stk;
                current = stk->baselen;
        }
@@@ -635,8 -652,7 +684,8 @@@ int match_pathname(const char *pathname
                namelen -= prefix;
        }
  
 -      return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0;
 +      return wildmatch(pattern, name,
 +                       ignore_case ? FNM_CASEFOLD : 0) == 0;
  }
  
  /*
@@@ -712,18 -728,23 +761,23 @@@ static struct exclude *last_exclude_mat
                                             int *dtype_p)
  {
        int pathlen = strlen(pathname);
-       int st;
+       int i, j;
+       struct exclude_list_group *group;
        struct exclude *exclude;
        const char *basename = strrchr(pathname, '/');
        basename = (basename) ? basename+1 : pathname;
  
        prep_exclude(dir, pathname, basename-pathname);
-       for (st = EXC_CMDL; st <= EXC_FILE; st++) {
-               exclude = last_exclude_matching_from_list(
-                       pathname, pathlen, basename, dtype_p,
-                       &dir->exclude_list[st]);
-               if (exclude)
-                       return exclude;
+       for (i = EXC_CMDL; i <= EXC_FILE; i++) {
+               group = &dir->exclude_list_group[i];
+               for (j = group->nr - 1; j >= 0; j--) {
+                       exclude = last_exclude_matching_from_list(
+                               pathname, pathlen, basename, dtype_p,
+                               &group->el[j]);
+                       if (exclude)
+                               return exclude;
+               }
        }
        return NULL;
  }
@@@ -842,8 -863,7 +896,8 @@@ static struct dir_entry *dir_entry_new(
  
  static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
  {
 -      if (cache_name_exists(pathname, len, ignore_case))
 +      if (!(dir->flags & DIR_SHOW_IGNORED) &&
 +          cache_name_exists(pathname, len, ignore_case))
                return NULL;
  
        ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
@@@ -945,9 -965,8 +999,9 @@@ static enum exist_status directory_exis
   * traversal routine.
   *
   * Case 1: If we *already* have entries in the index under that
 - * directory name, we always recurse into the directory to see
 - * all the files.
 + * directory name, we recurse into the directory to see all the files,
 + * unless the directory is excluded and we want to show ignored
 + * directories
   *
   * Case 2: If we *already* have that directory name as a gitlink,
   * we always continue to see it as a gitlink, regardless of whether
   *      just a directory, unless "hide_empty_directories" is
   *      also true and the directory is empty, in which case
   *      we just ignore it entirely.
 + *      if we are looking for ignored directories, look if it
 + *      contains only ignored files to decide if it must be shown as
 + *      ignored or not.
   *  (b) if it looks like a git directory, and we don't have
   *      'no_gitlinks' set we treat it as a gitlink, and show it
   *      as a directory.
@@@ -976,15 -992,12 +1030,15 @@@ enum directory_treatment 
  };
  
  static enum directory_treatment treat_directory(struct dir_struct *dir,
 -      const char *dirname, int len,
 +      const char *dirname, int len, int exclude,
        const struct path_simplify *simplify)
  {
        /* The "len-1" is to strip the final '/' */
        switch (directory_exists_in_index(dirname, len-1)) {
        case index_directory:
 +              if ((dir->flags & DIR_SHOW_OTHER_DIRECTORIES) && exclude)
 +                      break;
 +
                return recurse_into_directory;
  
        case index_gitdir:
        }
  
        /* This is the "show_other_directories" case */
 -      if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
 +
 +      /*
 +       * We are looking for ignored files and our directory is not ignored,
 +       * check if it contains only ignored files
 +       */
 +      if ((dir->flags & DIR_SHOW_IGNORED) && !exclude) {
 +              int ignored;
 +              dir->flags &= ~DIR_SHOW_IGNORED;
 +              dir->flags |= DIR_HIDE_EMPTY_DIRECTORIES;
 +              ignored = read_directory_recursive(dir, dirname, len, 1, simplify);
 +              dir->flags &= ~DIR_HIDE_EMPTY_DIRECTORIES;
 +              dir->flags |= DIR_SHOW_IGNORED;
 +
 +              return ignored ? ignore_directory : show_directory;
 +      }
 +      if (!(dir->flags & DIR_SHOW_IGNORED) &&
 +          !(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
                return show_directory;
        if (!read_directory_recursive(dir, dirname, len, 1, simplify))
                return ignore_directory;
        return show_directory;
  }
  
 +/*
 + * Decide what to do when we find a file while traversing the
 + * filesystem. Mostly two cases:
 + *
 + *  1. We are looking for ignored files
 + *   (a) File is ignored, include it
 + *   (b) File is in ignored path, include it
 + *   (c) File is not ignored, exclude it
 + *
 + *  2. Other scenarios, include the file if not excluded
 + *
 + * Return 1 for exclude, 0 for include.
 + */
 +static int treat_file(struct dir_struct *dir, struct strbuf *path, int exclude, int *dtype)
 +{
 +      struct path_exclude_check check;
 +      int exclude_file = 0;
 +
 +      if (exclude)
 +              exclude_file = !(dir->flags & DIR_SHOW_IGNORED);
 +      else if (dir->flags & DIR_SHOW_IGNORED) {
 +              /* Always exclude indexed files */
 +              struct cache_entry *ce = index_name_exists(&the_index,
 +                  path->buf, path->len, ignore_case);
 +
 +              if (ce)
 +                      return 1;
 +
 +              path_exclude_check_init(&check, dir);
 +
 +              if (!is_path_excluded(&check, path->buf, path->len, dtype))
 +                      exclude_file = 1;
 +
 +              path_exclude_check_clear(&check);
 +      }
 +
 +      return exclude_file;
 +}
 +
  /*
   * This is an inexact early pruning of any recursive directory
   * reading - if the path cannot possibly be in the pathspec,
@@@ -1204,14 -1162,27 +1258,14 @@@ static enum path_treatment treat_one_pa
        if (dtype == DT_UNKNOWN)
                dtype = get_dtype(de, path->buf, path->len);
  
 -      /*
 -       * Do we want to see just the ignored files?
 -       * We still need to recurse into directories,
 -       * even if we don't ignore them, since the
 -       * directory may contain files that we do..
 -       */
 -      if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) {
 -              if (dtype != DT_DIR)
 -                      return path_ignored;
 -      }
 -
        switch (dtype) {
        default:
                return path_ignored;
        case DT_DIR:
                strbuf_addch(path, '/');
 -              switch (treat_directory(dir, path->buf, path->len, simplify)) {
 +
 +              switch (treat_directory(dir, path->buf, path->len, exclude, simplify)) {
                case show_directory:
 -                      if (exclude != !!(dir->flags
 -                                        & DIR_SHOW_IGNORED))
 -                              return path_ignored;
                        break;
                case recurse_into_directory:
                        return path_recurse;
                break;
        case DT_REG:
        case DT_LNK:
 -              break;
 +              switch (treat_file(dir, path, exclude, &dtype)) {
 +              case 1:
 +                      return path_ignored;
 +              default:
 +                      break;
 +              }
        }
        return path_handled;
  }
@@@ -1530,17 -1496,12 +1584,17 @@@ int remove_dir_recursively(struct strbu
  void setup_standard_excludes(struct dir_struct *dir)
  {
        const char *path;
 +      char *xdg_path;
  
        dir->exclude_per_dir = ".gitignore";
        path = git_path("info/exclude");
 -      if (!access(path, R_OK))
 +      if (!excludes_file) {
 +              home_config_paths(NULL, &xdg_path, "ignore");
 +              excludes_file = xdg_path;
 +      }
 +      if (!access_or_warn(path, R_OK))
                add_excludes_from_file(dir, path);
 -      if (excludes_file && !access(excludes_file, R_OK))
 +      if (excludes_file && !access_or_warn(excludes_file, R_OK))
                add_excludes_from_file(dir, excludes_file);
  }
  
@@@ -1594,18 -1555,9 +1648,18 @@@ int init_pathspec(struct pathspec *path
  
                item->match = path;
                item->len = strlen(path);
 -              item->use_wildcard = !no_wildcard(path);
 -              if (item->use_wildcard)
 -                      pathspec->has_wildcard = 1;
 +              item->flags = 0;
 +              if (limit_pathspec_to_literal()) {
 +                      item->nowildcard_len = item->len;
 +              } else {
 +                      item->nowildcard_len = simple_length(path);
 +                      if (item->nowildcard_len < item->len) {
 +                              pathspec->has_wildcard = 1;
 +                              if (path[item->nowildcard_len] == '*' &&
 +                                  no_wildcard(path + item->nowildcard_len + 1))
 +                                      item->flags |= PATHSPEC_ONESTAR;
 +                      }
 +              }
        }
  
        qsort(pathspec->items, pathspec->nr,
@@@ -1620,10 -1572,32 +1674,40 @@@ void free_pathspec(struct pathspec *pat
        pathspec->items = NULL;
  }
  
 +int limit_pathspec_to_literal(void)
 +{
 +      static int flag = -1;
 +      if (flag < 0)
 +              flag = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
 +      return flag;
 +}
++
+ /*
+  * Frees memory within dir which was allocated for exclude lists and
+  * the exclude_stack.  Does not free dir itself.
+  */
+ void clear_directory(struct dir_struct *dir)
+ {
+       int i, j;
+       struct exclude_list_group *group;
+       struct exclude_list *el;
+       struct exclude_stack *stk;
+       for (i = EXC_CMDL; i <= EXC_FILE; i++) {
+               group = &dir->exclude_list_group[i];
+               for (j = 0; j < group->nr; j++) {
+                       el = &group->el[j];
+                       if (i == EXC_DIRS)
+                               free((char *)el->src);
+                       clear_exclude_list(el);
+               }
+               free(group->el);
+       }
+       stk = dir->exclude_stack;
+       while (stk) {
+               struct exclude_stack *prev = stk->prev;
+               free(stk);
+               stk = prev;
+       }
+ }
diff --combined dir.h
index ae1bc467ae909e6db151b055e212ded45fac34f6,136e8383fb1dfabce62c3fc5802ac065efd0aefd..c3eb4b520effb63e73653194e4266c0ef628cccd
--- 1/dir.h
--- 2/dir.h
+++ b/dir.h
@@@ -16,21 -16,41 +16,41 @@@ struct dir_entry 
  #define EXC_FLAG_NEGATIVE 16
  
  /*
-  * Each .gitignore file will be parsed into patterns which are then
-  * appended to the relevant exclude_list (either EXC_DIRS or
-  * EXC_FILE).  exclude_lists are also used to represent the list of
-  * --exclude values passed via CLI args (EXC_CMDL).
+  * Each excludes file will be parsed into a fresh exclude_list which
+  * is appended to the relevant exclude_list_group (either EXC_DIRS or
+  * EXC_FILE).  An exclude_list within the EXC_CMDL exclude_list_group
+  * can also be used to represent the list of --exclude values passed
+  * via CLI args.
   */
  struct exclude_list {
        int nr;
        int alloc;
+       /* remember pointer to exclude file contents so we can free() */
+       char *filebuf;
+       /* origin of list, e.g. path to filename, or descriptive string */
+       const char *src;
        struct exclude {
+               /*
+                * This allows callers of last_exclude_matching() etc.
+                * to determine the origin of the matching pattern.
+                */
+               struct exclude_list *el;
                const char *pattern;
                int patternlen;
                int nowildcardlen;
                const char *base;
                int baselen;
                int flags;
+               /*
+                * Counting starts from 1 for line numbers in ignore files,
+                * and from -1 decrementing for patterns from CLI args.
+                */
+               int srcpos;
        } **excludes;
  };
  
   */
  struct exclude_stack {
        struct exclude_stack *prev; /* the struct exclude_stack for the parent directory */
-       char *filebuf; /* remember pointer to per-directory exclude file contents so we can free() */
        int baselen;
-       int exclude_ix;
+       int exclude_ix; /* index of exclude_list within EXC_DIRS exclude_list_group */
+ };
+ struct exclude_list_group {
+       int nr, alloc;
+       struct exclude_list *el;
  };
  
  struct dir_struct {
  
        /* Exclude info */
        const char *exclude_per_dir;
-       struct exclude_list exclude_list[3];
        /*
-        * We maintain three exclude pattern lists:
+        * We maintain three groups of exclude pattern lists:
+        *
         * EXC_CMDL lists patterns explicitly given on the command line.
         * EXC_DIRS lists patterns obtained from per-directory ignore files.
-        * EXC_FILE lists patterns from fallback ignore files.
+        * EXC_FILE lists patterns from fallback ignore files, e.g.
+        *   - .git/info/exclude
+        *   - core.excludesfile
+        *
+        * Each group contains multiple exclude lists, a single list
+        * per source.
         */
  #define EXC_CMDL 0
  #define EXC_DIRS 1
  #define EXC_FILE 2
+       struct exclude_list_group exclude_list_group[3];
  
        /*
         * Temporary variables which are used during loading of the
        char basebuf[PATH_MAX];
  };
  
+ /*
+  * The ordering of these constants is significant, with
+  * higher-numbered match types signifying "closer" (i.e. more
+  * specific) matches which will override lower-numbered match types
+  * when populating the seen[] array.
+  */
  #define MATCHED_RECURSIVELY 1
  #define MATCHED_FNMATCH 2
  #define MATCHED_EXACTLY 3
@@@ -129,13 -166,16 +166,16 @@@ extern struct exclude *last_exclude_mat
  extern int is_path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype);
  
  
+ extern struct exclude_list *add_exclude_list(struct dir_struct *dir,
+                                            int group_type, const char *src);
  extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
-                                         char **buf_p, struct exclude_list *el, int check_index);
+                                         struct exclude_list *el, int check_index);
  extern void add_excludes_from_file(struct dir_struct *, const char *fname);
  extern void parse_exclude_pattern(const char **string, int *patternlen, int *flags, int *nowildcardlen);
  extern void add_exclude(const char *string, const char *base,
-                       int baselen, struct exclude_list *el);
+                       int baselen, struct exclude_list *el, int srcpos);
  extern void clear_exclude_list(struct exclude_list *el);
+ extern void clear_directory(struct dir_struct *dir);
  extern int file_exists(const char *);
  
  extern int is_inside_dir(const char *dir);
@@@ -164,13 -204,4 +204,13 @@@ extern int strcmp_icase(const char *a, 
  extern int strncmp_icase(const char *a, const char *b, size_t count);
  extern int fnmatch_icase(const char *pattern, const char *string, int flags);
  
 +/*
 + * The prefix part of pattern must not contains wildcards.
 + */
 +#define GFNM_PATHNAME 1               /* similar to FNM_PATHNAME */
 +#define GFNM_ONESTAR  2               /* there is only _one_ wildcard, a star */
 +
 +extern int git_fnmatch(const char *pattern, const char *string,
 +                     int flags, int prefix);
 +
  #endif
diff --combined git.c
index ed66c660d15010af9a8b0c2ea1da8839e316e1db,0b31e668533b7fdd9f0c2eb441a0d44b7fb6713a..b10c18b0419904631d7e8fa4a1fd11e8533b3034
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -17,6 -17,39 +17,6 @@@ const char git_more_info_string[] 
  
  static struct startup_info git_startup_info;
  static int use_pager = -1;
 -struct pager_config {
 -      const char *cmd;
 -      int want;
 -      char *value;
 -};
 -
 -static int pager_command_config(const char *var, const char *value, void *data)
 -{
 -      struct pager_config *c = data;
 -      if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd)) {
 -              int b = git_config_maybe_bool(var, value);
 -              if (b >= 0)
 -                      c->want = b;
 -              else {
 -                      c->want = 1;
 -                      c->value = xstrdup(value);
 -              }
 -      }
 -      return 0;
 -}
 -
 -/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
 -int check_pager_config(const char *cmd)
 -{
 -      struct pager_config c;
 -      c.cmd = cmd;
 -      c.want = -1;
 -      c.value = NULL;
 -      git_config(pager_command_config, &c);
 -      if (c.value)
 -              pager_program = c.value;
 -      return c.want;
 -}
  
  static void commit_pager_choice(void) {
        switch (use_pager) {
@@@ -135,14 -168,6 +135,14 @@@ static int handle_options(const char **
                        git_config_push_parameter((*argv)[1]);
                        (*argv)++;
                        (*argc)--;
 +              } else if (!strcmp(cmd, "--literal-pathspecs")) {
 +                      setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "1", 1);
 +                      if (envchanged)
 +                              *envchanged = 1;
 +              } else if (!strcmp(cmd, "--no-literal-pathspecs")) {
 +                      setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "0", 1);
 +                      if (envchanged)
 +                              *envchanged = 1;
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
                        usage(git_usage_string);
@@@ -231,6 -256,8 +231,6 @@@ static int handle_alias(int *argcp, con
        return ret;
  }
  
 -const char git_version_string[] = GIT_VERSION;
 -
  #define RUN_SETUP             (1<<0)
  #define RUN_SETUP_GENTLY      (1<<1)
  #define USE_PAGER             (1<<2)
@@@ -313,6 -340,7 +313,7 @@@ static void handle_internal_command(in
                { "bundle", cmd_bundle, RUN_SETUP_GENTLY },
                { "cat-file", cmd_cat_file, RUN_SETUP },
                { "check-attr", cmd_check_attr, RUN_SETUP },
+               { "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
                { "check-ref-format", cmd_check_ref_format },
                { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
                { "checkout-index", cmd_checkout_index,
                { "commit-tree", cmd_commit_tree, RUN_SETUP },
                { "config", cmd_config, RUN_SETUP_GENTLY },
                { "count-objects", cmd_count_objects, RUN_SETUP },
 +              { "credential", cmd_credential, RUN_SETUP_GENTLY },
                { "describe", cmd_describe, RUN_SETUP },
                { "diff", cmd_diff },
                { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
diff --combined setup.c
index f108c4b990c0e4f6a98c1fe34d3031040c84195a,95701475d58dcf9dd169ae0e07a1003018f19129..1ccfafaa7a85875338a49953518207b74dca62c4
+++ b/setup.c
@@@ -1,6 -1,5 +1,6 @@@
  #include "cache.h"
  #include "dir.h"
 +#include "string-list.h"
  
  static int inside_git_dir = -1;
  static int inside_work_tree = -1;
@@@ -78,6 -77,9 +78,6 @@@ static void NORETURN die_verify_filenam
                                         const char *arg,
                                         int diagnose_misspelt_rev)
  {
 -      unsigned char sha1[20];
 -      unsigned mode;
 -
        if (!diagnose_misspelt_rev)
                die("%s: no such path in the working tree.\n"
                    "Use 'git <command> -- <path>...' to specify paths that do not exist locally.",
         * Saying "'(icase)foo' does not exist in the index" when the
         * user gave us ":(icase)foo" is just stupid.  A magic pathspec
         * begins with a colon and is followed by a non-alnum; do not
 -       * let get_sha1_with_mode_1(only_to_die=1) to even trigger.
 +       * let maybe_die_on_misspelt_object_name() even trigger.
         */
        if (!(arg[0] == ':' && !isalnum(arg[1])))
 -              /* try a detailed diagnostic ... */
 -              get_sha1_with_mode_1(arg, sha1, &mode, 1, prefix);
 +              maybe_die_on_misspelt_object_name(arg, prefix);
  
        /* ... or fall back the most general message. */
        die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
@@@ -246,6 -249,25 +246,25 @@@ static const char *prefix_pathspec(cons
                return prefix_path(prefix, prefixlen, copyfrom);
  }
  
+ /*
+  * N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
+  * based interface - see pathspec_magic above.
+  *
+  * Arguments:
+  *  - prefix - a path relative to the root of the working tree
+  *  - pathspec - a list of paths underneath the prefix path
+  *
+  * Iterates over pathspec, prepending each path with prefix,
+  * and return the resulting list.
+  *
+  * If pathspec is empty, return a singleton list containing prefix.
+  *
+  * If pathspec and prefix are both empty, return an empty list.
+  *
+  * This is typically used by built-in commands such as add.c, in order
+  * to normalize argv arguments provided to the built-in into a list of
+  * paths to process, all relative to the root of the working tree.
+  */
  const char **get_pathspec(const char *prefix, const char **pathspec)
  {
        const char *entry = *pathspec;
@@@ -621,27 -643,6 +640,27 @@@ static dev_t get_device_or_die(const ch
        return buf.st_dev;
  }
  
 +/*
 + * A "string_list_each_func_t" function that canonicalizes an entry
 + * from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or
 + * discards it if unusable.
 + */
 +static int canonicalize_ceiling_entry(struct string_list_item *item,
 +                                    void *unused)
 +{
 +      char *ceil = item->string;
 +      const char *real_path;
 +
 +      if (!*ceil || !is_absolute_path(ceil))
 +              return 0;
 +      real_path = real_path_if_valid(ceil);
 +      if (!real_path)
 +              return 0;
 +      free(item->string);
 +      item->string = xstrdup(real_path);
 +      return 1;
 +}
 +
  /*
   * We cannot decide in this function whether we are in the work tree or
   * not, since the config can only be read _after_ this function was called.
  static const char *setup_git_directory_gently_1(int *nongit_ok)
  {
        const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
 +      struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
        static char cwd[PATH_MAX+1];
        const char *gitdirenv, *ret;
        char *gitfile;
 -      int len, offset, offset_parent, ceil_offset;
 +      int len, offset, offset_parent, ceil_offset = -1;
        dev_t current_device = 0;
        int one_filesystem = 1;
  
        if (gitdirenv)
                return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
  
 -      ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
 +      if (env_ceiling_dirs) {
 +              string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
 +              filter_string_list(&ceiling_dirs, 0,
 +                                 canonicalize_ceiling_entry, NULL);
 +              ceil_offset = longest_ancestor_length(cwd, &ceiling_dirs);
 +              string_list_clear(&ceiling_dirs, 0);
 +      }
 +
        if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
                ceil_offset = 1;
  
diff --combined unpack-trees.c
index 0e1a196ace33110e2bb74cde90d6f62358413ead,de8da4626d400cf09605ac399127cd2327c661d3..09e53df3b2a39e7ec8c7d601c5b8b8ae4de39b9a
@@@ -539,8 -539,7 +539,8 @@@ static struct cache_entry *create_ce_en
        struct cache_entry *ce = xcalloc(1, cache_entry_size(len));
  
        ce->ce_mode = create_ce_mode(n->mode);
 -      ce->ce_flags = create_ce_flags(len, stage);
 +      ce->ce_flags = create_ce_flags(stage);
 +      ce->ce_namelen = len;
        hashcpy(ce->sha1, n->sha1);
        make_traverse_path(ce->name, info, n);
  
@@@ -1020,7 -1019,7 +1020,7 @@@ int unpack_trees(unsigned len, struct t
        if (!core_apply_sparse_checkout || !o->update)
                o->skip_sparse_checkout = 1;
        if (!o->skip_sparse_checkout) {
-               if (add_excludes_from_file_to_list(git_path("info/sparse-checkout"), "", 0, NULL, &el, 0) < 0)
+               if (add_excludes_from_file_to_list(git_path("info/sparse-checkout"), "", 0, &el, 0) < 0)
                        o->skip_sparse_checkout = 1;
                else
                        o->el = &el;
@@@ -1299,7 -1298,7 +1299,7 @@@ static int verify_clean_subdirectory(st
         * First let's make sure we do not have a local modification
         * in that directory.
         */
 -      namelen = strlen(ce->name);
 +      namelen = ce_namelen(ce);
        for (i = locate_in_src_index(ce, o);
             i < o->src_index->cache_nr;
             i++) {
@@@ -1836,7 -1835,7 +1836,7 @@@ int oneway_merge(struct cache_entry **s
  
        if (old && same(old, a)) {
                int update = 0;
 -              if (o->reset && !ce_uptodate(old) && !ce_skip_worktree(old)) {
 +              if (o->reset && o->update && !ce_uptodate(old) && !ce_skip_worktree(old)) {
                        struct stat st;
                        if (lstat(old->name, &st) ||
                            ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))