Merge branch 'jc/grep-lookahead'
authorJunio C Hamano <gitster@pobox.com>
Wed, 20 Jan 2010 22:43:41 +0000 (14:43 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 20 Jan 2010 22:43:41 +0000 (14:43 -0800)
* jc/grep-lookahead:
  grep --no-index: allow use of "git grep" outside a git repository
  grep: prepare to run outside of a work tree
  grep: rip out pessimization to use fixmatch()
  grep: rip out support for external grep
  grep: optimize built-in grep by skipping lines that do not hit

Conflicts:
builtin-grep.c
t/t7002-grep.sh

1  2 
Documentation/config.txt
Makefile
builtin-grep.c

diff --combined Documentation/config.txt
@@@ -130,14 -130,6 +130,14 @@@ advice.*:
                Advice shown when linkgit:git-merge[1] refuses to
                merge to avoid overwritting local changes.
                Default: true.
 +      resolveConflict::
 +              Advices shown by various commands when conflicts
 +              prevent the operation from being performed.
 +              Default: true.
 +      implicitIdentity::
 +              Advice on how to set your identity configuration when
 +              your information is guessed from the system username and
 +              domain name. Default: true.
  --
  
  core.fileMode::
@@@ -305,24 -297,17 +305,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
@@@ -510,10 -495,6 +510,10 @@@ 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'
@@@ -549,7 -530,7 +549,7 @@@ apply.whitespace:
        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`
@@@ -664,14 -645,6 +664,6 @@@ color.grep:
        `never`), never.  When set to `true` or `auto`, use color only
        when the output is written to the terminal.  Defaults to `false`.
  
- color.grep.external::
-       The string value of this variable is passed to an external 'grep'
-       command as a command line option if match highlighting is turned
-       on.  If set to an empty string, no option is passed at all,
-       turning off coloring for external 'grep' calls; this is the default.
-       For GNU grep, set it to `--color=always` to highlight matches even
-       when a pager is used.
  color.grep.match::
        Use customized color for matches.  The value of this variable
        may be specified as in color.branch.<slot>.  It is passed using
@@@ -724,11 -697,6 +716,11 @@@ color.ui:
        terminal. When more specific variables of color.* are set, they always
        take precedence over this setting. Defaults to false.
  
 +commit.status
 +      A boolean to enable/disable inclusion of status information in the
 +      commit message template when using an editor to prepare the commit
 +      message.  Defaults to true.
 +
  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
@@@ -742,7 -710,7 +734,7 @@@ diff.autorefreshindex:
        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
@@@ -858,8 -826,8 +850,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.
@@@ -892,12 -860,15 +884,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'.
@@@ -1153,12 -1124,6 +1145,12 @@@ 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.
@@@ -1488,10 -1453,6 +1480,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].
diff --combined Makefile
+++ b/Makefile
@@@ -168,8 -168,6 +168,8 @@@ all:
  #
  # 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
  # is a simplified version of the merge sort used in glibc. This is
  # recommended if Git triggers O(n^2) behavior in your platform's qsort().
  #
- # Define NO_EXTERNAL_GREP if you don't want "git grep" to ever call
- # your external grep (e.g., if your system lacks grep, if its grep is
- # broken, or spawning external process is slower than built-in grep git has).
- #
  # Define UNRELIABLE_FSTAT if your system's fstat does not return the same
  # information on a not yet closed file that lstat would return for the same
  # file after it was closed.
  #   DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
  #   DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
  
 -GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
 +GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
  -include GIT-VERSION-FILE
  
@@@ -343,7 -337,6 +339,7 @@@ LIB_H 
  LIB_OBJS =
  PROGRAMS =
  SCRIPT_PERL =
 +SCRIPT_PYTHON =
  SCRIPT_SH =
  TEST_PROGRAMS =
  
@@@ -382,7 -375,6 +378,7 @@@ SCRIPT_PERL += git-svn.per
  
  SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
          $(patsubst %.perl,%,$(SCRIPT_PERL)) \
 +        $(patsubst %.py,%,$(SCRIPT_PYTHON)) \
          git-instaweb
  
  # Empty...
@@@ -431,15 -423,6 +427,15 @@@ 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,12 -430,8 +443,12 @@@ 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
@@@ -468,7 -447,6 +464,7 @@@ LIB_H += commit.
  LIB_H += compat/bswap.h
  LIB_H += compat/cygwin.h
  LIB_H += compat/mingw.h
 +LIB_H += compat/win32/pthread.h
  LIB_H += csum-file.h
  LIB_H += decorate.h
  LIB_H += delta.h
@@@ -795,7 -773,6 +791,6 @@@ ifeq ($(uname_S),SunOS
        NO_MKDTEMP = YesPlease
        NO_MKSTEMPS = YesPlease
        NO_REGEX = YesPlease
-       NO_EXTERNAL_GREP = YesPlease
        THREADED_DELTA_SEARCH = YesPlease
        ifeq ($(uname_R),5.7)
                NEEDS_RESOLV = YesPlease
@@@ -846,7 -823,6 +841,7 @@@ ifeq ($(uname_O),Cygwin
  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
@@@ -914,7 -890,6 +909,6 @@@ ifeq ($(uname_S),IRIX
        # 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
@@@ -934,7 -909,6 +928,6 @@@ ifeq ($(uname_S),IRIX64
        # 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
@@@ -986,16 -960,15 +979,16 @@@ ifeq ($(uname_S),Windows
        OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
        NO_REGEX = YesPlease
        NO_CURL = YesPlease
 -      NO_PTHREADS = YesPlease
 +      NO_PYTHON = YesPlease
        BLK_SHA1 = YesPlease
 +      THREADED_DELTA_SEARCH = 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\"
 +      COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o
 +      COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -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 =
@@@ -1037,13 -1010,10 +1030,13 @@@ ifneq (,$(findstring MINGW,$(uname_S))
        UNRELIABLE_FSTAT = UnfortunatelyYes
        OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
        NO_REGEX = YesPlease
 +      NO_PYTHON = YesPlease
        BLK_SHA1 = YesPlease
 +      THREADED_DELTA_SEARCH = 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
 +      COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
 +              compat/win32/pthread.o
        EXTLIBS += -lws2_32
        X = .exe
  ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
        EXTLIBS += /mingw/lib/libz.a
        NO_R_TO_GCC_LINKER = YesPlease
        INTERNAL_QSORT = YesPlease
 -      THREADED_DELTA_SEARCH = YesPlease
  else
        NO_CURL = YesPlease
 -      NO_PTHREADS = YesPlease
  endif
  endif
  
@@@ -1102,9 -1074,6 +1095,9 @@@ endi
  
  ifdef NO_CURL
        BASIC_CFLAGS += -DNO_CURL
 +      REMOTE_CURL_PRIMARY =
 +      REMOTE_CURL_ALIASES =
 +      REMOTE_CURL_NAMES =
  else
        ifdef CURLDIR
                # Try "-Wl,-rpath=$(CURLDIR)/$(lib)" in such a case.
        else
                CURL_LIBCURL = -lcurl
        endif
 -      PROGRAMS += git-remote-curl$X git-http-fetch$X
 +      REMOTE_CURL_PRIMARY = git-remote-http$X
 +      REMOTE_CURL_ALIASES = git-remote-https$X git-remote-ftp$X git-remote-ftps$X
 +      REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
 +      PROGRAMS += $(REMOTE_CURL_NAMES) git-http-fetch$X
        curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p)
        ifeq "$(curl_check)" "070908"
                ifndef NO_EXPAT
@@@ -1349,9 -1315,6 +1342,6 @@@ endi
  ifdef DIR_HAS_BSD_GROUP_SEMANTICS
        COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
  endif
- ifdef NO_EXTERNAL_GREP
-       BASIC_CFLAGS += -DNO_EXTERNAL_GREP
- endif
  ifdef UNRELIABLE_FSTAT
        BASIC_CFLAGS += -DUNRELIABLE_FSTAT
  endif
@@@ -1373,10 -1336,6 +1363,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  =
  
@@@ -1424,7 -1383,6 +1414,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)
@@@ -1471,9 -1429,6 +1461,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)
  
@@@ -1485,19 -1440,20 +1475,19 @@@ shell_compatibility_test: please_set_SH
  strip: $(PROGRAMS) git$X
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
  
 -git.o: git.c common-cmds.h GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
 -              '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
 -              $(ALL_CFLAGS) -o $@ -c $(filter %.c,$^)
 +git.o: common-cmds.h
 +git.s git.o: ALL_CFLAGS += -DGIT_VERSION='"$(GIT_VERSION)"' \
 +      '-DGIT_HTML_PATH="$(htmldir_SQ)"'
  
  git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
  
 -builtin-help.o: builtin-help.c common-cmds.h GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
 -              '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
 -              '-DGIT_MAN_PATH="$(mandir_SQ)"' \
 -              '-DGIT_INFO_PATH="$(infodir_SQ)"' $<
 +builtin-help.o: common-cmds.h
 +builtin-help.s builtin-help.o: ALL_CFLAGS += \
 +      '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
 +      '-DGIT_MAN_PATH="$(mandir_SQ)"' \
 +      '-DGIT_INFO_PATH="$(infodir_SQ)"'
  
  $(BUILT_INS): git$X
        $(QUIET_BUILT_IN)$(RM) $@ && \
@@@ -1600,41 -1556,11 +1590,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' \
@@@ -1650,26 -1576,30 +1640,26 @@@ git.o git.spec 
  
  %.o: %.c GIT-CFLAGS
        $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
 -%.s: %.c GIT-CFLAGS
 +%.s: %.c GIT-CFLAGS FORCE
        $(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
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
 -              '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
 -              '-DBINDIR="$(bindir_relative_SQ)"' \
 -              '-DPREFIX="$(prefix_SQ)"' \
 -              $<
 +exec_cmd.s exec_cmd.o: ALL_CFLAGS += \
 +      '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
 +      '-DBINDIR="$(bindir_relative_SQ)"' \
 +      '-DPREFIX="$(prefix_SQ)"'
  
 -builtin-init-db.o: builtin-init-db.c GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
 +builtin-init-db.s builtin-init-db.o: ALL_CFLAGS += \
 +      -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
  
 -config.o: config.c GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $<
 +config.s config.o: ALL_CFLAGS += -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
  
 -http.o: http.c GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $<
 +http.s http.o: ALL_CFLAGS += -DGIT_USER_AGENT='"git/$(GIT_VERSION)"'
  
  ifdef NO_EXPAT
 -http-walker.o: http-walker.c http.h GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DNO_EXPAT $<
 +http-walker.o: http.h
 +http-walker.s http-walker.o: ALL_CFLAGS += -DNO_EXPAT
  endif
  
  git-%$X: %.o $(GITLIBS)
@@@ -1690,13 -1620,7 +1680,13 @@@ git-http-push$X: revision.o http.o http
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
  
 -git-remote-curl$X: remote-curl.o http.o http-walker.o $(GITLIBS)
 +$(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
 +      $(QUIET_LNCP)$(RM) $@ && \
 +      ln $< $@ 2>/dev/null || \
 +      ln -s $< $@ 2>/dev/null || \
 +      cp $< $@
 +
 +$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
  
@@@ -1747,7 -1671,7 +1737,7 @@@ cscope
  TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
               $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
  
 -GIT-CFLAGS: .FORCE-GIT-CFLAGS
 +GIT-CFLAGS: FORCE
        @FLAGS='$(TRACK_CFLAGS)'; \
            if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \
                echo 1>&2 "    * new build flags or prefix"; \
  # We need to apply sq twice, once to protect from the shell
  # that runs GIT-BUILD-OPTIONS, and then again to protect it
  # and the first level quoting from the shell that runs "echo".
 -GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
 +GIT-BUILD-OPTIONS: FORCE
        @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
  TRACK_VARS = $(subst ','\'',-DTCLTK_PATH='$(TCLTK_PATH_SQ)')
  
 -GIT-GUI-VARS: .FORCE-GIT-GUI-VARS
 +GIT-GUI-VARS: FORCE
        @VARS='$(TRACK_VARS)'; \
            if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \
                echo 1>&2 "    * new Tcl/Tk interpreter location"; \
                echo "$$VARS" >$@; \
              fi
 -
 -.PHONY: .FORCE-GIT-GUI-VARS
  endif
  
  ### 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_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))
  
 -all:: $(TEST_PROGRAMS)
 +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
@@@ -1864,20 -1777,15 +1854,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
@@@ -1885,7 -1793,6 +1875,7 @@@ endi
  ifneq (,$X)
        $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
  endif
 +
        bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
        execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
        { test "$$bindir/" = "$$execdir/" || \
                ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
                cp "$$execdir/git$X" "$$execdir/$$p" || exit; \
          done; } && \
 +      { for p in $(REMOTE_CURL_ALIASES); do \
 +              $(RM) "$$execdir/$$p" && \
 +              ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
 +              ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
 +              cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \
 +        done; } && \
        ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
  
  install-doc:
@@@ -1991,7 -1892,6 +1981,7 @@@ clean
                $(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
@@@ -2016,7 -1913,8 +2006,7 @@@ endi
  
  .PHONY: all install clean strip
  .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
 -.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags cscope .FORCE-GIT-CFLAGS
 -.PHONY: .FORCE-GIT-BUILD-OPTIONS
 +.PHONY: FORCE TAGS tags cscope
  
  ### Check documentation
  #
diff --combined builtin-grep.c
  #include "userdiff.h"
  #include "grep.h"
  #include "quote.h"
- #ifndef NO_EXTERNAL_GREP
- #ifdef __unix__
- #define NO_EXTERNAL_GREP 0
- #else
- #define NO_EXTERNAL_GREP 1
- #endif
- #endif
+ #include "dir.h"
  
  static char const * const grep_usage[] = {
        "git grep [options] [-e] <pattern> [<rev>...] [[--] path...]",
@@@ -42,8 -35,6 +35,6 @@@ static int grep_config(const char *var
                opt->color = git_config_colorbool(var, value, -1);
                return 0;
        }
-       if (!strcmp(var, "color.grep.external"))
-               return git_config_string(&(opt->color_external), var, value);
        if (!strcmp(var, "color.grep.match")) {
                if (!value)
                        return config_error_nonbool(var);
@@@ -191,6 -182,8 +182,6 @@@ static int grep_file(struct grep_opt *o
                        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);
                return 0;
        }
        close(i);
 +      data[sz] = 0;
        if (opt->relative && opt->prefix_length)
                filename = quote_path_relative(filename, -1, &buf, opt->prefix);
        i = grep_buffer(opt, filename, data, sz);
        return i;
  }
  
- #if !NO_EXTERNAL_GREP
- static int exec_grep(int argc, const char **argv)
- {
-       pid_t pid;
-       int status;
-       argv[argc] = NULL;
-       trace_argv_printf(argv, "trace: grep:");
-       pid = fork();
-       if (pid < 0)
-               return pid;
-       if (!pid) {
-               execvp("grep", (char **) argv);
-               exit(255);
-       }
-       while (waitpid(pid, &status, 0) < 0) {
-               if (errno == EINTR)
-                       continue;
-               return -1;
-       }
-       if (WIFEXITED(status)) {
-               if (!WEXITSTATUS(status))
-                       return 1;
-               return 0;
-       }
-       return -1;
- }
- #define MAXARGS 1000
- #define ARGBUF 4096
- #define push_arg(a) do { \
-       if (nr < MAXARGS) argv[nr++] = (a); \
-       else die("maximum number of args exceeded"); \
-       } while (0)
- /*
-  * If you send a singleton filename to grep, it does not give
-  * the name of the file.  GNU grep has "-H" but we would want
-  * that behaviour in a portable way.
-  *
-  * So we keep two pathnames in argv buffer unsent to grep in
-  * the main loop if we need to do more than one grep.
-  */
- static int flush_grep(struct grep_opt *opt,
-                     int argc, int arg0, const char **argv, int *kept)
- {
-       int status;
-       int count = argc - arg0;
-       const char *kept_0 = NULL;
-       if (count <= 2) {
-               /*
-                * Because we keep at least 2 paths in the call from
-                * the main loop (i.e. kept != NULL), and MAXARGS is
-                * far greater than 2, this usually is a call to
-                * conclude the grep.  However, the user could attempt
-                * to overflow the argv buffer by giving too many
-                * options to leave very small number of real
-                * arguments even for the call in the main loop.
-                */
-               if (kept)
-                       die("insanely many options to grep");
-               /*
-                * If we have two or more paths, we do not have to do
-                * anything special, but we need to push /dev/null to
-                * get "-H" behaviour of GNU grep portably but when we
-                * are not doing "-l" nor "-L" nor "-c".
-                */
-               if (count == 1 &&
-                   !opt->name_only &&
-                   !opt->unmatch_name_only &&
-                   !opt->count) {
-                       argv[argc++] = "/dev/null";
-                       argv[argc] = NULL;
-               }
-       }
-       else if (kept) {
-               /*
-                * Called because we found many paths and haven't finished
-                * iterating over the cache yet.  We keep two paths
-                * for the concluding call.  argv[argc-2] and argv[argc-1]
-                * has the last two paths, so save the first one away,
-                * replace it with NULL while sending the list to grep,
-                * and recover them after we are done.
-                */
-               *kept = 2;
-               kept_0 = argv[argc-2];
-               argv[argc-2] = NULL;
-               argc -= 2;
-       }
-       if (opt->pre_context || opt->post_context) {
-               /*
-                * grep handles hunk marks between files, but we need to
-                * do that ourselves between multiple calls.
-                */
-               if (opt->show_hunk_mark)
-                       write_or_die(1, "--\n", 3);
-               else
-                       opt->show_hunk_mark = 1;
-       }
-       status = exec_grep(argc, argv);
-       if (kept_0) {
-               /*
-                * Then recover them.  Now the last arg is beyond the
-                * terminating NULL which is at argc, and the second
-                * from the last is what we saved away in kept_0
-                */
-               argv[arg0++] = kept_0;
-               argv[arg0] = argv[argc+1];
-       }
-       return status;
- }
- static void grep_add_color(struct strbuf *sb, const char *escape_seq)
- {
-       size_t orig_len = sb->len;
-       while (*escape_seq) {
-               if (*escape_seq == 'm')
-                       strbuf_addch(sb, ';');
-               else if (*escape_seq != '\033' && *escape_seq  != '[')
-                       strbuf_addch(sb, *escape_seq);
-               escape_seq++;
-       }
-       if (sb->len > orig_len && sb->buf[sb->len - 1] == ';')
-               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;
-       const char *argv[MAXARGS+1];
-       char randarg[ARGBUF];
-       char *argptr = randarg;
-       struct grep_pat *p;
-       if (opt->extended || (opt->relative && opt->prefix_length)
-           || has_skip_worktree_entry(opt, paths))
-               return -1;
-       len = nr = 0;
-       push_arg("grep");
-       if (opt->fixed)
-               push_arg("-F");
-       if (opt->linenum)
-               push_arg("-n");
-       if (!opt->pathname)
-               push_arg("-h");
-       if (opt->regflags & REG_EXTENDED)
-               push_arg("-E");
-       if (opt->ignore_case)
-               push_arg("-i");
-       if (opt->binary == GREP_BINARY_NOMATCH)
-               push_arg("-I");
-       if (opt->word_regexp)
-               push_arg("-w");
-       if (opt->name_only)
-               push_arg("-l");
-       if (opt->unmatch_name_only)
-               push_arg("-L");
-       if (opt->null_following_name)
-               /* in GNU grep git's "-z" translates to "-Z" */
-               push_arg("-Z");
-       if (opt->count)
-               push_arg("-c");
-       if (opt->post_context || opt->pre_context) {
-               if (opt->post_context != opt->pre_context) {
-                       if (opt->pre_context) {
-                               push_arg("-B");
-                               len += snprintf(argptr, sizeof(randarg)-len,
-                                               "%u", opt->pre_context) + 1;
-                               if (sizeof(randarg) <= len)
-                                       die("maximum length of args exceeded");
-                               push_arg(argptr);
-                               argptr += len;
-                       }
-                       if (opt->post_context) {
-                               push_arg("-A");
-                               len += snprintf(argptr, sizeof(randarg)-len,
-                                               "%u", opt->post_context) + 1;
-                               if (sizeof(randarg) <= len)
-                                       die("maximum length of args exceeded");
-                               push_arg(argptr);
-                               argptr += len;
-                       }
-               }
-               else {
-                       push_arg("-C");
-                       len += snprintf(argptr, sizeof(randarg)-len,
-                                       "%u", opt->post_context) + 1;
-                       if (sizeof(randarg) <= len)
-                               die("maximum length of args exceeded");
-                       push_arg(argptr);
-                       argptr += len;
-               }
-       }
-       for (p = opt->pattern_list; p; p = p->next) {
-               push_arg("-e");
-               push_arg(p->pattern);
-       }
-       if (opt->color) {
-               struct strbuf sb = STRBUF_INIT;
-               grep_add_color(&sb, opt->color_match);
-               setenv("GREP_COLOR", sb.buf, 1);
-               strbuf_reset(&sb);
-               strbuf_addstr(&sb, "mt=");
-               grep_add_color(&sb, opt->color_match);
-               strbuf_addstr(&sb, ":sl=:cx=:fn=:ln=:bn=:se=");
-               setenv("GREP_COLORS", sb.buf, 1);
-               strbuf_release(&sb);
-               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;
-       for (i = 0; i < active_nr; i++) {
-               struct cache_entry *ce = active_cache[i];
-               char *name;
-               int kept;
-               if (!S_ISREG(ce->ce_mode))
-                       continue;
-               if (!pathspec_matches(paths, ce->name, opt->max_depth))
-                       continue;
-               name = ce->name;
-               if (name[0] == '-') {
-                       int len = ce_namelen(ce);
-                       name = xmalloc(len + 3);
-                       memcpy(name, "./", 2);
-                       memcpy(name + 2, ce->name, len + 1);
-               }
-               argv[argc++] = name;
-               if (MAXARGS <= argc) {
-                       status = flush_grep(opt, argc, nr, argv, &kept);
-                       if (0 < status)
-                               hit = 1;
-                       argc = nr + kept;
-               }
-               if (ce_stage(ce)) {
-                       do {
-                               i++;
-                       } while (i < active_nr &&
-                                !strcmp(ce->name, active_cache[i]->name));
-                       i--; /* compensate for loop control */
-               }
-       }
-       if (argc > nr) {
-               status = flush_grep(opt, argc, nr, argv, NULL);
-               if (0 < status)
-                       hit = 1;
-       }
-       return hit;
- }
- #endif
- static int grep_cache(struct grep_opt *opt, const char **paths, int cached,
-                     int external_grep_allowed)
+ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
  {
        int hit = 0;
        int nr;
        read_cache();
  
- #if !NO_EXTERNAL_GREP
-       /*
-        * Use the external "grep" command for the case where
-        * we grep through the checked-out files. It tends to
-        * be a lot more optimized
-        */
-       if (!cached && external_grep_allowed) {
-               hit = external_grep(opt, paths, cached);
-               if (hit >= 0)
-                       return hit;
-               hit = 0;
-       }
- #endif
        for (nr = 0; nr < active_nr; nr++) {
                struct cache_entry *ce = active_cache[nr];
                if (!S_ISREG(ce->ce_mode))
                 * 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);
@@@ -626,6 -321,21 +320,21 @@@ static int grep_object(struct grep_opt 
        die("unable to grep from object of type %s", typename(obj->type));
  }
  
+ static int grep_directory(struct grep_opt *opt, const char **paths)
+ {
+       struct dir_struct dir;
+       int i, hit = 0;
+       memset(&dir, 0, sizeof(dir));
+       setup_standard_excludes(&dir);
+       fill_directory(&dir, paths);
+       for (i = 0; i < dir.nr; i++)
+               hit |= grep_file(opt, dir.entries[i]->name);
+       free_grep_patterns(opt);
+       return hit;
+ }
  static int context_callback(const struct option *opt, const char *arg,
                            int unset)
  {
@@@ -713,16 -423,19 +422,19 @@@ int cmd_grep(int argc, const char **arg
  {
        int hit = 0;
        int cached = 0;
-       int external_grep_allowed = 1;
        int seen_dashdash = 0;
+       int external_grep_allowed__ignored;
        struct grep_opt opt;
        struct object_array list = { 0, 0, NULL };
        const char **paths = NULL;
        int i;
        int dummy;
+       int nongit = 0, use_index = 1;
        struct option options[] = {
                OPT_BOOLEAN(0, "cached", &cached,
                        "search in index instead of in the work tree"),
+               OPT_BOOLEAN(0, "index", &use_index,
+                       "--no-index finds in contents not managed by git"),
                OPT_GROUP(""),
                OPT_BOOLEAN('v', "invert-match", &opt.invert,
                        "show non-matching lines"),
                OPT_BOOLEAN(0, "all-match", &opt.all_match,
                        "show only matches from files that match all patterns"),
                OPT_GROUP(""),
- #if NO_EXTERNAL_GREP
-               OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed,
-                       "allow calling of grep(1) (ignored by this build)"),
- #else
-               OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed,
-                       "allow calling of grep(1) (default)"),
- #endif
+               OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored,
+                           "allow calling of grep(1) (ignored by this build)"),
                { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
                  PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
                OPT_END()
        };
  
+       prefix = setup_git_directory_gently(&nongit);
        /*
         * 'git grep -h', unlike 'git grep -h <pattern>', is a request
         * to show usage information and exit.
                             PARSE_OPT_STOP_AT_NON_OPTION |
                             PARSE_OPT_NO_INTERNAL_HELP);
  
+       if (use_index && nongit)
+               /* die the same way as if we did it at the beginning */
+               setup_git_directory();
        /* First unrecognized non-option token */
        if (argc > 0 && !opt.pattern_list) {
                append_grep_pattern(&opt, argv[0], "command line", 0,
                argc--;
        }
  
-       if ((opt.color && !opt.color_external) || opt.funcname)
-               external_grep_allowed = 0;
        if (!opt.pattern_list)
                die("no pattern given.");
        if (!opt.fixed && opt.ignore_case)
                paths[1] = NULL;
        }
  
+       if (!use_index) {
+               if (cached)
+                       die("--cached cannot be used with --no-index.");
+               if (list.nr)
+                       die("--no-index cannot be used with revs.");
+               return !grep_directory(&opt, paths);
+       }
        if (!list.nr) {
                if (!cached)
                        setup_work_tree();
-               return !grep_cache(&opt, paths, cached, external_grep_allowed);
+               return !grep_cache(&opt, paths, cached);
        }
  
        if (cached)