Merge branch 'nd/sparse'
authorJunio C Hamano <gitster@pobox.com>
Wed, 13 Jan 2010 19:58:34 +0000 (11:58 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 13 Jan 2010 19:58:34 +0000 (11:58 -0800)
* nd/sparse: (25 commits)
t7002: test for not using external grep on skip-worktree paths
t7002: set test prerequisite "external-grep" if supported
grep: do not do external grep on skip-worktree entries
commit: correctly respect skip-worktree bit
ie_match_stat(): do not ignore skip-worktree bit with CE_MATCH_IGNORE_VALID
tests: rename duplicate t1009
sparse checkout: inhibit empty worktree
Add tests for sparse checkout
read-tree: add --no-sparse-checkout to disable sparse checkout support
unpack-trees(): ignore worktree check outside checkout area
unpack_trees(): apply $GIT_DIR/info/sparse-checkout to the final index
unpack-trees(): "enable" sparse checkout and load $GIT_DIR/info/sparse-checkout
unpack-trees.c: generalize verify_* functions
unpack-trees(): add CE_WT_REMOVE to remove on worktree alone
Introduce "sparse checkout"
dir.c: export excluded_1() and add_excludes_from_file_1()
excluded_1(): support exclude files in index
unpack-trees(): carry skip-worktree bit over in merged_entry()
Read .gitignore from index if it is skip-worktree
Avoid writing to buffer in add_excludes_from_file_1()
...

Conflicts:
.gitignore
Documentation/config.txt
Documentation/git-update-index.txt
Makefile
entry.c
t/t7002-grep.sh

25 files changed:
1  2 
.gitignore
Documentation/config.txt
Documentation/git-ls-files.txt
Documentation/git-read-tree.txt
Documentation/git-update-index.txt
Makefile
builtin-apply.c
builtin-clean.c
builtin-commit.c
builtin-grep.c
builtin-ls-files.c
builtin-read-tree.c
builtin-update-index.c
cache.h
config.c
diff-lib.c
diff.c
dir.c
dir.h
entry.c
environment.c
read-cache.c
t/t7002-grep.sh
t/t7300-clean.sh
unpack-trees.c
diff --combined .gitignore
index 5d32289664bbff40f85a450cff7f2261384204b0,e3a864c0ad54754de437b9d5bbbdba89211fe339..0746a4d2090c5387d7dbe6e9e40b529064e18a8d
 -GIT-BUILD-OPTIONS
 -GIT-CFLAGS
 -GIT-GUI-VARS
 -GIT-VERSION-FILE
 -git
 -git-add
 -git-add--interactive
 -git-am
 -git-annotate
 -git-apply
 -git-archimport
 -git-archive
 -git-bisect
 -git-bisect--helper
 -git-blame
 -git-branch
 -git-bundle
 -git-cat-file
 -git-check-attr
 -git-check-ref-format
 -git-checkout
 -git-checkout-index
 -git-cherry
 -git-cherry-pick
 -git-clean
 -git-clone
 -git-commit
 -git-commit-tree
 -git-config
 -git-count-objects
 -git-cvsexportcommit
 -git-cvsimport
 -git-cvsserver
 -git-daemon
 -git-diff
 -git-diff-files
 -git-diff-index
 -git-diff-tree
 -git-difftool
 -git-difftool--helper
 -git-describe
 -git-fast-export
 -git-fast-import
 -git-fetch
 -git-fetch--tool
 -git-fetch-pack
 -git-filter-branch
 -git-fmt-merge-msg
 -git-for-each-ref
 -git-format-patch
 -git-fsck
 -git-fsck-objects
 -git-gc
 -git-get-tar-commit-id
 -git-grep
 -git-hash-object
 -git-help
 -git-http-fetch
 -git-http-push
 -git-imap-send
 -git-index-pack
 -git-init
 -git-init-db
 -git-instaweb
 -git-log
 -git-lost-found
 -git-ls-files
 -git-ls-remote
 -git-ls-tree
 -git-mailinfo
 -git-mailsplit
 -git-merge
 -git-merge-base
 -git-merge-index
 -git-merge-file
 -git-merge-tree
 -git-merge-octopus
 -git-merge-one-file
 -git-merge-ours
 -git-merge-recursive
 -git-merge-resolve
 -git-merge-subtree
 -git-mergetool
 -git-mergetool--lib
 -git-mktag
 -git-mktree
 -git-name-rev
 -git-mv
 -git-pack-redundant
 -git-pack-objects
 -git-pack-refs
 -git-parse-remote
 -git-patch-id
 -git-peek-remote
 -git-prune
 -git-prune-packed
 -git-pull
 -git-push
 -git-quiltimport
 -git-read-tree
 -git-rebase
 -git-rebase--interactive
 -git-receive-pack
 -git-reflog
 -git-relink
 -git-remote
 -git-repack
 -git-repo-config
 -git-request-pull
 -git-rerere
 -git-reset
 -git-rev-list
 -git-rev-parse
 -git-revert
 -git-rm
 -git-send-email
 -git-send-pack
 -git-sh-setup
 -git-shell
 -git-shortlog
 -git-show
 -git-show-branch
 -git-show-index
 -git-show-ref
 -git-stage
 -git-stash
 -git-status
 -git-stripspace
 -git-submodule
 -git-svn
 -git-symbolic-ref
 -git-tag
 -git-tar-tree
 -git-unpack-file
 -git-unpack-objects
 -git-update-index
 -git-update-ref
 -git-update-server-info
 -git-upload-archive
 -git-upload-pack
 -git-var
 -git-verify-pack
 -git-verify-tag
 -git-web--browse
 -git-whatchanged
 -git-write-tree
 -git-core-*/?*
 -gitk-wish
 -gitweb/gitweb.cgi
 -test-chmtime
 -test-ctype
 -test-date
 -test-delta
 -test-dump-cache-tree
 -test-genrandom
 -test-index-version
 -test-match-trees
 -test-parse-options
 -test-path-utils
 -test-sha1
 -test-sigchain
 -common-cmds.h
 +/GIT-BUILD-OPTIONS
 +/GIT-CFLAGS
 +/GIT-GUI-VARS
 +/GIT-VERSION-FILE
 +/bin-wrappers/
 +/git
 +/git-add
 +/git-add--interactive
 +/git-am
 +/git-annotate
 +/git-apply
 +/git-archimport
 +/git-archive
 +/git-bisect
 +/git-bisect--helper
 +/git-blame
 +/git-branch
 +/git-bundle
 +/git-cat-file
 +/git-check-attr
 +/git-check-ref-format
 +/git-checkout
 +/git-checkout-index
 +/git-cherry
 +/git-cherry-pick
 +/git-clean
 +/git-clone
 +/git-commit
 +/git-commit-tree
 +/git-config
 +/git-count-objects
 +/git-cvsexportcommit
 +/git-cvsimport
 +/git-cvsserver
 +/git-daemon
 +/git-diff
 +/git-diff-files
 +/git-diff-index
 +/git-diff-tree
 +/git-difftool
 +/git-difftool--helper
 +/git-describe
 +/git-fast-export
 +/git-fast-import
 +/git-fetch
 +/git-fetch--tool
 +/git-fetch-pack
 +/git-filter-branch
 +/git-fmt-merge-msg
 +/git-for-each-ref
 +/git-format-patch
 +/git-fsck
 +/git-fsck-objects
 +/git-gc
 +/git-get-tar-commit-id
 +/git-grep
 +/git-hash-object
 +/git-help
 +/git-http-backend
 +/git-http-fetch
 +/git-http-push
 +/git-imap-send
 +/git-index-pack
 +/git-init
 +/git-init-db
 +/git-instaweb
 +/git-log
 +/git-lost-found
 +/git-ls-files
 +/git-ls-remote
 +/git-ls-tree
 +/git-mailinfo
 +/git-mailsplit
 +/git-merge
 +/git-merge-base
 +/git-merge-index
 +/git-merge-file
 +/git-merge-tree
 +/git-merge-octopus
 +/git-merge-one-file
 +/git-merge-ours
 +/git-merge-recursive
 +/git-merge-resolve
 +/git-merge-subtree
 +/git-mergetool
 +/git-mergetool--lib
 +/git-mktag
 +/git-mktree
 +/git-name-rev
 +/git-mv
 +/git-notes
 +/git-pack-redundant
 +/git-pack-objects
 +/git-pack-refs
 +/git-parse-remote
 +/git-patch-id
 +/git-peek-remote
 +/git-prune
 +/git-prune-packed
 +/git-pull
 +/git-push
 +/git-quiltimport
 +/git-read-tree
 +/git-rebase
 +/git-rebase--interactive
 +/git-receive-pack
 +/git-reflog
 +/git-relink
 +/git-remote
 +/git-remote-curl
 +/git-repack
 +/git-replace
 +/git-repo-config
 +/git-request-pull
 +/git-rerere
 +/git-reset
 +/git-rev-list
 +/git-rev-parse
 +/git-revert
 +/git-rm
 +/git-send-email
 +/git-send-pack
 +/git-sh-setup
 +/git-shell
 +/git-shortlog
 +/git-show
 +/git-show-branch
 +/git-show-index
 +/git-show-ref
 +/git-stage
 +/git-stash
 +/git-status
 +/git-stripspace
 +/git-submodule
 +/git-svn
 +/git-symbolic-ref
 +/git-tag
 +/git-tar-tree
 +/git-unpack-file
 +/git-unpack-objects
 +/git-update-index
 +/git-update-ref
 +/git-update-server-info
 +/git-upload-archive
 +/git-upload-pack
 +/git-var
 +/git-verify-pack
 +/git-verify-tag
 +/git-web--browse
 +/git-whatchanged
 +/git-write-tree
 +/git-core-*/?*
 +/gitk-git/gitk-wish
 +/gitweb/gitweb.cgi
 +/test-chmtime
 +/test-ctype
 +/test-date
 +/test-delta
 +/test-dump-cache-tree
 +/test-genrandom
++/test-index-version
 +/test-match-trees
 +/test-parse-options
 +/test-path-utils
 +/test-sha1
 +/test-sigchain
 +/common-cmds.h
  *.tar.gz
  *.dsc
  *.deb
 -git.spec
 +/git.spec
  *.exe
  *.[aos]
  *.py[co]
 -config.mak
 -autom4te.cache
 -config.cache
 -config.log
 -config.status
 -config.mak.autogen
 -config.mak.append
 -configure
 -tags
 -TAGS
 -cscope*
 +*+
 +/config.mak
 +/autom4te.cache
 +/config.cache
 +/config.log
 +/config.status
 +/config.mak.autogen
 +/config.mak.append
 +/configure
 +/tags
 +/TAGS
 +/cscope*
 +*.obj
 +*.lib
 +*.sln
 +*.suo
 +*.ncb
 +*.vcproj
 +*.user
 +*.idb
 +*.pdb
 +/Debug/
 +/Release/
diff --combined Documentation/config.txt
index 9f40955f8e74a0263019eb228a548ffd2b1fd301,5825c914fbe9bbf3d8d9317b67648ca27703e60d..8acb613ec3a56dbe76459075a31fd4e66c218991
@@@ -113,33 -113,10 +113,33 @@@ For command-specific variables, you wil
  in the appropriate manual page. You will find a description of non-core
  porcelain configuration variables in the respective porcelain documentation.
  
 +advice.*::
 +      When set to 'true', display the given optional help message.
 +      When set to 'false', do not display. The configuration variables
 +      are:
 ++
 +--
 +      pushNonFastForward::
 +              Advice shown when linkgit:git-push[1] refuses
 +              non-fast-forward refs. Default: true.
 +      statusHints::
 +              Directions on how to stage/unstage/add shown in the
 +              output of linkgit:git-status[1] and the template shown
 +              when writing commit messages. Default: true.
 +      commitBeforeMerge::
 +              Advice shown when linkgit:git-merge[1] refuses to
 +              merge to avoid overwritting local changes.
 +              Default: true.
 +--
 +
  core.fileMode::
        If false, the executable bit differences between the index and
        the working copy are ignored; useful on broken filesystems like FAT.
 -      See linkgit:git-update-index[1]. True by default.
 +      See linkgit:git-update-index[1].
 ++
 +The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 +will probe and set core.fileMode false if appropriate when the
 +repository is created.
  
  core.ignoreCygwinFSTricks::
        This option is only used by Cygwin implementation of Git. If false,
        is true, in which case ignoreCygwinFSTricks is ignored as Cygwin's
        POSIX emulation is required to support core.filemode.
  
 +core.ignorecase::
 +      If true, this option enables various workarounds to enable
 +      git to work better on filesystems that are not case sensitive,
 +      like FAT. For example, if a directory listing finds
 +      "makefile" when git expects "Makefile", git will assume
 +      it is really the same file, and continue to remember it as
 +      "Makefile".
 ++
 +The default is false, except linkgit:git-clone[1] or linkgit:git-init[1]
 +will probe and set core.ignorecase true if appropriate when the repository
 +is created.
 +
  core.trustctime::
        If false, the ctime differences between the index and the
        working copy are ignored; useful when the inode change time
@@@ -189,10 -154,9 +189,10 @@@ core.autocrlf:
        writing to the filesystem.  The variable can be set to
        'input', in which case the conversion happens only while
        reading from the filesystem but files are written out with
 -      `LF` at the end of lines.  Currently, which paths to consider
 -      "text" (i.e. be subjected to the autocrlf mechanism) is
 -      decided purely based on the contents.
 +      `LF` at the end of lines.  A file is considered
 +      "text" (i.e. be subjected to the autocrlf mechanism) based on
 +      the file's `crlf` attribute, or if `crlf` is unspecified,
 +      based on the file's contents.  See linkgit:gitattributes[5].
  
  core.safecrlf::
        If true, makes git check if converting `CRLF` as controlled by
@@@ -244,11 -208,7 +244,11 @@@ core.symlinks:
        contain the link text. linkgit:git-update-index[1] and
        linkgit:git-add[1] will not change the recorded type to regular
        file. Useful on filesystems like FAT that do not support
 -      symbolic links. True by default.
 +      symbolic links.
 ++
 +The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
 +will probe and set core.symlinks false if appropriate when the repository
 +is created.
  
  core.gitProxy::
        A "proxy command" to execute (as 'command host port') instead
@@@ -297,24 -257,17 +297,24 @@@ false), while all other repositories ar
  = true).
  
  core.worktree::
 -      Set the path to the working tree.  The value will not be
 -      used in combination with repositories found automatically in
 -      a .git directory (i.e. $GIT_DIR is not set).
 +      Set the path to the root of the work tree.
        This can be overridden by the GIT_WORK_TREE environment
        variable and the '--work-tree' command line option. It can be
 -      a absolute path or relative path to the directory specified by
 -      --git-dir or GIT_DIR.
 -      Note: If --git-dir or GIT_DIR are specified but none of
 +      an absolute path or a relative path to the .git directory,
 +      either specified by --git-dir or GIT_DIR, or automatically
 +      discovered.
 +      If --git-dir or GIT_DIR are specified but none of
        --work-tree, GIT_WORK_TREE and core.worktree is specified,
 -      the current working directory is regarded as the top directory
 -      of your working tree.
 +      the current working directory is regarded as the root of the
 +      work tree.
 ++
 +Note that this variable is honored even when set in a configuration
 +file in a ".git" subdirectory of a directory, and its value differs
 +from the latter directory (e.g. "/path/to/.git/config" has
 +core.worktree set to "/different/path"), which is most likely a
 +misconfiguration.  Running git commands in "/path/to" directory will
 +still use "/different/path" as the root of the work tree and can cause
 +great confusion to the users.
  
  core.logAllRefUpdates::
        Enable the reflog. Updates to a ref <ref> is logged to the file
@@@ -412,15 -365,16 +412,15 @@@ Common unit suffixes of 'k', 'm', or 'g
  core.excludesfile::
        In addition to '.gitignore' (per-directory) and
        '.git/info/exclude', git looks into this file for patterns
 -      of files which are not meant to be tracked.  See
 -      linkgit:gitignore[5].
 +      of files which are not meant to be tracked.  "{tilde}/" is expanded
 +      to the value of `$HOME` and "{tilde}user/" to the specified user's
 +      home directory.  See linkgit:gitignore[5].
  
  core.editor::
        Commands such as `commit` and `tag` that lets you edit
        messages by launching an editor uses the value of this
        variable when it is set, and the environment variable
 -      `GIT_EDITOR` is not set.  The order of preference is
 -      `GIT_EDITOR` environment, `core.editor`, `VISUAL` and
 -      `EDITOR` environment variables and then finally `vi`.
 +      `GIT_EDITOR` is not set.  See linkgit:git-var[1].
  
  core.pager::
        The command that git will use to paginate output.  Can
@@@ -447,17 -401,13 +447,17 @@@ core.whitespace:
        consider them as errors.  You can prefix `-` to disable
        any of them (e.g. `-trailing-space`):
  +
 -* `trailing-space` treats trailing whitespaces at the end of the line
 +* `blank-at-eol` treats trailing whitespaces at the end of the line
    as an error (enabled by default).
  * `space-before-tab` treats a space character that appears immediately
    before a tab character in the initial indent part of the line as an
    error (enabled by default).
  * `indent-with-non-tab` treats a line that is indented with 8 or more
    space characters as an error (not enabled by default).
 +* `blank-at-eof` treats blank lines added at the end of file as an error
 +  (enabled by default).
 +* `trailing-space` is a short-hand to cover both `blank-at-eol` and
 +  `blank-at-eof`.
  * `cr-at-eol` treats a carriage-return at the end of line as
    part of the line terminator, i.e. with it, `trailing-space`
    does not trigger if the character before such a carriage-return
@@@ -489,19 -439,10 +489,23 @@@ On some file system/operating system co
  Set this config setting to 'rename' there; However, This will remove the
  check that makes sure that existing object files will not get overwritten.
  
 +core.notesRef::
 +      When showing commit messages, also show notes which are stored in
 +      the given ref.  This ref is expected to contain files named
 +      after the full SHA-1 of the commit they annotate.
 ++
 +If such a file exists in the given ref, the referenced blob is read, and
 +appended to the commit message, separated by a "Notes:" line.  If the
 +given ref itself does not exist, it is not an error, but means that no
 +notes should be printed.
 ++
 +This setting defaults to "refs/notes/commits", and can be overridden by
 +the `GIT_NOTES_REF` environment variable.
 +
+ core.sparseCheckout::
+       Enable "sparse checkout" feature. See section "Sparse checkout" in
+       linkgit:git-read-tree[1] for more information.
  add.ignore-errors::
        Tells 'git-add' to continue adding files when some files cannot be
        added due to indexing errors. Equivalent to the '--ignore-errors'
@@@ -524,20 -465,12 +528,20 @@@ it will be treated as a shell command
  executed from the top-level directory of a repository, which may
  not necessarily be the current directory.
  
 +apply.ignorewhitespace::
 +      When set to 'change', tells 'git-apply' to ignore changes in
 +      whitespace, in the same way as the '--ignore-space-change'
 +      option.
 +      When set to one of: no, none, never, false tells 'git-apply' to
 +      respect all whitespace differences.
 +      See linkgit:git-apply[1].
 +
  apply.whitespace::
        Tells 'git-apply' how to handle whitespaces, in the same way
        as the '--whitespace' option. See linkgit:git-apply[1].
  
  branch.autosetupmerge::
 -      Tells 'git-branch' and 'git-checkout' to setup new branches
 +      Tells 'git-branch' and 'git-checkout' to set up new branches
        so that linkgit:git-pull[1] will appropriately merge from the
        starting point branch. Note that even if this option is not set,
        this behavior can be chosen per-branch using the `--track`
@@@ -587,7 -520,7 +591,7 @@@ branch.<name>.merge:
  
  branch.<name>.mergeoptions::
        Sets default options for merging into branch <name>. The syntax and
 -      supported options are equal to that of linkgit:git-merge[1], but
 +      supported options are the same as those of linkgit:git-merge[1], but
        option values containing whitespace characters are currently not
        supported.
  
@@@ -642,10 -575,10 +646,10 @@@ color.diff.<slot>:
        Use customized color for diff colorization.  `<slot>` specifies
        which part of the patch to use the specified color, and is one
        of `plain` (context text), `meta` (metainformation), `frag`
 -      (hunk header), `old` (removed lines), `new` (added lines),
 -      `commit` (commit headers), or `whitespace` (highlighting
 -      whitespace errors). The values of these variables may be specified as
 -      in color.branch.<slot>.
 +      (hunk header), 'func' (function in hunk header), `old` (removed lines),
 +      `new` (added lines), `commit` (commit headers), or `whitespace`
 +      (highlighting whitespace errors). The values of these variables may be
 +      specified as in color.branch.<slot>.
  
  color.grep::
        When set to `always`, always highlight matches.  When `false` (or
@@@ -676,7 -609,7 +680,7 @@@ color.interactive.<slot>:
        Use customized color for 'git-add --interactive'
        output. `<slot>` may be `prompt`, `header`, `help` or `error`, for
        four distinct types of normal output from interactive
 -      programs.  The values of these variables may be specified as
 +      commands.  The values of these variables may be specified as
        in color.branch.<slot>.
  
  color.pager::
@@@ -714,8 -647,6 +718,8 @@@ color.ui:
  
  commit.template::
        Specify a file to use as the template for new commit messages.
 +      "{tilde}/" is expanded to the value of `$HOME` and "{tilde}user/" to the
 +      specified user's home directory.
  
  diff.autorefreshindex::
        When using 'git-diff' to compare with work tree
        contents in the work tree match the contents in the
        index.  This option defaults to true.  Note that this
        affects only 'git-diff' Porcelain, and not lower level
 -      'diff' commands, such as 'git-diff-files'.
 +      'diff' commands such as 'git-diff-files'.
  
  diff.external::
        If this config variable is set, diff generation is not
@@@ -841,8 -772,8 +845,8 @@@ format.pretty:
  
  format.thread::
        The default threading style for 'git-format-patch'.  Can be
 -      either a boolean value, `shallow` or `deep`.  `shallow`
 -      threading makes every mail a reply to the head of the series,
 +      a boolean value, or `shallow` or `deep`.  `shallow` threading
 +      makes every mail a reply to the head of the series,
        where the head is chosen from the cover letter, the
        `\--in-reply-to`, and the first patch mail, in this order.
        `deep` threading makes every mail a reply to the previous one.
@@@ -875,12 -806,15 +879,12 @@@ gc.autopacklimit:
        default value is 50.  Setting this to 0 disables it.
  
  gc.packrefs::
 -      'git-gc' does not run `git pack-refs` in a bare repository by
 -      default so that older dumb-transport clients can still fetch
 -      from the repository.  Setting this to `true` lets 'git-gc'
 -      to run `git pack-refs`.  Setting this to `false` tells
 -      'git-gc' never to run `git pack-refs`. The default setting is
 -      `notbare`. Enable it only when you know you do not have to
 -      support such clients.  The default setting will change to `true`
 -      at some stage, and setting this to `false` will continue to
 -      prevent `git pack-refs` from being run from 'git-gc'.
 +      Running `git pack-refs` in a repository renders it
 +      unclonable by Git versions prior to 1.5.1.2 over dumb
 +      transports such as HTTP.  This variable determines whether
 +      'git gc' runs `git pack-refs`. This can be set to "nobare"
 +      to enable it within all non-bare repos or it can be set to a
 +      boolean value.  The default is `true`.
  
  gc.pruneexpire::
        When 'git-gc' is run, it will call 'prune --expire 2.weeks.ago'.
@@@ -1136,20 -1070,6 +1140,20 @@@ http.maxRequests:
        How many HTTP requests to launch in parallel. Can be overridden
        by the 'GIT_HTTP_MAX_REQUESTS' environment variable. Default is 5.
  
 +http.minSessions::
 +      The number of curl sessions (counted across slots) to be kept across
 +      requests. They will not be ended with curl_easy_cleanup() until
 +      http_cleanup() is invoked. If USE_CURL_MULTI is not defined, this
 +      value will be capped at 1. Defaults to 1.
 +
 +http.postBuffer::
 +      Maximum size in bytes of the buffer used by smart HTTP
 +      transports when POSTing data to the remote system.
 +      For requests larger than this buffer size, HTTP/1.1 and
 +      Transfer-Encoding: chunked is used to avoid creating a
 +      massive pack file locally.  Default is 1 MiB, which is
 +      sufficient for most requests.
 +
  http.lowSpeedLimit, http.lowSpeedTime::
        If the HTTP transfer speed is less than 'http.lowSpeedLimit'
        for longer than 'http.lowSpeedTime' seconds, the transfer is aborted.
@@@ -1197,7 -1117,7 +1201,7 @@@ instaweb.port:
        linkgit:git-instaweb[1].
  
  interactive.singlekey::
 -      In interactive programs, allow the user to provide one-letter
 +      In interactive commands, allow the user to provide one-letter
        input with a single key (i.e., without hitting enter).
        Currently this is used only by the `\--patch` mode of
        linkgit:git-add[1].  Note that this setting is silently
@@@ -1381,11 -1301,6 +1385,11 @@@ rebase.stat:
        Whether to show a diffstat of what changed upstream since the last
        rebase. False by default.
  
 +receive.autogc::
 +      By default, git-receive-pack will run "git-gc --auto" after
 +      receiving data from git-push and updating refs.  You can stop
 +      it by setting this variable to false.
 +
  receive.fsckObjects::
        If it is set to true, git-receive-pack will check all received
        objects. It will abort in the case of a malformed object or a
@@@ -1417,14 -1332,10 +1421,14 @@@ receive.denyCurrentBranch:
  
  receive.denyNonFastForwards::
        If set to true, git-receive-pack will deny a ref update which is
 -      not a fast forward. Use this to prevent such an update via a push,
 +      not a fast-forward. Use this to prevent such an update via a push,
        even if that push is forced. This configuration variable is
        set when initializing a shared repository.
  
 +receive.updateserverinfo::
 +      If set to true, git-receive-pack will run git-update-server-info
 +      after receiving data from git-push and updating refs.
 +
  remote.<name>.url::
        The URL of a remote repository.  See linkgit:git-fetch[1] or
        linkgit:git-push[1].
@@@ -1451,13 -1362,7 +1455,13 @@@ remote.<name>.mirror:
  
  remote.<name>.skipDefaultUpdate::
        If true, this remote will be skipped by default when updating
 -      using the update subcommand of linkgit:git-remote[1].
 +      using linkgit:git-fetch[1] or the `update` subcommand of
 +      linkgit:git-remote[1].
 +
 +remote.<name>.skipFetchAll::
 +      If true, this remote will be skipped by default when updating
 +      using linkgit:git-fetch[1] or the `update` subcommand of
 +      linkgit:git-remote[1].
  
  remote.<name>.receivepack::
        The default program to execute on the remote side when pushing.  See
@@@ -1471,10 -1376,6 +1475,10 @@@ remote.<name>.tagopt:
        Setting this value to \--no-tags disables automatic tag following when
        fetching from remote <name>
  
 +remote.<name>.vcs::
 +      Setting this to a value <vcs> will cause git to interact with
 +      the remote with the git-remote-<vcs> helper.
 +
  remotes.<group>::
        The list of remotes which are fetched by "git remote update
        <group>".  See linkgit:git-remote[1].
@@@ -1595,19 -1496,6 +1599,19 @@@ url.<base>.insteadOf:
        never-before-seen repository on the site.  When more than one
        insteadOf strings match a given URL, the longest match is used.
  
 +url.<base>.pushInsteadOf::
 +      Any URL that starts with this value will not be pushed to;
 +      instead, it will be rewritten to start with <base>, and the
 +      resulting URL will be pushed to. In cases where some site serves
 +      a large number of repositories, and serves them with multiple
 +      access methods, some of which do not allow push, this feature
 +      allows people to specify a pull-only URL and have git
 +      automatically use an appropriate URL to push, even for a
 +      never-before-seen repository on the site.  When more than one
 +      pushInsteadOf strings match a given URL, the longest match is
 +      used.  If a remote has an explicit pushurl, git will ignore this
 +      setting for that remote.
 +
  user.email::
        Your email address to be recorded in any newly created commits.
        Can be overridden by the 'GIT_AUTHOR_EMAIL', 'GIT_COMMITTER_EMAIL', and
index 625723e41fa072523fa850e37534677cfe8af631,6f9d880aa432cd55f6fec07277b1dcb02eb05c90..98f3b9e7589cd810d0bc04f08e84dd057039e258
@@@ -48,10 -48,8 +48,10 @@@ OPTION
  
  -i::
  --ignored::
 -      Show ignored files in the output.
 -      Note that this also reverses any exclude list present.
 +      Show only ignored files in the output. When showing files in the
 +      index, print only those matched by an exclude pattern. When
 +      showing "other" files, show only those matched by an exclude
 +      pattern.
  
  -s::
  --stage::
        Identify the file status with the following tags (followed by
        a space) at the start of each line:
        H::     cached
+       S::     skip-worktree
        M::     unmerged
        R::     removed/deleted
        C::     modified/changed
index a10ce4ba40cc509a0f3a8f39551310fdd9231e71,ea7b0b2f5c4630aebd6352cd2bd92fbfaef0863a..d6faa141495521b2f7281040364d540a7cf41bb3
@@@ -10,7 -10,7 +10,7 @@@ SYNOPSI
  --------
  'git read-tree' [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>]
                [-u [--exclude-per-directory=<gitignore>] | -i]]
