Merge branch 'jn/cherry-pick-strategy-option'
authorJunio C Hamano <gitster@pobox.com>
Thu, 10 Feb 2011 00:41:16 +0000 (16:41 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 10 Feb 2011 00:41:16 +0000 (16:41 -0800)
* jn/cherry-pick-strategy-option:
cherry-pick/revert: add support for -X/--strategy-option

92 files changed:
.gitignore
Documentation/CodingGuidelines
Documentation/RelNotes/1.7.3.5.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.4.txt
Documentation/config.txt
Documentation/fetch-options.txt
Documentation/git-add.txt
Documentation/git-archive.txt
Documentation/git-bundle.txt
Documentation/git-diff.txt
Documentation/git-fast-import.txt
Documentation/git-fmt-merge-msg.txt
Documentation/git-pull.txt
Documentation/git-remote-ext.txt
Documentation/git-remote-fd.txt
Documentation/git-reset.txt
Documentation/git-rev-parse.txt
Documentation/git-svn.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/githooks.txt
Documentation/gitmodules.txt
Documentation/howto/using-merge-subtree.txt
Documentation/merge-config.txt
Documentation/technical/api-sigchain.txt
GIT-VERSION-GEN
Makefile
builtin/commit.c
builtin/diff.c
builtin/init-db.c
builtin/remote-ext.c
bundle.c
cache.h
commit.c
commit.h
config.c
contrib/hooks/post-receive-email
convert.c
daemon.c
environment.c
exec_cmd.c
fast-import.c
git-am.sh
git-cvsimport.perl
git-rebase--interactive.sh
git-rebase.sh
git-submodule.sh
git.c
gitk-git/gitk [changed mode: 0644->0755]
gitweb/INSTALL
gitweb/gitweb.perl
ll-merge.c
quote.h
run-command.c
setup.c
sha1_file.c
t/README
t/lib-git-svn.sh
t/t0000-basic.sh
t/t0001-init.sh
t/t0021-conversion.sh
t/t1020-subdirectory.sh
t/t1501-worktree.sh
t/t1510-repo-setup.sh [new file with mode: 0755]
t/t3032-merge-recursive-options.sh
t/t3301-notes.sh
t/t3404-rebase-interactive.sh
t/t3509-cherry-pick-merge-df.sh
t/t4013-diff-various.sh
t/t4013/diff.diff_--cached [new file with mode: 0644]
t/t4013/diff.diff_--cached_--_file0 [new file with mode: 0644]
t/t4018-diff-funcname.sh
t/t4120-apply-popt.sh
t/t5407-post-rewrite-hook.sh
t/t5526-fetch-submodules.sh
t/t6038-merge-text-auto.sh
t/t7400-submodule-basic.sh
t/t7407-submodule-foreach.sh
t/t9001-send-email.sh
t/t9010-svn-fe.sh
t/t9157-git-svn-fetch-merge.sh
t/t9300-fast-import.sh
t/t9301-fast-import-notes.sh
t/t9600-cvsimport.sh
t/test-lib.sh
tag.c
tag.h
test-subprocess.c [new file with mode: 0644]
trace.c
userdiff.c
vcs-svn/svndump.c
xdiff-interface.c
index 87b833c9d8940a61ff77ec6bd35241b3f85decb5..3dd6ef7d259d8fe2811f68525b5309e97c79f4cc 100644 (file)
 /test-sha1
 /test-sigchain
 /test-string-pool
+/test-subprocess
 /test-svn-fe
 /test-treap
 /common-cmds.h
index 1b1c45df5ce3ef30e588555bbd5ab404c2b7397c..ba2006d892ec09d606f8846588c7727396b1ee28 100644 (file)
@@ -157,7 +157,7 @@ Writing Documentation:
    --sort=<key>
    --abbrev[=<n>]
 
- Possibility of multiple occurences is indicated by three dots:
+ Possibility of multiple occurrences is indicated by three dots:
    <file>...
    (One or more of <file>.)
 
diff --git a/Documentation/RelNotes/1.7.3.5.txt b/Documentation/RelNotes/1.7.3.5.txt
new file mode 100644 (file)
index 0000000..40f3ba5
--- /dev/null
@@ -0,0 +1,34 @@
+Git 1.7.3.5 Release Notes
+=========================
+
+ * The xfuncname pattern used by "git diff" and "git grep" to show the
+   last notable line in context were broken for python and ruby for a long
+   time.
+
+ * "git merge" into an unborn branch removed an untracked file "foo" from
+   the working tree when merged branch had "foo" (this fix was already in
+   1.7.3.3 but was omitted from the release notes by mistake).
+
+ * "git status -s" did not quote unprintable characters in paths as
+   documented.
+
+ * "git am --abort" used to always reset to the commit at the beginning of
+   the last "am" invocation that has stopped, losing any unrelated commits
+   that may have been made since then.  Now it refrains from doing so and
+   instead issues a warning.
+
+ * "git blame" incorrectly reused bogusly cached result of textconv
+   filter for files from the working tree.
+
+ * "git commit" used to abort after the user edited the log message
+   when the committer information was not correctly set up.  It now
+   aborts before starting the editor.
+
+ * "git commit --date=invalid" used to silently ignore the incorrectly
+   specified date; it is now diagnosed as an error.
+
+ * "git rebase --skip" to skip the last commit in a series used to fail
+   to run post-rewrite hook and to copy notes from old commits that have
+   successfully been rebased so far.  Now it do (backmerge ef88ad2).
+
+ * "gitweb" tried to show a wrong feed logo when none was specified.
index ace061f5fe4d60341fcf7be6bca08cc1fcb27929..d5bca731b589dde2b8a1edad2977e9376e0ec433 100644 (file)
@@ -1,5 +1,5 @@
-Git v1.7.4 Release Notes (draft)
-================================
+Git v1.7.4 Release Notes
+========================
 
 Updates since v1.7.3
 --------------------
@@ -8,15 +8,14 @@ Updates since v1.7.3
    docbook-xsl >= 1.73. If you have older versions, you can set
    ASCIIDOC7 and ASCIIDOC_ROFF, respectively.
 
- * The option parsers of various commands that create new branch (or
+ * The option parsers of various commands that create new branches (or
    rename existing ones to a new name) were too loose and users were
-   allowed to call a branch with a name that begins with a dash by
-   creative abuse of their command line options, which only lead to
-   burn themselves.  The name of a branch cannot begin with a dash
-   now.
+   allowed to give a branch a name that begins with a dash by creative
+   abuse of their command line options, which only led to burning
+   themselves.  The name of a branch cannot begin with a dash now.
 
  * System-wide fallback default attributes can be stored in
-   /etc/gitattributes; core.attributesfile configuration variable can
+   /etc/gitattributes; the core.attributesfile configuration variable can
    be used to customize the path to this file.
 
  * The thread structure generated by "git send-email" has changed
@@ -26,33 +25,39 @@ Updates since v1.7.3
    cover letter of the previous series; this has been changed to make
    the patches in the new series replies to the new cover letter.
 
- * Bash completion script in contrib/ has been adjusted to be also
-   usable by zsh.
+ * The Bash completion script in contrib/ has been adjusted to be usable with
+   Bash 4 (options with '=value' didn't complete).  It has been also made
+   usable with zsh.
 
  * Different pagers can be chosen depending on which subcommand is
-   being run under the pager, using "pager.<subcommand>" variable.
+   being run under the pager, using the "pager.<subcommand>" variable.
 
- * The hardcoded tab-width of 8 used in whitespace breakage checks is now
+ * The hardcoded tab-width of 8 that is used in whitespace breakage checks is now
    configurable via the attributes mechanism.
 
  * Support of case insensitive filesystems (i.e. "core.ignorecase") has
    been improved.  For example, the gitignore mechanism didn't pay attention
-   to the case insensitivity.
+   to case insensitivity.
 
- * The <tree>:<path> syntax to name a blob in a tree, and :<path>
-   syntax to name a blob in the index (e.g. "master:Makefile",
+ * The <tree>:<path> syntax for naming a blob in a tree, and the :<path>
+   syntax for naming a blob in the index (e.g. "master:Makefile",
    ":hello.c") have been extended.  You can start <path> with "./" to
    implicitly have the (sub)directory you are in prefixed to the
    lookup.  Similarly, ":../Makefile" from a subdirectory would mean
    "the Makefile of the parent directory in the index".
 
- * "git blame" learned --show-email option to display the e-mail
+ * "git blame" learned the --show-email option to display the e-mail
    addresses instead of the names of authors.
 
- * "git commit" learned --fixup and --squash options to help later invocation
-   of the interactive rebase.
+ * "git commit" learned the --fixup and --squash options to help later invocation
+   of interactive rebase.
 
- * "git daemon" can be built in MinGW environment.
+ * Command line options to "git cvsimport" whose names are in capital
+   letters (-A, -M, -R and -S) can now be specified as the default in
+   the .git/config file by their longer names (cvsimport.authorsFile,
+   cvsimport.mergeRegex, cvsimport.trackRevisions, cvsimport.ignorePaths).
+
+ * "git daemon" can be built in the MinGW environment.
 
  * "git daemon" can take more than one --listen option to listen to
    multiple addresses.
@@ -60,13 +65,13 @@ Updates since v1.7.3
  * "git describe --exact-match" was optimized not to read commit
    objects unnecessarily.
 
- * "git diff" and "git grep" learned how functions and subroutines
-   in Fortran look like.
+ * "git diff" and "git grep" learned what functions and subroutines
+   in Fortran, Pascal and Perl look like.
 
- * "git fetch" learned "--recurse-submodules" option.
+ * "git fetch" learned the "--recurse-submodules" option.
 
- * "git mergetool" tells vim/gvim to show three-way diff by default
-   (use vimdiff2/gvimdiff2 as the tool name for old behaviour).
+ * "git mergetool" tells vim/gvim to show three-way diff by default
+   (use vimdiff2/gvimdiff2 as the tool name for old behavior).
 
  * "git log -G<pattern>" limits the output to commits whose change has
    added or deleted lines that match the given pattern.
@@ -76,8 +81,8 @@ Updates since v1.7.3
    use the new --empty option to be more explicit instead.
 
  * "git repack -f" does not spend cycles to recompress objects in the
-   non-delta representation anymore (use -F if you really mean it when
-   e.g. you changed the compression level).
+   non-delta representation anymore (use -F if you really mean it
+   e.g. after you changed the core.compression variable setting).
 
  * "git merge --log" used to limit the resulting merge log to 20
    entries; this is now customizable by giving e.g. "--log=47".
@@ -86,33 +91,42 @@ Updates since v1.7.3
    directory in one branch while a new file is created in place of that
    directory in the other branch.
 
- * "git rebase --autosquash" can use SHA-1 object names to name which
-   commit to fix up (e.g. "fixup! e83c5163").
+ * "git merge" learned the "--abort" option, synonymous to
+   "git reset --merge" when a merge is in progress.
+
+ * "git notes" learned the "merge" subcommand to merge notes refs.
+   In addition to the default manual conflict resolution, there are
+   also several notes merge strategies for automatically resolving
+   notes merge conflicts.
+
+ * "git rebase --autosquash" can use SHA-1 object names to name the
+   commit which is to be fixed up (e.g. "fixup! e83c5163").
 
- * The default "recursive" merge strategy learned --rename-threshold
+ * The default "recursive" merge strategy learned the --rename-threshold
    option to influence the rename detection, similar to the -M option
-   of "git diff".  E.g. "git merge -Xrename-threshold=50% ..." to use
-   this.
+   of "git diff".  From the "git merge" frontend, the "-X<strategy option>"
+   interface, e.g. "git merge -Xrename-threshold=50% ...", can be used
+   to trigger this.
 
  * The "recursive" strategy also learned to ignore various whitespace
    changes; the most notable is -Xignore-space-at-eol.
 
  * "git send-email" learned "--to-cmd", similar to "--cc-cmd", to read
-   recipient list from a command output.
+   the recipient list from a command output.
 
  * "git send-email" learned to read and use "To:" from its input files.
 
  * you can extend "git shell", which is often used on boxes that allow
-   git-only login over ssh as login shell, with custom set of
+   git-only login over ssh as login shell, with custom set of
    commands.
 
  * The current branch name in "git status" output can be colored differently
-   from the generic header color by setting "color.status.branch" variable.
+   from the generic header color by setting the "color.status.branch" variable.
 
  * "git submodule sync" updates metainformation for all submodules,
    not just the ones that have been checked out.
 
- * gitweb can use custom 'highlight' command with its configuration file.
+ * gitweb can use custom 'highlight' command with its configuration file.
 
  * other gitweb updates.
 
@@ -123,26 +137,20 @@ Also contains various documentation updates.
 Fixes since v1.7.3
 ------------------
 
-All of the fixes in v1.7.3.X maintenance series are included in this
+All of the fixes in the v1.7.3.X maintenance series are included in this
 release, unless otherwise noted.
 
  * "git log --author=me --author=her" did not find commits written by
    me or by her; instead it looked for commits written by me and by
    her, which is impossible.
 
- * "git merge" into an unborn branch removed an untracked file "foo"
-   from the working tree when merged branch had "foo" (2caf20c..172b642).
-
  * "git push --progress" shows progress indicators now.
 
+ * "git rebase -i" showed a confusing error message when given a
+   branch name that does not exist.
+
  * "git repack" places its temporary packs under $GIT_OBJECT_DIRECTORY/pack
    instead of $GIT_OBJECT_DIRECTORY/ to avoid cross directory renames.
 
  * "git submodule update --recursive --other-flags" passes flags down
    to its subinvocations.
-
----
-exec >/var/tmp/1
-O=v1.7.3.4-567-g38a5932
-echo O=$(git describe master)
-git shortlog --no-merges ^maint ^$O master
index 54597f18979fb376e2f1d9ea29f5ac247e9df230..c5e183516a104e6efb7ed597fb4498d75560ab68 100644 (file)
@@ -317,24 +317,26 @@ false), while all other repositories are assumed to be bare (bare
 = true).
 
 core.worktree::
-       Set the path to the root of the work tree.
+       Set the path to the root of the working tree.
        This can be overridden by the GIT_WORK_TREE environment
-       variable and the '--work-tree' command line option. It can be
-       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
+       variable and the '--work-tree' command line option.
+       The value can an absolute path or relative to the path to
+       the .git directory, which is either specified by --git-dir
+       or GIT_DIR, or automatically discovered.
+       If --git-dir or GIT_DIR is specified but none of
        --work-tree, GIT_WORK_TREE and core.worktree is specified,
-       the current working directory is regarded as the root of the
-       work tree.
+       the current working directory is regarded as the top level
+       of your working 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
+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
+misconfiguration.  Running git commands in the "/path/to" directory will
 still use "/different/path" as the root of the work tree and can cause
-great confusion to the users.
+confusion unless you know what you are doing (e.g. you are creating a
+read-only snapshot of the same index to a location different from the
+repository's usual working tree).
 
 core.logAllRefUpdates::
        Enable the reflog. Updates to a ref <ref> is logged to the file
@@ -899,7 +901,7 @@ diff.wordRegex::
 
 fetch.recurseSubmodules::
        A boolean value which changes the behavior for fetch and pull, the
-       default is to not recursively fetch populated sumodules unless
+       default is to not recursively fetch populated submodules unless
        configured otherwise.
 
 fetch.unpackLimit::
@@ -1818,7 +1820,7 @@ submodule.<name>.update::
 
 submodule.<name>.fetchRecurseSubmodules::
        This option can be used to enable/disable recursive fetching of this
-       submodule. It can be overriden by using the --[no-]recurse-submodules
+       submodule. It can be overridden by using the --[no-]recurse-submodules
        command line option to "git fetch" and "git pull".
        This setting will override that from in the linkgit:gitmodules[5]
        file.
index 695696da1b6e78639014388e1d4ac8bf09a0e12d..f37276e5add75583fd363af2cd0b7ba051771a97 100644 (file)
@@ -64,13 +64,11 @@ ifndef::git-pull[]
        downloaded. The default behavior for a remote may be
        specified with the remote.<name>.tagopt setting. See
        linkgit:git-config[1].
-endif::git-pull[]
 
 --[no-]recurse-submodules::
        This option controls if new commits of all populated submodules should
        be fetched too (see linkgit:git-config[1] and linkgit:gitmodules[5]).
 
-ifndef::git-pull[]
 --submodule-prefix=<path>::
        Prepend <path> to paths printed in informative messages
        such as "Fetching submodule foo".  This option is used
index 54aaaeb41b969be4c79a2a8072bc6daca469ca8d..a03448f9231f78340fc492bffa009b96648ee6ac 100644 (file)
@@ -333,7 +333,7 @@ likely to introduce confusing changes to the index.
 There are also more complex operations that can be performed. But beware
 that because the patch is applied only to the index and not the working
 tree, the working tree will appear to "undo" the change in the index.
-For example, introducing a new line into the index that is in neither
+For example, introducing a new line into the index that is in neither
 the HEAD nor the working tree will stage the new line for commit, but
 the line will appear to be reverted in the working tree.
 
index 4163a1bcb1643e7f05b6a79034ac9f63135d6ac9..bf5037ab2a5042a20e9cb603f0831bb186ac3b74 100644 (file)
@@ -116,7 +116,7 @@ Note that attributes are by default taken from the `.gitattributes` files
 in the tree that is being archived.  If you want to tweak the way the
 output is generated after the fact (e.g. you committed without adding an
 appropriate export-ignore in its `.gitattributes`), adjust the checked out
-`.gitattributes` file as necessary and use `--work-tree-attributes`
+`.gitattributes` file as necessary and use `--worktree-attributes`
 option.  Alternatively you can keep necessary attributes that should apply
 while archiving any tree in your `$GIT_DIR/info/attributes` file.
 
index 6266a3a6020db72c8629ad521dfedccc9d790a03..299007b206cb5d810d19eed9b7831c3ea6368043 100644 (file)
@@ -59,7 +59,7 @@ unbundle <file>::
 
 <git-rev-list-args>::
        A list of arguments, acceptable to 'git rev-parse' and
-       'git rev-list' (and containg a named ref, see SPECIFYING REFERENCES
+       'git rev-list' (and containing a named ref, see SPECIFYING REFERENCES
        below), that specifies the specific objects and references
        to transport.  For example, `master{tilde}10..master` causes the
        current master reference to be packaged along with all objects
index f6ac847507a635759323565be44b088b479d8bf0..49105102dbf899c62833572fdda51cefaed53476 100644 (file)
@@ -38,6 +38,8 @@ directories. This behavior can be forced by --no-index.
        commit relative to the named <commit>.  Typically you
        would want comparison with the latest commit, so if you
        do not give <commit>, it defaults to HEAD.
+       If HEAD does not exist (e.g. unborned branches) and
+       <commit> is not given, it shows all staged changes.
        --staged is a synonym of --cached.
 
 'git diff' [--options] <commit> [--] [<path>...]::
index f56dfcabb96d1510abfd61a13c36135f3824b744..02bb49886cc5f8415cec8786282681b4114a6380 100644 (file)
@@ -534,9 +534,6 @@ start with double quote (`"`).
 If an `LF` or double quote must be encoded into `<path>` shell-style
 quoting should be used, e.g. `"path/with\n and \" in it"`.
 
-Additionally, in `040000` mode, `<path>` may also be an empty string
-(`""`) to specify the root of the tree.
-
 The value of `<path>` must be in canonical form. That is it must not:
 
 * contain an empty directory component (e.g. `foo//bar` is invalid),
@@ -545,6 +542,8 @@ The value of `<path>` must be in canonical form. That is it must not:
 * contain the special component `.` or `..` (e.g. `foo/./bar` and
   `foo/../bar` are invalid).
 
+The root of the tree can be represented by an empty string as `<path>`.
+
 It is recommended that `<path>` always be encoded using UTF-8.
 
 `filedelete`
@@ -905,7 +904,7 @@ The `<dataref>` can be either a mark reference (`:<idnum>`)
 set previously or a full 40-byte SHA-1 of a Git blob, preexisting or
 ready to be written.
 
-output uses the same format as `git cat-file --batch`:
+Output uses the same format as `git cat-file --batch`:
 
 ====
        <sha1> SP 'blob' SP <size> LF
@@ -949,6 +948,13 @@ cat-blob::
        rather than wasting time on the early part of an import
        before the unsupported command is detected.
 
+notes::
+       Require that the backend support the 'notemodify' (N)
+       subcommand to the 'commit' command.
+       Versions of fast-import not supporting notes will exit
+       with a message indicating so.
+
+
 `option`
 ~~~~~~~~
 Processes the specified option so that git fast-import behaves in a
index 40dba8c0a9f308064f67d8f38ce8a22b2a42a77c..75adf7a502e18aa11e7a8424acf217b4bf6be64c 100644 (file)
@@ -57,7 +57,7 @@ merge.log::
        In addition to branch names, populate the log message with at
        most the specified number of one-line descriptions from the
        actual commits that are being merged.  Defaults to false, and
-       true is a synoym for 20.
+       true is a synonym for 20.
 
 merge.summary::
        Synonym to `merge.log`; this is deprecated and will be removed in
index 30466917dad52eefd76de95aead3fdc12ad8425d..b33e6be872508778faa59f478229cd6e16bddad7 100644 (file)
@@ -84,6 +84,15 @@ must be given before the options meant for 'git fetch'.
 --verbose::
        Pass --verbose to git-fetch and git-merge.
 
+--[no-]recurse-submodules::
+       This option controls if new commits of all populated submodules should
+       be fetched too (see linkgit:git-config[1] and linkgit:gitmodules[5]).
+       That might be necessary to get the data needed for merging submodule
+       commits, a feature git learned in 1.7.3. Notice that the result of a
+       merge will not be checked out in the submodule, "git submodule update"
+       has to be called afterwards to bring the work tree up to date with the
+       merge result.
+
 Options related to merging
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
index f4fbf672094ed11acb5ca551b5cc411a86f3f1ba..2d65cfefd5d2aeaafcbc0bb6e6705f8379b2f826 100644 (file)
@@ -15,12 +15,12 @@ This remote helper uses the specified 'program' to connect
 to a remote git server.
 
 Data written to stdin of this specified 'program' is assumed
-to be sent to git:// server, git-upload-pack, git-receive-pack
+to be sent to git:// server, git-upload-pack, git-receive-pack
 or git-upload-archive (depending on situation), and data read
 from stdout of this program is assumed to be received from
 the same service.
 
-Command and arguments are separated by unescaped space.
+Command and arguments are separated by an unescaped space.
 
 The following sequences have a special meaning:
 
@@ -39,19 +39,19 @@ The following sequences have a special meaning:
        git-upload-pack, or git-upload-archive) of the service
        git wants to invoke.
 
-'%G' (must be first characters in argument)::
+'%G' (must be the first characters in an argument)::
        This argument will not be passed to 'program'. Instead, it
-       will cause helper to start by sending git:// service request to
-       remote side with service field set to approiate value and
-       repository field set to rest of the argument. Default is not to send
-       such request.
+       will cause the helper to start by sending git:// service requests to
+       the remote side with the service field set to an appropriate value and
+       the repository field set to rest of the argument. Default is not to send
+       such request.
 +
 This is useful if remote side is git:// server accessed over
 some tunnel.
 
 '%V' (must be first characters in argument)::
        This argument will not be passed to 'program'. Instead it sets
-       the vhost field in git:// service request (to rest of the argument).
+       the vhost field in the git:// service request (to rest of the argument).
        Default is not to send vhost in such request (if sent).
 
 ENVIRONMENT VARIABLES:
index abc49441be7a86e25a2b09d98f7de2ddcf0b0bb2..4aecd4d1878e0af6c3e6c87a63df1375606ff65a 100644 (file)
@@ -11,20 +11,20 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This helper uses specified file descriptors to connect to remote git server.
+This helper uses specified file descriptors to connect to remote git server.
 This is not meant for end users but for programs and scripts calling git
 fetch, push or archive.
 
-If only <infd> is given, it is assumed to be bidirectional socket connected
+If only <infd> is given, it is assumed to be bidirectional socket connected
 to remote git server (git-upload-pack, git-receive-pack or
 git-upload-achive). If both <infd> and <outfd> are given, they are assumed
-to be pipes connected to remote git server (<infd> being the inbound pipe
+to be pipes connected to remote git server (<infd> being the inbound pipe
 and <outfd> being the outbound pipe.
 
 It is assumed that any handshaking procedures have already been completed
 (such as sending service request for git://) before this helper is started.
 
-<anything> can be any string. It is ignored. It is meant for provoding
+<anything> can be any string. It is ignored. It is meant for providing
 information to user in the URL in case that URL is displayed in some
 context.
 
index fd72976371cee0fcd25e3419138eb13382dc6ab8..927ecee2f26cdf0bd30457d5016b654c01a23a14 100644 (file)
@@ -76,15 +76,10 @@ In other words, --merge does something like a 'git read-tree -u -m <commit>',
 but carries forward unmerged index entries.
 
 --keep::
-       Resets the index, updates files in the working tree that are
-       different between <commit> and HEAD, but keeps those
-       which are different between HEAD and the working tree (i.e.
-       which have local changes).
+       Resets index entries and updates files in the working tree that are
+       different between <commit> and HEAD.
        If a file that is different between <commit> and HEAD has local changes,
        reset is aborted.
-+
-In other words, --keep does a 2-way merge between <commit> and HEAD followed by
-'git reset --mixed <commit>'.
 --
 
 If you want to undo a commit other than the latest on a branch,
index 4a27643c1ea0e908a0a54b84f668d5a80f6d7100..ff23cb0219d602803a83da273195fcc4ca71b5f5 100644 (file)
@@ -136,7 +136,12 @@ appending `/{asterisk}`.
        directory (typically a sequence of "../", or an empty string).
 
 --git-dir::
-       Show `$GIT_DIR` if defined else show the path to the .git directory.
+       Show `$GIT_DIR` if defined. Otherwise show the path to
+       the .git directory, relative to the current directory.
++
+If `$GIT_DIR` is not defined and the current directory
+is not detected to lie in a git repository or work tree
+print a message to stderr and exit with nonzero status.
 
 --is-inside-git-dir::
        When the current working directory is below the repository
index 139d314ba54c4e7897ffcf257a1fd847eb7939fa..0ade2ce54efee3cd2241fc7e3009909eef5cf8bb 100644 (file)
@@ -613,7 +613,7 @@ old references to SVN revision numbers in existing documentation, bug
 reports and archives.  If you plan to eventually migrate from SVN to git
 and are certain about dropping SVN history, consider
 linkgit:git-filter-branch[1] instead.  filter-branch also allows
-reformating of metadata for ease-of-reading and rewriting authorship
+reformatting of metadata for ease-of-reading and rewriting authorship
 info for non-"svn.authorsFile" users.
 
 svn.useSvmProps::
@@ -729,8 +729,11 @@ have each person clone that repository with 'git clone':
        cd project
        git init
        git remote add origin server:/pub/project
-       git config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
+       git config --replace-all remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
        git fetch
+# Prevent fetch/pull from remote git server in the future,
+# we only want to use git svn for future updates
+       git config --remove-section remote.origin
 # Create a local branch from one of the branches just fetched
        git checkout -b master FETCH_HEAD
 # Initialize 'git svn' locally (be sure to use the same URL and -T/-b/-t options as were used on server)
index 012837145e86b144d4676c9e1517486226e137df..e968ed4aa09705d98530add23135e76141ec75c2 100644 (file)
@@ -44,9 +44,15 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.7.3.4/git.html[documentation for release 1.7.3.4]
+* link:v1.7.4/git.html[documentation for release 1.7.4]
 
 * release notes for
+  link:RelNotes/1.7.4.txt[1.7.4].
+
+* link:v1.7.3.5/git.html[documentation for release 1.7.3.5]
+
+* release notes for
+  link:RelNotes/1.7.3.5.txt[1.7.3.5],
   link:RelNotes/1.7.3.4.txt[1.7.3.4],
   link:RelNotes/1.7.3.3.txt[1.7.3.3],
   link:RelNotes/1.7.3.2.txt[1.7.3.2],
@@ -290,17 +296,12 @@ help ...`.
        path or relative path to current working directory.
 
 --work-tree=<path>::
-       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 working tree. It can be an absolute path
+       or a path relative to the current working directory.
        This can also be controlled by setting the GIT_WORK_TREE
        environment variable and the core.worktree configuration
-       variable. It can be an 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
-       --work-tree, GIT_WORK_TREE and core.worktree is specified,
-       the current working directory is regarded as the top directory
-       of your working tree.
+       variable (see core.worktree in linkgit:git-config[1] for a
+       more detailed discussion).
 
 --bare::
        Treat the repository as a bare repository.  If GIT_DIR
index 5a7f9364299cb4ed34a7dc35688c9bddcd35ff3d..7e7e12168eb69d43f6d7eea9cde2176e06fe73d5 100644 (file)
@@ -335,6 +335,16 @@ input that is already correctly indented.  In this case, the lack of a
 smudge filter means that the clean filter _must_ accept its own output
 without modifying it.
 
+Sequence "%f" on the filter command line is replaced with the name of
+the file the filter is working on.  A filter might use this in keyword
+substitution.  For example:
+
+------------------------
+[filter "p4"]
+       clean = git-p4-filter --clean %f
+       smudge = git-p4-filter --smudge %f
+------------------------
+
 
 Interaction between checkin/checkout attributes
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -494,6 +504,8 @@ patterns are available:
 
 - `pascal` suitable for source code in the Pascal/Delphi language.
 
+- `perl` suitable for source code in the Perl language.
+
 - `php` suitable for source code in the PHP language.
 
 - `python` suitable for source code in the Python language.
@@ -581,6 +593,39 @@ and now produces better output), you can remove the cache
 manually with `git update-ref -d refs/notes/textconv/jpg` (where
 "jpg" is the name of the diff driver, as in the example above).
 
+Marking files as binary
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Git usually guesses correctly whether a blob contains text or binary
+data by examining the beginning of the contents. However, sometimes you
+may want to override its decision, either because a blob contains binary
+data later in the file, or because the content, while technically
+composed of text characters, is opaque to a human reader. For example,
+many postscript files contain only ascii characters, but produce noisy
+and meaningless diffs.
+
+The simplest way to mark a file as binary is to unset the diff
+attribute in the `.gitattributes` file:
+
+------------------------
+*.ps -diff
+------------------------
+
+This will cause git to generate `Binary files differ` (or a binary
+patch, if binary patches are enabled) instead of a regular diff.
+
+However, one may also want to specify other diff driver attributes. For
+example, you might want to use `textconv` to convert postscript files to
+an ascii representation for human viewing, but otherwise treat them as
+binary files. You cannot specify both `-diff` and `diff=ps` attributes.
+The solution is to use the `diff.*.binary` config option:
+
+------------------------
+[diff "ps"]
+  textconv = ps2ascii
+  binary = true
+------------------------
+
 Performing a three-way merge
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
index 7183aa9abbc35018dc50a7c0e5254cc72115af23..28edefa202fb0d1065f161f59787ceae39439eb3 100644 (file)
@@ -350,10 +350,6 @@ rebase::
 The commits are guaranteed to be listed in the order that they were
 processed by rebase.
 
-There is no default 'post-rewrite' hook, but see the
-`post-receive-copy-notes` script in `contrib/hooks` for an example
-that copies your git-notes to the rewritten commits.
-
 
 GIT
 ---
index 6c93202e735e7b7caad89120245050e0a06e5537..68977943e7bba092f5e55e6ad1b9ede83f4c2b67 100644 (file)
@@ -49,7 +49,7 @@ submodule.<name>.fetchRecurseSubmodules::
        submodule. If this option is also present in the submodules entry in
        .git/config of the superproject, the setting there will override the
        one found in .gitmodules.
-       Both settings can be overriden on the command line by using the
+       Both settings can be overridden on the command line by using the
        "--[no-]recurse-submodules" option to "git fetch" and "git pull"..
 
 submodule.<name>.ignore::
index 0953a50b693307976977c81a4c0b611fd5dfb490..2933056120bf0a0d6249c6951ab1e964ae40674b 100644 (file)
@@ -71,5 +71,5 @@ Additional tips
   relevant parts of your tree.
 
 - Please note that if the other project merges from you, then it will
-  connects its history to yours, which can be something they don't want
+  connect its history to yours, which can be something they don't want
   to.
index 92772e7c4eb8921d3b2763fe1b533c380bd2b92b..1e5c22c5e5c19dab5d5c35ec2401870237830a5d 100644 (file)
@@ -10,7 +10,7 @@ merge.log::
        In addition to branch names, populate the log message with at
        most the specified number of one-line descriptions from the
        actual commits that are being merged.  Defaults to false, and
-       true is a synoym for 20.
+       true is a synonym for 20.
 
 merge.renameLimit::
        The number of files to consider when performing rename detection
index 535cdff164f1f1cdf829f18fa192783efb9f0086..9e1189ef01dff889447c1bf92802c9792f267b9b 100644 (file)
@@ -32,7 +32,7 @@ and installation code should look something like:
   }
 ------------------------------------------
 
-Handlers are given the typdef of sigchain_fun. This is the same type
+Handlers are given the typedef of sigchain_fun. This is the same type
 that is given to signal() or sigaction(). It is perfectly reasonable to
 push SIG_DFL or SIG_IGN onto the stack.
 
index d441d88d6fbd6d98bb617e5cf5d2bd7704f86a45..92fe7a59dbf81b0a055280f9351811641ce7044a 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.3.GIT
+DEF_VER=v1.7.4
 
 LF='
 '
index ff351543754f231a92c8cf3aa3b12d6693ba119a..775ee838c332c7311df34a98448fc3723c6bd95e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -431,6 +431,7 @@ TEST_PROGRAMS_NEED_X += test-run-command
 TEST_PROGRAMS_NEED_X += test-sha1
 TEST_PROGRAMS_NEED_X += test-sigchain
 TEST_PROGRAMS_NEED_X += test-string-pool
+TEST_PROGRAMS_NEED_X += test-subprocess
 TEST_PROGRAMS_NEED_X += test-svn-fe
 TEST_PROGRAMS_NEED_X += test-treap
 TEST_PROGRAMS_NEED_X += test-index-version
index 22ba54f9bb2ea9f9f9f01528e8a155723da7a4da..03cff5af631fec975442c528b1ffba264b879c8e 100644 (file)
@@ -45,9 +45,9 @@ static const char implicit_ident_advice[] =
 "    git config --global user.name \"Your Name\"\n"
 "    git config --global user.email you@example.com\n"
 "\n"
-"If the identity used for this commit is wrong, you can fix it with:\n"
+"After doing this, you may fix the identity used for this commit with:\n"
 "\n"
-"    git commit --amend --author='Your Name <you@example.com>'\n";
+"    git commit --amend --reset-author\n";
 
 static const char empty_amend_advice[] =
 "You asked to amend the most recent commit, but doing so would make\n"
index 945e7583a8294f0612682f3228687498e5c61822..42822cd5374dbcf0e63c17078a55284c432ddc77 100644 (file)
@@ -330,8 +330,11 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                        else if (!strcmp(arg, "--cached") ||
                                 !strcmp(arg, "--staged")) {
                                add_head_to_pending(&rev);
-                               if (!rev.pending.nr)
-                                       die("No HEAD commit to compare with (yet)");
+                               if (!rev.pending.nr) {
+                                       struct tree *tree;
+                                       tree = lookup_tree((const unsigned char*)EMPTY_TREE_SHA1_BIN);
+                                       add_pending_object(&rev, &tree->object, "HEAD");
+                               }
                                break;
                        }
                }
index 9d4886c71675f2bc50671ea284875ebae9a34735..e3af9eaa877089639d6ba4f47d7155a0c1ee106e 100644 (file)
@@ -414,6 +414,7 @@ static const char *const init_db_usage[] = {
 int cmd_init_db(int argc, const char **argv, const char *prefix)
 {
        const char *git_dir;
+       const char *work_tree;
        const char *template_dir = NULL;
        unsigned int flags = 0;
        const struct option init_db_options[] = {
@@ -480,8 +481,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
         * without --bare.  Catch the error early.
         */
        git_dir = getenv(GIT_DIR_ENVIRONMENT);
-       if ((!git_dir || is_bare_repository_cfg == 1)
-           && getenv(GIT_WORK_TREE_ENVIRONMENT))
+       work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
+       if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
                die("%s (or --work-tree=<directory>) not allowed without "
                    "specifying %s (or --git-dir=<directory>)",
                    GIT_WORK_TREE_ENVIRONMENT,
@@ -510,10 +511,18 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                        if (!getcwd(git_work_tree_cfg, PATH_MAX))
                                die_errno ("Cannot access current working directory");
                }
+               if (work_tree)
+                       set_git_work_tree(make_absolute_path(work_tree));
+               else
+                       set_git_work_tree(git_work_tree_cfg);
                if (access(get_git_work_tree(), X_OK))
                        die_errno ("Cannot access work tree '%s'",
                                   get_git_work_tree());
        }
+       else {
+               if (work_tree)
+                       set_git_work_tree(make_absolute_path(work_tree));
+       }
 
        set_git_dir(make_absolute_path(git_dir));
 
index 1f773171cbdde76cc105e37928cc5f2ecb2ed93f..ea71977c8360e1a7899bbd035cf26f93d889800b 100644 (file)
@@ -212,16 +212,16 @@ static int command_loop(const char *child)
        char buffer[MAXCOMMAND];
 
        while (1) {
-               size_t length;
+               size_t i;
                if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
                        if (ferror(stdin))
                                die("Comammand input error");
                        exit(0);
                }
                /* Strip end of line characters. */
-               length = strlen(buffer);
-               while (isspace((unsigned char)buffer[length - 1]))
-                       buffer[--length] = 0;
+               i = strlen(buffer);
+               while (i > 0 && isspace(buffer[i - 1]))
+                       buffer[--i] = 0;
 
                if (!strcmp(buffer, "capabilities")) {
                        printf("*connect\n\n");
index 65ea26bdb8c2cef671030c3a62d87d84612e8144..f48fd7d4c1c706b68e879e4dfabdd3fb8597a328 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -200,7 +200,7 @@ int create_bundle(struct bundle_header *header, const char *path,
        int bundle_fd = -1;
        int bundle_to_stdout;
        const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *));
-       const char **argv_pack = xmalloc(5 * sizeof(const char *));
+       const char **argv_pack = xmalloc(6 * sizeof(const char *));
        int i, ref_count = 0;
        char buffer[1024];
        struct rev_info revs;
@@ -346,7 +346,8 @@ int create_bundle(struct bundle_header *header, const char *path,
        argv_pack[1] = "--all-progress-implied";
        argv_pack[2] = "--stdout";
        argv_pack[3] = "--thin";
-       argv_pack[4] = NULL;
+       argv_pack[4] = "--delta-base-offset";
+       argv_pack[5] = NULL;
        memset(&rls, 0, sizeof(rls));
        rls.argv = argv_pack;
        rls.in = -1;
diff --git a/cache.h b/cache.h
index 32170c293d8f2e303b246cd5892f4d0b5d848861..d83d68c859904fadbe2501cabd8575be09131d7b 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -987,6 +987,7 @@ extern int git_config_parse_parameter(const char *text);
 extern int git_config_parse_environment(void);
 extern int git_config_from_parameters(config_fn_t fn, void *data);
 extern int git_config(config_fn_t fn, void *);
+extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
 extern int git_parse_ulong(const char *, unsigned long *);
 extern int git_config_int(const char *, const char *);
 extern unsigned long git_config_ulong(const char *, const char *);
@@ -1066,6 +1067,7 @@ __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, ...);
+extern void trace_repo_setup(const char *prefix);
 
 /* convert.c */
 /* returns 1 if *dst was used */
index 74d66018800d7a2a2b3a3365e87a23049690da6b..ac337c7d7dc1724fa918f9340816d3102edb10bd 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -245,10 +245,10 @@ int unregister_shallow(const unsigned char *sha1)
        return 0;
 }
 
-int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
+int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size)
 {
-       char *tail = buffer;
-       char *bufptr = buffer;
+       const char *tail = buffer;
+       const char *bufptr = buffer;
        unsigned char parent[20];
        struct commit_list **pptr;
        struct commit_graft *graft;
index eb6c5af1f6b18546b3b3f1683142b15bb0ae9e34..659c87c3ee90c23064f617e3bcf3ace12e32ea04 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -38,7 +38,7 @@ struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
                                              int quiet);
 struct commit *lookup_commit_reference_by_name(const char *name);
 
-int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size);
+int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size);
 int parse_commit(struct commit *item);
 
 /* Find beginning and length of commit subject. */
index d73b090b6a60d05b18309755dee4ce3b6e055b2d..625e0518767712583f917762634c2fc852c4d2eb 100644 (file)
--- a/config.c
+++ b/config.c
@@ -852,10 +852,9 @@ int git_config_from_parameters(config_fn_t fn, void *data)
        return 0;
 }
 
-int git_config(config_fn_t fn, void *data)
+int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 {
        int ret = 0, found = 0;
-       char *repo_config = NULL;
        const char *home = NULL;
 
        /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
@@ -877,12 +876,10 @@ int git_config(config_fn_t fn, void *data)
                free(user_config);
        }
 
-       repo_config = git_pathdup("config");
-       if (!access(repo_config, R_OK)) {
+       if (repo_config && !access(repo_config, R_OK)) {
                ret += git_config_from_file(fn, repo_config, data);
                found += 1;
        }
-       free(repo_config);
 
        ret += git_config_from_parameters(fn, data);
        if (config_parameters)
@@ -891,6 +888,18 @@ int git_config(config_fn_t fn, void *data)
        return ret == 0 ? found : ret;
 }
 
+int git_config(config_fn_t fn, void *data)
+{
+       char *repo_config = NULL;
+       int ret;
+
+       repo_config = git_pathdup("config");
+       ret = git_config_early(fn, data, repo_config);
+       if (repo_config)
+               free(repo_config);
+       return ret;
+}
+
 /*
  * Find all the stuff for git_config_set() below.
  */
index f99ea9585014face001849aeeefa5f20e79bc1e2..21989fc6ab84c0503cdc9418673d9d0bf06f9d49 100755 (executable)
@@ -709,7 +709,7 @@ if [ -z "$GIT_DIR" ]; then
        exit 1
 fi
 
-projectdesc=$(sed -ne '1p' "$GIT_DIR/description")
+projectdesc=$(sed -ne '1p' "$GIT_DIR/description" 2>/dev/null)
 # Check if the description is unchanged from it's default, and shorten it to
 # a more manageable length if it is
 if expr "$projectdesc" : "Unnamed repository.*$" >/dev/null
index 01de9a84c21b31a0120065a32a386f27321cdf7b..d5aebed48df3387e966a23b6ee460dc2244f728e 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "attr.h"
 #include "run-command.h"
+#include "quote.h"
 
 /*
  * convert.c - convert a file when checking it out and checking it in.
@@ -318,6 +319,7 @@ struct filter_params {
        const char *src;
        unsigned long size;
        const char *cmd;
+       const char *path;
 };
 
 static int filter_buffer(int in, int out, void *data)
@@ -330,7 +332,23 @@ static int filter_buffer(int in, int out, void *data)
        int write_err, status;
        const char *argv[] = { NULL, NULL };
 
-       argv[0] = params->cmd;
+       /* apply % substitution to cmd */
+       struct strbuf cmd = STRBUF_INIT;
+       struct strbuf path = STRBUF_INIT;
+       struct strbuf_expand_dict_entry dict[] = {
+               { "f", NULL, },
+               { NULL, NULL, },
+       };
+
+       /* quote the path to preserve spaces, etc. */
+       sq_quote_buf(&path, params->path);
+       dict[0].value = path.buf;
+
+       /* expand all %f with the quoted path */
+       strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
+       strbuf_release(&path);
+
+       argv[0] = cmd.buf;
 
        memset(&child_process, 0, sizeof(child_process));
        child_process.argv = argv;
@@ -350,6 +368,8 @@ static int filter_buffer(int in, int out, void *data)
        status = finish_command(&child_process);
        if (status)
                error("external filter %s failed %d", params->cmd, status);
+
+       strbuf_release(&cmd);
        return (write_err || status);
 }
 
@@ -377,6 +397,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
        params.src = src;
        params.size = len;
        params.cmd = cmd;
+       params.path = path;
 
        fflush(NULL);
        if (start_async(&async))
index d2a4e023e895d57db798be76450b77afb2ac49be..347fd0c52b4cd797f5dafffb6885324f7c7f0274 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -1226,9 +1226,10 @@ int main(int argc, char **argv)
 
        /* prepare argv for serving-processes */
        cld_argv = xmalloc(sizeof (char *) * (argc + 2));
-       for (i = 0; i < argc; ++i)
-               cld_argv[i] = argv[i];
-       cld_argv[argc] = "--serve";
+       cld_argv[0] = argv[0];  /* git-daemon */
+       cld_argv[1] = "--serve";
+       for (i = 1; i < argc; ++i)
+               cld_argv[i+1] = argv[i];
        cld_argv[argc+1] = NULL;
 
        return serve(&listen_addr, listen_port, cred);
index c79f2a9b561de77e27abd7ee26831e2a58beb259..9564475f429312a467a020106f7443112367d5da 100644 (file)
@@ -139,30 +139,20 @@ static int git_work_tree_initialized;
  */
 void set_git_work_tree(const char *new_work_tree)
 {
-       if (is_bare_repository_cfg >= 0)
-               die("cannot set work tree after initialization");
+       if (git_work_tree_initialized) {
+               new_work_tree = make_absolute_path(new_work_tree);
+               if (strcmp(new_work_tree, work_tree))
+                       die("internal error: work tree has already been set\n"
+                           "Current worktree: %s\nNew worktree: %s",
+                           work_tree, new_work_tree);
+               return;
+       }
        git_work_tree_initialized = 1;
-       free(work_tree);
        work_tree = xstrdup(make_absolute_path(new_work_tree));
-       is_bare_repository_cfg = 0;
 }
 
 const char *get_git_work_tree(void)
 {
-       if (!git_work_tree_initialized) {
-               work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
-               /* core.bare = true overrides implicit and config work tree */
-               if (!work_tree && is_bare_repository_cfg < 1) {
-                       work_tree = git_work_tree_cfg;
-                       /* make_absolute_path also normalizes the path */
-                       if (work_tree && !is_absolute_path(work_tree))
-                               work_tree = xstrdup(make_absolute_path(git_path("%s", work_tree)));
-               } else if (work_tree)
-                       work_tree = xstrdup(make_absolute_path(work_tree));
-               git_work_tree_initialized = 1;
-               if (work_tree)
-                       is_bare_repository_cfg = 0;
-       }
        return work_tree;
 }
 
index bf225706ee377b89035eb21f76f9957cfaf6363b..38545e8bfd72c8cd4f91e0d33257b143db86bac5 100644 (file)
@@ -3,7 +3,6 @@
 #include "quote.h"
 #define MAX_ARGS       32
 
-extern char **environ;
 static const char *argv_exec_path;
 static const char *argv0_path;
 
index 785776086ccc22dcd5488e3ac0bad3318f57043e..970d8470ed7c350337f28570fd2c111186a7941d 100644 (file)
@@ -2231,6 +2231,12 @@ static void file_change_m(struct branch *b)
                p = uq.buf;
        }
 
+       /* Git does not track empty, non-toplevel directories. */
+       if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) {
+               tree_content_remove(&b->branch_tree, p, NULL);
+               return;
+       }
+
        if (S_ISGITLINK(mode)) {
                if (inline_data)
                        die("Git links cannot be specified 'inline': %s",
@@ -2985,6 +2991,8 @@ static int parse_one_feature(const char *feature, int from_stream)
                relative_marks_paths = 0;
        } else if (!prefixcmp(feature, "force")) {
                force_update = 1;
+       } else if (!strcmp(feature, "notes")) {
+               ; /* do nothing; we have the feature */
        } else {
                return 0;
        }
index cf1f64b574b180332105d95295dfa35c8f6e10bb..6cdd5910db50c96df3d149fba172750cb10c09cb 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -577,13 +577,6 @@ then
        resume=
 fi
 
-if test "$this" -gt "$last"
-then
-       say Nothing to do.
-       rm -fr "$dotest"
-       exit
-fi
-
 while test "$this" -le "$last"
 do
        msgnum=`printf "%0${prec}d" $this`
index d27abfe7f32ef47ee8b613293110147ca3006575..8e683e54783ab6e916bdb8ade56832ac81470648 100755 (executable)
@@ -90,23 +90,40 @@ ($)
 }
 
 # convert getopts specs for use by git config
+my %longmap = (
+       'A:' => 'authors-file',
+       'M:' => 'merge-regex',
+       'P:' => undef,
+       'R' => 'track-revisions',
+       'S:' => 'ignore-paths',
+);
+
 sub read_repo_config {
-    # Split the string between characters, unless there is a ':'
-    # So "abc:de" becomes ["a", "b", "c:", "d", "e"]
+       # Split the string between characters, unless there is a ':'
+       # So "abc:de" becomes ["a", "b", "c:", "d", "e"]
        my @opts = split(/ *(?!:)/, shift);
        foreach my $o (@opts) {
                my $key = $o;
                $key =~ s/://g;
                my $arg = 'git config';
                $arg .= ' --bool' if ($o !~ /:$/);
-
-        chomp(my $tmp = `$arg --get cvsimport.$key`);
+               my $ckey = $key;
+
+               if (exists $longmap{$o}) {
+                       # An uppercase option like -R cannot be
+                       # expressed in the configuration, as the
+                       # variable names are downcased.
+                       $ckey = $longmap{$o};
+                       next if (! defined $ckey);
+                       $ckey =~ s/-//g;
+               }
+               chomp(my $tmp = `$arg --get cvsimport.$ckey`);
                if ($tmp && !($arg =~ /--bool/ && $tmp eq 'false')) {
-            no strict 'refs';
-            my $opt_name = "opt_" . $key;
-            if (!$$opt_name) {
-                $$opt_name = $tmp;
-            }
+                       no strict 'refs';
+                       my $opt_name = "opt_" . $key;
+                       if (!$$opt_name) {
+                               $$opt_name = $tmp;
+                       }
                }
        }
 }
index a5ffd9a31eea0f361774d77867c83f444847279b..5873ba4bc3b2a94cd7754ae572072fd745dc059d 100755 (executable)
@@ -894,7 +894,7 @@ first and then run 'git rebase --continue' again."
 
                if test ! -z "$1"
                then
-                       output git checkout "$1" ||
+                       output git checkout "$1" -- ||
                                die "Could not checkout $1"
                fi
 
@@ -1021,7 +1021,7 @@ first and then run 'git rebase --continue' again."
 #  e, edit = use commit, but stop for amending
 #  s, squash = use commit, but meld into previous commit
 #  f, fixup = like "squash", but discard this commit's log message
-#  x <cmd>, exec <cmd> = Run a shell command <cmd>, and stop if it fails
+#  x, exec = run command (the rest of the line) using shell
 #
 # If you remove a line here THAT COMMIT WILL BE LOST.
 # However, if you remove everything, the rebase will be aborted.
index d8e190302668ca352fd58cd052a677347a29cdcd..cbb0ea90ed410d5af68ce814b7fd93a90829f3ee 100755 (executable)
@@ -482,6 +482,7 @@ case "$#" in
        then
                head_name="detached HEAD"
        else
+               echo >&2 "fatal: no such branch: $1"
                usage
        fi
        ;;
@@ -513,7 +514,7 @@ then
        if test -z "$force_rebase"
        then
                # Lazily switch to the target branch if needed...
-               test -z "$switch_to" || git checkout "$switch_to"
+               test -z "$switch_to" || git checkout "$switch_to" --
                say "Current branch $branch_name is up to date."
                exit 0
        else
index c21b77aee54cd045b7bb64ae7337387569bbf65a..8b9058971767dbb4d94e996876f6ba7ed178ddd6 100755 (executable)
@@ -37,12 +37,24 @@ resolve_relative_url ()
                die "remote ($remote) does not have a url defined in .git/config"
        url="$1"
        remoteurl=${remoteurl%/}
+       sep=/
        while test -n "$url"
        do
                case "$url" in
                ../*)
                        url="${url#../}"
-                       remoteurl="${remoteurl%/*}"
+                       case "$remoteurl" in
+                       */*)
+                               remoteurl="${remoteurl%/*}"
+                               ;;
+                       *:*)
+                               remoteurl="${remoteurl%:*}"
+                               sep=:
+                               ;;
+                       *)
+                               die "cannot strip one component off url '$remoteurl'"
+                               ;;
+                       esac
                        ;;
                ./*)
                        url="${url#./}"
@@ -51,7 +63,7 @@ resolve_relative_url ()
                        break;;
                esac
        done
-       echo "$remoteurl/${url%/}"
+       echo "$remoteurl$sep${url%/}"
 }
 
 #
diff --git a/git.c b/git.c
index d532576cdff244fcd3945ef4fcc580e1bf0b04ae..68334f6a3134bb76a8ffc59e4da773400c59a388 100644 (file)
--- a/git.c
+++ b/git.c
@@ -275,6 +275,10 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
                        use_pager = check_pager_config(p->cmd);
                if (use_pager == -1 && p->option & USE_PAGER)
                        use_pager = 1;
+
+               if ((p->option & (RUN_SETUP | RUN_SETUP_GENTLY)) &&
+                   startup_info->have_repository) /* get_git_dir() may set up repo, avoid that */
+                       trace_repo_setup(prefix);
        }
        commit_pager_choice();
 
old mode 100644 (file)
new mode 100755 (executable)
index 823053173c92e4097dad54945db16f42b4b5d994..4964a679b3013caa9bfa2f438dc110eaa0274b69 100644 (file)
@@ -237,6 +237,12 @@ Requirements
  - Perl modules: CGI, Encode, Fcntl, File::Find, File::Basename.
  - web server
 
+The following optional Perl modules are required for extra features
+ - Digest::MD5 - for gravatar support
+ - CGI::Fast and FCGI - for running gitweb as FastCGI script
+ - HTML::TagCloud - for fancy tag cloud in project list view
+ - HTTP::Date or Time::ParseDate - to support If-Modified-Since for feeds
+
 
 Example web server configuration
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index 47796180d2340ead3795ee7004ddae57d5bc1516..0779f12d6178c23a47f4b9a08152176d0e19a2a8 100755 (executable)
@@ -250,13 +250,14 @@ sub evaluate_uri {
        # main extensions, defining name of syntax;
        # see files in /usr/share/highlight/langDefs/ directory
        map { $_ => $_ }
-               qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl),
+               qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl sql make),
        # alternate extensions, see /etc/highlight/filetypes.conf
        'h' => 'c',
+       map { $_ => 'sh'  } qw(bash zsh ksh),
        map { $_ => 'cpp' } qw(cxx c++ cc),
-       map { $_ => 'php' } qw(php3 php4),
+       map { $_ => 'php' } qw(php3 php4 php5 phps),
        map { $_ => 'pl'  } qw(perl pm), # perhaps also 'cgi'
-       'mak' => 'make',
+       map { $_ => 'make'} qw(mak mk),
        map { $_ => 'xml' } qw(xhtml html htm),
 );
 
@@ -3464,11 +3465,10 @@ sub run_highlighter {
        my ($fd, $highlight, $syntax) = @_;
        return $fd unless ($highlight && defined $syntax);
 
-       close $fd
-               or die_error(404, "Reading blob failed");
+       close $fd;
        open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ".
                  quote_command($highlight_bin).
-                 " --xhtml --fragment --syntax $syntax |"
+                 " --fragment --syntax $syntax |"
                or die_error(500, "Couldn't open file or run syntax highlighter");
        return $fd;
 }
@@ -3601,10 +3601,15 @@ sub git_header_html {
                insert_file($site_header);
        }
 
-       print "<div class=\"page_header\">\n" .
-             $cgi->a({-href => esc_url($logo_url),
-                      -title => $logo_label},
-                     qq(<img src=").esc_url($logo).qq(" width="72" height="27" alt="git" class="logo"/>));
+       print "<div class=\"page_header\">\n";
+       if (defined $logo) {
+               print $cgi->a({-href => esc_url($logo_url),
+                              -title => $logo_label},
+                             $cgi->img({-src => esc_url($logo),
+                                        -width => 72, -height => 27,
+                                        -alt => "git",
+                                        -class => "logo"}));
+       }
        print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
        if (defined $project) {
                print $cgi->a({-href => href(action=>"summary")}, esc_html($project));
@@ -7169,7 +7174,7 @@ sub git_feed {
                if (defined $favicon) {
                        print "<icon>" . esc_url($favicon) . "</icon>\n";
                }
-               if (defined $logo_url) {
+               if (defined $logo) {
                        # not twice as wide as tall: 72 x 27 pixels
                        print "<logo>" . esc_url($logo) . "</logo>\n";
                }
index 007dd3e4d38ff657a29a06e559173b796f193763..6ce512efc4cce8042481e8a6947d033c272e78e6 100644 (file)
@@ -351,16 +351,13 @@ int ll_merge(mmbuffer_t *result_buf,
             const struct ll_merge_options *opts)
 {
        static struct git_attr_check check[2];
+       static const struct ll_merge_options default_opts;
        const char *ll_driver_name = NULL;
        int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
        const struct ll_merge_driver *driver;
 
-       if (!opts) {
-               struct ll_merge_options default_opts = {0};
-               return ll_merge(result_buf, path, ancestor, ancestor_label,
-                               ours, our_label, theirs, their_label,
-                               &default_opts);
-       }
+       if (!opts)
+               opts = &default_opts;
 
        if (opts->renormalize) {
                normalize_file(ancestor, path);
diff --git a/quote.h b/quote.h
index 38003bff5f97a11e051b106522a8548d43d24f6c..024e21d80ceaa37ec1f893acc907a62092560d21 100644 (file)
--- a/quote.h
+++ b/quote.h
@@ -1,8 +1,7 @@
 #ifndef QUOTE_H
 #define QUOTE_H
 
-#include <stddef.h>
-#include <stdio.h>
+struct strbuf;
 
 /* Help to copy the thing properly quoted for the shell safety.
  * any single quote is replaced with '\'', any exclamation point
index 2a1041ef6599c84fff6a8d9faf5dea23a2af3ab0..f91e446c86be8e27f98554567143d7ce6f934bd1 100644 (file)
@@ -194,6 +194,7 @@ int start_command(struct child_process *cmd)
        }
 
        trace_argv_printf(cmd->argv, "trace: run_command:");
+       fflush(NULL);
 
 #ifndef WIN32
 {
@@ -201,7 +202,6 @@ int start_command(struct child_process *cmd)
        if (pipe(notify_pipe))
                notify_pipe[0] = notify_pipe[1] = -1;
 
-       fflush(NULL);
        cmd->pid = fork();
        if (!cmd->pid) {
                /*
diff --git a/setup.c b/setup.c
index 91887a40b79d3bc2c82479bf7f09580c4c468665..dadc66659a4037b614b215b7f812c4df8969562b 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -208,24 +208,6 @@ int is_inside_work_tree(void)
        return inside_work_tree;
 }
 
-/*
- * set_work_tree() is only ever called if you set GIT_DIR explicitly.
- * The old behaviour (which we retain here) is to set the work tree root
- * to the cwd, unless overridden by the config, the command line, or
- * GIT_WORK_TREE.
- */
-static const char *set_work_tree(const char *dir)
-{
-       char buffer[PATH_MAX + 1];
-
-       if (!getcwd(buffer, sizeof(buffer)))
-               die ("Could not get the current working directory");
-       git_work_tree_cfg = xstrdup(buffer);
-       inside_work_tree = 1;
-
-       return NULL;
-}
-
 void setup_work_tree(void)
 {
        const char *work_tree, *git_dir;
@@ -239,13 +221,33 @@ void setup_work_tree(void)
                git_dir = make_absolute_path(git_dir);
        if (!work_tree || chdir(work_tree))
                die("This operation must be run in a work tree");
+
+       /*
+        * Make sure subsequent git processes find correct worktree
+        * if $GIT_WORK_TREE is set relative
+        */
+       if (getenv(GIT_WORK_TREE_ENVIRONMENT))
+               setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
+
        set_git_dir(make_relative_path(git_dir, work_tree));
        initialized = 1;
 }
 
-static int check_repository_format_gently(int *nongit_ok)
+static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 {
-       git_config(check_repository_format_version, NULL);
+       char repo_config[PATH_MAX+1];
+
+       /*
+        * git_config() can't be used here because it calls git_pathdup()
+        * to get $GIT_CONFIG/config. That call will make setup_git_env()
+        * set git_dir to ".git".
+        *
+        * We are in gitdir setup, no git dir has been found useable yet.
+        * Use a gentler version of git_config() to check if this repo
+        * is a good one.
+        */
+       snprintf(repo_config, PATH_MAX, "%s/config", gitdir);
+       git_config_early(check_repository_format_version, NULL, repo_config);
        if (GIT_REPO_VERSION < repository_format_version) {
                if (!nongit_ok)
                        die ("Expected git repo version <= %d, found %d",
@@ -314,64 +316,124 @@ const char *read_gitfile_gently(const char *path)
 }
 
 static const char *setup_explicit_git_dir(const char *gitdirenv,
-                               const char *work_tree_env, int *nongit_ok)
+                                         char *cwd, int len,
+                                         int *nongit_ok)
 {
-       static char buffer[1024 + 1];
-       const char *retval;
+       const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
+       const char *worktree;
+       char *gitfile;
 
        if (PATH_MAX - 40 < strlen(gitdirenv))
                die("'$%s' too big", GIT_DIR_ENVIRONMENT);
+
+       gitfile = (char*)read_gitfile_gently(gitdirenv);
+       if (gitfile) {
+               gitfile = xstrdup(gitfile);
+               gitdirenv = gitfile;
+       }
+
        if (!is_git_directory(gitdirenv)) {
                if (nongit_ok) {
                        *nongit_ok = 1;
+                       free(gitfile);
                        return NULL;
                }
                die("Not a git repository: '%s'", gitdirenv);
        }
-       if (!work_tree_env) {
-               retval = set_work_tree(gitdirenv);
-               /* config may override worktree */
-               if (check_repository_format_gently(nongit_ok))
-                       return NULL;
-               return retval;
+
+       if (check_repository_format_gently(gitdirenv, nongit_ok)) {
+               free(gitfile);
+               return NULL;
        }
-       if (check_repository_format_gently(nongit_ok))
+
+       /* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
+       if (work_tree_env)
+               set_git_work_tree(work_tree_env);
+       else if (is_bare_repository_cfg > 0) {
+               if (git_work_tree_cfg) /* #22.2, #30 */
+                       die("core.bare and core.worktree do not make sense");
+
+               /* #18, #26 */
+               set_git_dir(gitdirenv);
+               free(gitfile);
                return NULL;
-       retval = get_relative_cwd(buffer, sizeof(buffer) - 1,
-                       get_git_work_tree());
-       if (!retval || !*retval)
+       }
+       else if (git_work_tree_cfg) { /* #6, #14 */
+               if (is_absolute_path(git_work_tree_cfg))
+                       set_git_work_tree(git_work_tree_cfg);
+               else {
+                       char core_worktree[PATH_MAX];
+                       if (chdir(gitdirenv))
+                               die_errno("Could not chdir to '%s'", gitdirenv);
+                       if (chdir(git_work_tree_cfg))
+                               die_errno("Could not chdir to '%s'", git_work_tree_cfg);
+                       if (!getcwd(core_worktree, PATH_MAX))
+                               die_errno("Could not get directory '%s'", git_work_tree_cfg);
+                       if (chdir(cwd))
+                               die_errno("Could not come back to cwd");
+                       set_git_work_tree(core_worktree);
+               }
+       }
+       else /* #2, #10 */
+               set_git_work_tree(".");
+
+       /* set_git_work_tree() must have been called by now */
+       worktree = get_git_work_tree();
+
+       /* both get_git_work_tree() and cwd are already normalized */
+       if (!strcmp(cwd, worktree)) { /* cwd == worktree */
+               set_git_dir(gitdirenv);
+               free(gitfile);
                return NULL;
-       set_git_dir(make_absolute_path(gitdirenv));
-       if (chdir(work_tree_env) < 0)
-               die_errno ("Could not chdir to '%s'", work_tree_env);
-       strcat(buffer, "/");
-       return retval;
-}
+       }
 
-static int cwd_contains_git_dir(const char **gitfile_dirp)
-{
-       const char *gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
-       *gitfile_dirp = gitfile_dir;
-       if (gitfile_dir) {
-               if (set_git_dir(gitfile_dir))
-                       die("Repository setup failed");
-               return 1;
+       if (!prefixcmp(cwd, worktree) &&
+           cwd[strlen(worktree)] == '/') { /* cwd inside worktree */
+               set_git_dir(make_absolute_path(gitdirenv));
+               if (chdir(worktree))
+                       die_errno("Could not chdir to '%s'", worktree);
+               cwd[len++] = '/';
+               cwd[len] = '\0';
+               free(gitfile);
+               return cwd + strlen(worktree) + 1;
        }
-       return is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT);
+
+       /* cwd outside worktree */
+       set_git_dir(gitdirenv);
+       free(gitfile);
+       return NULL;
 }
 
-static const char *setup_discovered_git_dir(const char *work_tree_env,
-               int offset, int len, char *cwd, int *nongit_ok)
+static const char *setup_discovered_git_dir(const char *gitdir,
+                                           char *cwd, int offset, int len,
+                                           int *nongit_ok)
 {
-       int root_len;
+       if (check_repository_format_gently(gitdir, nongit_ok))
+               return NULL;
 
-       inside_git_dir = 0;
-       if (!work_tree_env)
-               inside_work_tree = 1;
-       root_len = offset_1st_component(cwd);
-       git_work_tree_cfg = xstrndup(cwd, offset > root_len ? offset : root_len);
-       if (check_repository_format_gently(nongit_ok))
+       /* --work-tree is set without --git-dir; use discovered one */
+       if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+               if (offset != len && !is_absolute_path(gitdir))
+                       gitdir = xstrdup(make_absolute_path(gitdir));
+               if (chdir(cwd))
+                       die_errno("Could not come back to cwd");
+               return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok);
+       }
+
+       /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
+       if (is_bare_repository_cfg > 0) {
+               set_git_dir(offset == len ? gitdir : make_absolute_path(gitdir));
+               if (chdir(cwd))
+                       die_errno("Could not come back to cwd");
                return NULL;
+       }
+
+       /* #0, #1, #5, #8, #9, #12, #13 */
+       set_git_work_tree(".");
+       if (strcmp(gitdir, DEFAULT_GIT_DIR_ENVIRONMENT))
+               set_git_dir(gitdir);
+       inside_git_dir = 0;
+       inside_work_tree = 1;
        if (offset == len)
                return NULL;
 
@@ -382,23 +444,35 @@ static const char *setup_discovered_git_dir(const char *work_tree_env,
        return cwd + offset;
 }
 
-static const char *setup_bare_git_dir(const char *work_tree_env,
-               int offset, int len, char *cwd, int *nongit_ok)
+/* #16.1, #17.1, #20.1, #21.1, #22.1 (see t1510) */
+static const char *setup_bare_git_dir(char *cwd, int offset, int len, int *nongit_ok)
 {
        int root_len;
 
+       if (check_repository_format_gently(".", nongit_ok))
+               return NULL;
+
+       /* --work-tree is set without --git-dir; use discovered one */
+       if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+               const char *gitdir;
+
+               gitdir = offset == len ? "." : xmemdupz(cwd, offset);
+               if (chdir(cwd))
+                       die_errno("Could not come back to cwd");
+               return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok);
+       }
+
        inside_git_dir = 1;
-       if (!work_tree_env)
-               inside_work_tree = 0;
+       inside_work_tree = 0;
        if (offset != len) {
                if (chdir(cwd))
                        die_errno("Cannot come back to cwd");
                root_len = offset_1st_component(cwd);
                cwd[offset > root_len ? offset : root_len] = '\0';
                set_git_dir(cwd);
-       } else
+       }
+       else
                set_git_dir(".");
-       check_repository_format_gently(nongit_ok);
        return NULL;
 }
 
@@ -428,11 +502,10 @@ static dev_t get_device_or_die(const char *path, const char *prefix)
  */
 static const char *setup_git_directory_gently_1(int *nongit_ok)
 {
-       const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
        const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
        static char cwd[PATH_MAX+1];
-       const char *gitdirenv;
-       const char *gitfile_dir;
+       const char *gitdirenv, *ret;
+       char *gitfile;
        int len, offset, ceil_offset;
        dev_t current_device = 0;
        int one_filesystem = 1;
@@ -445,6 +518,10 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
        if (nongit_ok)
                *nongit_ok = 0;
 
+       if (!getcwd(cwd, sizeof(cwd)-1))
+               die_errno("Unable to read current working directory");
+       offset = len = strlen(cwd);
+
        /*
         * If GIT_DIR is set explicitly, we're not going
         * to do any discovery, but we still do repository
@@ -452,10 +529,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
         */
        gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
        if (gitdirenv)
-               return setup_explicit_git_dir(gitdirenv, work_tree_env, nongit_ok);
-
-       if (!getcwd(cwd, sizeof(cwd)-1))
-               die_errno("Unable to read current working directory");
+               return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
 
        ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
        if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
@@ -472,17 +546,30 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
         * - ../../.git/
         *   etc.
         */
-       offset = len = strlen(cwd);
        one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
        if (one_filesystem)
                current_device = get_device_or_die(".", NULL);
        for (;;) {
-               if (cwd_contains_git_dir(&gitfile_dir))
-                       return setup_discovered_git_dir(work_tree_env, offset,
-                                                       len, cwd, nongit_ok);
+               gitfile = (char*)read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
+               if (gitfile)
+                       gitdirenv = gitfile = xstrdup(gitfile);
+               else {
+                       if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
+                               gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
+               }
+
+               if (gitdirenv) {
+                       ret = setup_discovered_git_dir(gitdirenv,
+                                                      cwd, offset, len,
+                                                      nongit_ok);
+                       free(gitfile);
+                       return ret;
+               }
+               free(gitfile);
+
                if (is_git_directory("."))
-                       return setup_bare_git_dir(work_tree_env, offset,
-                                                       len, cwd, nongit_ok);
+                       return setup_bare_git_dir(cwd, offset, len, nongit_ok);
+
                while (--offset > ceil_offset && cwd[offset] != '/');
                if (offset <= ceil_offset)
                        return setup_nongit(cwd, nongit_ok);
@@ -592,7 +679,7 @@ int check_repository_format_version(const char *var, const char *value, void *cb
 
 int check_repository_format(void)
 {
-       return check_repository_format_gently(NULL);
+       return check_repository_format_gently(get_git_dir(), NULL);
 }
 
 /*
@@ -603,19 +690,5 @@ int check_repository_format(void)
  */
 const char *setup_git_directory(void)
 {
-       const char *retval = setup_git_directory_gently(NULL);
-
-       /* If the work tree is not the default one, recompute prefix */
-       if (inside_work_tree < 0) {
-               static char buffer[PATH_MAX + 1];
-               char *rel;
-               if (retval && chdir(retval))
-                       die_errno ("Could not jump back into original cwd");
-               rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree());
-               if (rel && *rel && chdir(get_git_work_tree()))
-                       die_errno ("Could not jump to working directory");
-               return rel && *rel ? strcat(rel, "/") : NULL;
-       }
-
-       return retval;
+       return setup_git_directory_gently(NULL);
 }
index 1cafdfa617a833ec757b481826dc62282be8f374..0b830c8642fa2b141c9888c68713a29fc4df2ef2 100644 (file)
@@ -37,6 +37,41 @@ const unsigned char null_sha1[20];
 
 static int git_open_noatime(const char *name, struct packed_git *p);
 
+/*
+ * This is meant to hold a *small* number of objects that you would
+ * want read_sha1_file() to be able to return, but yet you do not want
+ * to write them into the object store (e.g. a browse-only
+ * application).
+ */
+static struct cached_object {
+       unsigned char sha1[20];
+       enum object_type type;
+       void *buf;
+       unsigned long size;
+} *cached_objects;
+static int cached_object_nr, cached_object_alloc;
+
+static struct cached_object empty_tree = {
+       EMPTY_TREE_SHA1_BIN,
+       OBJ_TREE,
+       "",
+       0
+};
+
+static struct cached_object *find_cached_object(const unsigned char *sha1)
+{
+       int i;
+       struct cached_object *co = cached_objects;
+
+       for (i = 0; i < cached_object_nr; i++, co++) {
+               if (!hashcmp(co->sha1, sha1))
+                       return co;
+       }
+       if (!hashcmp(sha1, empty_tree.sha1))
+               return &empty_tree;
+       return NULL;
+}
+
 int safe_create_leading_directories(char *path)
 {
        char *pos = path + offset_1st_component(path);
@@ -1985,9 +2020,17 @@ static int sha1_loose_object_info(const unsigned char *sha1, unsigned long *size
 
 int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
 {
+       struct cached_object *co;
        struct pack_entry e;
        int status;
 
+       co = find_cached_object(sha1);
+       if (co) {
+               if (sizep)
+                       *sizep = co->size;
+               return co->type;
+       }
+
        if (!find_pack_entry(sha1, &e)) {
                /* Most likely it's a loose object. */
                status = sha1_loose_object_info(sha1, sizep);
@@ -2033,41 +2076,6 @@ static void *read_packed_sha1(const unsigned char *sha1,
        return data;
 }
 
-/*
- * This is meant to hold a *small* number of objects that you would
- * want read_sha1_file() to be able to return, but yet you do not want
- * to write them into the object store (e.g. a browse-only
- * application).
- */
-static struct cached_object {
-       unsigned char sha1[20];
-       enum object_type type;
-       void *buf;
-       unsigned long size;
-} *cached_objects;
-static int cached_object_nr, cached_object_alloc;
-
-static struct cached_object empty_tree = {
-       EMPTY_TREE_SHA1_BIN,
-       OBJ_TREE,
-       "",
-       0
-};
-
-static struct cached_object *find_cached_object(const unsigned char *sha1)
-{
-       int i;
-       struct cached_object *co = cached_objects;
-
-       for (i = 0; i < cached_object_nr; i++, co++) {
-               if (!hashcmp(co->sha1, sha1))
-                       return co;
-       }
-       if (!hashcmp(sha1, empty_tree.sha1))
-               return &empty_tree;
-       return NULL;
-}
-
 int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
                      unsigned char *sha1)
 {
@@ -2141,7 +2149,7 @@ void *read_sha1_file_repl(const unsigned char *sha1,
                return data;
        }
 
-       if (errno != ENOENT)
+       if (errno && errno != ENOENT)
                die_errno("failed to read object %s", sha1_to_hex(sha1));
 
        /* die if we replaced an object with one that does not exist */
index 892d443f63428aea6d6b92458bdaa4575bc46da0..25f7d2d2e3cf70d54f5b854ad4199c831a74ae2a 100644 (file)
--- a/t/README
+++ b/t/README
@@ -283,6 +283,12 @@ Do:
    Tests that are likely to smoke out future regressions are better
    than tests that just inflate the coverage metrics.
 
+ - When a test checks for an absolute path that a git command generated,
+   construct the expected value using $(pwd) rather than $PWD,
+   $TEST_DIRECTORY, or $TRASH_DIRECTORY. It makes a difference on
+   Windows, where the shell (MSYS bash) mangles absolute path names.
+   For details, see the commit message of 4114156ae9.
+
 Don't:
 
  - exit() within a <script> part.
index 6a9d9757239f0476422b1a97228927b1ba1ac934..199f22c231b5ac1479929a89cdf988ac7aff4268 100644 (file)
@@ -68,8 +68,7 @@ svn_cmd () {
        svn "$orig_svncmd" --config-dir "$svnconf" "$@"
 }
 
-if test -n "$SVN_HTTPD_PORT"
-then
+prepare_httpd () {
        for d in \
                "$SVN_HTTPD_PATH" \
                /usr/sbin/apache2 \
@@ -83,8 +82,8 @@ then
        done
        if test -z "$SVN_HTTPD_PATH"
        then
-               skip_all='skipping git svn tests, Apache not found'
-               test_done
+               echo >&2 '*** error: Apache not found'
+               return 1
        fi
        for d in \
                "$SVN_HTTPD_MODULE_PATH" \
@@ -99,23 +98,16 @@ then
        done
        if test -z "$SVN_HTTPD_MODULE_PATH"
        then
-               skip_all='skipping git svn tests, Apache module dir not found'
-               test_done
-       fi
-fi
-
-start_httpd () {
-       repo_base_path="$1"
-       if test -z "$SVN_HTTPD_PORT"
-       then
-               echo >&2 'SVN_HTTPD_PORT is not defined!'
-               return
+               echo >&2 '*** error: Apache module dir not found'
+               return 1
        fi
-       if test -z "$repo_base_path"
+       if test ! -f "$SVN_HTTPD_MODULE_PATH/mod_dav_svn.so"
        then
-               repo_base_path=svn
+               echo >&2 '*** error: Apache module "mod_dav_svn" not found'
+               return 1
        fi
 
+       repo_base_path="${1-svn}"
        mkdir "$GIT_DIR"/logs
 
        cat > "$GIT_DIR/httpd.conf" <<EOF
@@ -132,12 +124,24 @@ LoadModule dav_svn_module $SVN_HTTPD_MODULE_PATH/mod_dav_svn.so
        SVNPath "$rawsvnrepo"
 </Location>
 EOF
+}
+
+start_httpd () {
+       if test -z "$SVN_HTTPD_PORT"
+       then
+               echo >&2 'SVN_HTTPD_PORT is not defined!'
+               return
+       fi
+
+       prepare_httpd "$1" || return 1
+
        "$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k start
        svnrepo="http://127.0.0.1:$SVN_HTTPD_PORT/$repo_base_path"
 }
 
 stop_httpd () {
        test -z "$SVN_HTTPD_PORT" && return
+       test ! -f "$GIT_DIR/httpd.conf" && return
        "$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k stop
 }
 
index 2f7002a5e57d61a69d418cc55d1e939198c6ac20..8deec75c3a0eef961986a0bb313a918ab532f58d 100755 (executable)
@@ -80,11 +80,11 @@ EOF
     chmod +x passing-todo.sh &&
     ./passing-todo.sh >out 2>err &&
     ! test -s err &&
-cat >expect <<EOF &&
-ok 1 - pretend we have fixed a known breakage # TODO known breakage
-# fixed 1 known breakage(s)
-# passed all 1 test(s)
-1..1
+sed -e 's/^> //' >expect <<EOF &&
+ok 1 - pretend we have fixed a known breakage # TODO known breakage
+# fixed 1 known breakage(s)
+# passed all 1 test(s)
+1..1
 EOF
     test_cmp expect out)
 "
@@ -164,19 +164,19 @@ EOF
     test_must_fail ./failing-cleanup.sh >out 2>err &&
     ! test -s err &&
     ! test -f \"trash directory.failing-cleanup/clean-after-failure\" &&
-sed -e 's/Z$//' >expect <<\EOF &&
-not ok - 1 tests clean up even after a failure
-#      Z
-#          touch clean-after-failure &&
-#          test_when_finished rm clean-after-failure &&
-#          (exit 1)
-#      Z
-not ok - 2 failure to clean up causes the test to fail
-#      Z
-#          test_when_finished \"(exit 2)\"
-#      Z
-# failed 2 among 2 test(s)
-1..2
+sed -e 's/Z$//' -e 's/^> //' >expect <<\EOF &&
+not ok - 1 tests clean up even after a failure
+> #    Z
+> #        touch clean-after-failure &&
+> #        test_when_finished rm clean-after-failure &&
+> #        (exit 1)
+> #    Z
+not ok - 2 failure to clean up causes the test to fail
+> #    Z
+> #        test_when_finished \"(exit 2)\"
+> #    Z
+# failed 2 among 2 test(s)
+1..2
 EOF
     test_cmp expect out)
 "
index d44194c35fe5de72af0721a05bb1038f1720b4ac..f6849932112f1bbea1dafad09150857a707b64e4 100755 (executable)
@@ -33,6 +33,62 @@ test_expect_success 'plain' '
        check_config plain/.git false unset
 '
 
+test_expect_success 'plain nested in bare' '
+       (
+               sane_unset GIT_DIR GIT_WORK_TREE &&
+               git init --bare bare-ancestor.git &&
+               cd bare-ancestor.git &&
+               mkdir plain-nested &&
+               cd plain-nested &&
+               git init
+       ) &&
+       check_config bare-ancestor.git/plain-nested/.git false unset
+'
+
+test_expect_success 'plain through aliased command, outside any git repo' '
+       (
+               sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL &&
+               HOME=$(pwd)/alias-config &&
+               export HOME &&
+               mkdir alias-config &&
+               echo "[alias] aliasedinit = init" >alias-config/.gitconfig &&
+
+               GIT_CEILING_DIRECTORIES=$(pwd) &&
+               export GIT_CEILING_DIRECTORIES &&
+
+               mkdir plain-aliased &&
+               cd plain-aliased &&
+               git aliasedinit
+       ) &&
+       check_config plain-aliased/.git false unset
+'
+
+test_expect_failure 'plain nested through aliased command' '
+       (
+               sane_unset GIT_DIR GIT_WORK_TREE &&
+               git init plain-ancestor-aliased &&
+               cd plain-ancestor-aliased &&
+               echo "[alias] aliasedinit = init" >>.git/config &&
+               mkdir plain-nested &&
+               cd plain-nested &&
+               git aliasedinit
+       ) &&
+       check_config plain-ancestor-aliased/plain-nested/.git false unset
+'
+
+test_expect_failure 'plain nested in bare through aliased command' '
+       (
+               sane_unset GIT_DIR GIT_WORK_TREE &&
+               git init --bare bare-ancestor-aliased.git &&
+               cd bare-ancestor-aliased.git &&
+               echo "[alias] aliasedinit = init" >>config &&
+               mkdir plain-nested &&
+               cd plain-nested &&
+               git aliasedinit
+       ) &&
+       check_config bare-ancestor-aliased.git/plain-nested/.git false unset
+'
+
 test_expect_success 'plain with GIT_WORK_TREE' '
        if (
                sane_unset GIT_DIR &&
index 828e35baf72d94908ad1f30dbd2e1aa6f9376e69..9078b84ae68b430285312749f62daee103dcc428 100755 (executable)
@@ -93,4 +93,47 @@ test_expect_success expanded_in_repo '
        cmp expanded-keywords expected-output
 '
 
+# The use of %f in a filter definition is expanded to the path to
+# the filename being smudged or cleaned.  It must be shell escaped.
+# First, set up some interesting file names and pet them in
+# .gitattributes.
+test_expect_success 'filter shell-escaped filenames' '
+       cat >argc.sh <<-EOF &&
+       #!$SHELL_PATH
+       cat >/dev/null
+       echo argc: \$# "\$@"
+       EOF
+       normal=name-no-magic &&
+       special="name  with '\''sq'\'' and \$x" &&
+       echo some test text >"$normal" &&
+       echo some test text >"$special" &&
+       git add "$normal" "$special" &&
+       git commit -q -m "add files" &&
+       echo "name* filter=argc" >.gitattributes &&
+
+       # delete the files and check them out again, using a smudge filter
+       # that will count the args and echo the command-line back to us
+       git config filter.argc.smudge "sh ./argc.sh %f" &&
+       rm "$normal" "$special" &&
+       git checkout -- "$normal" "$special" &&
+
+       # make sure argc.sh counted the right number of args
+       echo "argc: 1 $normal" >expect &&
+       test_cmp expect "$normal" &&
+       echo "argc: 1 $special" >expect &&
+       test_cmp expect "$special" &&
+
+       # do the same thing, but with more args in the filter expression
+       git config filter.argc.smudge "sh ./argc.sh %f --my-extra-arg" &&
+       rm "$normal" "$special" &&
+       git checkout -- "$normal" "$special" &&
+
+       # make sure argc.sh counted the right number of args
+       echo "argc: 2 $normal --my-extra-arg" >expect &&
+       test_cmp expect "$normal" &&
+       echo "argc: 2 $special --my-extra-arg" >expect &&
+       test_cmp expect "$special" &&
+       :
+'
+
 test_done
index a3ac33801a28fe7bd2ce67d4d4ae306c1050f5c1..1fd187c5eb188671934f6afe85ca5003c529a942 100755 (executable)
@@ -110,6 +110,14 @@ test_expect_success 'read-tree' '
        )
 '
 
+test_expect_success 'alias expansion' '
+       (
+               git config alias.ss status &&
+               cd dir &&
+               git status &&
+               git ss
+       )
+'
 test_expect_success 'no file/rev ambiguity check inside .git' '
        git commit -a -m 1 &&
        (
index 2c8f01f6684cbe492132575209f79371ad761d87..da6252b1179c47d39393c983d88c75d84a507cb7 100755 (executable)
@@ -340,4 +340,11 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
        git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
+       GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
+       test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&
+       echo "$(pwd)/repo.git/work" >expected &&
+       test_cmp expected actual
+'
+
 test_done
diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh
new file mode 100755 (executable)
index 0000000..15101d5
--- /dev/null
@@ -0,0 +1,776 @@
+#!/bin/sh
+
+test_description="Tests of cwd/prefix/worktree/gitdir setup in all cases
+
+A few rules for repo setup:
+
+1. GIT_DIR is relative to user's cwd. --git-dir is equivalent to
+   GIT_DIR.
+
+2. .git file is relative to parent directory. .git file is basically
+   symlink in disguise. The directory where .git file points to will
+   become new git_dir.
+
+3. core.worktree is relative to git_dir.
+
+4. GIT_WORK_TREE is relative to user's cwd. --work-tree is
+   equivalent to GIT_WORK_TREE.
+
+5. GIT_WORK_TREE/core.worktree was originally meant to work only if
+   GIT_DIR is set, but earlier git didn't enforce it, and some scripts
+   depend on the implementation that happened to first discover .git by
+   going up from the users $cwd and then using the specified working tree
+   that may or may not have any relation to where .git was found in.  This
+   historical behaviour must be kept.
+
+6. Effective GIT_WORK_TREE overrides core.worktree and core.bare
+
+7. Effective core.worktree conflicts with core.bare
+
+8. If GIT_DIR is set but neither worktree nor bare setting is given,
+   original cwd becomes worktree.
+
+9. If .git discovery is done inside a repo, the repo becomes a bare
+   repo. .git discovery is performed if GIT_DIR is not set.
+
+10. If no worktree is available, cwd remains unchanged, prefix is
+    NULL.
+
+11. When user's cwd is outside worktree, cwd remains unchanged,
+    prefix is NULL.
+"
+. ./test-lib.sh
+
+here=$(pwd)
+
+test_repo () {
+       (
+               cd "$1" &&
+               if test -n "$2"
+               then
+                       GIT_DIR="$2" &&
+                       export GIT_DIR
+               fi &&
+               if test -n "$3"
+               then
+                       GIT_WORK_TREE="$3" &&
+                       export GIT_WORK_TREE
+               fi &&
+               rm -f trace &&
+               GIT_TRACE="$(pwd)/trace" git symbolic-ref HEAD >/dev/null &&
+               grep '^setup: ' trace >result &&
+               test_cmp expected result
+       )
+}
+
+maybe_config () {
+       file=$1 var=$2 value=$3 &&
+       if test "$value" != unset
+       then
+               git config --file="$file" "$var" "$value"
+       fi
+}
+
+setup_repo () {
+       name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 &&
+       sane_unset GIT_DIR GIT_WORK_TREE &&
+
+       git init "$name" &&
+       maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
+       maybe_config "$name/.git/config" core.bare "$barecfg" &&
+       mkdir -p "$name/sub/sub" &&
+
+       if test "${gitfile:+set}"
+       then
+               mv "$name/.git" "$name.git" &&
+               echo "gitdir: ../$name.git" >"$name/.git"
+       fi
+}
+
+maybe_set () {
+       var=$1 value=$2 &&
+       if test "$value" != unset
+       then
+               eval "$var=\$value" &&
+               export $var
+       fi
+}
+
+setup_env () {
+       worktreenv=$1 gitdirenv=$2 &&
+       sane_unset GIT_DIR GIT_WORK_TREE &&
+       maybe_set GIT_DIR "$gitdirenv" &&
+       maybe_set GIT_WORK_TREE "$worktreeenv"
+}
+
+expect () {
+       cat >"$1/expected" <<-EOF
+       setup: git_dir: $2
+       setup: worktree: $3
+       setup: cwd: $4
+       setup: prefix: $5
+       EOF
+}
+
+try_case () {
+       name=$1 worktreeenv=$2 gitdirenv=$3 &&
+       setup_env "$worktreeenv" "$gitdirenv" &&
+       expect "$name" "$4" "$5" "$6" "$7" &&
+       test_repo "$name"
+}
+
+run_wt_tests () {
+       N=$1 gitfile=$2
+
+       absgit="$here/$N/.git"
+       dotgit=.git
+       dotdotgit=../../.git
+
+       if test "$gitfile"
+       then
+               absgit="$here/$N.git"
+               dotgit=$absgit dotdotgit=$absgit
+       fi
+
+       test_expect_success "#$N: explicit GIT_WORK_TREE and GIT_DIR at toplevel" '
+               try_case $N "$here/$N" .git \
+                       "$dotgit" "$here/$N" "$here/$N" "(null)" &&
+               try_case $N . .git \
+                       "$dotgit" "$here/$N" "$here/$N" "(null)" &&
+               try_case $N "$here/$N" "$here/$N/.git" \
+                       "$absgit" "$here/$N" "$here/$N" "(null)" &&
+               try_case $N . "$here/$N/.git" \
+                       "$absgit" "$here/$N" "$here/$N" "(null)"
+       '
+
+       test_expect_success "#$N: explicit GIT_WORK_TREE and GIT_DIR in subdir" '
+               try_case $N/sub/sub "$here/$N" ../../.git \
+                       "$absgit" "$here/$N" "$here/$N" sub/sub/ &&
+               try_case $N/sub/sub ../.. ../../.git \
+                       "$absgit" "$here/$N" "$here/$N" sub/sub/ &&
+               try_case $N/sub/sub "$here/$N" "$here/$N/.git" \
+                       "$absgit" "$here/$N" "$here/$N" sub/sub/ &&
+               try_case $N/sub/sub ../.. "$here/$N/.git" \
+                       "$absgit" "$here/$N" "$here/$N" sub/sub/
+       '
+
+       test_expect_success "#$N: explicit GIT_WORK_TREE from parent of worktree" '
+               try_case $N "$here/$N/wt" .git \
+                       "$dotgit" "$here/$N/wt" "$here/$N" "(null)" &&
+               try_case $N wt .git \
+                       "$dotgit" "$here/$N/wt" "$here/$N" "(null)" &&
+               try_case $N wt "$here/$N/.git" \
+                       "$absgit" "$here/$N/wt" "$here/$N" "(null)" &&
+               try_case $N "$here/$N/wt" "$here/$N/.git" \
+                       "$absgit" "$here/$N/wt" "$here/$N" "(null)"
+       '
+
+       test_expect_success "#$N: explicit GIT_WORK_TREE from nephew of worktree" '
+               try_case $N/sub/sub "$here/$N/wt" ../../.git \
+                       "$dotdotgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" &&
+               try_case $N/sub/sub ../../wt ../../.git \
+                       "$dotdotgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" &&
+               try_case $N/sub/sub ../../wt "$here/$N/.git" \
+                       "$absgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" &&
+               try_case $N/sub/sub "$here/$N/wt" "$here/$N/.git" \
+                       "$absgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)"
+       '
+
+       test_expect_success "#$N: chdir_to_toplevel uses worktree, not git dir" '
+               try_case $N "$here" .git \
+                       "$absgit" "$here" "$here" $N/ &&
+               try_case $N .. .git \
+                       "$absgit" "$here" "$here" $N/ &&
+               try_case $N .. "$here/$N/.git" \
+                       "$absgit" "$here" "$here" $N/ &&
+               try_case $N "$here" "$here/$N/.git" \
+                       "$absgit" "$here" "$here" $N/
+       '
+
+       test_expect_success "#$N: chdir_to_toplevel uses worktree (from subdir)" '
+               try_case $N/sub/sub "$here" ../../.git \
+                       "$absgit" "$here" "$here" $N/sub/sub/ &&
+               try_case $N/sub/sub ../../.. ../../.git \
+                       "$absgit" "$here" "$here" $N/sub/sub/ &&
+               try_case $N/sub/sub ../../../ "$here/$N/.git" \
+                       "$absgit" "$here" "$here" $N/sub/sub/ &&
+               try_case $N/sub/sub "$here" "$here/$N/.git" \
+                       "$absgit" "$here" "$here" $N/sub/sub/
+       '
+}
+
+# try_repo #c GIT_WORK_TREE GIT_DIR core.worktree .gitfile? core.bare \
+#      (git dir) (work tree) (cwd) (prefix) \  <-- at toplevel
+#      (git dir) (work tree) (cwd) (prefix)    <-- from subdir
+try_repo () {
+       name=$1 worktreeenv=$2 gitdirenv=$3 &&
+       setup_repo "$name" "$4" "$5" "$6" &&
+       shift 6 &&
+       try_case "$name" "$worktreeenv" "$gitdirenv" \
+               "$1" "$2" "$3" "$4" &&
+       shift 4 &&
+       case "$gitdirenv" in
+       /* | ?:/* | unset) ;;
+       *)
+               gitdirenv=../$gitdirenv ;;
+       esac &&
+       try_case "$name/sub" "$worktreeenv" "$gitdirenv" \
+               "$1" "$2" "$3" "$4"
+}
+
+# Bit 0 = GIT_WORK_TREE
+# Bit 1 = GIT_DIR
+# Bit 2 = core.worktree
+# Bit 3 = .git is a file
+# Bit 4 = bare repo
+# Case# = encoding of the above 5 bits
+
+test_expect_success '#0: nonbare repo, no explicit configuration' '
+       try_repo 0 unset unset unset "" unset \
+               .git "$here/0" "$here/0" "(null)" \
+               .git "$here/0" "$here/0" sub/ 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#1: GIT_WORK_TREE without explicit GIT_DIR is accepted' '
+       mkdir -p wt &&
+       try_repo 1 "$here" unset unset "" unset \
+               "$here/1/.git" "$here" "$here" 1/ \
+               "$here/1/.git" "$here" "$here" 1/sub/ 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#2: worktree defaults to cwd with explicit GIT_DIR' '
+       try_repo 2 unset "$here/2/.git" unset "" unset \
+               "$here/2/.git" "$here/2" "$here/2" "(null)" \
+               "$here/2/.git" "$here/2/sub" "$here/2/sub" "(null)"
+'
+
+test_expect_success '#2b: relative GIT_DIR' '
+       try_repo 2b unset ".git" unset "" unset \
+               ".git" "$here/2b" "$here/2b" "(null)" \
+               "../.git" "$here/2b/sub" "$here/2b/sub" "(null)"
+'
+
+test_expect_success '#3: setup' '
+       setup_repo 3 unset "" unset &&
+       mkdir -p 3/sub/sub 3/wt/sub
+'
+run_wt_tests 3
+
+test_expect_success '#4: core.worktree without GIT_DIR set is accepted' '
+       setup_repo 4 ../sub "" unset &&
+       mkdir -p 4/sub sub &&
+       try_case 4 unset unset \
+               .git "$here/4/sub" "$here/4" "(null)" \
+               "$here/4/.git" "$here/4/sub" "$here/4/sub" "(null)" 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#5: core.worktree + GIT_WORK_TREE is accepted' '
+       # or: you cannot intimidate away the lack of GIT_DIR setting
+       try_repo 5 "$here" unset "$here/5" "" unset \
+               "$here/5/.git" "$here" "$here" 5/ \
+               "$here/5/.git" "$here" "$here" 5/sub/ 2>message &&
+       try_repo 5a .. unset "$here/5a" "" unset \
+               "$here/5a/.git" "$here" "$here" 5a/ \
+               "$here/5a/.git" "$here/5a" "$here/5a" sub/ &&
+       ! test -s message
+'
+
+test_expect_success '#6: setting GIT_DIR brings core.worktree to life' '
+       setup_repo 6 "$here/6" "" unset &&
+       try_case 6 unset .git \
+               .git "$here/6" "$here/6" "(null)" &&
+       try_case 6 unset "$here/6/.git" \
+               "$here/6/.git" "$here/6" "$here/6" "(null)" &&
+       try_case 6/sub/sub unset ../../.git \
+               "$here/6/.git" "$here/6" "$here/6" sub/sub/ &&
+       try_case 6/sub/sub unset "$here/6/.git" \
+               "$here/6/.git" "$here/6" "$here/6" sub/sub/
+'
+
+test_expect_success '#6b: GIT_DIR set, core.worktree relative' '
+       setup_repo 6b .. "" unset &&
+       try_case 6b unset .git \
+               .git "$here/6b" "$here/6b" "(null)" &&
+       try_case 6b unset "$here/6b/.git" \
+               "$here/6b/.git" "$here/6b" "$here/6b" "(null)" &&
+       try_case 6b/sub/sub unset ../../.git \
+               "$here/6b/.git" "$here/6b" "$here/6b" sub/sub/ &&
+       try_case 6b/sub/sub unset "$here/6b/.git" \
+               "$here/6b/.git" "$here/6b" "$here/6b" sub/sub/
+'
+
+test_expect_success '#6c: GIT_DIR set, core.worktree=../wt (absolute)' '
+       setup_repo 6c "$here/6c/wt" "" unset &&
+       mkdir -p 6c/wt/sub &&
+
+       try_case 6c unset .git \
+               .git "$here/6c/wt" "$here/6c" "(null)" &&
+       try_case 6c unset "$here/6c/.git" \
+               "$here/6c/.git" "$here/6c/wt" "$here/6c" "(null)" &&
+       try_case 6c/sub/sub unset ../../.git \
+               ../../.git "$here/6c/wt" "$here/6c/sub/sub" "(null)" &&
+       try_case 6c/sub/sub unset "$here/6c/.git" \
+               "$here/6c/.git" "$here/6c/wt" "$here/6c/sub/sub" "(null)"
+'
+
+test_expect_success '#6d: GIT_DIR set, core.worktree=../wt (relative)' '
+       setup_repo 6d "$here/6d/wt" "" unset &&
+       mkdir -p 6d/wt/sub &&
+
+       try_case 6d unset .git \
+               .git "$here/6d/wt" "$here/6d" "(null)" &&
+       try_case 6d unset "$here/6d/.git" \
+               "$here/6d/.git" "$here/6d/wt" "$here/6d" "(null)" &&
+       try_case 6d/sub/sub unset ../../.git \
+               ../../.git "$here/6d/wt" "$here/6d/sub/sub" "(null)" &&
+       try_case 6d/sub/sub unset "$here/6d/.git" \
+               "$here/6d/.git" "$here/6d/wt" "$here/6d/sub/sub" "(null)"
+'
+
+test_expect_success '#6e: GIT_DIR set, core.worktree=../.. (absolute)' '
+       setup_repo 6e "$here" "" unset &&
+       try_case 6e unset .git \
+               "$here/6e/.git" "$here" "$here" 6e/ &&
+       try_case 6e unset "$here/6e/.git" \
+               "$here/6e/.git" "$here" "$here" 6e/ &&
+       try_case 6e/sub/sub unset ../../.git \
+               "$here/6e/.git" "$here" "$here" 6e/sub/sub/ &&
+       try_case 6e/sub/sub unset "$here/6e/.git" \
+               "$here/6e/.git" "$here" "$here" 6e/sub/sub/
+'
+
+test_expect_success '#6f: GIT_DIR set, core.worktree=../.. (relative)' '
+       setup_repo 6f ../../ "" unset &&
+       try_case 6f unset .git \
+               "$here/6f/.git" "$here" "$here" 6f/ &&
+       try_case 6f unset "$here/6f/.git" \
+               "$here/6f/.git" "$here" "$here" 6f/ &&
+       try_case 6f/sub/sub unset ../../.git \
+               "$here/6f/.git" "$here" "$here" 6f/sub/sub/ &&
+       try_case 6f/sub/sub unset "$here/6f/.git" \
+               "$here/6f/.git" "$here" "$here" 6f/sub/sub/
+'
+
+# case #7: GIT_WORK_TREE overrides core.worktree.
+test_expect_success '#7: setup' '
+       setup_repo 7 non-existent "" unset &&
+       mkdir -p 7/sub/sub 7/wt/sub
+'
+run_wt_tests 7
+
+test_expect_success '#8: gitfile, easy case' '
+       try_repo 8 unset unset unset gitfile unset \
+               "$here/8.git" "$here/8" "$here/8" "(null)" \
+               "$here/8.git" "$here/8" "$here/8" sub/
+'
+
+test_expect_success '#9: GIT_WORK_TREE accepted with gitfile' '
+       mkdir -p 9/wt &&
+       try_repo 9 wt unset unset gitfile unset \
+               "$here/9.git" "$here/9/wt" "$here/9" "(null)" \
+               "$here/9.git" "$here/9/sub/wt" "$here/9/sub" "(null)" 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#10: GIT_DIR can point to gitfile' '
+       try_repo 10 unset "$here/10/.git" unset gitfile unset \
+               "$here/10.git" "$here/10" "$here/10" "(null)" \
+               "$here/10.git" "$here/10/sub" "$here/10/sub" "(null)"
+'
+
+test_expect_success '#10b: relative GIT_DIR can point to gitfile' '
+       try_repo 10b unset .git unset gitfile unset \
+               "$here/10b.git" "$here/10b" "$here/10b" "(null)" \
+               "$here/10b.git" "$here/10b/sub" "$here/10b/sub" "(null)"
+'
+
+# case #11: GIT_WORK_TREE works, gitfile case.
+test_expect_success '#11: setup' '
+       setup_repo 11 unset gitfile unset &&
+       mkdir -p 11/sub/sub 11/wt/sub
+'
+run_wt_tests 11 gitfile
+
+test_expect_success '#12: core.worktree with gitfile is accepted' '
+       try_repo 12 unset unset "$here/12" gitfile unset \
+               "$here/12.git" "$here/12" "$here/12" "(null)" \
+               "$here/12.git" "$here/12" "$here/12" sub/ 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#13: core.worktree+GIT_WORK_TREE accepted (with gitfile)' '
+       # or: you cannot intimidate away the lack of GIT_DIR setting
+       try_repo 13 non-existent-too unset non-existent gitfile unset \
+               "$here/13.git" "$here/13/non-existent-too" "$here/13" "(null)" \
+               "$here/13.git" "$here/13/sub/non-existent-too" "$here/13/sub" "(null)" 2>message &&
+       ! test -s message
+'
+
+# case #14.
+# If this were more table-driven, it could share code with case #6.
+
+test_expect_success '#14: core.worktree with GIT_DIR pointing to gitfile' '
+       setup_repo 14 "$here/14" gitfile unset &&
+       try_case 14 unset .git \
+               "$here/14.git" "$here/14" "$here/14" "(null)" &&
+       try_case 14 unset "$here/14/.git" \
+               "$here/14.git" "$here/14" "$here/14" "(null)" &&
+       try_case 14/sub/sub unset ../../.git \
+               "$here/14.git" "$here/14" "$here/14" sub/sub/ &&
+       try_case 14/sub/sub unset "$here/14/.git" \
+               "$here/14.git" "$here/14" "$here/14" sub/sub/ &&
+
+       setup_repo 14c "$here/14c/wt" gitfile unset &&
+       mkdir -p 14c/wt/sub &&
+
+       try_case 14c unset .git \
+               "$here/14c.git" "$here/14c/wt" "$here/14c" "(null)" &&
+       try_case 14c unset "$here/14c/.git" \
+               "$here/14c.git" "$here/14c/wt" "$here/14c" "(null)" &&
+       try_case 14c/sub/sub unset ../../.git \
+               "$here/14c.git" "$here/14c/wt" "$here/14c/sub/sub" "(null)" &&
+       try_case 14c/sub/sub unset "$here/14c/.git" \
+               "$here/14c.git" "$here/14c/wt" "$here/14c/sub/sub" "(null)" &&
+
+       setup_repo 14d "$here/14d/wt" gitfile unset &&
+       mkdir -p 14d/wt/sub &&
+
+       try_case 14d unset .git \
+               "$here/14d.git" "$here/14d/wt" "$here/14d" "(null)" &&
+       try_case 14d unset "$here/14d/.git" \
+               "$here/14d.git" "$here/14d/wt" "$here/14d" "(null)" &&
+       try_case 14d/sub/sub unset ../../.git \
+               "$here/14d.git" "$here/14d/wt" "$here/14d/sub/sub" "(null)" &&
+       try_case 14d/sub/sub unset "$here/14d/.git" \
+               "$here/14d.git" "$here/14d/wt" "$here/14d/sub/sub" "(null)" &&
+
+       setup_repo 14e "$here" gitfile unset &&
+       try_case 14e unset .git \
+               "$here/14e.git" "$here" "$here" 14e/ &&
+       try_case 14e unset "$here/14e/.git" \
+               "$here/14e.git" "$here" "$here" 14e/ &&
+       try_case 14e/sub/sub unset ../../.git \
+               "$here/14e.git" "$here" "$here" 14e/sub/sub/ &&
+       try_case 14e/sub/sub unset "$here/14e/.git" \
+               "$here/14e.git" "$here" "$here" 14e/sub/sub/
+'
+
+test_expect_success '#14b: core.worktree is relative to actual git dir' '
+       setup_repo 14b ../14b gitfile unset &&
+       try_case 14b unset .git \
+               "$here/14b.git" "$here/14b" "$here/14b" "(null)" &&
+       try_case 14b unset "$here/14b/.git" \
+               "$here/14b.git" "$here/14b" "$here/14b" "(null)" &&
+       try_case 14b/sub/sub unset ../../.git \
+               "$here/14b.git" "$here/14b" "$here/14b" sub/sub/ &&
+       try_case 14b/sub/sub unset "$here/14b/.git" \
+               "$here/14b.git" "$here/14b" "$here/14b" sub/sub/ &&
+
+       setup_repo 14f ../ gitfile unset &&
+       try_case 14f unset .git \
+               "$here/14f.git" "$here" "$here" 14f/ &&
+       try_case 14f unset "$here/14f/.git" \
+               "$here/14f.git" "$here" "$here" 14f/ &&
+       try_case 14f/sub/sub unset ../../.git \
+               "$here/14f.git" "$here" "$here" 14f/sub/sub/ &&
+       try_case 14f/sub/sub unset "$here/14f/.git" \
+               "$here/14f.git" "$here" "$here" 14f/sub/sub/
+'
+
+# case #15: GIT_WORK_TREE overrides core.worktree (gitfile case).
+test_expect_success '#15: setup' '
+       setup_repo 15 non-existent gitfile unset &&
+       mkdir -p 15/sub/sub 15/wt/sub
+'
+run_wt_tests 15 gitfile
+
+test_expect_success '#16a: implicitly bare repo (cwd inside .git dir)' '
+       setup_repo 16a unset "" unset &&
+       mkdir -p 16a/.git/wt/sub &&
+
+       try_case 16a/.git unset unset \
+               . "(null)" "$here/16a/.git" "(null)" &&
+       try_case 16a/.git/wt unset unset \
+               "$here/16a/.git" "(null)" "$here/16a/.git/wt" "(null)" &&
+       try_case 16a/.git/wt/sub unset unset \
+               "$here/16a/.git" "(null)" "$here/16a/.git/wt/sub" "(null)"
+'
+
+test_expect_success '#16b: bare .git (cwd inside .git dir)' '
+       setup_repo 16b unset "" true &&
+       mkdir -p 16b/.git/wt/sub &&
+
+       try_case 16b/.git unset unset \
+               . "(null)" "$here/16b/.git" "(null)" &&
+       try_case 16b/.git/wt unset unset \
+               "$here/16b/.git" "(null)" "$here/16b/.git/wt" "(null)" &&
+       try_case 16b/.git/wt/sub unset unset \
+               "$here/16b/.git" "(null)" "$here/16b/.git/wt/sub" "(null)"
+'
+
+test_expect_success '#16c: bare .git has no worktree' '
+       try_repo 16c unset unset unset "" true \
+               .git "(null)" "$here/16c" "(null)" \
+               "$here/16c/.git" "(null)" "$here/16c/sub" "(null)"
+'
+
+test_expect_success '#17: GIT_WORK_TREE without explicit GIT_DIR is accepted (bare case)' '
+       # Just like #16.
+       setup_repo 17a unset "" true &&
+       setup_repo 17b unset "" true &&
+       mkdir -p 17a/.git/wt/sub &&
+       mkdir -p 17b/.git/wt/sub &&
+
+       try_case 17a/.git "$here/17a" unset \
+               "$here/17a/.git" "$here/17a" "$here/17a" .git/ \
+               2>message &&
+       try_case 17a/.git/wt "$here/17a" unset \
+               "$here/17a/.git" "$here/17a" "$here/17a" .git/wt/ &&
+       try_case 17a/.git/wt/sub "$here/17a" unset \
+               "$here/17a/.git" "$here/17a" "$here/17a" .git/wt/sub/ &&
+
+       try_case 17b/.git "$here/17b" unset \
+               "$here/17b/.git" "$here/17b" "$here/17b" .git/ &&
+       try_case 17b/.git/wt "$here/17b" unset \
+               "$here/17b/.git" "$here/17b" "$here/17b" .git/wt/ &&
+       try_case 17b/.git/wt/sub "$here/17b" unset \
+               "$here/17b/.git" "$here/17b" "$here/17b" .git/wt/sub/ &&
+
+       try_repo 17c "$here/17c" unset unset "" true \
+               .git "$here/17c" "$here/17c" "(null)" \
+               "$here/17c/.git" "$here/17c" "$here/17c" sub/ 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#18: bare .git named by GIT_DIR has no worktree' '
+       try_repo 18 unset .git unset "" true \
+               .git "(null)" "$here/18" "(null)" \
+               ../.git "(null)" "$here/18/sub" "(null)" &&
+       try_repo 18b unset "$here/18b/.git" unset "" true \
+               "$here/18b/.git" "(null)" "$here/18b" "(null)" \
+               "$here/18b/.git" "(null)" "$here/18b/sub" "(null)"
+'
+
+# Case #19: GIT_DIR + GIT_WORK_TREE suppresses bareness.
+test_expect_success '#19: setup' '
+       setup_repo 19 unset "" true &&
+       mkdir -p 19/sub/sub 19/wt/sub
+'
+run_wt_tests 19
+
+test_expect_success '#20a: core.worktree without GIT_DIR accepted (inside .git)' '
+       # Unlike case #16a.
+       setup_repo 20a "$here/20a" "" unset &&
+       mkdir -p 20a/.git/wt/sub &&
+       try_case 20a/.git unset unset \
+               "$here/20a/.git" "$here/20a" "$here/20a" .git/ 2>message &&
+       try_case 20a/.git/wt unset unset \
+               "$here/20a/.git" "$here/20a" "$here/20a" .git/wt/ &&
+       try_case 20a/.git/wt/sub unset unset \
+               "$here/20a/.git" "$here/20a" "$here/20a" .git/wt/sub/ &&
+       ! test -s message
+'
+
+test_expect_success '#20b/c: core.worktree and core.bare conflict' '
+       setup_repo 20b non-existent "" true &&
+       mkdir -p 20b/.git/wt/sub &&
+       (
+               cd 20b/.git &&
+               test_must_fail git symbolic-ref HEAD >/dev/null
+       ) 2>message &&
+       grep "core.bare and core.worktree" message
+'
+
+# Case #21: core.worktree/GIT_WORK_TREE overrides core.bare' '
+test_expect_success '#21: setup, core.worktree warns before overriding core.bare' '
+       setup_repo 21 non-existent "" unset &&
+       mkdir -p 21/.git/wt/sub &&
+       (
+               cd 21/.git &&
+               GIT_WORK_TREE="$here/21" &&
+               export GIT_WORK_TREE &&
+               git symbolic-ref HEAD >/dev/null
+       ) 2>message &&
+       ! test -s message
+
+'
+run_wt_tests 21
+
+test_expect_success '#22a: core.worktree = GIT_DIR = .git dir' '
+       # like case #6.
+
+       setup_repo 22a "$here/22a/.git" "" unset &&
+       setup_repo 22ab . "" unset
+       mkdir -p 22a/.git/sub 22a/sub &&
+       mkdir -p 22ab/.git/sub 22ab/sub &&
+       try_case 22a/.git unset . \
+               . "$here/22a/.git" "$here/22a/.git" "(null)" &&
+       try_case 22a/.git unset "$here/22a/.git" \
+               "$here/22a/.git" "$here/22a/.git" "$here/22a/.git" "(null)" &&
+       try_case 22a/.git/sub unset .. \
+               "$here/22a/.git" "$here/22a/.git" "$here/22a/.git" sub/ &&
+       try_case 22a/.git/sub unset "$here/22a/.git" \
+               "$here/22a/.git" "$here/22a/.git" "$here/22a/.git" sub/ &&
+
+       try_case 22ab/.git unset . \
+               . "$here/22ab/.git" "$here/22ab/.git" "(null)" &&
+       try_case 22ab/.git unset "$here/22ab/.git" \
+               "$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" "(null)" &&
+       try_case 22ab/.git/sub unset .. \
+               "$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" sub/ &&
+       try_case 22ab/.git unset "$here/22ab/.git" \
+               "$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" "(null)"
+'
+
+test_expect_success '#22b: core.worktree child of .git, GIT_DIR=.git' '
+       setup_repo 22b "$here/22b/.git/wt" "" unset &&
+       setup_repo 22bb wt "" unset &&
+       mkdir -p 22b/.git/sub 22b/sub 22b/.git/wt/sub 22b/wt/sub &&
+       mkdir -p 22bb/.git/sub 22bb/sub 22bb/.git/wt 22bb/wt &&
+
+       try_case 22b/.git unset . \
+               . "$here/22b/.git/wt" "$here/22b/.git" "(null)" &&
+       try_case 22b/.git unset "$here/22b/.git" \
+               "$here/22b/.git" "$here/22b/.git/wt" "$here/22b/.git" "(null)" &&
+       try_case 22b/.git/sub unset .. \
+               .. "$here/22b/.git/wt" "$here/22b/.git/sub" "(null)" &&
+       try_case 22b/.git/sub unset "$here/22b/.git" \
+               "$here/22b/.git" "$here/22b/.git/wt" "$here/22b/.git/sub" "(null)" &&
+
+       try_case 22bb/.git unset . \
+               . "$here/22bb/.git/wt" "$here/22bb/.git" "(null)" &&
+       try_case 22bb/.git unset "$here/22bb/.git" \
+               "$here/22bb/.git" "$here/22bb/.git/wt" "$here/22bb/.git" "(null)" &&
+       try_case 22bb/.git/sub unset .. \
+               .. "$here/22bb/.git/wt" "$here/22bb/.git/sub" "(null)" &&
+       try_case 22bb/.git/sub unset "$here/22bb/.git" \
+               "$here/22bb/.git" "$here/22bb/.git/wt" "$here/22bb/.git/sub" "(null)"
+'
+
+test_expect_success '#22c: core.worktree = .git/.., GIT_DIR=.git' '
+       setup_repo 22c "$here/22c" "" unset &&
+       setup_repo 22cb .. "" unset &&
+       mkdir -p 22c/.git/sub 22c/sub &&
+       mkdir -p 22cb/.git/sub 22cb/sub &&
+
+       try_case 22c/.git unset . \
+               "$here/22c/.git" "$here/22c" "$here/22c" .git/ &&
+       try_case 22c/.git unset "$here/22c/.git" \
+               "$here/22c/.git" "$here/22c" "$here/22c" .git/ &&
+       try_case 22c/.git/sub unset .. \
+               "$here/22c/.git" "$here/22c" "$here/22c" .git/sub/ &&
+       try_case 22c/.git/sub unset "$here/22c/.git" \
+               "$here/22c/.git" "$here/22c" "$here/22c" .git/sub/ &&
+
+       try_case 22cb/.git unset . \
+               "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/ &&
+       try_case 22cb/.git unset "$here/22cb/.git" \
+               "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/ &&
+       try_case 22cb/.git/sub unset .. \
+               "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/sub/ &&
+       try_case 22cb/.git/sub unset "$here/22cb/.git" \
+               "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/sub/
+'
+
+test_expect_success '#22.2: core.worktree and core.bare conflict' '
+       setup_repo 22 "$here/22" "" true &&
+       (
+               cd 22/.git &&
+               GIT_DIR=. &&
+               export GIT_DIR &&
+               test_must_fail git symbolic-ref HEAD 2>result
+       ) &&
+       (
+               cd 22 &&
+               GIT_DIR=.git &&
+               export GIT_DIR &&
+               test_must_fail git symbolic-ref HEAD 2>result
+       ) &&
+       grep "core.bare and core.worktree" 22/.git/result &&
+       grep "core.bare and core.worktree" 22/result
+'
+
+# Case #23: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses bareness.
+test_expect_success '#23: setup' '
+       setup_repo 23 non-existent "" true &&
+       mkdir -p 23/sub/sub 23/wt/sub
+'
+run_wt_tests 23
+
+test_expect_success '#24: bare repo has no worktree (gitfile case)' '
+       try_repo 24 unset unset unset gitfile true \
+               "$here/24.git" "(null)" "$here/24" "(null)" \
+               "$here/24.git" "(null)" "$here/24/sub" "(null)"
+'
+
+test_expect_success '#25: GIT_WORK_TREE accepted if GIT_DIR unset (bare gitfile case)' '
+       try_repo 25 "$here/25" unset unset gitfile true \
+               "$here/25.git" "$here/25" "$here/25" "(null)"  \
+               "$here/25.git" "$here/25" "$here/25" "sub/" 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#26: bare repo has no worktree (GIT_DIR -> gitfile case)' '
+       try_repo 26 unset "$here/26/.git" unset gitfile true \
+               "$here/26.git" "(null)" "$here/26" "(null)" \
+               "$here/26.git" "(null)" "$here/26/sub" "(null)" &&
+       try_repo 26b unset .git unset gitfile true \
+               "$here/26b.git" "(null)" "$here/26b" "(null)" \
+               "$here/26b.git" "(null)" "$here/26b/sub" "(null)"
+'
+
+# Case #27: GIT_DIR + GIT_WORK_TREE suppresses bareness (with gitfile).
+test_expect_success '#27: setup' '
+       setup_repo 27 unset gitfile true &&
+       mkdir -p 27/sub/sub 27/wt/sub
+'
+run_wt_tests 27 gitfile
+
+test_expect_success '#28: core.worktree and core.bare conflict (gitfile case)' '
+       setup_repo 28 "$here/28" gitfile true &&
+       (
+               cd 28 &&
+               test_must_fail git symbolic-ref HEAD
+       ) 2>message &&
+       ! grep "^warning:" message &&
+       grep "core.bare and core.worktree" message
+'
+
+# Case #29: GIT_WORK_TREE(+core.worktree) overrides core.bare (gitfile case).
+test_expect_success '#29: setup' '
+       setup_repo 29 non-existent gitfile true &&
+       mkdir -p 29/sub/sub 29/wt/sub
+       (
+               cd 29 &&
+               GIT_WORK_TREE="$here/29" &&
+               export GIT_WORK_TREE &&
+               git symbolic-ref HEAD >/dev/null
+       ) 2>message &&
+       ! test -s message
+'
+run_wt_tests 29 gitfile
+
+test_expect_success '#30: core.worktree and core.bare conflict (gitfile version)' '
+       # Just like case #22.
+       setup_repo 30 "$here/30" gitfile true &&
+       (
+               cd 30 &&
+               GIT_DIR=.git &&
+               export GIT_DIR &&
+               test_must_fail git symbolic-ref HEAD 2>result
+       ) &&
+       grep "core.bare and core.worktree" 30/result
+'
+
+# Case #31: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses
+# bareness (gitfile version).
+test_expect_success '#31: setup' '
+       setup_repo 31 non-existent gitfile true &&
+       mkdir -p 31/sub/sub 31/wt/sub
+'
+run_wt_tests 31 gitfile
+
+test_done
index 796f616abf17f40e59212b7abb80867f851baa55..2b17311cb0870ea210d9b5cbe167363d13641d67 100755 (executable)
@@ -13,16 +13,19 @@ test_description='merge-recursive options
 
 . ./test-lib.sh
 
+test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b
+test_have_prereq MINGW && export GREP_OPTIONS=-U
+
 test_expect_success 'setup' '
        conflict_hunks () {
-               sed -n -e "
-                       /^<<<</ b inconflict
+               sed $SED_OPTIONS -n -e "
+                       /^<<<</ b conflict
                        b
-                       : inconflict
+                       : conflict
                        p
                        /^>>>>/ b
                        n
-                       b inconflict
+                       b conflict
                " "$@"
        } &&
 
index dc2e04a0161c8d6b3f6eefc1873852a377a26393..1921ca3a73370d378e6aedd0820fd8d2a030da03 100755 (executable)
@@ -1067,7 +1067,7 @@ test_expect_success 'git notes copy diagnoses too many or too few parameters' '
 
 test_expect_success 'git notes get-ref (no overrides)' '
        git config --unset core.notesRef &&
-       unset GIT_NOTES_REF &&
+       sane_unset GIT_NOTES_REF &&
        test "$(git notes get-ref)" = "refs/notes/commits"
 '
 
index d3a3bd2679e061ce391930d2b59831aa7610926f..7d8147bb93df482cf7e11338ac96acdf43cf551e 100755 (executable)
@@ -71,8 +71,9 @@ test_expect_success 'setup' '
 # "exec" commands are ran with the user shell by default, but this may
 # be non-POSIX. For example, if SHELL=zsh then ">file" doesn't work
 # to create a file. Unseting SHELL avoids such non-portable behavior
-# in tests.
+# in tests. It must be exported for it to take effect where needed.
 SHELL=
+export SHELL
 
 test_expect_success 'rebase -i with the exec command' '
        git checkout master &&
index 948ca1bce66cab317bf74984b22384f2625418c1..df921d1f33df34dd2b2631580f8d53b18270662a 100755 (executable)
@@ -3,12 +3,14 @@
 test_description='Test cherry-pick with directory/file conflicts'
 . ./test-lib.sh
 
-test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' '
+test_expect_success 'Initialize repository' '
        mkdir a &&
        >a/f &&
        git add a &&
-       git commit -m a &&
+       git commit -m a
+'
 
+test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' '
        mkdir b &&
        ln -s ../a b/a &&
        git add b &&
index 9a665205884fcdb1c5888558d6edf960e335e013..b8f81d07c33d3596fef5f5a361f4774d5e357fca 100755 (executable)
@@ -290,4 +290,15 @@ test_expect_success 'log -S requires an argument' '
        test_must_fail git log -S
 '
 
+test_expect_success 'diff --cached on unborn branch' '
+       echo ref: refs/heads/unborn >.git/HEAD &&
+       git diff --cached >result &&
+       test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--cached" result
+'
+
+test_expect_success 'diff --cached -- file on unborn branch' '
+       git diff --cached -- file0 >result &&
+       test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--cached_--_file0" result
+'
+
 test_done
diff --git a/t/t4013/diff.diff_--cached b/t/t4013/diff.diff_--cached
new file mode 100644 (file)
index 0000000..ff16e83
--- /dev/null
@@ -0,0 +1,38 @@
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..992913c
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,8 @@
++A
++B
++C
++D
++E
++F
++1
++2
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..10a8a9f
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,9 @@
++1
++2
++3
++4
++5
++6
++A
++B
++C
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
diff --git a/t/t4013/diff.diff_--cached_--_file0 b/t/t4013/diff.diff_--cached_--_file0
new file mode 100644 (file)
index 0000000..b9bb858
--- /dev/null
@@ -0,0 +1,15 @@
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..10a8a9f
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,9 @@
++1
++2
++3
++4
++5
++6
++A
++B
++C
index 0a61b57b5f6f00ae4c0734a34ce45c0ba1fcf098..364693062399228cd6a18b52a21db173519d8e94 100755 (executable)
@@ -32,7 +32,7 @@ EOF
 
 sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
 
-builtin_patterns="bibtex cpp csharp fortran html java objc pascal php python ruby tex"
+builtin_patterns="bibtex cpp csharp fortran html java objc pascal perl php python ruby tex"
 for p in $builtin_patterns
 do
        test_expect_success "builtin $p pattern compiles" '
index 579c9e61054521301464bfc31351040d45966836..a33d510bf6b27a6bb2c640cfc9d11f462cbdf7a6 100755 (executable)
@@ -6,6 +6,7 @@
 test_description='git apply -p handling.'
 
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh
 
 test_expect_success setup '
        mkdir sub &&
@@ -62,8 +63,12 @@ test_expect_success 'apply (-p2) diff, mode change only' '
        old mode 100644
        new mode 100755
        EOF
-       chmod 644 file1 &&
-       git apply -p2 patch.chmod &&
+       test_chmod -x file1 &&
+       git apply --index -p2 patch.chmod &&
+       case $(git ls-files -s file1) in 100755*) : good;; *) false;; esac
+'
+
+test_expect_success FILEMODE 'file mode was changed' '
        test -x file1
 '
 
index 552da65a61e8f78d40f8e19cfc5b73696ebcf283..baa670cea5d8a9d8b4b4578de69917fe76f71d46 100755 (executable)
@@ -10,7 +10,11 @@ test_expect_success 'setup' '
        test_commit A foo A &&
        test_commit B foo B &&
        test_commit C foo C &&
-       test_commit D foo D
+       test_commit D foo D &&
+       git checkout A^0 &&
+       test_commit E bar E &&
+       test_commit F foo F &&
+       git checkout master
 '
 
 mkdir .git/hooks
@@ -79,6 +83,18 @@ EOF
        verify_hook_input
 '
 
+test_expect_success 'git rebase --skip the last one' '
+       git reset --hard F &&
+       clear_hook_input &&
+       test_must_fail git rebase --onto D A &&
+       git rebase --skip &&
+       echo rebase >expected.args &&
+       cat >expected.data <<EOF &&
+$(git rev-parse E) $(git rev-parse HEAD)
+EOF
+       verify_hook_input
+'
+
 test_expect_success 'git rebase -m' '
        git reset --hard D &&
        clear_hook_input &&
index 884a5e567c308e976ce50036dc93c3932b717603..a5f458533fd071c13550a72bf251e2e10c109637 100755 (executable)
@@ -124,7 +124,7 @@ test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setti
        (
                cd downstream &&
                git fetch --recurse-submodules >../actual.out 2>../actual.err &&
-               git config -f --unset .gitmodules submodule.submodule.fetchRecurseSubmodules true &&
+               git config --unset -f .gitmodules submodule.submodule.fetchRecurseSubmodules &&
                git config --unset submodule.submodule.fetchRecurseSubmodules
        ) &&
        test_cmp expect.out actual.out &&
index 460bf741b594d4d6b7f2220ac0f1a0d28c653619..d9c2d386ddf8caff4b87fa457c23757f76c293c7 100755 (executable)
@@ -14,7 +14,7 @@ test_description='CRLF merge conflict across text=auto change
 
 . ./test-lib.sh
 
-test_have_prereq MINGW && SED_OPTIONS=-b
+test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b
 
 test_expect_success setup '
        git config core.autocrlf false &&
index 2c49db9f6244225db7f82b574f21f05b58bfdc26..874279e32da98ac2c20137a207a0d115f073e444 100755 (executable)
@@ -446,4 +446,42 @@ test_expect_success 'add should fail when path is used by an existing directory'
        )
 '
 
+test_expect_success 'set up for relative path tests' '
+       mkdir reltest &&
+       (
+               cd reltest &&
+               git init &&
+               mkdir sub &&
+               (
+                       cd sub &&
+                       git init &&
+                       test_commit foo
+               ) &&
+               git add sub &&
+               git config -f .gitmodules submodule.sub.path sub &&
+               git config -f .gitmodules submodule.sub.url ../subrepo &&
+               cp .git/config pristine-.git-config
+       )
+'
+
+test_expect_success 'relative path works with URL' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               git config remote.origin.url ssh://hostname/repo &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = ssh://hostname/subrepo
+       )
+'
+
+test_expect_success 'relative path works with user@host:path' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               git config remote.origin.url user@host:repo &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = user@host:subrepo
+       )
+'
+
 test_done
index d8ad25036f325ecdcc71257614e19b5e6ab2cdc5..e5be13c271c92ce7c51601ee1eaf966d849d8ae4 100755 (executable)
@@ -238,6 +238,10 @@ test_expect_success 'ensure "status --cached --recursive" preserves the --cached
                ) &&
                git submodule status --cached --recursive -- nested1 > ../actual
        ) &&
+       if test_have_prereq MINGW
+       then
+               dos2unix actual
+       fi &&
        test_cmp expect actual
 '
 
index 5e48318013a5bf0e4c0ab80f2e5cad6d96887e6a..579ddb7572c27889060da315ddecb773b6fa1272 100755 (executable)
@@ -265,7 +265,7 @@ test_expect_success $PREREQ 'Author From: in message body' '
                --to=nobody@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches &&
-       sed "1,/^\$/d" < msgtxt1 > msgbody1
+       sed "1,/^\$/d" < msgtxt1 > msgbody1 &&
        grep "From: A <author@example.com>" msgbody1
 '
 
@@ -276,7 +276,7 @@ test_expect_success $PREREQ 'Author From: not in message body' '
                --to=nobody@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches &&
-       sed "1,/^\$/d" < msgtxt1 > msgbody1
+       sed "1,/^\$/d" < msgtxt1 > msgbody1 &&
        ! grep "From: A <author@example.com>" msgbody1
 '
 
@@ -298,7 +298,7 @@ test_expect_success $PREREQ 'Invalid In-Reply-To' '
                --in-reply-to=" " \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches \
-               2>errors
+               2>errors &&
        ! grep "^In-Reply-To: < *>" msgtxt1
 '
 
@@ -319,7 +319,7 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' '
        git send-email \
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
-               --no-chain-reply-to \
+               --nochain-reply-to \
                --in-reply-to="$(cat expect)" \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches $patches $patches \
@@ -617,7 +617,7 @@ EOF
 "
 
 test_expect_success $PREREQ '--suppress-cc=sob' '
-       git config --unset sendemail.cccmd
+       test_might_fail git config --unset sendemail.cccmd &&
        test_suppression sob
 '
 
@@ -1135,7 +1135,7 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
 # Note that the patches in this test are deliberately out of order; we
 # want to make sure it works even if the cover-letter is not in the
 # first mail.
-test_expect_success 'refusing to send cover letter template' '
+test_expect_success $PREREQ 'refusing to send cover letter template' '
        clean_fake_sendmail &&
        rm -fr outdir &&
        git format-patch --cover-letter -2 -o outdir &&
@@ -1151,7 +1151,7 @@ test_expect_success 'refusing to send cover letter template' '
        test -z "$(ls msgtxt*)"
 '
 
-test_expect_success '--force sends cover letter template anyway' '
+test_expect_success $PREREQ '--force sends cover letter template anyway' '
        clean_fake_sendmail &&
        rm -fr outdir &&
        git format-patch --cover-letter -2 -o outdir &&
index faf9092967fff63cb0f496064d237b4c6e900f23..88a9751dd3c73a39a15ec3d18d3dddb7790706bb 100755 (executable)
@@ -4,45 +4,55 @@ test_description='check svn dumpfile importer'
 
 . ./test-lib.sh
 
-if ! svnadmin -h >/dev/null 2>&1
-then
-       skip_all='skipping svn-fe tests, svn not available'
-       test_done
-fi
-
-svnconf=$PWD/svnconf
-export svnconf
-
-svn_cmd () {
-       subcommand=$1 &&
-       shift &&
-       mkdir -p "$svnconf" &&
-       svn "$subcommand" --config-dir "$svnconf" "$@"
+reinit_git () {
+       rm -fr .git &&
+       git init
 }
 
-test_dump () {
-       label=$1
-       dump=$2
-       test_expect_success "$dump" '
-               svnadmin create "$label-svn" &&
-               svnadmin load "$label-svn" < "$TEST_DIRECTORY/$dump" &&
-               svn_cmd export "file://$PWD/$label-svn" "$label-svnco" &&
-               git init "$label-git" &&
-               test-svn-fe "$TEST_DIRECTORY/$dump" >"$label.fe" &&
-               (
-                       cd "$label-git" &&
-                       git fast-import < ../"$label.fe"
-               ) &&
-               (
-                       cd "$label-svnco" &&
-                       git init &&
-                       git add . &&
-                       git fetch "../$label-git" master &&
-                       git diff --exit-code FETCH_HEAD
-               )
-       '
-}
+>empty
+
+test_expect_success 'empty dump' '
+       reinit_git &&
+       echo "SVN-fs-dump-format-version: 2" >input &&
+       test-svn-fe input >stream &&
+       git fast-import <stream
+'
+
+test_expect_success 'v3 dumps not supported' '
+       reinit_git &&
+       echo "SVN-fs-dump-format-version: 3" >input &&
+       test_must_fail test-svn-fe input >stream &&
+       test_cmp empty stream
+'
+
+test_expect_success 'set up svn repo' '
+       svnconf=$PWD/svnconf &&
+       mkdir -p "$svnconf" &&
 
-test_dump simple t9135/svn.dump
+       if
+               svnadmin -h >/dev/null 2>&1 &&
+               svnadmin create simple-svn &&
+               svnadmin load simple-svn <"$TEST_DIRECTORY/t9135/svn.dump" &&
+               svn export --config-dir "$svnconf" "file://$PWD/simple-svn" simple-svnco
+       then
+               test_set_prereq SVNREPO
+       fi
+'
+
+test_expect_success SVNREPO 't9135/svn.dump' '
+       git init simple-git &&
+       test-svn-fe "$TEST_DIRECTORY/t9135/svn.dump" >simple.fe &&
+       (
+               cd simple-git &&
+               git fast-import <../simple.fe
+       ) &&
+       (
+               cd simple-svnco &&
+               git init &&
+               git add . &&
+               git fetch ../simple-git master &&
+               git diff --exit-code FETCH_HEAD
+       )
+'
 
 test_done
index da582c53825a5719f6c9d82983e0951afcccd0df..991d2aa1be63c2440db93e6237201383e28a498a 100755 (executable)
@@ -6,6 +6,14 @@
 test_description='git svn merge detection'
 . ./lib-git-svn.sh
 
+svn_ver="$(svn --version --quiet)"
+case $svn_ver in
+0.* | 1.[0-4].*)
+       skip_all="skipping git-svn test - SVN too old ($svn_ver)"
+       test_done
+       ;;
+esac
+
 test_expect_success 'initialize source svn repo' '
        svn_cmd mkdir -m x "$svnrepo"/trunk &&
        svn_cmd mkdir -m x "$svnrepo"/branches &&
index 222d1059ef99879d3db387be798f973fb093f53e..986bc14d58c30201e75f3d95d9b8245e997b99e9 100755 (executable)
@@ -919,6 +919,48 @@ test_expect_success \
         git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
         compare_diff_raw expect actual'
 
+test_expect_success \
+       'N: delete directory by copying' \
+       'cat >expect <<-\EOF &&
+       OBJID
+       :100644 000000 OBJID OBJID D    foo/bar/qux
+       OBJID
+       :000000 100644 OBJID OBJID A    foo/bar/baz
+       :000000 100644 OBJID OBJID A    foo/bar/qux
+       EOF
+        empty_tree=$(git mktree </dev/null) &&
+        cat >input <<-INPUT_END &&
+       commit refs/heads/N-delete
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       collect data to be deleted
+       COMMIT
+
+       deleteall
+       M 100644 inline foo/bar/baz
+       data <<DATA_END
+       hello
+       DATA_END
+       C "foo/bar/baz" "foo/bar/qux"
+       C "foo/bar/baz" "foo/bar/quux/1"
+       C "foo/bar/baz" "foo/bar/quuux"
+       M 040000 $empty_tree foo/bar/quux
+       M 040000 $empty_tree foo/bar/quuux
+
+       commit refs/heads/N-delete
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       delete subdirectory
+       COMMIT
+
+       M 040000 $empty_tree foo/bar/qux
+       INPUT_END
+        git fast-import <input &&
+        git rev-list N-delete |
+               git diff-tree -r --stdin --root --always |
+               sed -e "s/$_x40/OBJID/g" >actual &&
+        test_cmp expect actual'
+
 test_expect_success \
        'N: modify copied tree' \
        'cat >expect <<-\EOF &&
index 7cf8cd8a2fed2191b31082c92a95598a3e06513d..463254c72734beaf74948b6c424367ef4fea9d1a 100755 (executable)
@@ -120,6 +120,7 @@ test_expect_success 'add notes with simple M command' '
 
 test_tick
 cat >input <<INPUT_END
+feature notes
 commit refs/notes/test
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 data <<COMMIT
index 432b82e3d5a361d0eba329f5d5c56c17009738db..4c384ff02333e1413cc67b1b4a6bed47ae3d00db 100755 (executable)
@@ -89,7 +89,8 @@ EOF
 test_expect_success PERL 'update git module' '
 
        (cd module-git &&
-       git cvsimport -a -R -z 0 module &&
+       git config cvsimport.trackRevisions true &&
+       git cvsimport -a -z 0 module &&
        git merge origin
        ) &&
        test_cmp module-cvs/o_fortuna module-git/o_fortuna
@@ -117,7 +118,8 @@ test_expect_success PERL 'cvsimport.module config works' '
 
        (cd module-git &&
                git config cvsimport.module module &&
-               git cvsimport -a -R -z0 &&
+               git config cvsimport.trackRevisions true &&
+               git cvsimport -a -z0 &&
                git merge origin
        ) &&
        test_cmp module-cvs/tick module-git/tick
@@ -137,6 +139,7 @@ test_expect_success PERL 'import from a CVS working tree' '
 
        $CVS co -d import-from-wt module &&
        (cd import-from-wt &&
+               git config cvsimport.trackRevisions false &&
                git cvsimport -a -z0 &&
                echo 1 >expect &&
                git log -1 --pretty=format:%s%n >actual &&
index cb1ca973aa16d82b3c52cc2b7834d977887567a2..0fdc541a7cd7d6b694c4f4a3fd06b6cf21dc7380 100644 (file)
@@ -70,6 +70,9 @@ unset GIT_NOTES_REF
 unset GIT_NOTES_DISPLAY_REF
 unset GIT_NOTES_REWRITE_REF
 unset GIT_NOTES_REWRITE_MODE
+unset GIT_REFLOG_ACTION
+unset GIT_CHERRY_PICK_HELP
+unset GIT_QUIET
 GIT_MERGE_VERBOSITY=5
 export GIT_MERGE_VERBOSITY
 export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
@@ -1057,6 +1060,13 @@ case $(uname -s) in
        # backslashes in pathspec are converted to '/'
        # exec does not inherit the PID
        test_set_prereq MINGW
+       test_set_prereq SED_STRIPS_CR
+       ;;
+*CYGWIN*)
+       test_set_prereq POSIXPERM
+       test_set_prereq EXECKEEPSPID
+       test_set_prereq NOT_MINGW
+       test_set_prereq SED_STRIPS_CR
        ;;
 *)
        test_set_prereq POSIXPERM
diff --git a/tag.c b/tag.c
index f789744ccaf5d5fb6f63ba0911a869492affc162..ecf7c1e9ce889514e04765695298ef11f28edab6 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -56,7 +56,7 @@ static unsigned long parse_tag_date(const char *buf, const char *tail)
        return strtoul(dateptr, NULL, 10);
 }
 
-int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
+int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)
 {
        unsigned char sha1[20];
        char type[20];
diff --git a/tag.h b/tag.h
index 85223700396f5ddb00c046a1a9fdb63c92aae40e..5ee88e6550cafa78b7e4acaa1285d5805974a037 100644 (file)
--- a/tag.h
+++ b/tag.h
@@ -13,7 +13,7 @@ struct tag {
 };
 
 extern struct tag *lookup_tag(const unsigned char *sha1);
-extern int parse_tag_buffer(struct tag *item, void *data, unsigned long size);
+extern int parse_tag_buffer(struct tag *item, const void *data, unsigned long size);
 extern int parse_tag(struct tag *item);
 extern struct object *deref_tag(struct object *, const char *, int);
 extern size_t parse_signature(const char *buf, unsigned long size);
diff --git a/test-subprocess.c b/test-subprocess.c
new file mode 100644 (file)
index 0000000..667d3e5
--- /dev/null
@@ -0,0 +1,21 @@
+#include "cache.h"
+#include "run-command.h"
+
+int main(int argc, char **argv)
+{
+       const char *prefix;
+       struct child_process cp;
+       int nogit = 0;
+
+       prefix = setup_git_directory_gently(&nogit);
+       if (nogit)
+               die("No git repo found");
+       if (!strcmp(argv[1], "--setup-work-tree")) {
+               setup_work_tree();
+               argv++;
+       }
+       memset(&cp, 0, sizeof(cp));
+       cp.git_cmd = 1;
+       cp.argv = (const char **)argv+1;
+       return run_command(&cp);
+}
diff --git a/trace.c b/trace.c
index 0fb2a2c64b63ab0067edff124b8f3d2c7175c70e..35d388dce44a4a8e3d6053dfd6abcb652771818a 100644 (file)
--- a/trace.c
+++ b/trace.c
@@ -127,3 +127,52 @@ void trace_argv_printf(const char **argv, const char *fmt, ...)
        if (need_close)
                close(fd);
 }
+
+static const char *quote_crnl(const char *path)
+{
+       static char new_path[PATH_MAX];
+       const char *p2 = path;
+       char *p1 = new_path;
+
+       if (!path)
+               return NULL;
+
+       while (*p2) {
+               switch (*p2) {
+               case '\\': *p1++ = '\\'; *p1++ = '\\'; break;
+               case '\n': *p1++ = '\\'; *p1++ = 'n'; break;
+               case '\r': *p1++ = '\\'; *p1++ = 'r'; break;
+               default:
+                       *p1++ = *p2;
+               }
+               p2++;
+       }
+       *p1 = '\0';
+       return new_path;
+}
+
+/* FIXME: move prefix to startup_info struct and get rid of this arg */
+void trace_repo_setup(const char *prefix)
+{
+       const char *git_work_tree;
+       char cwd[PATH_MAX];
+       char *trace = getenv("GIT_TRACE");
+
+       if (!trace || !strcmp(trace, "") ||
+           !strcmp(trace, "0") || !strcasecmp(trace, "false"))
+               return;
+
+       if (!getcwd(cwd, PATH_MAX))
+               die("Unable to get current working directory");
+
+       if (!(git_work_tree = get_git_work_tree()))
+               git_work_tree = "(null)";
+
+       if (!prefix)
+               prefix = "(null)";
+
+       trace_printf("setup: git_dir: %s\n", quote_crnl(get_git_dir()));
+       trace_printf("setup: worktree: %s\n", quote_crnl(git_work_tree));
+       trace_printf("setup: cwd: %s\n", quote_crnl(cwd));
+       trace_printf("setup: prefix: %s\n", quote_crnl(prefix));
+}
index 2d5453697aaf5287f524b72d0088ee15679e0691..9ebf231ea5ee2e7fd1f71c9557a6537d29428d8d 100644 (file)
@@ -52,7 +52,7 @@ PATTERNS("objc",
         "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"
         "|[^[:space:]]|[\x80-\xff]+"),
 PATTERNS("pascal",
-        "^((procedure|function|constructor|destructor|interface|"
+        "^(((class[ \t]+)?(procedure|function)|constructor|destructor|interface|"
                "implementation|initialization|finalization)[ \t]*.*)$"
         "\n"
         "^(.*=[ \t]*(class|record).*)$",
@@ -61,6 +61,23 @@ PATTERNS("pascal",
         "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
         "|<>|<=|>=|:=|\\.\\."
         "|[^[:space:]]|[\x80-\xff]+"),
+PATTERNS("perl",
+        "^[ \t]*package .*;\n"
+        "^[ \t]*sub .* \\{\n"
+        "^[A-Z]+ \\{\n"        /* BEGIN, END, ... */
+        "^=head[0-9] ",        /* POD */
+        /* -- */
+        "[[:alpha:]_'][[:alnum:]_']*"
+        "|0[xb]?[0-9a-fA-F_]*"
+        /* taking care not to interpret 3..5 as (3.)(.5) */
+        "|[0-9a-fA-F_]+(\\.[0-9a-fA-F_]+)?([eE][-+]?[0-9_]+)?"
+        "|=>|-[rwxoRWXOezsfdlpSugkbctTBMAC>]|~~|::"
+        "|&&=|\\|\\|=|//=|\\*\\*="
+        "|&&|\\|\\||//|\\+\\+|--|\\*\\*|\\.\\.\\.?"
+        "|[-+*/%.^&<>=!|]="
+        "|=~|!~"
+        "|<<|<>|<=>|>>"
+        "|[^[:space:]]"),
 PATTERNS("php",
         "^[\t ]*(((public|protected|private|static)[\t ]+)*function.*)$\n"
         "^[\t ]*(class.*)$",
index 53d0215d2d8f38fee589321890c9305c8da4d2c5..2ad2c307dd6e8f4bddf5cbd9c588973a085bf870 100644 (file)
@@ -51,14 +51,14 @@ static struct {
 } rev_ctx;
 
 static struct {
-       uint32_t uuid, url;
+       uint32_t version, uuid, url;
 } dump_ctx;
 
 static struct {
        uint32_t svn_log, svn_author, svn_date, svn_executable, svn_special, uuid,
                revision_number, node_path, node_kind, node_action,
                node_copyfrom_path, node_copyfrom_rev, text_content_length,
-               prop_content_length, content_length;
+               prop_content_length, content_length, svn_fs_dump_format_version;
 } keys;
 
 static void reset_node_ctx(char *fname)
@@ -85,6 +85,7 @@ static void reset_rev_ctx(uint32_t revision)
 static void reset_dump_ctx(uint32_t url)
 {
        dump_ctx.url = url;
+       dump_ctx.version = 1;
        dump_ctx.uuid = ~0;
 }
 
@@ -105,6 +106,7 @@ static void init_keys(void)
        keys.text_content_length = pool_intern("Text-content-length");
        keys.prop_content_length = pool_intern("Prop-content-length");
        keys.content_length = pool_intern("Content-length");
+       keys.svn_fs_dump_format_version = pool_intern("SVN-fs-dump-format-version");
 }
 
 static void read_props(void)
@@ -206,7 +208,12 @@ void svndump_read(const char *url)
                *val++ = '\0';
                key = pool_intern(t);
 
-               if (key == keys.uuid) {
+               if (key == keys.svn_fs_dump_format_version) {
+                       dump_ctx.version = atoi(val);
+                       if (dump_ctx.version > 2)
+                               die("expected svn dump format version <= 2, found %"PRIu32,
+                                   dump_ctx.version);
+               } else if (key == keys.uuid) {
                        dump_ctx.uuid = pool_intern(val);
                } else if (key == keys.revision_number) {
                        if (active_ctx == NODE_CTX)
index e1e054e4d982de30d8a9c8c4109c6d62448f62a9..164581f87f49935f0d1b1885420960a4d11dea56 100644 (file)
@@ -212,8 +212,10 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
                return error("Could not open %s", filename);
        sz = xsize_t(st.st_size);
        ptr->ptr = xmalloc(sz ? sz : 1);
-       if (sz && fread(ptr->ptr, sz, 1, f) != 1)
+       if (sz && fread(ptr->ptr, sz, 1, f) != 1) {
+               fclose(f);
                return error("Could not read %s", filename);
+       }
        fclose(f);
        ptr->size = sz;
        return 0;