-               [--index-output=<file>]
+               [--index-output=<file>] [--no-sparse-checkout]
                <tree-ish1> [<tree-ish2> [<tree-ish3>]]
  
  
@@@ -110,6 -110,10 +110,10 @@@ OPTION
        directories the index file and index output file are
        located in.
  
+ --no-sparse-checkout::
+       Disable sparse checkout support even if `core.sparseCheckout`
+       is true.
  <tree-ish#>::
        The id of the tree object(s) to be read/merged.
  
@@@ -144,7 -148,7 +148,7 @@@ Two Tree Merg
  Typically, this is invoked as `git read-tree -m $H $M`, where $H
  is the head commit of the current repository, and $M is the head
  of a foreign tree, which is simply ahead of $H (i.e. we are in a
 -fast forward situation).
 +fast-forward situation).
  
  When two trees are specified, the user is telling 'git-read-tree'
  the following:
@@@ -360,6 -364,52 +364,52 @@@ middle of doing, and when your working 
  have finished your work-in-progress), attempt the merge again.
  
  
+ Sparse checkout
+ ---------------
+ "Sparse checkout" allows to sparsely populate working directory.
+ It uses skip-worktree bit (see linkgit:git-update-index[1]) to tell
+ Git whether a file on working directory is worth looking at.
+ "git read-tree" and other merge-based commands ("git merge", "git
+ checkout"...) can help maintaining skip-worktree bitmap and working
+ directory update. `$GIT_DIR/info/sparse-checkout` is used to
+ define the skip-worktree reference bitmap. When "git read-tree" needs
+ to update working directory, it will reset skip-worktree bit in index
+ based on this file, which uses the same syntax as .gitignore files.
+ If an entry matches a pattern in this file, skip-worktree will be
+ set on that entry. Otherwise, skip-worktree will be unset.
+ Then it compares the new skip-worktree value with the previous one. If
+ skip-worktree turns from unset to set, it will add the corresponding
+ file back. If it turns from set to unset, that file will be removed.
+ While `$GIT_DIR/info/sparse-checkout` is usually used to specify what
+ files are in. You can also specify what files are _not_ in, using
+ negate patterns. For example, to remove file "unwanted":
+ ----------------
+ *
+ !unwanted
+ ----------------
+ Another tricky thing is fully repopulating working directory when you
+ no longer want sparse checkout. You cannot just disable "sparse
+ checkout" because skip-worktree are still in the index and you working
+ directory is still sparsely populated. You should re-populate working
+ directory with the `$GIT_DIR/info/sparse-checkout` file content as
+ follows:
+ ----------------
+ *
+ ----------------
+ Then you can disable sparse checkout. Sparse checkout support in "git
+ read-tree" and similar commands is disabled by default. You need to
+ turn `core.sparseCheckout` on in order to have sparse checkout
+ support.
  SEE ALSO
  --------
  linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
index 6052484ab9e28d5565067885b1c4ed5667e8e90f,a10f355b7cf6a11f936131a03fb9efab9ee5e2ea..8d88018eedd08511e2676013d88c8d44b10e97ac
@@@ -15,6 -15,7 +15,7 @@@ SYNOPSI
             [--cacheinfo <mode> <object> <file>]\*
             [--chmod=(+|-)x]
             [--assume-unchanged | --no-assume-unchanged]
+            [--skip-worktree | --no-skip-worktree]
             [--ignore-submodules]
             [--really-refresh] [--unresolve] [--again | -g]
             [--info-only] [--index-info]
@@@ -99,10 -100,13 +100,17 @@@ in the index e.g. when merging in a com
  thus, in case the assumed-untracked file is changed upstream,
  you will need to handle the situation manually.
  
 +--really-refresh::
 +      Like '--refresh', but checks stat information unconditionally,
 +      without regard to the "assume unchanged" setting.
 +
+ --skip-worktree::
+ --no-skip-worktree::
+       When one of these flags is specified, the object name recorded
+       for the paths are not updated. Instead, these options
+       set and unset the "skip-worktree" bit for the paths. See
+       section "Skip-worktree bit" below for more information.
  -g::
  --again::
        Runs 'git-update-index' itself on the paths whose index
@@@ -308,11 -312,32 +316,32 @@@ M foo.
  <9> now it checks with lstat(2) and finds it has been changed.
  
  
+ Skip-worktree bit
+ -----------------
+ Skip-worktree bit can be defined in one (long) sentence: When reading
+ an entry, if it is marked as skip-worktree, then Git pretends its
+ working directory version is up to date and read the index version
+ instead.
+ To elaborate, "reading" means checking for file existence, reading
+ file attributes or file content. The working directory version may be
+ present or absent. If present, its content may match against the index
+ version or not. Writing is not affected by this bit, content safety
+ is still first priority. Note that Git _can_ update working directory
+ file, that is marked skip-worktree, if it is safe to do so (i.e.
+ working directory version matches index version)
+ Although this bit looks similar to assume-unchanged bit, its goal is
+ different from assume-unchanged bit's. Skip-worktree also takes
+ precedence over assume-unchanged bit when both are set.
  Configuration
  -------------
  
  The command honors `core.filemode` configuration variable.  If
 -your repository is on an filesystem whose executable bits are
 +your repository is on a filesystem whose executable bits are
  unreliable, this should be set to 'false' (see linkgit:git-config[1]).
  This causes the command to ignore differences in file modes recorded
  in the index and the file mode on the filesystem if they differ only on
diff --combined Makefile
index be1838953451f78443ab1a97f569428b2001fcfb,3c5b890223f3795e6db120a725dc7f35d5df3d2c..412dda83ac6a9cf76682153b5d66c274e2a362fd
+++ b/Makefile
@@@ -16,7 -16,7 +16,7 @@@ all:
  # when attempting to read from an fopen'ed directory.
  #
  # Define NO_OPENSSL environment variable if you do not have OpenSSL.
 -# This also implies MOZILLA_SHA1.
 +# This also implies BLK_SHA1.
  #
  # Define NO_CURL if you do not have libcurl installed.  git-http-pull and
  # git-http-push are not built, and you cannot use http:// and https://
  # specify your own (or DarwinPort's) include directories and
  # library directories by defining CFLAGS and LDFLAGS appropriately.
  #
 +# Define BLK_SHA1 environment variable if you want the C version
 +# of the SHA1 that assumes you can do unaligned 32-bit loads and
 +# have a fast htonl() function.
 +#
  # Define PPC_SHA1 environment variable when running make to make use of
  # a bundled SHA1 routine optimized for PowerPC.
  #
 -# Define ARM_SHA1 environment variable when running make to make use of
 -# a bundled SHA1 routine optimized for ARM.
 -#
 -# Define MOZILLA_SHA1 environment variable when running make to make use of
 -# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
 -# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
 -# choice) has very fast version optimized for i586.
 +# Define NEEDS_CRYPTO_WITH_SSL if you need -lcrypto when using -lssl (Darwin).
  #
 -# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
 +# Define NEEDS_SSL_WITH_CRYPTO if you need -lssl when using -lcrypto (Darwin).
  #
  # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
  #
  #
  # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
  #
 -# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
 +# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72
 +# (not v1.73 or v1.71).
 +#
 +# Define ASCIIDOC_NO_ROFF if your DocBook XSL escapes raw roff directives
 +# (versions 1.72 and later and 1.68.1 and earlier).
 +#
 +# Define GNU_ROFF if your target system uses GNU groff.  This forces
 +# apostrophes to be ASCII so that cut&pasting examples to the shell
 +# will work.
  #
  # 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 NO_PYTHON if you do not want Python scripts or libraries at all.
 +#
  # Define NO_TCLTK if you do not want Tcl/Tk GUI.
  #
  # The TCL_PATH variable governs the location of the Tcl interpreter
  # memory allocators with the nedmalloc allocator written by Niall Douglas.
  #
  # Define NO_REGEX if you have no or inferior regex support in your C library.
 +#
 +# Define JSMIN to point to JavaScript minifier that functions as
 +# a filter to have gitweb.js minified.
 +#
 +# Define DEFAULT_PAGER to a sensible pager command (defaults to "less") if
 +# you want to use something different.  The value will be interpreted by the
 +# shell at runtime when it is used.
 +#
 +# Define DEFAULT_EDITOR to a sensible editor command (defaults to "vi") if you
 +# want to use something different.  The value will be interpreted by the shell
 +# if necessary when it is used.  Examples:
 +#
 +#   DEFAULT_EDITOR='~/bin/vi',
 +#   DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
 +#   DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
  
  GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@@ -233,12 -210,6 +233,12 @@@ uname_R := $(shell sh -c 'uname -r 2>/d
  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
@@@ -279,9 -250,6 +279,9 @@@ lib = li
  # DESTDIR=
  pathsep = :
  
 +# JavaScript minifier invocation that can function as filter
 +JSMIN =
 +
  # default configuration for gitweb
  GITWEB_CONFIG = gitweb_config.perl
  GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
@@@ -297,11 -265,6 +297,11 @@@ GITWEB_HOMETEXT = indextext.htm
  GITWEB_CSS = gitweb.css
  GITWEB_LOGO = git-logo.png
  GITWEB_FAVICON = git-favicon.png
 +ifdef JSMIN
 +GITWEB_JS = gitweb.min.js
 +else
 +GITWEB_JS = gitweb.js
 +endif
  GITWEB_SITE_HEADER =
  GITWEB_SITE_FOOTER =
  
@@@ -343,7 -306,6 +343,7 @@@ LIB_H 
  LIB_OBJS =
  PROGRAMS =
  SCRIPT_PERL =
 +SCRIPT_PYTHON =
  SCRIPT_SH =
  TEST_PROGRAMS =
  
@@@ -357,7 -319,6 +357,7 @@@ SCRIPT_SH += git-merge-one-file.s
  SCRIPT_SH += git-merge-resolve.sh
  SCRIPT_SH += git-mergetool.sh
  SCRIPT_SH += git-mergetool--lib.sh
 +SCRIPT_SH += git-notes.sh
  SCRIPT_SH += git-parse-remote.sh
  SCRIPT_SH += git-pull.sh
  SCRIPT_SH += git-quiltimport.sh
@@@ -382,7 -343,6 +382,7 @@@ SCRIPT_PERL += git-svn.per
  
  SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
          $(patsubst %.perl,%,$(SCRIPT_PERL)) \
 +        $(patsubst %.py,%,$(SCRIPT_PYTHON)) \
          git-instaweb
  
  # Empty...
@@@ -392,7 -352,6 +392,7 @@@ EXTRA_PROGRAMS 
  PROGRAMS += $(EXTRA_PROGRAMS)
  PROGRAMS += git-fast-import$X
  PROGRAMS += git-hash-object$X
 +PROGRAMS += git-imap-send$X
  PROGRAMS += git-index-pack$X
  PROGRAMS += git-merge-index$X
  PROGRAMS += git-merge-tree$X
@@@ -402,9 -361,9 +402,9 @@@ PROGRAMS += git-patch-id$
  PROGRAMS += git-shell$X
  PROGRAMS += git-show-index$X
  PROGRAMS += git-unpack-file$X
 -PROGRAMS += git-update-server-info$X
  PROGRAMS += git-upload-pack$X
  PROGRAMS += git-var$X
 +PROGRAMS += git-http-backend$X
  
  # List built-in command $C whose implementation cmd_$C() is not in
  # builtin-$C.o but is linked in as part of some other command.
@@@ -424,22 -383,12 +424,22 @@@ BUILT_INS += git-stage$
  BUILT_INS += git-status$X
  BUILT_INS += git-whatchanged$X
  
 -# what 'all' will build and 'install' will install, in gitexecdir
 +# what 'all' will build and 'install' will install in gitexecdir,
 +# excluding programs for built-in commands
  ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
  
  # what 'all' will build but not install in gitexecdir
  OTHER_PROGRAMS = git$X
  
 +# what test wrappers are needed and 'install' will install, in bindir
 +BINDIR_PROGRAMS_NEED_X += git
 +BINDIR_PROGRAMS_NEED_X += git-upload-pack
 +BINDIR_PROGRAMS_NEED_X += git-receive-pack
 +BINDIR_PROGRAMS_NEED_X += git-upload-archive
 +BINDIR_PROGRAMS_NEED_X += git-shell
 +
 +BINDIR_PROGRAMS_NO_X += git-cvsserver
 +
  # Set paths to tools early so that they can be used for version tests.
  ifndef SHELL_PATH
        SHELL_PATH = /bin/sh
@@@ -447,17 -396,12 +447,17 @@@ endi
  ifndef PERL_PATH
        PERL_PATH = /usr/bin/perl
  endif
 +ifndef PYTHON_PATH
 +      PYTHON_PATH = /usr/bin/python
 +endif
  
  export PERL_PATH
 +export PYTHON_PATH
  
  LIB_FILE=libgit.a
  XDIFF_LIB=xdiff/lib.a
  
 +LIB_H += advice.h
  LIB_H += archive.h
  LIB_H += attr.h
  LIB_H += blob.h
@@@ -465,7 -409,6 +465,7 @@@ LIB_H += builtin.
  LIB_H += cache.h
  LIB_H += cache-tree.h
  LIB_H += commit.h
 +LIB_H += compat/bswap.h
  LIB_H += compat/cygwin.h
  LIB_H += compat/mingw.h
  LIB_H += csum-file.h
@@@ -486,7 -429,6 +486,7 @@@ LIB_H += ll-merge.
  LIB_H += log-tree.h
  LIB_H += mailmap.h
  LIB_H += merge-recursive.h
 +LIB_H += notes.h
  LIB_H += object.h
  LIB_H += pack.h
  LIB_H += pack-refs.h
@@@ -507,7 -449,6 +507,7 @@@ LIB_H += sideband.
  LIB_H += sigchain.h
  LIB_H += strbuf.h
  LIB_H += string-list.h
 +LIB_H += submodule.h
  LIB_H += tag.h
  LIB_H += transport.h
  LIB_H += tree.h
@@@ -518,7 -459,6 +518,7 @@@ LIB_H += utf8.
  LIB_H += wt-status.h
  
  LIB_OBJS += abspath.o
 +LIB_OBJS += advice.o
  LIB_OBJS += alias.o
  LIB_OBJS += alloc.o
  LIB_OBJS += archive.o
@@@ -572,7 -512,6 +572,7 @@@ LIB_OBJS += match-trees.
  LIB_OBJS += merge-file.o
  LIB_OBJS += merge-recursive.o
  LIB_OBJS += name-hash.o
 +LIB_OBJS += notes.o
  LIB_OBJS += object.o
  LIB_OBJS += pack-check.o
  LIB_OBJS += pack-refs.o
@@@ -593,7 -532,6 +593,7 @@@ LIB_OBJS += read-cache.
  LIB_OBJS += reflog-walk.o
  LIB_OBJS += refs.o
  LIB_OBJS += remote.o
 +LIB_OBJS += replace_object.o
  LIB_OBJS += rerere.o
  LIB_OBJS += revision.o
  LIB_OBJS += run-command.o
@@@ -607,12 -545,10 +607,12 @@@ LIB_OBJS += sideband.
  LIB_OBJS += sigchain.o
  LIB_OBJS += strbuf.o
  LIB_OBJS += string-list.o
 +LIB_OBJS += submodule.o
  LIB_OBJS += symlinks.o
  LIB_OBJS += tag.o
  LIB_OBJS += trace.o
  LIB_OBJS += transport.o
 +LIB_OBJS += transport-helper.o
  LIB_OBJS += tree-diff.o
  LIB_OBJS += tree.o
  LIB_OBJS += tree-walk.o
@@@ -652,6 -588,7 +652,6 @@@ BUILTIN_OBJS += builtin-diff-index.
  BUILTIN_OBJS += builtin-diff-tree.o
  BUILTIN_OBJS += builtin-diff.o
  BUILTIN_OBJS += builtin-fast-export.o
 -BUILTIN_OBJS += builtin-fetch--tool.o
  BUILTIN_OBJS += builtin-fetch-pack.o
  BUILTIN_OBJS += builtin-fetch.o
  BUILTIN_OBJS += builtin-fmt-merge-msg.o
@@@ -684,7 -621,6 +684,7 @@@ BUILTIN_OBJS += builtin-read-tree.
  BUILTIN_OBJS += builtin-receive-pack.o
  BUILTIN_OBJS += builtin-reflog.o
  BUILTIN_OBJS += builtin-remote.o
 +BUILTIN_OBJS += builtin-replace.o
  BUILTIN_OBJS += builtin-rerere.o
  BUILTIN_OBJS += builtin-reset.o
  BUILTIN_OBJS += builtin-rev-list.o
@@@ -702,7 -638,6 +702,7 @@@ BUILTIN_OBJS += builtin-tar-tree.
  BUILTIN_OBJS += builtin-unpack-objects.o
  BUILTIN_OBJS += builtin-update-index.o
  BUILTIN_OBJS += builtin-update-ref.o
 +BUILTIN_OBJS += builtin-update-server-info.o
  BUILTIN_OBJS += builtin-upload-archive.o
  BUILTIN_OBJS += builtin-verify-pack.o
  BUILTIN_OBJS += builtin-verify-tag.o
@@@ -771,7 -706,6 +771,7 @@@ ifeq ($(uname_S),SCO_SV
        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)
@@@ -795,7 -729,6 +795,7 @@@ ifeq ($(uname_S),SunOS
        NO_MKSTEMPS = YesPlease
        NO_REGEX = YesPlease
        NO_EXTERNAL_GREP = YesPlease
 +      THREADED_DELTA_SEARCH = YesPlease
        ifeq ($(uname_R),5.7)
                NEEDS_RESOLV = YesPlease
                NO_IPV6 = YesPlease
                NO_C99_FORMAT = YesPlease
                NO_STRTOUMAX = YesPlease
        endif
 -      ifdef NO_IPV6
 -              NEEDS_RESOLV = YesPlease
 -      endif
        INSTALL = /usr/ucb/install
        TAR = gtar
        BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H
@@@ -833,19 -769,15 +833,19 @@@ ifeq ($(uname_O),Cygwin
        NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
        NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
        OLD_ICONV = 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
        NO_IPV6 = YesPlease
        X = .exe
 +      COMPAT_OBJS += compat/cygwin.o
 +      UNRELIABLE_FSTAT = UnfortunatelyYes
  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
@@@ -906,18 -838,11 +906,18 @@@ ifeq ($(uname_S),IRIX
        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_EXTERNAL_GREP = UnfortunatelyYes
        SNPRINTF_RETURNS_BOGUS = YesPlease
        SHELL_PATH = /usr/gnu/bin/bash
        NEEDS_LIBGEN = YesPlease
 +      THREADED_DELTA_SEARCH = YesPlease
  endif
  ifeq ($(uname_S),IRIX64)
        NO_SETENV=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_EXTERNAL_GREP = UnfortunatelyYes
        SNPRINTF_RETURNS_BOGUS = YesPlease
        SHELL_PATH=/usr/gnu/bin/bash
        NEEDS_LIBGEN = YesPlease
 +      THREADED_DELTA_SEARCH = YesPlease
  endif
  ifeq ($(uname_S),HP-UX)
        NO_IPV6=YesPlease
        NO_SYS_SELECT_H = YesPlease
        SNPRINTF_RETURNS_BOGUS = YesPlease
  endif
 -ifneq (,$(findstring CYGWIN,$(uname_S)))
 -      COMPAT_OBJS += compat/cygwin.o
 +ifeq ($(uname_S),Windows)
 +      GIT_VERSION := $(GIT_VERSION).MSVC
 +      pathsep = ;
 +      NO_PREAD = YesPlease
 +      NEEDS_CRYPTO_WITH_SSL = YesPlease
 +      NO_LIBGEN_H = YesPlease
 +      NO_SYMLINK_HEAD = YesPlease
 +      NO_IPV6 = YesPlease
 +      NO_SETENV = YesPlease
 +      NO_UNSETENV = YesPlease
 +      NO_STRCASESTR = YesPlease
 +      NO_STRLCPY = YesPlease
 +      NO_MEMMEM = YesPlease
 +      # NEEDS_LIBICONV = YesPlease
 +      NO_ICONV = YesPlease
 +      NO_C99_FORMAT = 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_POSIX_ONLY_PROGRAMS = 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_PTHREADS = YesPlease
 +      BLK_SHA1 = 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/fnmatch/fnmatch.o compat/winansi.o
 +      COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\"
 +      BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
 +      EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib
 +      lib =
 +ifndef DEBUG
 +      BASIC_CFLAGS += -GL -Os -MT
 +      BASIC_LDFLAGS += -LTCG
 +      AR += -LTCG
 +else
 +      BASIC_CFLAGS += -Zi -MTd
 +endif
 +      X = .exe
  endif
  ifneq (,$(findstring MINGW,$(uname_S)))
        pathsep = ;
        NO_PREAD = YesPlease
 -      NO_OPENSSL = YesPlease
 +      NEEDS_CRYPTO_WITH_SSL = YesPlease
        NO_LIBGEN_H = YesPlease
        NO_SYMLINK_HEAD = YesPlease
 -      NO_IPV6 = YesPlease
        NO_SETENV = YesPlease
        NO_UNSETENV = YesPlease
        NO_STRCASESTR = YesPlease
        UNRELIABLE_FSTAT = UnfortunatelyYes
        OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
        NO_REGEX = YesPlease
 +      BLK_SHA1 = YesPlease
        COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
        COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o
@@@ -1054,6 -922,10 +1054,6 @@@ els
        NO_PTHREADS = YesPlease
  endif
  endif
 -ifneq (,$(findstring arm,$(uname_M)))
 -      ARM_SHA1 = YesPlease
 -      NO_MKSTEMPS = YesPlease
 -endif
  
  -include config.mak.autogen
  -include config.mak
@@@ -1107,7 -979,9 +1107,7 @@@ els
        else
                CURL_LIBCURL = -lcurl
        endif
 -      BUILTIN_OBJS += builtin-http-fetch.o
 -      EXTLIBS += $(CURL_LIBCURL)
 -      LIB_OBJS += http.o http-walker.o
 +      PROGRAMS += git-remote-curl$X git-http-fetch$X
        curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p)
        ifeq "$(curl_check)" "070908"
                ifndef NO_EXPAT
@@@ -1132,6 -1006,7 +1132,6 @@@ EXTLIBS += -l
  
  ifndef NO_POSIX_ONLY_PROGRAMS
        PROGRAMS += git-daemon$X
 -      PROGRAMS += git-imap-send$X
  endif
  ifndef NO_OPENSSL
        OPENSSL_LIBSSL = -lssl
        else
                OPENSSL_LINK =
        endif
 +      ifdef NEEDS_CRYPTO_WITH_SSL
 +              OPENSSL_LINK += -lcrypto
 +      endif
  else
        BASIC_CFLAGS += -DNO_OPENSSL
 -      MOZILLA_SHA1 = 1
 +      BLK_SHA1 = 1
        OPENSSL_LIBSSL =
  endif
  ifdef NEEDS_SSL_WITH_CRYPTO
@@@ -1295,18 -1167,23 +1295,18 @@@ ifdef NO_DEFLATE_BOUN
        BASIC_CFLAGS += -DNO_DEFLATE_BOUND
  endif
  
 +ifdef BLK_SHA1
 +      SHA1_HEADER = "block-sha1/sha1.h"
 +      LIB_OBJS += block-sha1/sha1.o
 +else
  ifdef PPC_SHA1
        SHA1_HEADER = "ppc/sha1.h"
        LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
 -else
 -ifdef ARM_SHA1
 -      SHA1_HEADER = "arm/sha1.h"
 -      LIB_OBJS += arm/sha1.o arm/sha1_arm.o
 -else
 -ifdef MOZILLA_SHA1
 -      SHA1_HEADER = "mozilla-sha1/sha1.h"
 -      LIB_OBJS += mozilla-sha1/sha1.o
  else
        SHA1_HEADER = <openssl/sha.h>
        EXTLIBS += $(LIB_4_CRYPTO)
  endif
  endif
 -endif
  ifdef NO_PERL_MAKEMAKER
        export NO_PERL_MAKEMAKER
  endif
@@@ -1364,10 -1241,6 +1364,10 @@@ ifeq ($(PERL_PATH),
  NO_PERL=NoThanks
  endif
  
 +ifeq ($(PYTHON_PATH),)
 +NO_PYTHON=NoThanks
 +endif
 +
  QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir
  QUIET_SUBDIR1  =
  
@@@ -1384,7 -1257,6 +1384,7 @@@ ifndef 
        QUIET_LINK     = @echo '   ' LINK $@;
        QUIET_BUILT_IN = @echo '   ' BUILTIN $@;
        QUIET_GEN      = @echo '   ' GEN $@;
 +      QUIET_LNCP     = @echo '   ' LN/CP $@;
        QUIET_SUBDIR0  = +@subdir=
        QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
                         $(MAKE) $(PRINT_DIR) -C $$subdir
@@@ -1415,7 -1287,6 +1415,7 @@@ prefix_SQ = $(subst ','\'',$(prefix)
  
  SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
  PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
 +PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
  TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
  
  LIBS = $(GITLIBS) $(EXTLIBS)
@@@ -1424,22 -1295,6 +1424,22 @@@ BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_H
        $(COMPAT_CFLAGS)
  LIB_OBJS += $(COMPAT_OBJS)
  
 +# Quote for C
 +
 +ifdef DEFAULT_EDITOR
 +DEFAULT_EDITOR_CQ = "$(subst ",\",$(subst \,\\,$(DEFAULT_EDITOR)))"
 +DEFAULT_EDITOR_CQ_SQ = $(subst ','\'',$(DEFAULT_EDITOR_CQ))
 +
 +BASIC_CFLAGS += -DDEFAULT_EDITOR='$(DEFAULT_EDITOR_CQ_SQ)'
 +endif
 +
 +ifdef DEFAULT_PAGER
 +DEFAULT_PAGER_CQ = "$(subst ",\",$(subst \,\\,$(DEFAULT_PAGER)))"
 +DEFAULT_PAGER_CQ_SQ = $(subst ','\'',$(DEFAULT_PAGER_CQ))
 +
 +BASIC_CFLAGS += -DDEFAULT_PAGER='$(DEFAULT_PAGER_CQ_SQ)'
 +endif
 +
  ALL_CFLAGS += $(BASIC_CFLAGS)
  ALL_LDFLAGS += $(BASIC_LDFLAGS)
  
@@@ -1452,7 -1307,7 +1452,7 @@@ SHELL = $(SHELL_PATH
  
  all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
  ifneq (,$X)
 -      $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
 +      $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';)
  endif
  
  all::
@@@ -1462,9 -1317,6 +1462,9 @@@ ifndef NO_TCLT
  endif
  ifndef NO_PERL
        $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
 +endif
 +ifndef NO_PYTHON
 +      $(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all
  endif
        $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1)
  
@@@ -1479,7 -1331,7 +1479,7 @@@ strip: $(PROGRAMS) git$
  git.o: git.c common-cmds.h GIT-CFLAGS
        $(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
                '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
 -              $(ALL_CFLAGS) -c $(filter %.c,$^)
 +              $(ALL_CFLAGS) -o $@ -c $(filter %.c,$^)
  
  git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
@@@ -1535,13 -1387,8 +1535,13 @@@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % 
        chmod +x $@+ && \
        mv $@+ $@
  
 +ifdef JSMIN
 +OTHER_PROGRAMS += gitweb/gitweb.cgi   gitweb/gitweb.min.js
 +gitweb/gitweb.cgi: gitweb/gitweb.perl gitweb/gitweb.min.js
 +else
  OTHER_PROGRAMS += gitweb/gitweb.cgi
  gitweb/gitweb.cgi: gitweb/gitweb.perl
 +endif
        $(QUIET_GEN)$(RM) $@ $@+ && \
        sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
            -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
            -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \
            -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \
            -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
 +          -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
            -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
            -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
            $< >$@+ && \
        chmod +x $@+ && \
        mv $@+ $@
  
 -git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
 +git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js
        $(QUIET_GEN)$(RM) $@ $@+ && \
        sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
            -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
            -e '/@@GITWEB_CGI@@/d' \
            -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
            -e '/@@GITWEB_CSS@@/d' \
 +          -e '/@@GITWEB_JS@@/r gitweb/gitweb.js' \
 +          -e '/@@GITWEB_JS@@/d' \
            -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
            $@.sh > $@+ && \
        chmod +x $@+ && \
@@@ -1592,41 -1436,6 +1592,41 @@@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git
        mv $@+ $@
  endif # NO_PERL
  
 +
 +ifdef JSMIN
 +gitweb/gitweb.min.js: gitweb/gitweb.js
 +      $(QUIET_GEN)$(JSMIN) <$< >$@
 +endif # JSMIN
 +
 +ifndef NO_PYTHON
 +$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS
 +$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
 +      $(QUIET_GEN)$(RM) $@ $@+ && \
 +      INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
 +              --no-print-directory prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' \
 +              instlibdir` && \
 +      sed -e '1{' \
 +          -e '        s|#!.*python|#!$(PYTHON_PATH_SQ)|' \
 +          -e '}' \
 +          -e 's|^import sys.*|&; \\\
 +                 import os; \\\
 +                 sys.path[0] = os.environ.has_key("GITPYTHONLIB") and \\\
 +                               os.environ["GITPYTHONLIB"] or \\\
 +                               "@@INSTLIBDIR@@"|' \
 +          -e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \
 +          $@.py >$@+ && \
 +      chmod +x $@+ && \
 +      mv $@+ $@
 +else # NO_PYTHON
 +$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : unimplemented.sh
 +      $(QUIET_GEN)$(RM) $@ $@+ && \
 +      sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
 +          -e 's|@@REASON@@|NO_PYTHON=$(NO_PYTHON)|g' \
 +          unimplemented.sh >$@+ && \
 +      chmod +x $@+ && \
 +      mv $@+ $@
 +endif # NO_PYTHON
 +
  configure: configure.ac
        $(QUIET_GEN)$(RM) $@ $<+ && \
        sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
@@@ -1644,7 -1453,7 +1644,7 @@@ git.o git.spec 
        $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
  %.s: %.c GIT-CFLAGS
        $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
 -%.o: %.S
 +%.o: %.S GIT-CFLAGS
        $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
  
  exec_cmd.o: exec_cmd.c GIT-CFLAGS
@@@ -1675,21 -1484,12 +1675,21 @@@ git-imap-send$X: imap-send.o $(GITLIBS
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
  
 -http.o http-walker.o http-push.o transport.o: http.h
 +http.o http-walker.o http-push.o: http.h
  
 +http.o http-walker.o: $(LIB_H)
 +
 +git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS)
 +      $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 +              $(LIBS) $(CURL_LIBCURL)
  git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
  
 +git-remote-curl$X: remote-curl.o http.o http-walker.o $(GITLIBS)
 +      $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 +              $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
 +
  $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
  $(patsubst git-%$X,%.o,$(PROGRAMS)) git.o: $(LIB_H) $(wildcard */*.h)
  builtin-revert.o wt-status.o: wt-status.h
@@@ -1749,11 -1549,9 +1749,11 @@@ GIT-CFLAGS: .FORCE-GIT-CFLAG
  # and the first level quoting from the shell that runs "echo".
  GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
        @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
 +      @echo PERL_PATH=\''$(subst ','\'',$(PERL_PATH_SQ))'\' >>$@
        @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
        @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
        @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
 +      @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@
  
  ### Detect Tck/Tk interpreter path changes
  ifndef NO_TCLTK
@@@ -1771,30 -1569,20 +1771,31 @@@ endi
  
  ### Testing rules
  
 -TEST_PROGRAMS += test-chmtime$X
 -TEST_PROGRAMS += test-ctype$X
 -TEST_PROGRAMS += test-date$X
 -TEST_PROGRAMS += test-delta$X
 -TEST_PROGRAMS += test-dump-cache-tree$X
 -TEST_PROGRAMS += test-genrandom$X
 -TEST_PROGRAMS += test-match-trees$X
 -TEST_PROGRAMS += test-parse-options$X
 -TEST_PROGRAMS += test-path-utils$X
 -TEST_PROGRAMS += test-sha1$X
 -TEST_PROGRAMS += test-sigchain$X
 -TEST_PROGRAMS += test-index-version$X
 -
 -all:: $(TEST_PROGRAMS)
 +TEST_PROGRAMS_NEED_X += test-chmtime
 +TEST_PROGRAMS_NEED_X += test-ctype
 +TEST_PROGRAMS_NEED_X += test-date
 +TEST_PROGRAMS_NEED_X += test-delta
 +TEST_PROGRAMS_NEED_X += test-dump-cache-tree
 +TEST_PROGRAMS_NEED_X += test-genrandom
 +TEST_PROGRAMS_NEED_X += test-match-trees
 +TEST_PROGRAMS_NEED_X += test-parse-options
 +TEST_PROGRAMS_NEED_X += test-path-utils
 +TEST_PROGRAMS_NEED_X += test-sha1
 +TEST_PROGRAMS_NEED_X += test-sigchain
++TEST_PROGRAMS_NEED_X += test-index-version
 +
 +TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
 +
 +test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))
 +
 +all:: $(TEST_PROGRAMS) $(test_bindir_programs)
 +
 +bin-wrappers/%: wrap-for-bin.sh
 +      @mkdir -p bin-wrappers
 +      $(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
 +           -e 's|@@BUILD_DIR@@|$(shell pwd)|' \
 +           -e 's|@@PROG@@|$(@F)|' < $< > $@ && \
 +      chmod +x $@
  
  # GNU make supports exporting all variables by "export" without parameters.
  # However, the environment gets quite big, and some programs have problems
@@@ -1855,20 -1643,15 +1856,20 @@@ endi
  gitexec_instdir_SQ = $(subst ','\'',$(gitexec_instdir))
  export gitexec_instdir
  
 +install_bindir_programs := $(patsubst %,%$X,$(BINDIR_PROGRAMS_NEED_X)) $(BINDIR_PROGRAMS_NO_X)
 +
  install: all
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 -      $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)'
 +      $(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
        $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
  ifndef NO_PERL
        $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
  endif
 +ifndef NO_PYTHON
 +      $(MAKE) -C git_remote_helpers prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
 +endif
  ifndef NO_TCLTK
        $(MAKE) -C gitk-git install
        $(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
@@@ -1940,10 -1723,7 +1941,10 @@@ dist: git.spec git-archive$(X) configur
        gzip -f -9 $(GIT_TARNAME).tar
  
  rpm: dist
 -      $(RPMBUILD) -ta $(GIT_TARNAME).tar.gz
 +      $(RPMBUILD) \
 +              --define "_source_filedigest_algorithm md5" \
 +              --define "_binary_filedigest_algorithm md5" \
 +              -ta $(GIT_TARNAME).tar.gz
  
  htmldocs = git-htmldocs-$(GIT_VERSION)
  manpages = git-manpages-$(GIT_VERSION)
@@@ -1971,11 -1751,10 +1972,11 @@@ distclean: clea
        $(RM) configure
  
  clean:
 -      $(RM) *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
 +      $(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o \
                $(LIB_FILE) $(XDIFF_LIB)
        $(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
        $(RM) $(TEST_PROGRAMS)
 +      $(RM) -r bin-wrappers
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
        $(RM) -r autom4te.cache
        $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
  ifndef NO_PERL
        $(RM) gitweb/gitweb.cgi
        $(MAKE) -C perl clean
 +endif
 +ifndef NO_PYTHON
 +      $(MAKE) -C git_remote_helpers clean
  endif
        $(MAKE) -C templates/ clean
        $(MAKE) -C t/ clean
diff --combined builtin-apply.c
index 36e2f9dda5c85c346e31f45afa6d28b107679970,7717a667432554ee44ff447d78b61f685c92c464..541493e1ba81462f4b01bb99c2840938bae02e4f
@@@ -61,13 -61,6 +61,13 @@@ static enum ws_error_action 
  static int whitespace_error;
  static int squelch_whitespace_errors = 5;
  static int applied_after_fixing_ws;
 +
 +static enum ws_ignore {
 +      ignore_ws_none,
 +      ignore_ws_change,
 +} ws_ignore_action = ignore_ws_none;
 +
 +
  static const char *patch_input_file;
  static const char *root;
  static int root_len;
@@@ -104,21 -97,6 +104,21 @@@ static void parse_whitespace_option(con
        die("unrecognized whitespace option '%s'", option);
  }
  
 +static void parse_ignorewhitespace_option(const char *option)
 +{
 +      if (!option || !strcmp(option, "no") ||
 +          !strcmp(option, "false") || !strcmp(option, "never") ||
 +          !strcmp(option, "none")) {
 +              ws_ignore_action = ignore_ws_none;
 +              return;
 +      }
 +      if (!strcmp(option, "change")) {
 +              ws_ignore_action = ignore_ws_change;
 +              return;
 +      }
 +      die("unrecognized whitespace ignore option '%s'", option);
 +}
 +
  static void set_default_whitespace_mode(const char *whitespace_option)
  {
        if (!whitespace_option && !apply_default_whitespace)
@@@ -153,7 -131,6 +153,7 @@@ struct fragment 
        const char *patch;
        int size;
        int rejected;
 +      int linenr;
        struct fragment *next;
  };
  
@@@ -237,62 -214,6 +237,62 @@@ static uint32_t hash_line(const char *c
        return h;
  }
  
 +/*
 + * Compare lines s1 of length n1 and s2 of length n2, ignoring
 + * whitespace difference. Returns 1 if they match, 0 otherwise
 + */
 +static int fuzzy_matchlines(const char *s1, size_t n1,
 +                          const char *s2, size_t n2)
 +{
 +      const char *last1 = s1 + n1 - 1;
 +      const char *last2 = s2 + n2 - 1;
 +      int result = 0;
 +
 +      if (n1 < 0 || n2 < 0)
 +              return 0;
 +
 +      /* ignore line endings */
 +      while ((*last1 == '\r') || (*last1 == '\n'))
 +              last1--;
 +      while ((*last2 == '\r') || (*last2 == '\n'))
 +              last2--;
 +
 +      /* skip leading whitespace */
 +      while (isspace(*s1) && (s1 <= last1))
 +              s1++;
 +      while (isspace(*s2) && (s2 <= last2))
 +              s2++;
 +      /* early return if both lines are empty */
 +      if ((s1 > last1) && (s2 > last2))
 +              return 1;
 +      while (!result) {
 +              result = *s1++ - *s2++;
 +              /*
 +               * Skip whitespace inside. We check for whitespace on
 +               * both buffers because we don't want "a b" to match
 +               * "ab"
 +               */
 +              if (isspace(*s1) && isspace(*s2)) {
 +                      while (isspace(*s1) && s1 <= last1)
 +                              s1++;
 +                      while (isspace(*s2) && s2 <= last2)
 +                              s2++;
 +              }
 +              /*
 +               * If we reached the end on one side only,
 +               * lines don't match
 +               */
 +              if (
 +                  ((s2 > last2) && (s1 <= last1)) ||
 +                  ((s1 > last1) && (s2 <= last2)))
 +                      return 0;
 +              if ((s1 > last1) && (s2 > last2))
 +                      break;
 +      }
 +
 +      return !result;
 +}
 +
  static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag)
  {
        ALLOC_GROW(img->line_allocated, img->nr + 1, img->alloc);
@@@ -823,13 -744,12 +823,13 @@@ static int gitdiff_unrecognized(const c
  
  static const char *stop_at_slash(const char *line, int llen)
  {
 +      int nslash = p_value;
        int i;
  
        for (i = 0; i < llen; i++) {
                int ch = line[i];
 -              if (ch == '/')
 -                      return line + i;
 +              if (ch == '/' && --nslash <= 0)
 +                      return &line[i];
        }
        return NULL;
  }
@@@ -1229,29 -1149,23 +1229,29 @@@ static int find_header(char *line, unsi
        return -1;
  }
  
 -static void check_whitespace(const char *line, int len, unsigned ws_rule)
 +static void record_ws_error(unsigned result, const char *line, int len, int linenr)
  {
        char *err;
 -      unsigned result = ws_check(line + 1, len - 1, ws_rule);
 +
        if (!result)
                return;
  
        whitespace_error++;
        if (squelch_whitespace_errors &&
            squelch_whitespace_errors < whitespace_error)
 -              ;
 -      else {
 -              err = whitespace_error_string(result);
 -              fprintf(stderr, "%s:%d: %s.\n%.*s\n",
 -                      patch_input_file, linenr, err, len - 2, line + 1);
 -              free(err);
 -      }
 +              return;
 +
 +      err = whitespace_error_string(result);
 +      fprintf(stderr, "%s:%d: %s.\n%.*s\n",
 +              patch_input_file, linenr, err, len, line);
 +      free(err);
 +}
 +
 +static void check_whitespace(const char *line, int len, unsigned ws_rule)
 +{
 +      unsigned result = ws_check(line + 1, len - 1, ws_rule);
 +
 +      record_ws_error(result, line + 1, len - 2, linenr);
  }
  
  /*
@@@ -1367,7 -1281,6 +1367,7 @@@ static int parse_single_patch(char *lin
                int len;
  
                fragment = xcalloc(1, sizeof(*fragment));
 +              fragment->linenr = linenr;
                len = parse_fragment(line, size, patch, fragment);
                if (len <= 0)
                        die("corrupt patch at line %d", linenr);
@@@ -1759,17 -1672,10 +1759,17 @@@ static int read_old_data(struct stat *s
        }
  }
  
 +/*
 + * Update the preimage, and the common lines in postimage,
 + * from buffer buf of length len. If postlen is 0 the postimage
 + * is updated in place, otherwise it's updated on a new buffer
 + * of length postlen
 + */
 +
  static void update_pre_post_images(struct image *preimage,
                                   struct image *postimage,
                                   char *buf,
 -                                 size_t len)
 +                                 size_t len, size_t postlen)
  {
        int i, ctx;
        char *new, *old, *fixed;
        *preimage = fixed_preimage;
  
        /*
 -       * Adjust the common context lines in postimage, in place.
 -       * This is possible because whitespace fixing does not make
 -       * the string grow.
 +       * Adjust the common context lines in postimage. This can be
 +       * done in-place when we are just doing whitespace fixing,
 +       * which does not make the string grow, but needs a new buffer
 +       * when ignoring whitespace causes the update, since in this case
 +       * we could have e.g. tabs converted to multiple spaces.
 +       * We trust the caller to tell us if the update can be done
 +       * in place (postlen==0) or not.
         */
 -      new = old = postimage->buf;
 +      old = postimage->buf;
 +      if (postlen)
 +              new = postimage->buf = xmalloc(postlen);
 +      else
 +              new = old;
        fixed = preimage->buf;
        for (i = ctx = 0; i < postimage->nr; i++) {
                size_t len = postimage->line[i].len;
@@@ -1875,56 -1773,12 +1875,56 @@@ static int match_fragment(struct image 
            !memcmp(img->buf + try, preimage->buf, preimage->len))
                return 1;
  
 +      /*
 +       * No exact match. If we are ignoring whitespace, run a line-by-line
 +       * fuzzy matching. We collect all the line length information because
 +       * we need it to adjust whitespace if we match.
 +       */
 +      if (ws_ignore_action == ignore_ws_change) {
 +              size_t imgoff = 0;
 +              size_t preoff = 0;
 +              size_t postlen = postimage->len;
 +              for (i = 0; i < preimage->nr; i++) {
 +                      size_t prelen = preimage->line[i].len;
 +                      size_t imglen = img->line[try_lno+i].len;
 +
 +                      if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
 +                                            preimage->buf + preoff, prelen))
 +                              return 0;
 +                      if (preimage->line[i].flag & LINE_COMMON)
 +                              postlen += imglen - prelen;
 +                      imgoff += imglen;
 +                      preoff += prelen;
 +              }
 +
 +              /*
 +               * Ok, the preimage matches with whitespace fuzz. Update it and
 +               * the common postimage lines to use the same whitespace as the
 +               * target. imgoff now holds the true length of the target that
 +               * matches the preimage, and we need to update the line lengths
 +               * of the preimage to match the target ones.
 +               */
 +              fixed_buf = xmalloc(imgoff);
 +              memcpy(fixed_buf, img->buf + try, imgoff);
 +              for (i = 0; i < preimage->nr; i++)
 +                      preimage->line[i].len = img->line[try_lno+i].len;
 +
 +              /*
 +               * Update the preimage buffer and the postimage context lines.
 +               */
 +              update_pre_post_images(preimage, postimage,
 +                              fixed_buf, imgoff, postlen);
 +              return 1;
 +      }
 +
        if (ws_error_action != correct_ws_error)
                return 0;
  
        /*
         * The hunk does not apply byte-by-byte, but the hash says
 -       * it might with whitespace fuzz.
 +       * it might with whitespace fuzz. We haven't been asked to
 +       * ignore whitespace, we were asked to correct whitespace
 +       * errors, so let's try matching after whitespace correction.
         */
        fixed_buf = xmalloc(preimage->len + 1);
        buf = fixed_buf;
         * hunk match.  Update the context lines in the postimage.
         */
        update_pre_post_images(preimage, postimage,
 -                             fixed_buf, buf - fixed_buf);
 +                             fixed_buf, buf - fixed_buf, 0);
        return 1;
  
   unmatch_exit:
@@@ -2151,7 -2005,6 +2151,7 @@@ static int apply_one_fragment(struct im
                int len = linelen(patch, size);
                int plen, added;
                int added_blank_line = 0;
 +              int is_blank_context = 0;
  
                if (!len)
                        break;
                        *new++ = '\n';
                        add_line_info(&preimage, "\n", 1, LINE_COMMON);
                        add_line_info(&postimage, "\n", 1, LINE_COMMON);
 +                      is_blank_context = 1;
                        break;
                case ' ':
 +                      if (plen && (ws_rule & WS_BLANK_AT_EOF) &&
 +                          ws_blank_line(patch + 1, plen, ws_rule))
 +                              is_blank_context = 1;
                case '-':
                        memcpy(old, patch + 1, plen);
                        add_line_info(&preimage, old, plen,
                                      (first == '+' ? 0 : LINE_COMMON));
                        new += added;
                        if (first == '+' &&
 -                          added == 1 && new[-1] == '\n')
 +                          (ws_rule & WS_BLANK_AT_EOF) &&
 +                          ws_blank_line(patch + 1, plen, ws_rule))
                                added_blank_line = 1;
                        break;
                case '@': case '\\':
                }
                if (added_blank_line)
                        new_blank_lines_at_end++;
 +              else if (is_blank_context)
 +                      ;
                else
                        new_blank_lines_at_end = 0;
                patch += len;
        }
  
        if (applied_pos >= 0) {
 -              if (ws_error_action == correct_ws_error &&
 -                  new_blank_lines_at_end &&
 -                  postimage.nr + applied_pos == img->nr) {
 +              if (new_blank_lines_at_end &&
 +                  preimage.nr + applied_pos == img->nr &&
 +                  (ws_rule & WS_BLANK_AT_EOF) &&
 +                  ws_error_action != nowarn_ws_error) {
 +                      record_ws_error(WS_BLANK_AT_EOF, "+", 1, frag->linenr);
 +                      if (ws_error_action == correct_ws_error) {
 +                              while (new_blank_lines_at_end--)
 +                                      remove_last_line(&postimage);
 +                      }
                        /*
 -                       * If the patch application adds blank lines
 -                       * at the end, and if the patch applies at the
 -                       * end of the image, remove those added blank
 -                       * lines.
 +                       * We would want to prevent write_out_results()
 +                       * from taking place in apply_patch() that follows
 +                       * the callchain led us here, which is:
 +                       * apply_patch->check_patch_list->check_patch->
 +                       * apply_data->apply_fragments->apply_one_fragment
                         */
 -                      while (new_blank_lines_at_end--)
 -                              remove_last_line(&postimage);
 +                      if (ws_error_action == die_on_ws_error)
 +                              apply = 0;
                }
  
                /*
@@@ -2666,7 -2505,7 +2666,7 @@@ static int verify_index_match(struct ca
                        return -1;
                return 0;
        }
-       return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);
+       return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
  }
  
  static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
@@@ -3433,8 -3272,6 +3433,8 @@@ static int git_apply_config(const char 
  {
        if (!strcmp(var, "apply.whitespace"))
                return git_config_string(&apply_default_whitespace, var, value);
 +      else if (!strcmp(var, "apply.ignorewhitespace"))
 +              return git_config_string(&apply_default_ignorewhitespace, var, value);
        return git_default_config(var, value, cb);
  }
  
@@@ -3471,16 -3308,6 +3471,16 @@@ static int option_parse_z(const struct 
        return 0;
  }
  
 +static int option_parse_space_change(const struct option *opt,
 +                        const char *arg, int unset)
 +{
 +      if (unset)
 +              ws_ignore_action = ignore_ws_none;
 +      else
 +              ws_ignore_action = ignore_ws_change;
 +      return 0;
 +}
 +
  static int option_parse_whitespace(const struct option *opt,
                                   const char *arg, int unset)
  {
@@@ -3557,12 -3384,6 +3557,12 @@@ int cmd_apply(int argc, const char **ar
                { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, "action",
                        "detect new or modified lines that have whitespace errors",
                        0, option_parse_whitespace },
 +              { OPTION_CALLBACK, 0, "ignore-space-change", NULL, NULL,
 +                      "ignore changes in whitespace when finding context",
 +                      PARSE_OPT_NOARG, option_parse_space_change },
 +              { OPTION_CALLBACK, 0, "ignore-whitespace", NULL, NULL,
 +                      "ignore changes in whitespace when finding context",
 +                      PARSE_OPT_NOARG, option_parse_space_change },
                OPT_BOOLEAN('R', "reverse", &apply_in_reverse,
                        "apply the patch in reverse"),
                OPT_BOOLEAN(0, "unidiff-zero", &unidiff_zero,
        git_config(git_apply_config, NULL);
        if (apply_default_whitespace)
                parse_whitespace_option(apply_default_whitespace);
 +      if (apply_default_ignorewhitespace)
 +              parse_ignorewhitespace_option(apply_default_ignorewhitespace);
  
        argc = parse_options(argc, argv, prefix, builtin_apply_options,
                        apply_usage, 0);
diff --combined builtin-clean.c
index 28cdcd0274dd5891c7ad3dc3804cb0acead883f2,e424b77e6b7367a5704d586ab38d34908684de55..3a70fa81bdd8f0e087476560f7c2f668a3cda0ea
@@@ -31,7 -31,6 +31,7 @@@ int cmd_clean(int argc, const char **ar
        int i;
        int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
        int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
 +      int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
        struct strbuf directory = STRBUF_INIT;
        struct dir_struct dir;
        static const char **pathspec;
@@@ -41,7 -40,7 +41,7 @@@
        struct option options[] = {
                OPT__QUIET(&quiet),
                OPT__DRY_RUN(&show_only),
 -              OPT_BOOLEAN('f', NULL, &force, "force"),
 +              OPT_BOOLEAN('f', "force", &force, "force"),
                OPT_BOOLEAN('d', NULL, &remove_directories,
                                "remove whole directories"),
                OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
                die("clean.requireForce%s set and -n or -f not given; "
                    "refusing to clean", config_set ? "" : " not");
  
 +      if (force > 1)
 +              rm_flags = 0;
 +
        dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
  
+       if (read_cache() < 0)
+               die("index file corrupt");
        if (!ignored)
                setup_standard_excludes(&dir);
  
        pathspec = get_pathspec(prefix, argv);
-       read_cache();
  
        fill_directory(&dir, pathspec);
  
                                   (matches == MATCHED_EXACTLY)) {
                                if (!quiet)
                                        printf("Removing %s\n", qname);
 -                              if (remove_dir_recursively(&directory, 0) != 0) {
 +                              if (remove_dir_recursively(&directory,
 +                                                         rm_flags) != 0) {
                                        warning("failed to remove '%s'", qname);
                                        errors++;
                                }
diff --combined builtin-commit.c
index 073fe90ba1e04c3845fe49521db39b28339acb43,9d596903bfa2118e1385ebce9625bc14a63d53e7..592b10396d1d6aa25d5d1c0aa27556c93c219877
@@@ -24,7 -24,6 +24,7 @@@
  #include "string-list.h"
  #include "rerere.h"
  #include "unpack-trees.h"
 +#include "quote.h"
  
  static const char * const builtin_commit_usage[] = {
        "git commit [options] [--] <filepattern>...",
@@@ -36,7 -35,7 +36,7 @@@ static const char * const builtin_statu
        NULL
  };
  
 -static unsigned char head_sha1[20], merge_head_sha1[20];
 +static unsigned char head_sha1[20];
  static char *use_message_buffer;
  static const char commit_editmsg[] = "COMMIT_EDITMSG";
  static struct lock_file index_lock; /* real index */
@@@ -52,8 -51,8 +52,8 @@@ static const char *template_file
  static char *edit_message, *use_message;
  static char *author_name, *author_email, *author_date;
  static int all, edit_flag, also, interactive, only, amend, signoff;
 -static int quiet, verbose, no_verify, allow_empty;
 -static char *untracked_files_arg;
 +static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 +static char *untracked_files_arg, *force_date;
  /*
   * The default commit message cleanup mode will remove the lines
   * beginning with # (shell comments) and leading and trailing
@@@ -72,13 -71,6 +72,13 @@@ static int use_editor = 1, initial_comm
  static const char *only_include_assumed;
  static struct strbuf message;
  
 +static int null_termination;
 +static enum {
 +      STATUS_FORMAT_LONG,
 +      STATUS_FORMAT_SHORT,
 +      STATUS_FORMAT_PORCELAIN,
 +} status_format = STATUS_FORMAT_LONG;
 +
  static int opt_parse_m(const struct option *opt, const char *arg, int unset)
  {
        struct strbuf *buf = opt->value;
  static struct option builtin_commit_options[] = {
        OPT__QUIET(&quiet),
        OPT__VERBOSE(&verbose),
 -      OPT_GROUP("Commit message options"),
  
 +      OPT_GROUP("Commit message options"),
        OPT_FILENAME('F', "file", &logfile, "read log from file"),
        OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"),
 +      OPT_STRING(0, "date", &force_date, "DATE", "override date for commit"),
        OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m),
 -      OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "),
 +      OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit"),
        OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
 +      OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C-c/--amend)"),
        OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
        OPT_FILENAME('t', "template", &template_file, "use specified template file"),
        OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
 +      OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
 +      /* end commit message options */
  
        OPT_GROUP("Commit contents options"),
        OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
        OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
        OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
        OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
 +      OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
 +      OPT_SET_INT(0, "short", &status_format, "show status concisely",
 +                  STATUS_FORMAT_SHORT),
 +      OPT_SET_INT(0, "porcelain", &status_format,
 +                  "show porcelain output format", STATUS_FORMAT_PORCELAIN),
 +      OPT_BOOLEAN('z', "null", &null_termination,
 +                  "terminate entries with NUL"),
        OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
        { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
        OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"),
 -      OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
 +      /* end commit contents options */
  
        OPT_END()
  };
@@@ -183,11 -164,15 +183,15 @@@ static int list_paths(struct string_lis
  
        for (i = 0; i < active_nr; i++) {
                struct cache_entry *ce = active_cache[i];
+               struct string_list_item *item;
                if (ce->ce_flags & CE_UPDATE)
                        continue;
                if (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m))
                        continue;
-               string_list_insert(ce->name, list);
+               item = string_list_insert(ce->name, list);
+               if (ce_skip_worktree(ce))
+                       item->util = item; /* better a valid pointer than a fake one */
        }
  
        return report_path_error(m, pattern, prefix ? strlen(prefix) : 0);
@@@ -200,6 -185,10 +204,10 @@@ static void add_remove_files(struct str
                struct stat st;
                struct string_list_item *p = &(list->items[i]);
  
+               /* p->util is skip-worktree */
+               if (p->util)
+                       continue;
                if (!lstat(p->string, &st)) {
                        if (add_to_cache(p->string, &st, 0))
                                die("updating files failed");
@@@ -236,15 -225,12 +244,15 @@@ static void create_base_index(void
                exit(128); /* We've already reported the error, finish dying */
  }
  
 -static char *prepare_index(int argc, const char **argv, const char *prefix)
 +static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status)
  {
        int fd;
        struct string_list partial;
        const char **pathspec = NULL;
 +      int refresh_flags = REFRESH_QUIET;
  
 +      if (is_status)
 +              refresh_flags |= REFRESH_UNMERGED;
        if (interactive) {
                if (interactive_add(argc, argv, prefix) != 0)
                        die("interactive add failed");
        if (all || (also && pathspec && *pathspec)) {
                int fd = hold_locked_index(&index_lock, 1);
                add_files_to_cache(also ? prefix : NULL, pathspec, 0);
 -              refresh_cache(REFRESH_QUIET);
 +              refresh_cache(refresh_flags);
                if (write_cache(fd, active_cache, active_nr) ||
                    close_lock_file(&index_lock))
                        die("unable to write new_index file");
         */
        if (!pathspec || !*pathspec) {
                fd = hold_locked_index(&index_lock, 1);
 -              refresh_cache(REFRESH_QUIET);
 +              refresh_cache(refresh_flags);
                if (write_cache(fd, active_cache, active_nr) ||
                    commit_locked_index(&index_lock))
                        die("unable to write new_index file");
         */
        commit_style = COMMIT_PARTIAL;
  
 -      if (file_exists(git_path("MERGE_HEAD")))
 +      if (in_merge)
                die("cannot do a partial commit during a merge.");
  
        memset(&partial, 0, sizeof(partial));
        return false_lock.filename;
  }
  
 -static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn)
 +static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
 +                    struct wt_status *s)
  {
 -      struct wt_status s;
 +      unsigned char sha1[20];
  
 -      wt_status_prepare(&s);
 -      if (wt_status_relative_paths)
 -              s.prefix = prefix;
 +      if (s->relative_paths)
 +              s->prefix = prefix;
  
        if (amend) {
 -              s.amend = 1;
 -              s.reference = "HEAD^1";
 +              s->amend = 1;
 +              s->reference = "HEAD^1";
        }
 -      s.verbose = verbose;
 -      s.untracked = (show_untracked_files == SHOW_ALL_UNTRACKED_FILES);
 -      s.index_file = index_file;
 -      s.fp = fp;
 -      s.nowarn = nowarn;
 +      s->verbose = verbose;
 +      s->index_file = index_file;
 +      s->fp = fp;
 +      s->nowarn = nowarn;
 +      s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
  
 -      wt_status_print(&s);
 +      wt_status_collect(s);
  
 -      return s.commitable;
 +      switch (status_format) {
 +      case STATUS_FORMAT_SHORT:
 +              wt_shortstatus_print(s, null_termination);
 +              break;
 +      case STATUS_FORMAT_PORCELAIN:
 +              wt_porcelain_print(s, null_termination);
 +              break;
 +      case STATUS_FORMAT_LONG:
 +              wt_status_print(s);
 +              break;
 +      }
 +
 +      return s->commitable;
  }
  
  static int is_a_merge(const unsigned char *sha1)
@@@ -414,7 -388,7 +422,7 @@@ static void determine_author_info(void
        email = getenv("GIT_AUTHOR_EMAIL");
        date = getenv("GIT_AUTHOR_DATE");
  
 -      if (use_message) {
 +      if (use_message && !renew_authorship) {
                const char *a, *lb, *rb, *eol;
  
                a = strstr(use_message_buffer, "\nauthor ");
                email = xstrndup(lb + 2, rb - (lb + 2));
        }
  
 +      if (force_date)
 +              date = force_date;
 +
        author_name = name;
        author_email = email;
        author_date = date;
  }
  
 -static int prepare_to_commit(const char *index_file, const char *prefix)
 +static int ends_rfc2822_footer(struct strbuf *sb)
 +{
 +      int ch;
 +      int hit = 0;
 +      int i, j, k;
 +      int len = sb->len;
 +      int first = 1;
 +      const char *buf = sb->buf;
 +
 +      for (i = len - 1; i > 0; i--) {
 +              if (hit && buf[i] == '\n')
 +                      break;
 +              hit = (buf[i] == '\n');
 +      }
 +
 +      while (i < len - 1 && buf[i] == '\n')
 +              i++;
 +
 +      for (; i < len; i = k) {
 +              for (k = i; k < len && buf[k] != '\n'; k++)
 +                      ; /* do nothing */
 +              k++;
 +
 +              if ((buf[k] == ' ' || buf[k] == '\t') && !first)
 +                      continue;
 +
 +              first = 0;
 +
 +              for (j = 0; i + j < len; j++) {
 +                      ch = buf[i + j];
 +                      if (ch == ':')
 +                              break;
 +                      if (isalnum(ch) ||
 +                          (ch == '-'))
 +                              continue;
 +                      return 0;
 +              }
 +      }
 +      return 1;
 +}
 +
 +static int prepare_to_commit(const char *index_file, const char *prefix,
 +                           struct wt_status *s)
  {
        struct stat statbuf;
        int commitable, saved_color_setting;
                for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--)
                        ; /* do nothing */
                if (prefixcmp(sb.buf + i, sob.buf)) {
 -                      if (prefixcmp(sb.buf + i, sign_off_header))
 +                      if (!i || !ends_rfc2822_footer(&sb))
                                strbuf_addch(&sb, '\n');
                        strbuf_addbuf(&sb, &sob);
                }
                if (ident_shown)
                        fprintf(fp, "#\n");
  
 -              saved_color_setting = wt_status_use_color;
 -              wt_status_use_color = 0;
 -              commitable = run_status(fp, index_file, prefix, 1);
 -              wt_status_use_color = saved_color_setting;
 +              saved_color_setting = s->use_color;
 +              s->use_color = 0;
 +              commitable = run_status(fp, index_file, prefix, 1, s);
 +              s->use_color = saved_color_setting;
        } else {
                unsigned char sha1[20];
                const char *parent = "HEAD";
  
        if (!commitable && !in_merge && !allow_empty &&
            !(amend && is_a_merge(head_sha1))) {
 -              run_status(stdout, index_file, prefix, 0);
 +              run_status(stdout, index_file, prefix, 0, s);
                return 0;
        }
  
@@@ -761,34 -690,16 +769,34 @@@ static const char *find_author_by_nickn
        prepare_revision_walk(&revs);
        commit = get_revision(&revs);
        if (commit) {
 +              struct pretty_print_context ctx = {0};
 +              ctx.date_mode = DATE_NORMAL;
                strbuf_release(&buf);
 -              format_commit_message(commit, "%an <%ae>", &buf, DATE_NORMAL);
 +              format_commit_message(commit, "%an <%ae>", &buf, &ctx);
                return strbuf_detach(&buf, NULL);
        }
        die("No existing author found with '%s'", name);
  }
  
 +
 +static void handle_untracked_files_arg(struct wt_status *s)
 +{
 +      if (!untracked_files_arg)
 +              ; /* default already initialized */
 +      else if (!strcmp(untracked_files_arg, "no"))
 +              s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
 +      else if (!strcmp(untracked_files_arg, "normal"))
 +              s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
 +      else if (!strcmp(untracked_files_arg, "all"))
 +              s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
 +      else
 +              die("Invalid untracked files mode '%s'", untracked_files_arg);
 +}
 +
  static int parse_and_validate_options(int argc, const char *argv[],
                                      const char * const usage[],
 -                                    const char *prefix)
 +                                    const char *prefix,
 +                                    struct wt_status *s)
  {
        int f = 0;
  
        if (force_author && !strchr(force_author, '>'))
                force_author = find_author_by_nickname(force_author);
  
 +      if (force_author && renew_authorship)
 +              die("Using both --reset-author and --author does not make sense");
 +
        if (logfile || message.len || use_message)
                use_editor = 0;
        if (edit_flag)
        if (get_sha1("HEAD", head_sha1))
                initial_commit = 1;
  
 -      if (!get_sha1("MERGE_HEAD", merge_head_sha1))
 -              in_merge = 1;
 -
        /* Sanity check options */
        if (amend && initial_commit)
                die("You have nothing to amend.");
                use_message = edit_message;
        if (amend && !use_message)
                use_message = "HEAD";
 +      if (!use_message && renew_authorship)
 +              die("--reset-author can be used only with -C, -c or --amend.");
        if (use_message) {
                unsigned char sha1[20];
                static char utf8[] = "UTF-8";
        else
                die("Invalid cleanup mode %s", cleanup_arg);
  
 -      if (!untracked_files_arg)
 -              ; /* default already initialized */
 -      else if (!strcmp(untracked_files_arg, "no"))
 -              show_untracked_files = SHOW_NO_UNTRACKED_FILES;
 -      else if (!strcmp(untracked_files_arg, "normal"))
 -              show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
 -      else if (!strcmp(untracked_files_arg, "all"))
 -              show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
 -      else
 -              die("Invalid untracked files mode '%s'", untracked_files_arg);
 +      handle_untracked_files_arg(s);
  
        if (all && argc > 0)
                die("Paths with -a does not make sense.");
        else if (interactive && argc > 0)
                die("Paths with --interactive does not make sense.");
  
 +      if (null_termination && status_format == STATUS_FORMAT_LONG)
 +              status_format = STATUS_FORMAT_PORCELAIN;
 +      if (status_format != STATUS_FORMAT_LONG)
 +              dry_run = 1;
 +
        return argc;
  }
  
 -int cmd_status(int argc, const char **argv, const char *prefix)
 +static int dry_run_commit(int argc, const char **argv, const char *prefix,
 +                        struct wt_status *s)
  {
 -      const char *index_file;
        int commitable;
 +      const char *index_file;
  
 -      git_config(git_status_config, NULL);
 +      index_file = prepare_index(argc, argv, prefix, 1);
 +      commitable = run_status(stdout, index_file, prefix, 0, s);
 +      rollback_index_files();
  
 -      if (wt_status_use_color == -1)
 -              wt_status_use_color = git_use_color_default;
 +      return commitable ? 0 : 1;
 +}
  
 -      if (diff_use_color_default == -1)
 -              diff_use_color_default = git_use_color_default;
 +static int parse_status_slot(const char *var, int offset)
 +{
 +      if (!strcasecmp(var+offset, "header"))
 +              return WT_STATUS_HEADER;
 +      if (!strcasecmp(var+offset, "updated")
 +              || !strcasecmp(var+offset, "added"))
 +              return WT_STATUS_UPDATED;
 +      if (!strcasecmp(var+offset, "changed"))
 +              return WT_STATUS_CHANGED;
 +      if (!strcasecmp(var+offset, "untracked"))
 +              return WT_STATUS_UNTRACKED;
 +      if (!strcasecmp(var+offset, "nobranch"))
 +              return WT_STATUS_NOBRANCH;
 +      if (!strcasecmp(var+offset, "unmerged"))
 +              return WT_STATUS_UNMERGED;
 +      return -1;
 +}
  
 -      argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix);
 +static int git_status_config(const char *k, const char *v, void *cb)
 +{
 +      struct wt_status *s = cb;
  
 -      index_file = prepare_index(argc, argv, prefix);
 +      if (!strcmp(k, "status.submodulesummary")) {
 +              int is_bool;
 +              s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
 +              if (is_bool && s->submodule_summary)
 +                      s->submodule_summary = -1;
 +              return 0;
 +      }
 +      if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
 +              s->use_color = git_config_colorbool(k, v, -1);
 +              return 0;
 +      }
 +      if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
 +              int slot = parse_status_slot(k, 13);
 +              if (slot < 0)
 +                      return 0;
 +              if (!v)
 +                      return config_error_nonbool(k);
 +              color_parse(v, k, s->color_palette[slot]);
 +              return 0;
 +      }
 +      if (!strcmp(k, "status.relativepaths")) {
 +              s->relative_paths = git_config_bool(k, v);
 +              return 0;
 +      }
 +      if (!strcmp(k, "status.showuntrackedfiles")) {
 +              if (!v)
 +                      return config_error_nonbool(k);
 +              else if (!strcmp(v, "no"))
 +                      s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
 +              else if (!strcmp(v, "normal"))
 +                      s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
 +              else if (!strcmp(v, "all"))
 +                      s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
 +              else
 +                      return error("Invalid untracked files mode '%s'", v);
 +              return 0;
 +      }
 +      return git_diff_ui_config(k, v, NULL);
 +}
  
 -      commitable = run_status(stdout, index_file, prefix, 0);
 +int cmd_status(int argc, const char **argv, const char *prefix)
 +{
 +      struct wt_status s;
 +      unsigned char sha1[20];
 +      static struct option builtin_status_options[] = {
 +              OPT__VERBOSE(&verbose),
 +              OPT_SET_INT('s', "short", &status_format,
 +                          "show status concisely", STATUS_FORMAT_SHORT),
 +              OPT_SET_INT(0, "porcelain", &status_format,
 +                          "show porcelain output format",
 +                          STATUS_FORMAT_PORCELAIN),
 +              OPT_BOOLEAN('z', "null", &null_termination,
 +                          "terminate entries with NUL"),
 +              { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
 +                "mode",
 +                "show untracked files, optional modes: all, normal, no. (Default: all)",
 +                PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
 +              OPT_END(),
 +      };
 +
 +      if (null_termination && status_format == STATUS_FORMAT_LONG)
 +              status_format = STATUS_FORMAT_PORCELAIN;
  
 -      rollback_index_files();
 +      wt_status_prepare(&s);
 +      git_config(git_status_config, &s);
 +      in_merge = file_exists(git_path("MERGE_HEAD"));
 +      argc = parse_options(argc, argv, prefix,
 +                           builtin_status_options,
 +                           builtin_status_usage, 0);
 +      handle_untracked_files_arg(&s);
  
 -      return commitable ? 0 : 1;
 +      if (*argv)
 +              s.pathspec = get_pathspec(prefix, argv);
 +
 +      read_cache();
 +      refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
 +      s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
 +      s.in_merge = in_merge;
 +      wt_status_collect(&s);
 +
 +      if (s.relative_paths)
 +              s.prefix = prefix;
 +      if (s.use_color == -1)
 +              s.use_color = git_use_color_default;
 +      if (diff_use_color_default == -1)
 +              diff_use_color_default = git_use_color_default;
 +
 +      switch (status_format) {
 +      case STATUS_FORMAT_SHORT:
 +              wt_shortstatus_print(&s, null_termination);
 +              break;
 +      case STATUS_FORMAT_PORCELAIN:
 +              wt_porcelain_print(&s, null_termination);
 +              break;
 +      case STATUS_FORMAT_LONG:
 +              s.verbose = verbose;
 +              wt_status_print(&s);
 +              break;
 +      }
 +      return 0;
  }
  
  static void print_summary(const char *prefix, const unsigned char *sha1)
                initial_commit ? " (root-commit)" : "");
  
        if (!log_tree_commit(&rev, commit)) {
 +              struct pretty_print_context ctx = {0};
                struct strbuf buf = STRBUF_INIT;
 -              format_commit_message(commit, format + 7, &buf, DATE_NORMAL);
 +              ctx.date_mode = DATE_NORMAL;
 +              format_commit_message(commit, format + 7, &buf, &ctx);
                printf("%s\n", buf.buf);
                strbuf_release(&buf);
        }
  
  static int git_commit_config(const char *k, const char *v, void *cb)
  {
 +      struct wt_status *s = cb;
 +
        if (!strcmp(k, "commit.template"))
 -              return git_config_string(&template_file, k, v);
 +              return git_config_pathname(&template_file, k, v);
  
 -      return git_status_config(k, v, cb);
 +      return git_status_config(k, v, s);
  }
  
  int cmd_commit(int argc, const char **argv, const char *prefix)
        struct commit_list *parents = NULL, **pptr = &parents;
        struct stat statbuf;
        int allow_fast_forward = 1;
 +      struct wt_status s;
  
 -      git_config(git_commit_config, NULL);
 -
 -      if (wt_status_use_color == -1)
 -              wt_status_use_color = git_use_color_default;
 -
 -      argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix);
 -
 -      index_file = prepare_index(argc, argv, prefix);
 +      wt_status_prepare(&s);
 +      git_config(git_commit_config, &s);
 +      in_merge = file_exists(git_path("MERGE_HEAD"));
 +      s.in_merge = in_merge;
 +
 +      if (s.use_color == -1)
 +              s.use_color = git_use_color_default;
 +      argc = parse_and_validate_options(argc, argv, builtin_commit_usage,
 +                                        prefix, &s);
 +      if (dry_run) {
 +              if (diff_use_color_default == -1)
 +                      diff_use_color_default = git_use_color_default;
 +              return dry_run_commit(argc, argv, prefix, &s);
 +      }
 +      index_file = prepare_index(argc, argv, prefix, 0);
  
        /* Set up everything for writing the commit object.  This includes
           running hooks, writing the trees, and interacting with the user.  */
 -      if (!prepare_to_commit(index_file, prefix)) {
 +      if (!prepare_to_commit(index_file, prefix, &s)) {
                rollback_index_files();
                return 1;
        }
diff --combined builtin-grep.c
index af6c6fe8a7ed677de84cdbd828e8daae0a6bb12d,04ac60a29a55189d2c757a0a205b4cc0e7ece9da..529461fb8fdf6bdbee86b8cc46fa610696cb9382
@@@ -13,7 -13,6 +13,7 @@@
  #include "parse-options.h"
  #include "userdiff.h"
  #include "grep.h"
 +#include "quote.h"
  
  #ifndef NO_EXTERNAL_GREP
  #ifdef __unix__
@@@ -158,8 -157,8 +158,8 @@@ static int grep_sha1(struct grep_opt *o
        unsigned long size;
        char *data;
        enum object_type type;
 -      char *to_free = NULL;
        int hit;
 +      struct strbuf pathbuf = STRBUF_INIT;
  
        data = read_sha1_file(sha1, &type, &size);
        if (!data) {
                return 0;
        }
        if (opt->relative && opt->prefix_length) {
 -              static char name_buf[PATH_MAX];
 -              char *cp;
 -              int name_len = strlen(name) - opt->prefix_length + 1;
 -
 -              if (!tree_name_len)
 -                      name += opt->prefix_length;
 -              else {
 -                      if (ARRAY_SIZE(name_buf) <= name_len)
 -                              cp = to_free = xmalloc(name_len);
 -                      else
 -                              cp = name_buf;
 -                      memcpy(cp, name, tree_name_len);
 -                      strcpy(cp + tree_name_len,
 -                             name + tree_name_len + opt->prefix_length);
 -                      name = cp;
 -              }
 +              quote_path_relative(name + tree_name_len, -1, &pathbuf, opt->prefix);
 +              strbuf_insert(&pathbuf, 0, name, tree_name_len);
 +              name = pathbuf.buf;
        }
        hit = grep_buffer(opt, name, data, size);
 +      strbuf_release(&pathbuf);
        free(data);
 -      free(to_free);
        return hit;
  }
  
@@@ -183,7 -195,6 +183,7 @@@ static int grep_file(struct grep_opt *o
        int i;
        char *data;
        size_t sz;
 +      struct strbuf buf = STRBUF_INIT;
  
        if (lstat(filename, &st) < 0) {
        err_ret:
                        error("'%s': %s", filename, strerror(errno));
                return 0;
        }
 -      if (!st.st_size)
 -              return 0; /* empty file -- no grep hit */
        if (!S_ISREG(st.st_mode))
                return 0;
        sz = xsize_t(st.st_size);
        }
        close(i);
        if (opt->relative && opt->prefix_length)
 -              filename += opt->prefix_length;
 +              filename = quote_path_relative(filename, -1, &buf, opt->prefix);
        i = grep_buffer(opt, filename, data, sz);
 +      strbuf_release(&buf);
        free(data);
        return i;
  }
@@@ -220,6 -232,7 +220,7 @@@ static int exec_grep(int argc, const ch
        int status;
  
        argv[argc] = NULL;
+       trace_argv_printf(argv, "trace: grep:");
        pid = fork();
        if (pid < 0)
                return pid;
@@@ -345,6 -358,21 +346,21 @@@ static void grep_add_color(struct strbu
                strbuf_setlen(sb, sb->len - 1);
  }
  
+ static int has_skip_worktree_entry(struct grep_opt *opt, const char **paths)
+ {
+       int nr;
+       for (nr = 0; nr < active_nr; nr++) {
+               struct cache_entry *ce = active_cache[nr];
+               if (!S_ISREG(ce->ce_mode))
+                       continue;
+               if (!pathspec_matches(paths, ce->name, opt->max_depth))
+                       continue;
+               if (ce_skip_worktree(ce))
+                       return 1;
+       }
+       return 0;
+ }
  static int external_grep(struct grep_opt *opt, const char **paths, int cached)
  {
        int i, nr, argc, hit, len, status;
        char *argptr = randarg;
        struct grep_pat *p;
  
-       if (opt->extended || (opt->relative && opt->prefix_length))
+       if (opt->extended || (opt->relative && opt->prefix_length)
+           || has_skip_worktree_entry(opt, paths))
                return -1;
        len = nr = 0;
        push_arg("grep");
                push_arg("-h");
        if (opt->regflags & REG_EXTENDED)
                push_arg("-E");
 -      if (opt->regflags & REG_ICASE)
 +      if (opt->ignore_case)
                push_arg("-i");
        if (opt->binary == GREP_BINARY_NOMATCH)
                push_arg("-I");
  
                if (opt->color_external && strlen(opt->color_external) > 0)
                        push_arg(opt->color_external);
 +      } else {
 +              unsetenv("GREP_COLOR");
 +              unsetenv("GREP_COLORS");
        }
 +      unsetenv("GREP_OPTIONS");
  
        hit = 0;
        argc = nr;
@@@ -495,7 -520,6 +512,7 @@@ static int grep_cache(struct grep_opt *
                hit = external_grep(opt, paths, cached);
                if (hit >= 0)
                        return hit;
 +              hit = 0;
        }
  #endif
  
                 * are identical, even if worktree file has been modified, so use
                 * cache version instead
                 */
-               if (cached || (ce->ce_flags & CE_VALID)) {
+               if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) {
                        if (ce_stage(ce))
                                continue;
                        hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
@@@ -633,7 -657,7 +650,7 @@@ static int file_callback(const struct o
        struct grep_opt *grep_opt = opt->value;
        FILE *patterns;
        int lno = 0;
 -      struct strbuf sb;
 +      struct strbuf sb = STRBUF_INIT;
  
        patterns = fopen(arg, "r");
        if (!patterns)
@@@ -708,8 -732,8 +725,8 @@@ int cmd_grep(int argc, const char **arg
                OPT_GROUP(""),
                OPT_BOOLEAN('v', "invert-match", &opt.invert,
                        "show non-matching lines"),
 -              OPT_BIT('i', "ignore-case", &opt.regflags,
 -                      "case insensitive matching", REG_ICASE),
 +              OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case,
 +                      "case insensitive matching"),
                OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
                        "match patterns only at word boundaries"),
                OPT_SET_INT('a', "text", &opt.binary,
                OPT_END()
        };
  
 +      /*
 +       * 'git grep -h', unlike 'git grep -h <pattern>', is a request
 +       * to show usage information and exit.
 +       */
 +      if (argc == 2 && !strcmp(argv[1], "-h"))
 +              usage_with_options(grep_usage, options);
 +
        memset(&opt, 0, sizeof(opt));
 +      opt.prefix = prefix;
        opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
        opt.relative = 1;
        opt.pathname = 1;
                external_grep_allowed = 0;
        if (!opt.pattern_list)
                die("no pattern given.");
 +      if (!opt.fixed && opt.ignore_case)
 +              opt.regflags |= REG_ICASE;
        if ((opt.regflags != REG_NEWLINE) && opt.fixed)
                die("cannot mix --fixed-strings and regexp");
        compile_grep_patterns(&opt);
                        verify_filename(prefix, argv[j]);
        }
  
 -      if (i < argc) {
 +      if (i < argc)
                paths = get_pathspec(prefix, argv + i);
 -              if (opt.prefix_length && opt.relative) {
 -                      /* Make sure we do not get outside of paths */
 -                      for (i = 0; paths[i]; i++)
 -                              if (strncmp(prefix, paths[i], opt.prefix_length))
 -                                      die("git grep: cannot generate relative filenames containing '..'");
 -              }
 -      }
        else if (prefix) {
                paths = xcalloc(2, sizeof(const char *));
                paths[0] = prefix;
diff --combined builtin-ls-files.c
index c9a03e5427bbf1390aeefb9d48b4e362ca6a8e1b,2e47242b9d28077fa256170365c69f84493d3707..738215768ea701f0a35ed1e7bdc543779e6f4185
@@@ -37,6 -37,7 +37,7 @@@ static const char *tag_removed = ""
  static const char *tag_other = "";
  static const char *tag_killed = "";
  static const char *tag_modified = "";
+ static const char *tag_skip_worktree = "";
  
  static void show_dir_entry(const char *tag, struct dir_entry *ent)
  {
@@@ -171,14 -172,15 +172,15 @@@ static void show_files(struct dir_struc
                for (i = 0; i < active_nr; i++) {
                        struct cache_entry *ce = active_cache[i];
                        int dtype = ce_to_dtype(ce);
 -                      if (excluded(dir, ce->name, &dtype) !=
 -                                      !!(dir->flags & DIR_SHOW_IGNORED))
 +                      if (dir->flags & DIR_SHOW_IGNORED &&
 +                          !excluded(dir, ce->name, &dtype))
                                continue;
                        if (show_unmerged && !ce_stage(ce))
                                continue;
                        if (ce->ce_flags & CE_UPDATE)
                                continue;
-                       show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);
+                       show_ce_entry(ce_stage(ce) ? tag_unmerged :
+                               (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);
                }
        }
        if (show_deleted | show_modified) {
                        struct stat st;
                        int err;
                        int dtype = ce_to_dtype(ce);
 -                      if (excluded(dir, ce->name, &dtype) !=
 -                                      !!(dir->flags & DIR_SHOW_IGNORED))
 +                      if (dir->flags & DIR_SHOW_IGNORED &&
 +                          !excluded(dir, ce->name, &dtype))
                                continue;
                        if (ce->ce_flags & CE_UPDATE)
                                continue;
+                       if (ce_skip_worktree(ce))
+                               continue;
                        err = lstat(ce->name, &st);
                        if (show_deleted && err)
                                show_ce_entry(tag_removed, ce);
@@@ -481,6 -485,9 +485,9 @@@ int cmd_ls_files(int argc, const char *
                prefix_offset = strlen(prefix);
        git_config(git_default_config, NULL);
  
+       if (read_cache() < 0)
+               die("index file corrupt");
        argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
                        ls_files_usage, 0);
        if (show_tag || show_valid_bit) {
                tag_modified = "C ";
                tag_other = "? ";
                tag_killed = "K ";
+               tag_skip_worktree = "S ";
        }
        if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
                require_work_tree = 1;
        pathspec = get_pathspec(prefix, argv);
  
        /* be nice with submodule paths ending in a slash */
-       read_cache();
        if (pathspec)
                strip_trailing_slash_from_submodules();
  
                ps_matched = xcalloc(1, num);
        }
  
 -      if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) {
 -              fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
 -                      argv[0]);
 -              exit(1);
 -      }
 +      if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given)
 +              die("ls-files --ignored needs some exclude pattern");
  
        /* With no flags, we default to showing the cached files */
        if (!(show_stage | show_deleted | show_others | show_unmerged |
diff --combined builtin-read-tree.c
index 2a3a32cbfe83a0e0366d04a99bb49606f647f594,f5acb1aa93ef7b223011c50486df71b785049982..50413ca17df294a8b10dd406db55a24cf601bb55
@@@ -31,7 -31,7 +31,7 @@@ static int list_tree(unsigned char *sha
  }
  
  static const char * const read_tree_usage[] = {
-       "git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]]  [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]]",
+       "git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]]",
        NULL
  };
  
@@@ -98,6 -98,8 +98,8 @@@ int cmd_read_tree(int argc, const char 
                  PARSE_OPT_NONEG, exclude_per_directory_cb },
                OPT_SET_INT('i', NULL, &opts.index_only,
                            "don't check the working tree after merging", 1),
+               OPT_SET_INT(0, "no-sparse-checkout", &opts.skip_sparse_checkout,
+                           "skip applying sparse checkout filter", 1),
                OPT_END()
        };
  
  
        git_config(git_default_config, NULL);
  
 -      newfd = hold_locked_index(&lock_file, 1);
 -
        argc = parse_options(argc, argv, unused_prefix, read_tree_options,
                             read_tree_usage, 0);
  
 -      if (read_cache_unmerged() && (opts.prefix || opts.merge))
 -              die("You need to resolve your current index first");
 +      newfd = hold_locked_index(&lock_file, 1);
  
        prefix_set = opts.prefix ? 1 : 0;
        if (1 < opts.merge + opts.reset + prefix_set)
                die("Which one? -m, --reset, or --prefix?");
 -      stage = opts.merge = (opts.reset || opts.merge || prefix_set);
 +
 +      if (opts.reset || opts.merge || opts.prefix) {
 +              if (read_cache_unmerged() && (opts.prefix || opts.merge))
 +                      die("You need to resolve your current index first");
 +              stage = opts.merge = 1;
 +      }
  
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
diff --combined builtin-update-index.c
index a6b7f2d6361fc1e8ea9713082affc72362f08d76,97b9ea61f7605970875776bd5c84c00abbb0f2f6..a64a752990b85b69590cdbeed3901154642007b8
@@@ -24,10 -24,10 +24,11 @@@ static int info_only
  static int force_remove;
  static int verbose;
  static int mark_valid_only;
- #define MARK_VALID 1
- #define UNMARK_VALID 2
+ static int mark_skip_worktree_only;
+ #define MARK_FLAG 1
+ #define UNMARK_FLAG 2
  
 +__attribute__((format (printf, 1, 2)))
  static void report(const char *fmt, ...)
  {
        va_list vp;
        va_end(vp);
  }
  
- static int mark_valid(const char *path)
+ static int mark_ce_flags(const char *path, int flag, int mark)
  {
        int namelen = strlen(path);
        int pos = cache_name_pos(path, namelen);
        if (0 <= pos) {
-               switch (mark_valid_only) {
-               case MARK_VALID:
-                       active_cache[pos]->ce_flags |= CE_VALID;
-                       break;
-               case UNMARK_VALID:
-                       active_cache[pos]->ce_flags &= ~CE_VALID;
-                       break;
-               }
+               if (mark)
+                       active_cache[pos]->ce_flags |= flag;
+               else
+                       active_cache[pos]->ce_flags &= ~flag;
                cache_tree_invalidate_path(active_cache_tree, path);
                active_cache_changed = 1;
                return 0;
@@@ -176,29 -172,29 +173,29 @@@ static int process_directory(const cha
        return error("%s: is a directory - add files inside instead", path);
  }
  
- /*
-  * Process a regular file
-  */
- static int process_file(const char *path, int len, struct stat *st)
- {
-       int pos = cache_name_pos(path, len);
-       struct cache_entry *ce = pos < 0 ? NULL : active_cache[pos];
-       if (ce && S_ISGITLINK(ce->ce_mode))
-               return error("%s is already a gitlink, not replacing", path);
-       return add_one_path(ce, path, len, st);
- }
  static int process_path(const char *path)
  {
-       int len;
+       int pos, len;
        struct stat st;
+       struct cache_entry *ce;
  
        len = strlen(path);
        if (has_symlink_leading_path(path, len))
                return error("'%s' is beyond a symbolic link", path);
  
+       pos = cache_name_pos(path, len);
+       ce = pos < 0 ? NULL : active_cache[pos];
+       if (ce && ce_skip_worktree(ce)) {
+               /*
+                * working directory version is assumed "good"
+                * so updating it does not make sense.
+                * On the other hand, removing it from index should work
+                */
+               if (allow_remove && remove_file_from_cache(path))
+                       return error("%s: cannot remove from the index", path);
+               return 0;
+       }
        /*
         * First things first: get the stat information, to decide
         * what to do about the pathname!
        if (S_ISDIR(st.st_mode))
                return process_directory(path, len, &st);
  
-       return process_file(path, len, &st);
+       /*
+        * Process a regular file
+        */
+       if (ce && S_ISGITLINK(ce->ce_mode))
+               return error("%s is already a gitlink, not replacing", path);
+       return add_one_path(ce, path, len, &st);
  }
  
  static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
@@@ -277,7 -279,12 +280,12 @@@ static void update_one(const char *path
                goto free_return;
        }
        if (mark_valid_only) {
-               if (mark_valid(p))
+               if (mark_ce_flags(p, CE_VALID, mark_valid_only == MARK_FLAG))
+                       die("Unable to mark file %s", path);
+               goto free_return;
+       }
+       if (mark_skip_worktree_only) {
+               if (mark_ce_flags(p, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG))
                        die("Unable to mark file %s", path);
                goto free_return;
        }
@@@ -389,7 -396,7 +397,7 @@@ static void read_index_info(int line_te
  }
  
  static const char update_index_usage[] =
- "git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+ "git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--skip-worktree|--no-skip-worktree] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
  
  static unsigned char head_sha1[20];
  static unsigned char merge_head_sha1[20];
@@@ -648,11 -655,19 +656,19 @@@ int cmd_update_index(int argc, const ch
                                continue;
                        }
                        if (!strcmp(path, "--assume-unchanged")) {
-                               mark_valid_only = MARK_VALID;
+                               mark_valid_only = MARK_FLAG;
                                continue;
                        }
                        if (!strcmp(path, "--no-assume-unchanged")) {
-                               mark_valid_only = UNMARK_VALID;
+                               mark_valid_only = UNMARK_FLAG;
+                               continue;
+                       }
+                       if (!strcmp(path, "--no-skip-worktree")) {
+                               mark_skip_worktree_only = UNMARK_FLAG;
+                               continue;
+                       }
+                       if (!strcmp(path, "--skip-worktree")) {
+                               mark_skip_worktree_only = MARK_FLAG;
                                continue;
                        }
                        if (!strcmp(path, "--info-only")) {
diff --combined cache.h
index 3f9ee861477883a5a9f27aea768a8c070559a891,9dcaf41a6c7aa4cd97f37eae33dd0aa7cc45753f..46606477b626c9bdb6a60f9c0cf826c8fc435e00
+++ b/cache.h
@@@ -4,7 -4,6 +4,7 @@@
  #include "git-compat-util.h"
  #include "strbuf.h"
  #include "hash.h"
 +#include "advice.h"
  
  #include SHA1_HEADER
  #ifndef git_SHA_CTX
@@@ -178,14 -177,18 +178,18 @@@ struct cache_entry 
  #define CE_HASHED    (0x100000)
  #define CE_UNHASHED  (0x200000)
  
+ /* Only remove in work directory, not index */
+ #define CE_WT_REMOVE (0x400000)
  /*
   * Extended on-disk flags
   */
  #define CE_INTENT_TO_ADD 0x20000000
+ #define CE_SKIP_WORKTREE 0x40000000
  /* CE_EXTENDED2 is for future extension */
  #define CE_EXTENDED2 0x80000000
  
- #define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD)
+ #define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
  
  /*
   * Safeguard to avoid saving wrong flags:
@@@ -234,6 -237,7 +238,7 @@@ static inline size_t ce_namelen(const s
                            ondisk_cache_entry_size(ce_namelen(ce)))
  #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
  #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
+ #define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
  #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
  
  #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
@@@ -331,7 -335,7 +336,7 @@@ static inline void remove_name_hash(str
  #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
  #define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
  #define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags))
 -#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
 +#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
  #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
  #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
  #define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
@@@ -369,12 -373,9 +374,12 @@@ static inline enum object_type object_t
  #define CONFIG_ENVIRONMENT "GIT_CONFIG"
  #define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
  #define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
 +#define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
  #define GITATTRIBUTES_FILE ".gitattributes"
  #define INFOATTRIBUTES_FILE "info/attributes"
  #define ATTRIBUTE_MACRO_PREFIX "[attr]"
 +#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
 +#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
  
  extern int is_bare_repository_cfg;
  extern int is_bare_repository(void);
@@@ -399,7 -400,6 +404,7 @@@ extern const char *setup_git_directory_
  extern const char *setup_git_directory(void);
  extern const char *prefix_path(const char *prefix, int len, const char *path);
  extern const char *prefix_filename(const char *prefix, int len, const char *path);
 +extern int check_filename(const char *prefix, const char *name);
  extern void verify_filename(const char *prefix, const char *name);
  extern void verify_non_filename(const char *prefix, const char *name);
  
@@@ -464,7 -464,9 +469,9 @@@ extern int index_name_is_other(const st
  /* do stat comparison even if CE_VALID is true */
  #define CE_MATCH_IGNORE_VALID         01
  /* do not check the contents but report dirty on racily-clean entries */
- #define CE_MATCH_RACY_IS_DIRTY        02
+ #define CE_MATCH_RACY_IS_DIRTY                02
+ /* do stat comparison even if CE_SKIP_WORKTREE is true */
+ #define CE_MATCH_IGNORE_SKIP_WORKTREE 04
  extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
  extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
  
@@@ -474,15 -476,15 +481,15 @@@ extern int index_path(unsigned char *sh
  extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
  
  /* "careful lstat()" */
 -extern int check_path(const char *path, int len, struct stat *st);
 +extern int check_path(const char *path, int len, struct stat *st, int skiplen);
  
  #define REFRESH_REALLY                0x0001  /* ignore_valid */
  #define REFRESH_UNMERGED      0x0002  /* allow unmerged */
  #define REFRESH_QUIET         0x0004  /* be quiet about it */
  #define REFRESH_IGNORE_MISSING        0x0008  /* ignore non-existent */
  #define REFRESH_IGNORE_SUBMODULES     0x0010  /* ignore submodules */
 -#define REFRESH_SAY_CHANGED   0x0020  /* say "changed" not "needs update" */
 -extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen);
 +#define REFRESH_IN_PORCELAIN  0x0020  /* user friendly output, not "needs update" */
 +extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, char *header_msg);
  
  struct lock_file {
        struct lock_file *next;
  };
  #define LOCK_DIE_ON_ERROR 1
  #define LOCK_NODEREF 2
 +extern int unable_to_lock_error(const char *path, int err);
  extern NORETURN void unable_to_lock_index_die(const char *path, int err);
  extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
  extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
@@@ -518,7 -519,6 +525,7 @@@ extern int log_all_ref_updates
  extern int warn_ambiguous_refs;
  extern int shared_repository;
  extern const char *apply_default_whitespace;
 +extern const char *apply_default_ignorewhitespace;
  extern int zlib_compression_level;
  extern int core_compression_level;
  extern int core_compression_seen;
@@@ -526,9 -526,9 +533,10 @@@ extern size_t packed_git_window_size
  extern size_t packed_git_limit;
  extern size_t delta_base_cache_limit;
  extern int auto_crlf;
 +extern int read_replace_refs;
  extern int fsync_object_files;
  extern int core_preload_index;
+ extern int core_apply_sparse_checkout;
  
  enum safe_crlf {
        SAFE_CRLF_FALSE = 0,
@@@ -571,8 -571,6 +579,8 @@@ enum object_creation_mode 
  
  extern enum object_creation_mode object_creation_mode;
  
 +extern char *notes_ref_name;
 +
  extern int grafts_replace_parents;
  
  #define GIT_REPO_VERSION 0
@@@ -650,7 -648,6 +658,7 @@@ int set_shared_perm(const char *path, i
  #define adjust_shared_perm(path) set_shared_perm((path), 0)
  int safe_create_leading_directories(char *path);
  int safe_create_leading_directories_const(const char *path);
 +extern char *expand_user_path(const char *path);
  char *enter_repo(char *path, int strict);
  static inline int is_absolute_path(const char *path)
  {
@@@ -663,15 -660,10 +671,15 @@@ const char *make_relative_path(const ch
  int normalize_path_copy(char *dst, const char *src);
  int longest_ancestor_length(const char *path, const char *prefix_list);
  char *strip_path_suffix(const char *path, const char *suffix);
 +int daemon_avoid_alias(const char *path);
  
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
 -extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size);
 +extern void *read_sha1_file_repl(const unsigned char *sha1, enum object_type *type, unsigned long *size, const unsigned char **replacement);
 +static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
 +{
 +      return read_sha1_file_repl(sha1, type, size, NULL);
 +}
  extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
  extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
@@@ -702,11 -694,7 +710,11 @@@ static inline unsigned int hexval(unsig
  #define DEFAULT_ABBREV 7
  
  extern int get_sha1(const char *str, unsigned char *sha1);
 -extern int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode);
 +extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int gently, const char *prefix);
 +static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
 +{
 +      return get_sha1_with_mode_1(str, sha1, mode, 1, NULL);
 +}
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
  extern int read_ref(const char *filename, unsigned char *sha1);
@@@ -745,14 -733,9 +753,14 @@@ enum date_mode 
  };
  
  const char *show_date(unsigned long time, int timezone, enum date_mode mode);
 +const char *show_date_relative(unsigned long time, int tz,
 +                             const struct timeval *now,
 +                             char *timebuf,
 +                             size_t timebuf_size);
  int parse_date(const char *date, char *buf, int bufsize);
  void datestamp(char *buf, int bufsize);
  unsigned long approxidate(const char *);
 +unsigned long approxidate_relative(const char *date, const struct timeval *now);
  enum date_mode parse_date_format(const char *format);
  
  #define IDENT_WARN_ON_NO_NAME  1
@@@ -762,8 -745,6 +770,8 @@@ extern const char *git_author_info(int)
  extern const char *git_committer_info(int);
  extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
  extern const char *fmt_name(const char *name, const char *email);
 +extern const char *git_editor(void);
 +extern const char *git_pager(void);
  
  struct checkout {
        const char *base_dir;
@@@ -870,6 -851,7 +878,6 @@@ extern struct ref *find_ref_by_name(con
  extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
  extern int finish_connect(struct child_process *conn);
  extern int path_match(const char *path, int nr, char **match);
 -extern int get_ack(int fd, unsigned char *result_sha1);
  struct extra_have_objects {
        int nr, alloc;
        unsigned char (*array)[20];
@@@ -915,7 -897,6 +923,7 @@@ extern unsigned long git_config_ulong(c
  extern int git_config_bool_or_int(const char *, const char *, int *);
  extern int git_config_bool(const char *, const char *);
  extern int git_config_string(const char **, const char *, const char *);
 +extern int git_config_pathname(const char **, const char *, const char *);
  extern int git_config_set(const char *, const char *);
  extern int git_config_set_multivar(const char *, const char *, const char *, int);
  extern int git_config_rename_section(const char *, const char *);
@@@ -939,19 -920,13 +947,19 @@@ extern const char *git_mailmap_file
  extern void maybe_flush_or_die(FILE *, const char *);
  extern int copy_fd(int ifd, int ofd);
  extern int copy_file(const char *dst, const char *src, int mode);
 -extern ssize_t read_in_full(int fd, void *buf, size_t count);
 -extern ssize_t write_in_full(int fd, const void *buf, size_t count);
 +extern int copy_file_with_time(const char *dst, const char *src, int mode);
  extern void write_or_die(int fd, const void *buf, size_t count);
  extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
  extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
  extern void fsync_or_die(int fd, const char *);
  
 +extern ssize_t read_in_full(int fd, void *buf, size_t count);
 +extern ssize_t write_in_full(int fd, const void *buf, size_t count);
 +static inline ssize_t write_str_in_full(int fd, const char *str)
 +{
 +      return write_in_full(fd, str, strlen(str));
 +}
 +
  /* pager.c */
  extern void setup_pager(void);
  extern const char *pager_program;
@@@ -974,9 -949,7 +982,9 @@@ extern void *alloc_object_node(void)
  extern void alloc_report(void);
  
  /* trace.c */
 +__attribute__((format (printf, 1, 2)))
  extern void trace_printf(const char *format, ...);
 +__attribute__((format (printf, 2, 3)))
  extern void trace_argv_printf(const char **argv, const char *format, ...);
  
  /* convert.c */
@@@ -1002,12 -975,10 +1010,12 @@@ void shift_tree(const unsigned char *, 
   * whitespace rules.
   * used by both diff and apply
   */
 -#define WS_TRAILING_SPACE     01
 +#define WS_BLANK_AT_EOL         01
  #define WS_SPACE_BEFORE_TAB   02
  #define WS_INDENT_WITH_NON_TAB        04
  #define WS_CR_AT_EOL           010
 +#define WS_BLANK_AT_EOF        020
 +#define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
  #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
  extern unsigned whitespace_rule_cfg;
  extern unsigned whitespace_rule(const char *);
diff --combined config.c
index 37385ce9d338ecbd2556cef9455000784ebab7e5,abd762ebfaaa6c82d691cd478d3c088a732d499a..f4f2c59a34cd9fc70db940871caaf00b94a6ef2e
+++ b/config.c
@@@ -351,16 -351,6 +351,16 @@@ int git_config_string(const char **dest
        return 0;
  }
  
 +int git_config_pathname(const char **dest, const char *var, const char *value)
 +{
 +      if (!value)
 +              return config_error_nonbool(var);
 +      *dest = expand_user_path(value);
 +      if (!*dest)
 +              die("Failed to expand user dir in: '%s'", value);
 +      return 0;
 +}
 +
  static int git_default_core_config(const char *var, const char *value)
  {
        /* This needs a better name */
                return 0;
        }
  
 +      if (!strcmp(var, "core.notesref")) {
 +              notes_ref_name = xstrdup(value);
 +              return 0;
 +      }
 +
        if (!strcmp(var, "core.pager"))
                return git_config_string(&pager_program, var, value);
  
                return git_config_string(&editor_program, var, value);
  
        if (!strcmp(var, "core.excludesfile"))
 -              return git_config_string(&excludes_file, var, value);
 +              return git_config_pathname(&excludes_file, var, value);
  
        if (!strcmp(var, "core.whitespace")) {
                if (!value)
                return 0;
        }
  
+       if (!strcmp(var, "core.sparsecheckout")) {
+               core_apply_sparse_checkout = git_config_bool(var, value);
+               return 0;
+       }
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
  }
@@@ -642,9 -632,6 +647,9 @@@ int git_default_config(const char *var
        if (!prefixcmp(var, "mailmap."))
                return git_default_mailmap_config(var, value);
  
 +      if (!prefixcmp(var, "advice."))
 +              return git_default_advice_config(var, value);
 +
        if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
                pager_use_color = git_config_bool(var,value);
                return 0;
@@@ -1134,7 -1121,7 +1139,7 @@@ int git_config_set_multivar(const char 
                                    copy_end - copy_begin)
                                        goto write_err_out;
                                if (new_line &&
 -                                  write_in_full(fd, "\n", 1) != 1)
 +                                  write_str_in_full(fd, "\n") != 1)
                                        goto write_err_out;
                        }
                        copy_begin = store.offset[i];
diff --combined diff-lib.c
index 349f612b615fc152e9d272900b1ac5177f4a025c,b0b379d9d208a9d70f67b6602bf1e19efbfc5674..1c7e652a8048524e73f2f34833647d7ec1610bc9
@@@ -73,7 -73,7 +73,7 @@@ int run_diff_files(struct rev_info *rev
                struct cache_entry *ce = active_cache[i];
                int changed;
  
 -              if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
 +              if (DIFF_OPT_TST(&revs->diffopt, QUICK) &&
                        DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
                        break;
  
                                continue;
                }
  
-               if (ce_uptodate(ce))
+               if (ce_uptodate(ce) || ce_skip_worktree(ce))
                        continue;
  
                /* If CE_VALID is set, don't look at workdir for file removal */
@@@ -309,6 -309,22 +309,6 @@@ static int show_modified(struct rev_inf
        return 0;
  }
  
 -/*
 - * This turns all merge entries into "stage 3". That guarantees that
 - * when we read in the new tree (into "stage 1"), we won't lose sight
 - * of the fact that we had unmerged entries.
 - */
 -static void mark_merge_entries(void)
 -{
 -      int i;
 -      for (i = 0; i < active_nr; i++) {
 -              struct cache_entry *ce = active_cache[i];
 -              if (!ce_stage(ce))
 -                      continue;
 -              ce->ce_flags |= CE_STAGEMASK;
 -      }
 -}
 -
  /*
   * This gets a mix of an existing index and a tree, one pathname entry
   * at a time. The index entry may be a single stage-0 one, but it could
@@@ -323,7 -339,8 +323,8 @@@ static void do_oneway_diff(struct unpac
        int match_missing, cached;
  
        /* if the entry is not checked out, don't examine work tree */
-       cached = o->index_only || (idx && (idx->ce_flags & CE_VALID));
+       cached = o->index_only ||
+               (idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx)));
        /*
         * Backward compatibility wart - "diff-index -m" does
         * not mean "do not ignore merges", but "match_missing".
        match_missing = !revs->ignore_merges;
  
        if (cached && idx && ce_stage(idx)) {
 -              if (tree)
 -                      diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, idx->sha1);
 +              diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode,
 +                           idx->sha1);
                return;
        }
  
@@@ -383,7 -400,7 +384,7 @@@ static inline void skip_same_name(struc
   * For diffing, the index is more important, and we only have a
   * single tree.
   *
 - * We're supposed to return how many index entries we want to skip.
 + * We're supposed to advance o->pos to skip what we have already processed.
   *
   * This wrapper makes it all more readable, and takes care of all
   * the fairly complex unpack_trees() semantic requirements, including
@@@ -421,6 -438,8 +422,6 @@@ int run_diff_index(struct rev_info *rev
        struct unpack_trees_options opts;
        struct tree_desc t;
  
 -      mark_merge_entries();
 -
        ent = revs->pending.objects[0].item;
        tree_name = revs->pending.objects[0].name;
        tree = parse_tree_indirect(ent->sha1);
@@@ -507,7 -526,7 +508,7 @@@ int index_differs_from(const char *def
  
        init_revisions(&rev, NULL);
        setup_revisions(0, NULL, &rev, def);
 -      DIFF_OPT_SET(&rev.diffopt, QUIET);
 +      DIFF_OPT_SET(&rev.diffopt, QUICK);
        DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
        rev.diffopt.flags |= diff_flags;
        run_diff_index(&rev, 1);
diff --combined diff.c
index aad4b3977a2960bac1391b4b3ec8afe814308902,3970df4afcbe62261757547bc7cc9570fd114ae9..04beb26a6a8aa46b5b0721b71236553cf549061b
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -13,7 -13,6 +13,7 @@@
  #include "utf8.h"
  #include "userdiff.h"
  #include "sigchain.h"
 +#include "submodule.h"
  
  #ifdef NO_FAST_WORKING_DIRECTORY
  #define FAST_WORKING_DIRECTORY 0
@@@ -39,7 -38,6 +39,7 @@@ static char diff_colors[][COLOR_MAXLEN
        GIT_COLOR_GREEN,        /* NEW */
        GIT_COLOR_YELLOW,       /* COMMIT */
        GIT_COLOR_BG_RED,       /* WHITESPACE */
 +      GIT_COLOR_NORMAL,       /* FUNCINFO */
  };
  
  static void diff_filespec_load_driver(struct diff_filespec *one);
@@@ -61,9 -59,7 +61,9 @@@ static int parse_diff_color_slot(const 
                return DIFF_COMMIT;
        if (!strcasecmp(var+ofs, "whitespace"))
                return DIFF_WHITESPACE;
 -      die("bad config variable '%s'", var);
 +      if (!strcasecmp(var+ofs, "func"))
 +              return DIFF_FUNCINFO;
 +      return -1;
  }
  
  static int git_config_rename(const char *var, const char *value)
@@@ -122,8 -118,6 +122,8 @@@ int git_diff_basic_config(const char *v
  
        if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
                int slot = parse_diff_color_slot(var, 11);
 +              if (slot < 0)
 +                      return 0;
                if (!value)
                        return config_error_nonbool(var);
                color_parse(value, var, diff_colors[slot]);
@@@ -180,213 -174,6 +180,213 @@@ static struct diff_tempfile 
        char tmp_path[PATH_MAX];
  } diff_temp[2];
  
 +typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
 +
 +struct emit_callback {
 +      int color_diff;
 +      unsigned ws_rule;
 +      int blank_at_eof_in_preimage;
 +      int blank_at_eof_in_postimage;
 +      int lno_in_preimage;
 +      int lno_in_postimage;
 +      sane_truncate_fn truncate;
 +      const char **label_path;
 +      struct diff_words_data *diff_words;
 +      int *found_changesp;
 +      FILE *file;
 +      struct strbuf *header;
 +};
 +
 +static int count_lines(const char *data, int size)
 +{
 +      int count, ch, completely_empty = 1, nl_just_seen = 0;
 +      count = 0;
 +      while (0 < size--) {
 +              ch = *data++;
 +              if (ch == '\n') {
 +                      count++;
 +                      nl_just_seen = 1;
 +                      completely_empty = 0;
 +              }
 +              else {
 +                      nl_just_seen = 0;
 +                      completely_empty = 0;
 +              }
 +      }
 +      if (completely_empty)
 +              return 0;
 +      if (!nl_just_seen)
 +              count++; /* no trailing newline */
 +      return count;
 +}
 +
 +static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
 +{
 +      if (!DIFF_FILE_VALID(one)) {
 +              mf->ptr = (char *)""; /* does not matter */
 +              mf->size = 0;
 +              return 0;
 +      }
 +      else if (diff_populate_filespec(one, 0))
 +              return -1;
 +
 +      mf->ptr = one->data;
 +      mf->size = one->size;
 +      return 0;
 +}
 +
 +static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule)
 +{
 +      char *ptr = mf->ptr;
 +      long size = mf->size;
 +      int cnt = 0;
 +
 +      if (!size)
 +              return cnt;
 +      ptr += size - 1; /* pointing at the very end */
 +      if (*ptr != '\n')
 +              ; /* incomplete line */
 +      else
 +              ptr--; /* skip the last LF */
 +      while (mf->ptr < ptr) {
 +              char *prev_eol;
 +              for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--)
 +                      if (*prev_eol == '\n')
 +                              break;
 +              if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule))
 +                      break;
 +              cnt++;
 +              ptr = prev_eol - 1;
 +      }
 +      return cnt;
 +}
 +
 +static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,
 +                             struct emit_callback *ecbdata)
 +{
 +      int l1, l2, at;
 +      unsigned ws_rule = ecbdata->ws_rule;
 +      l1 = count_trailing_blank(mf1, ws_rule);
 +      l2 = count_trailing_blank(mf2, ws_rule);
 +      if (l2 <= l1) {
 +              ecbdata->blank_at_eof_in_preimage = 0;
 +              ecbdata->blank_at_eof_in_postimage = 0;
 +              return;
 +      }
 +      at = count_lines(mf1->ptr, mf1->size);
 +      ecbdata->blank_at_eof_in_preimage = (at - l1) + 1;
 +
 +      at = count_lines(mf2->ptr, mf2->size);
 +      ecbdata->blank_at_eof_in_postimage = (at - l2) + 1;
 +}
 +
 +static void emit_line_0(FILE *file, const char *set, const char *reset,
 +                      int first, const char *line, int len)
 +{
 +      int has_trailing_newline, has_trailing_carriage_return;
 +      int nofirst;
 +
 +      if (len == 0) {
 +              has_trailing_newline = (first == '\n');
 +              has_trailing_carriage_return = (!has_trailing_newline &&
 +                                              (first == '\r'));
 +              nofirst = has_trailing_newline || has_trailing_carriage_return;
 +      } else {
 +              has_trailing_newline = (len > 0 && line[len-1] == '\n');
 +              if (has_trailing_newline)
 +                      len--;
 +              has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
 +              if (has_trailing_carriage_return)
 +                      len--;
 +              nofirst = 0;
 +      }
 +
 +      if (len || !nofirst) {
 +              fputs(set, file);
 +              if (!nofirst)
 +                      fputc(first, file);
 +              fwrite(line, len, 1, file);
 +              fputs(reset, file);
 +      }
 +      if (has_trailing_carriage_return)
 +              fputc('\r', file);
 +      if (has_trailing_newline)
 +              fputc('\n', file);
 +}
 +
 +static void emit_line(FILE *file, const char *set, const char *reset,
 +                    const char *line, int len)
 +{
 +      emit_line_0(file, set, reset, line[0], line+1, len-1);
 +}
 +
 +static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len)
 +{
 +      if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) &&
 +            ecbdata->blank_at_eof_in_preimage &&
 +            ecbdata->blank_at_eof_in_postimage &&
 +            ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage &&
 +            ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage))
 +              return 0;
 +      return ws_blank_line(line, len, ecbdata->ws_rule);
 +}
 +
 +static void emit_add_line(const char *reset,
 +                        struct emit_callback *ecbdata,
 +                        const char *line, int len)
 +{
 +      const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
 +      const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
 +
 +      if (!*ws)
 +              emit_line_0(ecbdata->file, set, reset, '+', line, len);
 +      else if (new_blank_line_at_eof(ecbdata, line, len))
 +              /* Blank line at EOF - paint '+' as well */
 +              emit_line_0(ecbdata->file, ws, reset, '+', line, len);
 +      else {
 +              /* Emit just the prefix, then the rest. */
 +              emit_line_0(ecbdata->file, set, reset, '+', "", 0);
 +              ws_check_emit(line, len, ecbdata->ws_rule,
 +                            ecbdata->file, set, reset, ws);
 +      }
 +}
 +
 +static void emit_hunk_header(struct emit_callback *ecbdata,
 +                           const char *line, int len)
 +{
 +      const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
 +      const char *frag = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO);
 +      const char *func = diff_get_color(ecbdata->color_diff, DIFF_FUNCINFO);
 +      const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
 +      static const char atat[2] = { '@', '@' };
 +      const char *cp, *ep;
 +
 +      /*
 +       * As a hunk header must begin with "@@ -<old>, +<new> @@",
 +       * it always is at least 10 bytes long.
 +       */
 +      if (len < 10 ||
 +          memcmp(line, atat, 2) ||
 +          !(ep = memmem(line + 2, len - 2, atat, 2))) {
 +              emit_line(ecbdata->file, plain, reset, line, len);
 +              return;
 +      }
 +      ep += 2; /* skip over @@ */
 +
 +      /* The hunk header in fraginfo color */
 +      emit_line(ecbdata->file, frag, reset, line, ep - line);
 +
 +      /* blank before the func header */
 +      for (cp = ep; ep - line < len; ep++)
 +              if (*ep != ' ' && *ep != '\t')
 +                      break;
 +      if (ep != cp)
 +              emit_line(ecbdata->file, plain, reset, cp, ep - cp);
 +
 +      if (ep < line + len)
 +              emit_line(ecbdata->file, func, reset, ep, line + len - ep);
 +}
 +
  static struct diff_tempfile *claim_diff_tempfile(void) {
        int i;
        for (i = 0; i < ARRAY_SIZE(diff_temp); i++)
@@@ -414,6 -201,29 +414,6 @@@ static void remove_tempfile_on_signal(i
        raise(signo);
  }
  
 -static int count_lines(const char *data, int size)
 -{
 -      int count, ch, completely_empty = 1, nl_just_seen = 0;
 -      count = 0;
 -      while (0 < size--) {
 -              ch = *data++;
 -              if (ch == '\n') {
 -                      count++;
 -                      nl_just_seen = 1;
 -                      completely_empty = 0;
 -              }
 -              else {
 -                      nl_just_seen = 0;
 -                      completely_empty = 0;
 -              }
 -      }
 -      if (completely_empty)
 -              return 0;
 -      if (!nl_just_seen)
 -              count++; /* no trailing newline */
 -      return count;
 -}
 -
  static void print_line_count(FILE *file, int count)
  {
        switch (count) {
        }
  }
  
 -static void copy_file_with_prefix(FILE *file,
 -                                int prefix, const char *data, int size,
 -                                const char *set, const char *reset)
 +static void emit_rewrite_lines(struct emit_callback *ecb,
 +                             int prefix, const char *data, int size)
  {
 -      int ch, nl_just_seen = 1;
 -      while (0 < size--) {
 -              ch = *data++;
 -              if (nl_just_seen) {
 -                      fputs(set, file);
 -                      putc(prefix, file);
 +      const char *endp = NULL;
 +      static const char *nneof = " No newline at end of file\n";
 +      const char *old = diff_get_color(ecb->color_diff, DIFF_FILE_OLD);
 +      const char *reset = diff_get_color(ecb->color_diff, DIFF_RESET);
 +
 +      while (0 < size) {
 +              int len;
 +
 +              endp = memchr(data, '\n', size);
 +              len = endp ? (endp - data + 1) : size;
 +              if (prefix != '+') {
 +                      ecb->lno_in_preimage++;
 +                      emit_line_0(ecb->file, old, reset, '-',
 +                                  data, len);
 +              } else {
 +                      ecb->lno_in_postimage++;
 +                      emit_add_line(reset, ecb, data, len);
                }
 -              if (ch == '\n') {
 -                      nl_just_seen = 1;
 -                      fputs(reset, file);
 -              } else
 -                      nl_just_seen = 0;
 -              putc(ch, file);
 +              size -= len;
 +              data += len;
 +      }
 +      if (!endp) {
 +              const char *plain = diff_get_color(ecb->color_diff,
 +                                                 DIFF_PLAIN);
 +              emit_line_0(ecb->file, plain, reset, '\\',
 +                          nneof, strlen(nneof));
        }
 -      if (!nl_just_seen)
 -              fprintf(file, "%s\n\\ No newline at end of file\n", reset);
  }
  
  static void emit_rewrite_diff(const char *name_a,
        const char *name_a_tab, *name_b_tab;
        const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO);
        const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO);
 -      const char *old = diff_get_color(color_diff, DIFF_FILE_OLD);
 -      const char *new = diff_get_color(color_diff, DIFF_FILE_NEW);
        const char *reset = diff_get_color(color_diff, DIFF_RESET);
        static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT;
        const char *a_prefix, *b_prefix;
        const char *data_one, *data_two;
        size_t size_one, size_two;
 +      struct emit_callback ecbdata;
  
        if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) {
                a_prefix = o->b_prefix;
                size_two = two->size;
        }
  
 +      memset(&ecbdata, 0, sizeof(ecbdata));
 +      ecbdata.color_diff = color_diff;
 +      ecbdata.found_changesp = &o->found_changes;
 +      ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
 +      ecbdata.file = o->file;
 +      if (ecbdata.ws_rule & WS_BLANK_AT_EOF) {
 +              mmfile_t mf1, mf2;
 +              mf1.ptr = (char *)data_one;
 +              mf2.ptr = (char *)data_two;
 +              mf1.size = size_one;
 +              mf2.size = size_two;
 +              check_blank_at_eof(&mf1, &mf2, &ecbdata);
 +      }
 +      ecbdata.lno_in_preimage = 1;
 +      ecbdata.lno_in_postimage = 1;
 +
        lc_a = count_lines(data_one, size_one);
        lc_b = count_lines(data_two, size_two);
        fprintf(o->file,
        print_line_count(o->file, lc_b);
        fprintf(o->file, " @@%s\n", reset);
        if (lc_a)
 -              copy_file_with_prefix(o->file, '-', data_one, size_one, old, reset);
 +              emit_rewrite_lines(&ecbdata, '-', data_one, size_one);
        if (lc_b)
 -              copy_file_with_prefix(o->file, '+', data_two, size_two, new, reset);
 -}
 -
 -static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
 -{
 -      if (!DIFF_FILE_VALID(one)) {
 -              mf->ptr = (char *)""; /* does not matter */
 -              mf->size = 0;
 -              return 0;
 -      }
 -      else if (diff_populate_filespec(one, 0))
 -              return -1;
 -
 -      mf->ptr = one->data;
 -      mf->size = one->size;
 -      return 0;
 +              emit_rewrite_lines(&ecbdata, '+', data_two, size_two);
  }
  
  struct diff_words_buffer {
@@@ -729,18 -529,26 +729,18 @@@ static void diff_words_show(struct diff
        diff_words->minus.text.size = diff_words->plus.text.size = 0;
  }
  
 -typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
 -
 -struct emit_callback {
 -      int nparents, color_diff;
 -      unsigned ws_rule;
 -      sane_truncate_fn truncate;
 -      const char **label_path;
 -      struct diff_words_data *diff_words;
 -      int *found_changesp;
 -      FILE *file;
 -};
 +/* In "color-words" mode, show word-diff of words accumulated in the buffer */
 +static void diff_words_flush(struct emit_callback *ecbdata)
 +{
 +      if (ecbdata->diff_words->minus.text.size ||
 +          ecbdata->diff_words->plus.text.size)
 +              diff_words_show(ecbdata->diff_words);
 +}
  
  static void free_diff_words_data(struct emit_callback *ecbdata)
  {
        if (ecbdata->diff_words) {
 -              /* flush buffers */
 -              if (ecbdata->diff_words->minus.text.size ||
 -                              ecbdata->diff_words->plus.text.size)
 -                      diff_words_show(ecbdata->diff_words);
 -
 +              diff_words_flush(ecbdata);
                free (ecbdata->diff_words->minus.text.ptr);
                free (ecbdata->diff_words->minus.orig);
                free (ecbdata->diff_words->plus.text.ptr);
@@@ -758,6 -566,42 +758,6 @@@ const char *diff_get_color(int diff_use
        return "";
  }
  
 -static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len)
 -{
 -      int has_trailing_newline, has_trailing_carriage_return;
 -
 -      has_trailing_newline = (len > 0 && line[len-1] == '\n');
 -      if (has_trailing_newline)
 -              len--;
 -      has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
 -      if (has_trailing_carriage_return)
 -              len--;
 -
 -      fputs(set, file);
 -      fwrite(line, len, 1, file);
 -      fputs(reset, file);
 -      if (has_trailing_carriage_return)
 -              fputc('\r', file);
 -      if (has_trailing_newline)
 -              fputc('\n', file);
 -}
 -
 -static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
 -{
 -      const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
 -      const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
 -
 -      if (!*ws)
 -              emit_line(ecbdata->file, set, reset, line, len);
 -      else {
 -              /* Emit just the prefix, then the rest. */
 -              emit_line(ecbdata->file, set, reset, line, ecbdata->nparents);
 -              ws_check_emit(line + ecbdata->nparents,
 -                            len - ecbdata->nparents, ecbdata->ws_rule,
 -                            ecbdata->file, set, reset, ws);
 -      }
 -}
 -
  static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, unsigned long len)
  {
        const char *cp;
        return allot - l;
  }
  
 +static void find_lno(const char *line, struct emit_callback *ecbdata)
 +{
 +      const char *p;
 +      ecbdata->lno_in_preimage = 0;
 +      ecbdata->lno_in_postimage = 0;
 +      p = strchr(line, '-');
 +      if (!p)
 +              return; /* cannot happen */
 +      ecbdata->lno_in_preimage = strtol(p + 1, NULL, 10);
 +      p = strchr(p, '+');
 +      if (!p)
 +              return; /* cannot happen */
 +      ecbdata->lno_in_postimage = strtol(p + 1, NULL, 10);
 +}
 +
  static void fn_out_consume(void *priv, char *line, unsigned long len)
  {
 -      int i;
 -      int color;
        struct emit_callback *ecbdata = priv;
        const char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
        const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
        const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
  
 +      if (ecbdata->header) {
 +              fprintf(ecbdata->file, "%s", ecbdata->header->buf);
 +              strbuf_reset(ecbdata->header);
 +              ecbdata->header = NULL;
 +      }
        *(ecbdata->found_changesp) = 1;
  
        if (ecbdata->label_path[0]) {
                len = 1;
        }
  
 -      /* This is not really necessary for now because
 -       * this codepath only deals with two-way diffs.
 -       */
 -      for (i = 0; i < len && line[i] == '@'; i++)
 -              ;
 -      if (2 <= i && i < len && line[i] == ' ') {
 -              ecbdata->nparents = i - 1;
 +      if (line[0] == '@') {
 +              if (ecbdata->diff_words)
 +                      diff_words_flush(ecbdata);
                len = sane_truncate_line(ecbdata, line, len);
 -              emit_line(ecbdata->file,
 -                        diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),
 -                        reset, line, len);
 +              find_lno(line, ecbdata);
 +              emit_hunk_header(ecbdata, line, len);
                if (line[len-1] != '\n')
                        putc('\n', ecbdata->file);
                return;
        }
  
 -      if (len < ecbdata->nparents) {
 +      if (len < 1) {
                emit_line(ecbdata->file, reset, reset, line, len);
                return;
        }
  
 -      color = DIFF_PLAIN;
 -      if (ecbdata->diff_words && ecbdata->nparents != 1)
 -              /* fall back to normal diff */
 -              free_diff_words_data(ecbdata);
        if (ecbdata->diff_words) {
                if (line[0] == '-') {
                        diff_words_append(line, len,
                                          &ecbdata->diff_words->plus);
                        return;
                }
 -              if (ecbdata->diff_words->minus.text.size ||
 -                  ecbdata->diff_words->plus.text.size)
 -                      diff_words_show(ecbdata->diff_words);
 +              diff_words_flush(ecbdata);
                line++;
                len--;
                emit_line(ecbdata->file, plain, reset, line, len);
                return;
        }
 -      for (i = 0; i < ecbdata->nparents && len; i++) {
 -              if (line[i] == '-')
 -                      color = DIFF_FILE_OLD;
 -              else if (line[i] == '+')
 -                      color = DIFF_FILE_NEW;
 -      }
  
 -      if (color != DIFF_FILE_NEW) {
 -              emit_line(ecbdata->file,
 -                        diff_get_color(ecbdata->color_diff, color),
 -                        reset, line, len);
 -              return;
 +      if (line[0] != '+') {
 +              const char *color =
 +                      diff_get_color(ecbdata->color_diff,
 +                                     line[0] == '-' ? DIFF_FILE_OLD : DIFF_PLAIN);
 +              ecbdata->lno_in_preimage++;
 +              if (line[0] == ' ')
 +                      ecbdata->lno_in_postimage++;
 +              emit_line(ecbdata->file, color, reset, line, len);
 +      } else {
 +              ecbdata->lno_in_postimage++;
 +              emit_add_line(reset, ecbdata, line + 1, len - 1);
        }
 -      emit_add_line(reset, ecbdata, line, len);
  }
  
  static char *pprint_rename(const char *a, const char *b)
@@@ -1161,7 -999,7 +1161,7 @@@ static void show_stats(struct diffstat_
               total_files, adds, dels);
  }
  
 -static void show_shortstats(struct diffstat_tdata, struct diff_options *options)
 +static void show_shortstats(struct diffstat_t *data, struct diff_options *options)
  {
        int i, adds = 0, dels = 0, total_files = data->nr;
  
@@@ -1373,6 -1211,7 +1373,6 @@@ struct checkdiff_t 
        struct diff_options *o;
        unsigned ws_rule;
        unsigned status;
 -      int trailing_blanks_start;
  };
  
  static int is_conflict_marker(const char *line, unsigned long len)
@@@ -1416,6 -1255,10 +1416,6 @@@ static void checkdiff_consume(void *pri
        if (line[0] == '+') {
                unsigned bad;
                data->lineno++;
 -              if (!ws_blank_line(line + 1, len - 1, data->ws_rule))
 -                      data->trailing_blanks_start = 0;
 -              else if (!data->trailing_blanks_start)
 -                      data->trailing_blanks_start = data->lineno;
                if (is_conflict_marker(line + 1, len - 1)) {
                        data->status |= 1;
                        fprintf(data->o->file,
                              data->o->file, set, reset, ws);
        } else if (line[0] == ' ') {
                data->lineno++;
 -              data->trailing_blanks_start = 0;
        } else if (line[0] == '@') {
                char *plus = strchr(line, '+');
                if (plus)
                        data->lineno = strtol(plus, NULL, 10) - 1;
                else
                        die("invalid diff");
 -              data->trailing_blanks_start = 0;
        }
  }
  
@@@ -1607,18 -1452,6 +1607,18 @@@ static void builtin_diff(const char *na
        const char *reset = diff_get_color_opt(o, DIFF_RESET);
        const char *a_prefix, *b_prefix;
        const char *textconv_one = NULL, *textconv_two = NULL;
 +      struct strbuf header = STRBUF_INIT;
 +
 +      if (DIFF_OPT_TST(o, SUBMODULE_LOG) &&
 +                      (!one->mode || S_ISGITLINK(one->mode)) &&
 +                      (!two->mode || S_ISGITLINK(two->mode))) {
 +              const char *del = diff_get_color_opt(o, DIFF_FILE_OLD);
 +              const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
 +              show_submodule_summary(o->file, one ? one->path : two->path,
 +                              one->sha1, two->sha1,
 +                              del, add, reset);
 +              return;
 +      }
  
        if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
                textconv_one = get_textconv(one);
        b_two = quote_two(b_prefix, name_b + (*name_b == '/'));
        lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
        lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
 -      fprintf(o->file, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
 +      strbuf_addf(&header, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
        if (lbl[0][0] == '/') {
                /* /dev/null */
 -              fprintf(o->file, "%snew file mode %06o%s\n", set, two->mode, reset);
 +              strbuf_addf(&header, "%snew file mode %06o%s\n", set, two->mode, reset);
                if (xfrm_msg && xfrm_msg[0])
 -                      fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset);
 +                      strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
        }
        else if (lbl[1][0] == '/') {
 -              fprintf(o->file, "%sdeleted file mode %06o%s\n", set, one->mode, reset);
 +              strbuf_addf(&header, "%sdeleted file mode %06o%s\n", set, one->mode, reset);
                if (xfrm_msg && xfrm_msg[0])
 -                      fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset);
 +                      strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
        }
        else {
                if (one->mode != two->mode) {
 -                      fprintf(o->file, "%sold mode %06o%s\n", set, one->mode, reset);
 -                      fprintf(o->file, "%snew mode %06o%s\n", set, two->mode, reset);
 +                      strbuf_addf(&header, "%sold mode %06o%s\n", set, one->mode, reset);
 +                      strbuf_addf(&header, "%snew mode %06o%s\n", set, two->mode, reset);
                }
                if (xfrm_msg && xfrm_msg[0])
 -                      fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset);
 +                      strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
 +
                /*
                 * we do not run diff between different kind
                 * of objects.
                if (complete_rewrite &&
                    (textconv_one || !diff_filespec_is_binary(one)) &&
                    (textconv_two || !diff_filespec_is_binary(two))) {
 +                      fprintf(o->file, "%s", header.buf);
 +                      strbuf_reset(&header);
                        emit_rewrite_diff(name_a, name_b, one, two,
                                                textconv_one, textconv_two, o);
                        o->found_changes = 1;
                if (mf1.size == mf2.size &&
                    !memcmp(mf1.ptr, mf2.ptr, mf1.size))
                        goto free_ab_and_return;
 +              fprintf(o->file, "%s", header.buf);
 +              strbuf_reset(&header);
                if (DIFF_OPT_TST(o, BINARY))
                        emit_binary_diff(o->file, &mf1, &mf2);
                else
                struct emit_callback ecbdata;
                const struct userdiff_funcname *pe;
  
 +              if (!DIFF_XDL_TST(o, WHITESPACE_FLAGS)) {
 +                      fprintf(o->file, "%s", header.buf);
 +                      strbuf_reset(&header);
 +              }
 +
                if (textconv_one) {
                        size_t size;
                        mf1.ptr = run_textconv(textconv_one, one, &size);
                ecbdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
                ecbdata.found_changesp = &o->found_changes;
                ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
 +              if (ecbdata.ws_rule & WS_BLANK_AT_EOF)
 +                      check_blank_at_eof(&mf1, &mf2, &ecbdata);
                ecbdata.file = o->file;
 +              ecbdata.header = header.len ? &header : NULL;
                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
                xecfg.ctxlen = o->context;
                xecfg.interhunkctxlen = o->interhunkcontext;
        }
  
   free_ab_and_return:
 +      strbuf_release(&header);
        diff_free_filespec_data(one);
        diff_free_filespec_data(two);
        free(a_one);
@@@ -1885,22 -1704,11 +1885,22 @@@ static void builtin_checkdiff(const cha
                xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
                              &xpp, &xecfg, &ecb);
  
 -              if ((data.ws_rule & WS_TRAILING_SPACE) &&
 -                  data.trailing_blanks_start) {
 -                      fprintf(o->file, "%s:%d: ends with blank lines.\n",
 -                              data.filename, data.trailing_blanks_start);
 -                      data.status = 1; /* report errors */
 +              if (data.ws_rule & WS_BLANK_AT_EOF) {
 +                      struct emit_callback ecbdata;
 +                      int blank_at_eof;
 +
 +                      ecbdata.ws_rule = data.ws_rule;
 +                      check_blank_at_eof(&mf1, &mf2, &ecbdata);
 +                      blank_at_eof = ecbdata.blank_at_eof_in_preimage;
 +
 +                      if (blank_at_eof) {
 +                              static char *err;
 +                              if (!err)
 +                                      err = whitespace_error_string(WS_BLANK_AT_EOF);
 +                              fprintf(o->file, "%s:%d: %s.\n",
 +                                      data.filename, blank_at_eof, err);
 +                              data.status = 1; /* report errors */
 +                      }
                }
        }
   free_and_return:
@@@ -1997,7 -1805,7 +1997,7 @@@ static int reuse_worktree_file(const ch
         * If ce is marked as "assume unchanged", there is no
         * guarantee that work tree matches what we are looking for.
         */
-       if (ce->ce_flags & CE_VALID)
+       if ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))
                return 0;
  
        /*
@@@ -2570,20 -2378,6 +2570,20 @@@ int diff_setup_done(struct diff_option
        if (count > 1)
                die("--name-only, --name-status, --check and -s are mutually exclusive");
  
 +      /*
 +       * Most of the time we can say "there are changes"
 +       * only by checking if there are changed paths, but
 +       * --ignore-whitespace* options force us to look
 +       * inside contents.
 +       */
 +
 +      if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) ||
 +          DIFF_XDL_TST(options, IGNORE_WHITESPACE_CHANGE) ||
 +          DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL))
 +              DIFF_OPT_SET(options, DIFF_FROM_CONTENTS);
 +      else
 +              DIFF_OPT_CLR(options, DIFF_FROM_CONTENTS);
 +
        if (DIFF_OPT_TST(options, FIND_COPIES_HARDER))
                options->detect_rename = DIFF_DETECT_COPY;
  
         * to have found.  It does not make sense not to return with
         * exit code in such a case either.
         */
 -      if (DIFF_OPT_TST(options, QUIET)) {
 +      if (DIFF_OPT_TST(options, QUICK)) {
                options->output_format = DIFF_FORMAT_NO_OUTPUT;
                DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        }
@@@ -2835,7 -2629,7 +2835,7 @@@ int diff_opt_parse(struct diff_options 
        else if (!strcmp(arg, "--exit-code"))
                DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        else if (!strcmp(arg, "--quiet"))
 -              DIFF_OPT_SET(options, QUIET);
 +              DIFF_OPT_SET(options, QUICK);
        else if (!strcmp(arg, "--ext-diff"))
                DIFF_OPT_SET(options, ALLOW_EXTERNAL);
        else if (!strcmp(arg, "--no-ext-diff"))
                DIFF_OPT_CLR(options, ALLOW_TEXTCONV);
        else if (!strcmp(arg, "--ignore-submodules"))
                DIFF_OPT_SET(options, IGNORE_SUBMODULES);
 +      else if (!strcmp(arg, "--submodule"))
 +              DIFF_OPT_SET(options, SUBMODULE_LOG);
 +      else if (!prefixcmp(arg, "--submodule=")) {
 +              if (!strcmp(arg + 12, "log"))
 +                      DIFF_OPT_SET(options, SUBMODULE_LOG);
 +      }
  
        /* misc options */
        else if (!strcmp(arg, "-z"))
@@@ -2903,7 -2691,7 +2903,7 @@@ static int parse_num(const char **cp_p
        num = 0;
        scale = 1;
        dot = 0;
 -      for(;;) {
 +      for (;;) {
                ch = *cp;
                if ( !dot && ch == '.' ) {
                        scale = 1;
@@@ -3542,18 -3330,6 +3542,18 @@@ free_queue
        q->nr = q->alloc = 0;
        if (options->close_file)
                fclose(options->file);
 +
 +      /*
 +       * Report the content-level differences with HAS_CHANGES;
 +       * diff_addremove/diff_change does not set the bit when
 +       * DIFF_FROM_CONTENTS is in effect (e.g. with -w).
 +       */
 +      if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
 +              if (options->found_changes)
 +                      DIFF_OPT_SET(options, HAS_CHANGES);
 +              else
 +                      DIFF_OPT_CLR(options, HAS_CHANGES);
 +      }
  }
  
  static void diffcore_apply_filter(const char *filter)
@@@ -3690,7 -3466,7 +3690,7 @@@ void diffcore_std(struct diff_options *
        diff_resolve_rename_copy();
        diffcore_apply_filter(options->filter);
  
 -      if (diff_queued_diff.nr)
 +      if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
                DIFF_OPT_SET(options, HAS_CHANGES);
        else
                DIFF_OPT_CLR(options, HAS_CHANGES);
@@@ -3750,8 -3526,7 +3750,8 @@@ void diff_addremove(struct diff_option
                fill_filespec(two, sha1, mode);
  
        diff_queue(&diff_queued_diff, one, two);
 -      DIFF_OPT_SET(options, HAS_CHANGES);
 +      if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
 +              DIFF_OPT_SET(options, HAS_CHANGES);
  }
  
  void diff_change(struct diff_options *options,
        fill_filespec(two, new_sha1, new_mode);
  
        diff_queue(&diff_queued_diff, one, two);
 -      DIFF_OPT_SET(options, HAS_CHANGES);
 +      if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
 +              DIFF_OPT_SET(options, HAS_CHANGES);
  }
  
  void diff_unmerge(struct diff_options *options,
@@@ -3823,13 -3597,11 +3823,13 @@@ static char *run_textconv(const char *p
        if (start_command(&child) != 0 ||
            strbuf_read(&buf, child.out, 0) < 0 ||
            finish_command(&child) != 0) {
 +              close(child.out);
                strbuf_release(&buf);
                remove_tempfile();
                error("error running textconv command '%s'", pgm);
                return NULL;
        }
 +      close(child.out);
        remove_tempfile();
  
        return strbuf_detach(&buf, outsize);
diff --combined dir.c
index d0999ba055367c31571b251fb34bb46ed6c7051d,6b1c47822fd725d7d71871c806b9f631555985db..3a8d3e67a529c03659dc950d64f4b0d6226f9925
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -200,11 -200,35 +200,35 @@@ void add_exclude(const char *string, co
        which->excludes[which->nr++] = x;
  }
  
- static int add_excludes_from_file_1(const char *fname,
-                                   const char *base,
-                                   int baselen,
-                                   char **buf_p,
-                                   struct exclude_list *which)
+ static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
+ {
+       int pos, len;
+       unsigned long sz;
+       enum object_type type;
+       void *data;
+       struct index_state *istate = &the_index;
+       len = strlen(path);
+       pos = index_name_pos(istate, path, len);
+       if (pos < 0)
+               return NULL;
+       if (!ce_skip_worktree(istate->cache[pos]))
+               return NULL;
+       data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
+       if (!data || type != OBJ_BLOB) {
+               free(data);
+               return NULL;
+       }
+       *size = xsize_t(sz);
+       return data;
+ }
+ int add_excludes_from_file_to_list(const char *fname,
+                                  const char *base,
+                                  int baselen,
+                                  char **buf_p,
+                                  struct exclude_list *which,
+                                  int check_index)
  {
        struct stat st;
        int fd, i;
        char *buf, *entry;
  
        fd = open(fname, O_RDONLY);
-       if (fd < 0 || fstat(fd, &st) < 0)
-               goto err;
-       size = xsize_t(st.st_size);
-       if (size == 0) {
-               close(fd);
-               return 0;
+       if (fd < 0 || fstat(fd, &st) < 0) {
+               if (0 <= fd)
+                       close(fd);
+               if (!check_index ||
+                   (buf = read_skip_worktree_file_from_index(fname, &size)) == NULL)
+                       return -1;
        }
-       buf = xmalloc(size+1);
-       if (read_in_full(fd, buf, size) != size)
-       {
-               free(buf);
-               goto err;
+       else {
+               size = xsize_t(st.st_size);
+               if (size == 0) {
+                       close(fd);
+                       return 0;
+               }
+               buf = xmalloc(size);
+               if (read_in_full(fd, buf, size) != size) {
+                       close(fd);
+                       return -1;
+               }
+               close(fd);
        }
-       close(fd);
  
        if (buf_p)
                *buf_p = buf;
-       buf[size++] = '\n';
        entry = buf;
-       for (i = 0; i < size; i++) {
-               if (buf[i] == '\n') {
+       for (i = 0; i <= size; i++) {
+               if (i == size || buf[i] == '\n') {
                        if (entry != buf + i && entry[0] != '#') {
                                buf[i - (i && buf[i-1] == '\r')] = 0;
                                add_exclude(entry, base, baselen, which);
                }
        }
        return 0;
-  err:
-       if (0 <= fd)
-               close(fd);
-       return -1;
  }
  
  void add_excludes_from_file(struct dir_struct *dir, const char *fname)
  {
-       if (add_excludes_from_file_1(fname, "", 0, NULL,
-                                    &dir->exclude_list[EXC_FILE]) < 0)
+       if (add_excludes_from_file_to_list(fname, "", 0, NULL,
+                                          &dir->exclude_list[EXC_FILE], 0) < 0)
                die("cannot use %s as an exclude file", fname);
  }
  
@@@ -300,9 -324,9 +324,9 @@@ static void prep_exclude(struct dir_str
                memcpy(dir->basebuf + current, base + current,
                       stk->baselen - current);
                strcpy(dir->basebuf + stk->baselen, dir->exclude_per_dir);
-               add_excludes_from_file_1(dir->basebuf,
-                                        dir->basebuf, stk->baselen,
-                                        &stk->filebuf, el);
+               add_excludes_from_file_to_list(dir->basebuf,
+                                              dir->basebuf, stk->baselen,
+                                              &stk->filebuf, el, 1);
                dir->exclude_stack = stk;
                current = stk->baselen;
        }
  /* Scan the list and let the last match determine the fate.
   * Return 1 for exclude, 0 for include and -1 for undecided.
   */
static int excluded_1(const char *pathname,
-                     int pathlen, const char *basename, int *dtype,
-                     struct exclude_list *el)
int excluded_from_list(const char *pathname,
+                      int pathlen, const char *basename, int *dtype,
+                      struct exclude_list *el)
  {
        int i;
  
                        int to_exclude = x->to_exclude;
  
                        if (x->flags & EXC_FLAG_MUSTBEDIR) {
+                               if (!dtype) {
+                                       if (!prefixcmp(pathname, exclude))
+                                               return to_exclude;
+                                       else
+                                               continue;
+                               }
                                if (*dtype == DT_UNKNOWN)
                                        *dtype = get_dtype(NULL, pathname, pathlen);
                                if (*dtype != DT_DIR)
@@@ -382,8 -412,8 +412,8 @@@ int excluded(struct dir_struct *dir, co
  
        prep_exclude(dir, pathname, basename-pathname);
        for (st = EXC_CMDL; st <= EXC_FILE; st++) {
-               switch (excluded_1(pathname, pathlen, basename,
-                                  dtype_p, &dir->exclude_list[st])) {
+               switch (excluded_from_list(pathname, pathlen, basename,
+                                          dtype_p, &dir->exclude_list[st])) {
                case 0:
                        return 0;
                case 1:
@@@ -861,20 -891,12 +891,20 @@@ int is_empty_dir(const char *path
        return ret;
  }
  
 -int remove_dir_recursively(struct strbuf *path, int only_empty)
 +int remove_dir_recursively(struct strbuf *path, int flag)
  {
 -      DIR *dir = opendir(path->buf);
 +      DIR *dir;
        struct dirent *e;
        int ret = 0, original_len = path->len, len;
 +      int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY);
 +      unsigned char submodule_head[20];
  
 +      if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
 +          !resolve_gitlink_ref(path->buf, "HEAD", submodule_head))
 +              /* Do not descend and nuke a nested git work tree. */
 +              return 0;
 +
 +      dir = opendir(path->buf);
        if (!dir)
                return -1;
        if (path->buf[original_len - 1] != '/')
diff --combined dir.h
index 320b6a2f38b9289f910141148b5dddb4cb80815f,472e11e659a1b0e1f74c1e1a60d4ce9a5afc281a..3bead5f0e25a864c34f515b7bff4c89b55ce84fe
--- 1/dir.h
--- 2/dir.h
+++ b/dir.h
@@@ -69,7 -69,11 +69,11 @@@ extern int match_pathspec(const char **
  extern int fill_directory(struct dir_struct *dir, const char **pathspec);
  extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);
  
+ extern int excluded_from_list(const char *pathname, int pathlen, const char *basename,
+                             int *dtype, struct exclude_list *el);
  extern int excluded(struct dir_struct *, const char *, int *);
+ extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
+                                         char **buf_p, struct exclude_list *which, int check_index);
  extern void add_excludes_from_file(struct dir_struct *, const char *fname);
  extern void add_exclude(const char *string, const char *base,
                        int baselen, struct exclude_list *which);
@@@ -88,10 -92,7 +92,10 @@@ static inline int is_dot_or_dotdot(cons
  extern int is_empty_dir(const char *dir);
  
  extern void setup_standard_excludes(struct dir_struct *dir);
 -extern int remove_dir_recursively(struct strbuf *path, int only_empty);
 +
 +#define REMOVE_DIR_EMPTY_ONLY 01
 +#define REMOVE_DIR_KEEP_NESTED_GIT 02
 +extern int remove_dir_recursively(struct strbuf *path, int flag);
  
  /* tries to remove the path with empty directories along it, ignores ENOENT */
  extern int remove_path(const char *path);
diff --combined entry.c
index 06d24f14c6ba9401637aebfb11659ae747796c06,efee21fe199768ac1e69578e2c3f4d210f484aa4..9d5b232781c6760930c354c1792ad6b924f8a72d
+++ b/entry.c
@@@ -177,15 -177,11 +177,15 @@@ static int write_entry(struct cache_ent
  
  /*
   * This is like 'lstat()', except it refuses to follow symlinks
 - * in the path.
 + * in the path, after skipping "skiplen".
   */
 -int check_path(const char *path, int len, struct stat *st)
 +int check_path(const char *path, int len, struct stat *st, int skiplen)
  {
 -      if (has_symlink_leading_path(path, len)) {
 +      const char *slash = path + len;
 +
 +      while (path < slash && *slash != '/')
 +              slash--;
 +      if (!has_dirs_only_path(path, slash - path, skiplen)) {
                errno = ENOENT;
                return -1;
        }
@@@ -205,8 -201,8 +205,8 @@@ int checkout_entry(struct cache_entry *
        strcpy(path + len, ce->name);
        len += ce_namelen(ce);
  
 -      if (!check_path(path, len, &st)) {
 +      if (!check_path(path, len, &st, state->base_dir_len)) {
-               unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
+               unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
                if (!changed)
                        return 0;
                if (!state->force) {
diff --combined environment.c
index 5171d9f9a4a30054983638e9e19e61f422724373,020422c03430a7bab3c69c36710671dd93e0839b..739ec2704031f0dd9d4a380e07f001c09742a7be
@@@ -26,7 -26,6 +26,7 @@@ const char *git_commit_encoding
  const char *git_log_output_encoding;
  int shared_repository = PERM_UMASK;
  const char *apply_default_whitespace;
 +const char *apply_default_ignorewhitespace;
  int zlib_compression_level = Z_BEST_SPEED;
  int core_compression_level;
  int core_compression_seen;
@@@ -39,7 -38,6 +39,7 @@@ int pager_use_color = 1
  const char *editor_program;
  const char *excludes_file;
  int auto_crlf = 0;    /* 1: both ways, -1: only when adding git objects */
 +int read_replace_refs = 1;
  enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
  unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
  enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
@@@ -49,8 -47,8 +49,9 @@@ enum push_default_type push_default = P
  #define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
  #endif
  enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
 +char *notes_ref_name;
  int grafts_replace_parents = 1;
+ int core_apply_sparse_checkout;
  
  /* Parallel index stat data preload? */
  int core_preload_index = 0;
@@@ -84,8 -82,6 +85,8 @@@ static void setup_git_env(void
        git_graft_file = getenv(GRAFT_ENVIRONMENT);
        if (!git_graft_file)
                git_graft_file = git_pathdup("info/grafts");
 +      if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
 +              read_replace_refs = 0;
  }
  
  int is_bare_repository(void)
diff --combined read-cache.c
index 9033dd3ab938e2ee7b4248ff97645414ee3688db,b31861c87e2b6ec5bb1bc2f4a00ff3a11184dfcb..a0adb272fdbbb73765f54bb65be0b0453450bf0d
@@@ -259,12 -259,17 +259,17 @@@ int ie_match_stat(const struct index_st
  {
        unsigned int changed;
        int ignore_valid = options & CE_MATCH_IGNORE_VALID;
+       int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
        int assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY;
  
        /*
         * If it's marked as always valid in the index, it's
         * valid whatever the checked-out copy says.
+        *
+        * skip-worktree has the same effect with higher precedence
         */
+       if (!ignore_skip_worktree && ce_skip_worktree(ce))
+               return 0;
        if (!ignore_valid && (ce->ce_flags & CE_VALID))
                return 0;
  
@@@ -564,7 -569,7 +569,7 @@@ int add_to_index(struct index_state *is
        int size, namelen, was_same;
        mode_t st_mode = st->st_mode;
        struct cache_entry *ce, *alias;
-       unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
+       unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE|CE_MATCH_RACY_IS_DIRTY;
        int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);
        int pretend = flags & ADD_CACHE_PRETEND;
        int intent_only = flags & ADD_CACHE_INTENT;
@@@ -1000,14 -1005,20 +1005,20 @@@ static struct cache_entry *refresh_cach
        struct cache_entry *updated;
        int changed, size;
        int ignore_valid = options & CE_MATCH_IGNORE_VALID;
+       int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
  
        if (ce_uptodate(ce))
                return ce;
  
        /*
-        * CE_VALID means the user promised us that the change to
-        * the work tree does not matter and told us not to worry.
+        * CE_VALID or CE_SKIP_WORKTREE means the user promised us
+        * that the change to the work tree does not matter and told
+        * us not to worry.
         */
+       if (!ignore_skip_worktree && ce_skip_worktree(ce)) {
+               ce_mark_uptodate(ce);
+               return ce;
+       }
        if (!ignore_valid && (ce->ce_flags & CE_VALID)) {
                ce_mark_uptodate(ce);
                return ce;
        return updated;
  }
  
 -int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, char *seen)
 +static void show_file(const char * fmt, const char * name, int in_porcelain,
 +                    int * first, char *header_msg)
 +{
 +      if (in_porcelain && *first && header_msg) {
 +              printf("%s\n", header_msg);
 +              *first=0;
 +      }
 +      printf(fmt, name);
 +}
 +
 +int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,
 +                char *seen, char *header_msg)
  {
        int i;
        int has_errors = 0;
        int quiet = (flags & REFRESH_QUIET) != 0;
        int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
        int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;
 +      int first = 1;
 +      int in_porcelain = (flags & REFRESH_IN_PORCELAIN);
        unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
 -      const char *needs_update_message;
 +      const char *needs_update_fmt;
 +      const char *needs_merge_fmt;
  
 -      needs_update_message = ((flags & REFRESH_SAY_CHANGED)
 -                              ? "locally modified" : "needs update");
 +      needs_update_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
 +      needs_merge_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce, *new;
                int cache_errno = 0;
                        i--;
                        if (allow_unmerged)
                                continue;
 -                      printf("%s: needs merge\n", ce->name);
 +                      show_file(needs_merge_fmt, ce->name, in_porcelain, &first, header_msg);
                        has_errors = 1;
                        continue;
                }
                        }
                        if (quiet)
                                continue;
 -                      printf("%s: %s\n", ce->name, needs_update_message);
 +                      show_file(needs_update_fmt, ce->name, in_porcelain, &first, header_msg);
                        has_errors = 1;
                        continue;
                }
@@@ -1322,7 -1319,7 +1333,7 @@@ int read_index_from(struct index_state 
                 * extension name (4-byte) and section length
                 * in 4-byte network byte order.
                 */
 -              unsigned long extsize;
 +              uint32_t extsize;
                memcpy(&extsize, (char *)mmap + src_offset + 4, 4);
                extsize = ntohl(extsize);
                if (read_index_extension(istate,
diff --combined t/t7002-grep.sh
index abd14bf819f5c60fc1b9dc758c04974bd24b10a4,99142fd6bda0e9c241bad1c18a18583b30fda700..76c5e091b7d45bde38f34dc9726c51034ee7f9eb
@@@ -8,13 -8,24 +8,25 @@@ test_description='git grep various
  
  . ./test-lib.sh
  
+ test_expect_success 'Check for external grep support' '
+       case "$(git grep -h 2>&1|grep ext-grep)" in
+       *"(default)"*)
+               test_set_prereq EXTGREP
+               true;;
+       *"(ignored by this build)"*)
+               true;;
+       *)
+               false;;
+       esac
+ '
  cat >hello.c <<EOF
  #include <stdio.h>
  int main(int argc, const char **argv)
  {
        printf("Hello world.\n");
        return 0;
 +      /* char ?? */
  }
  EOF
  
@@@ -214,77 -225,6 +226,77 @@@ test_expect_success 'grep -e A --and --
        test_cmp expected actual
  '
  
 +test_expect_success 'grep should ignore GREP_OPTIONS' '
 +      GREP_OPTIONS=-v git grep " mmap bar\$" >actual &&
 +      test_cmp expected actual
 +'
 +
 +test_expect_success 'grep -f, non-existent file' '
 +      test_must_fail git grep -f patterns
 +'
 +
 +cat >expected <<EOF
 +file:foo mmap bar
 +file:foo_mmap bar
 +file:foo_mmap bar mmap
 +file:foo mmap bar_mmap
 +file:foo_mmap bar mmap baz
 +EOF
 +
 +cat >pattern <<EOF
 +mmap
 +EOF
 +
 +test_expect_success 'grep -f, one pattern' '
 +      git grep -f pattern >actual &&
 +      test_cmp expected actual
 +'
 +
 +cat >expected <<EOF
 +file:foo mmap bar
 +file:foo_mmap bar
 +file:foo_mmap bar mmap
 +file:foo mmap bar_mmap
 +file:foo_mmap bar mmap baz
 +t/a/v:vvv
 +t/v:vvv
 +v:vvv
 +EOF
 +
 +cat >patterns <<EOF
 +mmap
 +vvv
 +EOF
 +
 +test_expect_success 'grep -f, multiple patterns' '
 +      git grep -f patterns >actual &&
 +      test_cmp expected actual
 +'
 +
 +cat >expected <<EOF
 +file:foo mmap bar
 +file:foo_mmap bar
 +file:foo_mmap bar mmap
 +file:foo mmap bar_mmap
 +file:foo_mmap bar mmap baz
 +t/a/v:vvv
 +t/v:vvv
 +v:vvv
 +EOF
 +
 +cat >patterns <<EOF
 +
 +mmap
 +
 +vvv
 +
 +EOF
 +
 +test_expect_success 'grep -f, ignore empty lines' '
 +      git grep -f patterns >actual &&
 +      test_cmp expected actual
 +'
 +
  cat >expected <<EOF
  y:y yy
  --
@@@ -400,30 -340,16 +412,42 @@@ test_expect_success 'grep -p -B5' 
        test_cmp expected actual
  '
  
 +test_expect_success 'grep from a subdirectory to search wider area (1)' '
 +      mkdir -p s &&
 +      (
 +              cd s && git grep "x x x" ..
 +      )
 +'
 +
 +test_expect_success 'grep from a subdirectory to search wider area (2)' '
 +      mkdir -p s &&
 +      (
 +              cd s || exit 1
 +              ( git grep xxyyzz .. >out ; echo $? >status )
 +              ! test -s out &&
 +              test 1 = $(cat status)
 +      )
 +'
 +
 +cat >expected <<EOF
 +hello.c:int main(int argc, const char **argv)
 +EOF
 +
 +test_expect_success 'grep -Fi' '
 +      git grep -Fi "CHAR *" >actual &&
 +      test_cmp expected actual
 +'
 +
+ test_expect_success EXTGREP 'external grep is called' '
+       GIT_TRACE=2 git grep foo >/dev/null 2>actual &&
+       grep "trace: grep:.*foo" actual >/dev/null
+ '
+ test_expect_success EXTGREP 'no external grep when skip-worktree entries exist' '
+       git update-index --skip-worktree file &&
+       GIT_TRACE=2 git grep foo >/dev/null 2>actual &&
+       ! grep "trace: grep:" actual >/dev/null &&
+       git update-index --no-skip-worktree file
+ '
  test_done
diff --combined t/t7300-clean.sh
index 118c6ebb182b5cd4700e533d6a951b31529149af,8073d02be59b56f8cecb38fd4e0b92483ff73cde..7d8ed68befed0e85ad85f9f933a2b887125e38e8
@@@ -22,6 -22,25 +22,25 @@@ test_expect_success 'setup' 
  
  '
  
+ test_expect_success 'git clean with skip-worktree .gitignore' '
+       git update-index --skip-worktree .gitignore &&
+       rm .gitignore &&
+       mkdir -p build docs &&
+       touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
+       git clean &&
+       test -f Makefile &&
+       test -f README &&
+       test -f src/part1.c &&
+       test -f src/part2.c &&
+       test ! -f a.out &&
+       test ! -f src/part3.c &&
+       test -f docs/manual.txt &&
+       test -f obj.o &&
+       test -f build/lib.so &&
+       git update-index --no-skip-worktree .gitignore &&
+       git checkout .gitignore
+ '
  test_expect_success 'git clean' '
  
        mkdir -p build docs &&
@@@ -380,43 -399,4 +399,43 @@@ test_expect_success 'removal failure' 
  '
  chmod 755 foo
  
 +test_expect_success 'nested git work tree' '
 +      rm -fr foo bar &&
 +      mkdir foo bar &&
 +      (
 +              cd foo &&
 +              git init &&
 +              >hello.world
 +              git add . &&
 +              git commit -a -m nested
 +      ) &&
 +      (
 +              cd bar &&
 +              >goodbye.people
 +      ) &&
 +      git clean -f -d &&
 +      test -f foo/.git/index &&
 +      test -f foo/hello.world &&
 +      ! test -d bar
 +'
 +
 +test_expect_success 'force removal of nested git work tree' '
 +      rm -fr foo bar &&
 +      mkdir foo bar &&
 +      (
 +              cd foo &&
 +              git init &&
 +              >hello.world
 +              git add . &&
 +              git commit -a -m nested
 +      ) &&
 +      (
 +              cd bar &&
 +              >goodbye.people
 +      ) &&
 +      git clean -f -f -d &&
 +      ! test -d foo &&
 +      ! test -d bar
 +'
 +
  test_done
diff --combined unpack-trees.c
index dd5999c3562219b7993420b22257f4088ab82b8d,d33b39e084a7faa108803b520d0b7f869ec0fbc7..7570475b453bbaceab74fa04826ff0d23f9e6e8f
@@@ -32,6 -32,12 +32,12 @@@ static struct unpack_trees_error_msgs u
  
        /* bind_overlap */
        "Entry '%s' overlaps with '%s'.  Cannot bind.",
+       /* sparse_not_uptodate_file */
+       "Entry '%s' not uptodate. Cannot update sparse checkout.",
+       /* would_lose_orphaned */
+       "Working tree file '%s' would be %s by sparse checkout update.",
  };
  
  #define ERRORMSG(o,fld) \
@@@ -78,7 -84,7 +84,7 @@@ static int check_updates(struct unpack_
        if (o->update && o->verbose_update) {
                for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
                        struct cache_entry *ce = index->cache[cnt];
-                       if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
+                       if (ce->ce_flags & (CE_UPDATE | CE_REMOVE | CE_WT_REMOVE))
                                total++;
                }
  
        for (i = 0; i < index->cache_nr; i++) {
                struct cache_entry *ce = index->cache[i];
  
+               if (ce->ce_flags & CE_WT_REMOVE) {
+                       display_progress(progress, ++cnt);
+                       if (o->update)
+                               unlink_entry(ce);
+                       continue;
+               }
                if (ce->ce_flags & CE_REMOVE) {
                        display_progress(progress, ++cnt);
                        if (o->update)
        return errs != 0;
  }
  
+ static int verify_uptodate_sparse(struct cache_entry *ce, struct unpack_trees_options *o);
+ static int verify_absent_sparse(struct cache_entry *ce, const char *action, struct unpack_trees_options *o);
+ static int will_have_skip_worktree(const struct cache_entry *ce, struct unpack_trees_options *o)
+ {
+       const char *basename;
+       if (ce_stage(ce))
+               return 0;
+       basename = strrchr(ce->name, '/');
+       basename = basename ? basename+1 : ce->name;
+       return excluded_from_list(ce->name, ce_namelen(ce), basename, NULL, o->el) <= 0;
+ }
+ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_options *o)
+ {
+       int was_skip_worktree = ce_skip_worktree(ce);
+       if (will_have_skip_worktree(ce, o))
+               ce->ce_flags |= CE_SKIP_WORKTREE;
+       else
+               ce->ce_flags &= ~CE_SKIP_WORKTREE;
+       /*
+        * We only care about files getting into the checkout area
+        * If merge strategies want to remove some, go ahead, this
+        * flag will be removed eventually in unpack_trees() if it's
+        * outside checkout area.
+        */
+       if (ce->ce_flags & CE_REMOVE)
+               return 0;
+       if (!was_skip_worktree && ce_skip_worktree(ce)) {
+               /*
+                * If CE_UPDATE is set, verify_uptodate() must be called already
+                * also stat info may have lost after merged_entry() so calling
+                * verify_uptodate() again may fail
+                */
+               if (!(ce->ce_flags & CE_UPDATE) && verify_uptodate_sparse(ce, o))
+                       return -1;
+               ce->ce_flags |= CE_WT_REMOVE;
+       }
+       if (was_skip_worktree && !ce_skip_worktree(ce)) {
+               if (verify_absent_sparse(ce, "overwritten", o))
+                       return -1;
+               ce->ce_flags |= CE_UPDATE;
+       }
+       return 0;
+ }
  static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o)
  {
        int ret = o->fn(src, o);
@@@ -277,17 -341,6 +341,17 @@@ static int unpack_nondirectories(int n
        return 0;
  }
  
 +static int unpack_failed(struct unpack_trees_options *o, const char *message)
 +{
 +      discard_index(&o->result);
 +      if (!o->gently) {
 +              if (message)
 +                      return error("%s", message);
 +              return -1;
 +      }
 +      return -1;
 +}
 +
  static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *names, struct traverse_info *info)
  {
        struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
                        int cmp = compare_entry(ce, info, p);
                        if (cmp < 0) {
                                if (unpack_index_entry(ce, o) < 0)
 -                                      return -1;
 +                                      return unpack_failed(o, NULL);
                                continue;
                        }
                        if (!cmp) {
        return mask;
  }
  
 -static int unpack_failed(struct unpack_trees_options *o, const char *message)
 -{
 -      discard_index(&o->result);
 -      if (!o->gently) {
 -              if (message)
 -                      return error("%s", message);
 -              return -1;
 -      }
 -      return -1;
 -}
 -
  /*
   * N-way merge "len" trees.  Returns 0 on success, -1 on failure to manipulate the
   * resulting index, -2 on failure to reflect the changes to the work tree.
   */
  int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o)
  {
-       int ret;
+       int i, ret;
        static struct cache_entry *dfc;
+       struct exclude_list el;
  
        if (len > MAX_UNPACK_TREES)
                die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES);
        state.quiet = 1;
        state.refresh_cache = 1;
  
+       memset(&el, 0, sizeof(el));
+       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)
+                       o->skip_sparse_checkout = 1;
+               else
+                       o->el = &el;
+       }
        memset(&o->result, 0, sizeof(o->result));
        o->result.initialized = 1;
        if (o->src_index) {
                info.fn = unpack_callback;
                info.data = o;
  
-               if (traverse_trees(len, t, &info) < 0)
-                       return unpack_failed(o, NULL);
+               if (traverse_trees(len, t, &info) < 0) {
+                       ret = unpack_failed(o, NULL);
+                       goto done;
+               }
        }
  
        /* Any left-over entries in the index? */
        if (o->merge) {
                while (o->pos < o->src_index->cache_nr) {
                        struct cache_entry *ce = o->src_index->cache[o->pos];
-                       if (unpack_index_entry(ce, o) < 0)
-                               return unpack_failed(o, NULL);
+                       if (unpack_index_entry(ce, o) < 0) {
+                               ret = unpack_failed(o, NULL);
+                               goto done;
+                       }
                }
        }
  
-       if (o->trivial_merges_only && o->nontrivial_merge)
-               return unpack_failed(o, "Merge requires file-level merging");
+       if (o->trivial_merges_only && o->nontrivial_merge) {
+               ret = unpack_failed(o, "Merge requires file-level merging");
+               goto done;
+       }
+       if (!o->skip_sparse_checkout) {
+               int empty_worktree = 1;
+               for (i = 0;i < o->result.cache_nr;i++) {
+                       struct cache_entry *ce = o->result.cache[i];
+                       if (apply_sparse_checkout(ce, o)) {
+                               ret = -1;
+                               goto done;
+                       }
+                       /*
+                        * Merge strategies may set CE_UPDATE|CE_REMOVE outside checkout
+                        * area as a result of ce_skip_worktree() shortcuts in
+                        * verify_absent() and verify_uptodate(). Clear them.
+                        */
+                       if (ce_skip_worktree(ce))
+                               ce->ce_flags &= ~(CE_UPDATE | CE_REMOVE);
+                       else
+                               empty_worktree = 0;
+               }
+               if (o->result.cache_nr && empty_worktree) {
+                       ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory");
+                       goto done;
+               }
+       }
  
        o->src_index = NULL;
        ret = check_updates(o) ? (-2) : 0;
        if (o->dst_index)
                *o->dst_index = o->result;
+ done:
+       for (i = 0;i < el.nr;i++)
+               free(el.excludes[i]);
+       if (el.excludes)
+               free(el.excludes);
        return ret;
  }
  
@@@ -445,16 -559,17 +559,17 @@@ static int same(struct cache_entry *a, 
   * When a CE gets turned into an unmerged entry, we
   * want it to be up-to-date
   */
- static int verify_uptodate(struct cache_entry *ce,
-               struct unpack_trees_options *o)
+ static int verify_uptodate_1(struct cache_entry *ce,
+                                  struct unpack_trees_options *o,
+                                  const char *error_msg)
  {
        struct stat st;
  
-       if (o->index_only || o->reset || ce_uptodate(ce))
+       if (o->index_only || (!ce_skip_worktree(ce) && (o->reset || ce_uptodate(ce))))
                return 0;
  
        if (!lstat(ce->name, &st)) {
-               unsigned changed = ie_match_stat(o->src_index, ce, &st, CE_MATCH_IGNORE_VALID);
+               unsigned changed = ie_match_stat(o->src_index, ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
                if (!changed)
                        return 0;
                /*
        if (errno == ENOENT)
                return 0;
        return o->gently ? -1 :
-               error(ERRORMSG(o, not_uptodate_file), ce->name);
+               error(error_msg, ce->name);
+ }
+ static int verify_uptodate(struct cache_entry *ce,
+                          struct unpack_trees_options *o)
+ {
+       if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
+               return 0;
+       return verify_uptodate_1(ce, o, ERRORMSG(o, not_uptodate_file));
+ }
+ static int verify_uptodate_sparse(struct cache_entry *ce,
+                                 struct unpack_trees_options *o)
+ {
+       return verify_uptodate_1(ce, o, ERRORMSG(o, sparse_not_uptodate_file));
  }
  
  static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
@@@ -572,15 -701,16 +701,16 @@@ static int icase_exists(struct unpack_t
        struct cache_entry *src;
  
        src = index_name_exists(o->src_index, dst->name, ce_namelen(dst), 1);
-       return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID);
+       return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
  }
  
  /*
   * We do not want to remove or overwrite a working tree file that
   * is not tracked, unless it is ignored.
   */
- static int verify_absent(struct cache_entry *ce, const char *action,
-                        struct unpack_trees_options *o)
+ static int verify_absent_1(struct cache_entry *ce, const char *action,
+                                struct unpack_trees_options *o,
+                                const char *error_msg)
  {
        struct stat st;
  
                         * found "foo/." in the working tree.
                         * This is tricky -- if we have modified
                         * files that are in "foo/" we would lose
 -                       * it.
 +                       * them.
                         */
                        ret = verify_clean_subdirectory(ce, action, o);
                        if (ret < 0)
        }
        return 0;
  }
+ static int verify_absent(struct cache_entry *ce, const char *action,
+                        struct unpack_trees_options *o)
+ {
+       if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
+               return 0;
+       return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_untracked));
+ }
+ static int verify_absent_sparse(struct cache_entry *ce, const char *action,
+                        struct unpack_trees_options *o)
+ {
+       return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_orphaned));
+ }
  
  static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
                struct unpack_trees_options *o)
                } else {
                        if (verify_uptodate(old, o))
                                return -1;
+                       if (ce_skip_worktree(old))
+                               update |= CE_SKIP_WORKTREE;
                        invalidate_ce_path(old, o);
                }
        }
@@@ -895,7 -1040,7 +1040,7 @@@ int threeway_merge(struct cache_entry *
   * Two-way merge.
   *
   * The rule is to "carry forward" what is in the index without losing
 - * information across a "fast forward", favoring a successful merge
 + * information across a "fast-forward", favoring a successful merge
   * over a merge failure when it makes sense.  For details of the
   * "carry forward" rule, please see <Documentation/git-read-tree.txt>.
   *
@@@ -1004,10 -1149,10 +1149,10 @@@ int oneway_merge(struct cache_entry **s
  
        if (old && same(old, a)) {
                int update = 0;
-               if (o->reset && !ce_uptodate(old)) {
+               if (o->reset && !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))
+                           ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE))
                                update |= CE_UPDATE;
                }
                add_entry(o, old, update, 0);