Merge branch 'jk/test-path-utils-xsnprintf'
authorJunio C Hamano <gitster@pobox.com>
Wed, 17 Feb 2016 18:13:32 +0000 (10:13 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 17 Feb 2016 18:13:32 +0000 (10:13 -0800)
Some calls to strcpy(3) triggers a false warning from static
analysers that are less intelligent than humans, and reducing the
number of these false hits helps us notice real issues. A few
calls to strcpy(3) in test-path-utils that are already safe has
been rewritten to avoid false wanings.

* jk/test-path-utils-xsnprintf:
test-path-utils: use xsnprintf in favor of strcpy

86 files changed:
.gitignore
.travis.yml
Documentation/RelNotes/2.7.1.txt [new file with mode: 0644]
Documentation/RelNotes/2.8.0.txt
Documentation/config.txt
Documentation/git-bundle.txt
Documentation/git-clone.txt
Documentation/git-repack.txt
Documentation/git-update-index.txt
Documentation/git-worktree.txt
Documentation/git.txt
Documentation/gitcore-tutorial.txt
Documentation/gittutorial.txt
Documentation/revisions.txt
Documentation/technical/api-remote.txt
Documentation/urls.txt
Makefile
builtin/apply.c
builtin/check-attr.c
builtin/check-ignore.c
builtin/checkout-index.c
builtin/clean.c
builtin/hash-object.c
builtin/ls-files.c
builtin/update-index.c
cache.h
compat/mingw.c
config.c
config.mak.uname
contrib/completion/git-completion.bash
convert.c
dir.c
dir.h
environment.c
git.c
http.c
http.h
ident.c
perl/Git.pm
read-cache.c
refs/files-backend.c
remote.c
remote.h
setup.c
sha1_name.c
t/lib-git-daemon.sh
t/perf/p7300-clean.sh
t/t0008-ignores.sh
t/t0021-conversion.sh
t/t0060-path-utils.sh
t/t1508-at-combinations.sh
t/t1511-rev-parse-caret.sh
t/t3000-ls-files-others.sh
t/t3300-funny-names.sh
t/t3600-rm.sh
t/t3703-add-magic-pathspec.sh
t/t3902-quoted.sh
t/t4016-diff-quote.sh
t/t4135-apply-weird-filenames.sh
t/t5510-fetch.sh
t/t5533-push-cas.sh
t/t5601-clone.sh
t/t6023-merge-file.sh
t/t7063-status-untracked-cache.sh
t/t7517-per-repo-email.sh [new file with mode: 0755]
t/t7800-difftool.sh
t/t9003-help-autocorrect.sh [new file with mode: 0755]
t/t9100-git-svn-basic.sh
t/t9118-git-svn-funky-branch-names.sh
t/t9124-git-svn-dcommit-auto-props.sh
t/t9130-git-svn-authors-file.sh
t/t9200-git-cvsexportcommit.sh
t/t9400-git-cvsserver-server.sh
t/t9401-git-cvsserver-crlf.sh
t/t9402-git-cvsserver-refs.sh
t/t9700/test.pl
t/t9903-bash-prompt.sh
t/test-lib.sh
test-dump-untracked-cache.c
test-fake-ssh.c [new file with mode: 0644]
transport.c
tree-walk.c
tree-walk.h
unpack-trees.c
worktree.c
xdiff/xmerge.c
index 1c2f8321386f89ef8c03d11159c97a0f194c4423..5087ce1eb7e2210e7fc25a9a14ac3f499ad5ac2f 100644 (file)
 /test-dump-cache-tree
 /test-dump-split-index
 /test-dump-untracked-cache
+/test-fake-ssh
 /test-scrap-cache-tree
 /test-genrandom
 /test-hashmap
index c3bf9c6d4d1c6049dd38a5a861dceb4c8e1b7e99..f8b73ec3da4e998f673296d093a89d8e9e53ba24 100644 (file)
@@ -1,5 +1,11 @@
 language: c
 
+sudo: false
+
+cache:
+  directories:
+    - $HOME/travis-cache
+
 os:
   - linux
   - osx
@@ -18,7 +24,7 @@ env:
     - P4_VERSION="15.2"
     - GIT_LFS_VERSION="1.1.0"
     - DEFAULT_TEST_TARGET=prove
-    - GIT_PROVE_OPTS="--timer --jobs 3"
+    - GIT_PROVE_OPTS="--timer --jobs 3 --state=failed,slow,save"
     - GIT_TEST_OPTS="--verbose --tee"
     - CFLAGS="-g -O2 -Wall -Werror"
     - GIT_TEST_CLONE_2GB=YesPlease
@@ -67,6 +73,8 @@ before_install:
     p4 -V | grep Rev.;
     echo "$(tput setaf 6)Git-LFS Version$(tput sgr0)";
     git-lfs version;
+    mkdir -p $HOME/travis-cache;
+    ln -s $HOME/travis-cache/.prove t/.prove;
 
 before_script: make --jobs=2
 
diff --git a/Documentation/RelNotes/2.7.1.txt b/Documentation/RelNotes/2.7.1.txt
new file mode 100644 (file)
index 0000000..6553d69
--- /dev/null
@@ -0,0 +1,87 @@
+Git v2.7.1 Release Notes
+========================
+
+Fixes since v2.7
+----------------
+
+ * An earlier change in 2.5.x-era broke users' hooks and aliases by
+   exporting GIT_WORK_TREE to point at the root of the working tree,
+   interfering when they tried to use a different working tree without
+   setting GIT_WORK_TREE environment themselves.
+
+ * The "exclude_list" structure has the usual "alloc, nr" pair of
+   fields to be used by ALLOC_GROW(), but clear_exclude_list() forgot
+   to reset 'alloc' to 0 when it cleared 'nr' to discard the managed
+   array.
+
+ * "git send-email" was confused by escaped quotes stored in the alias
+   files saved by "mutt", which has been corrected.
+
+ * A few unportable C construct have been spotted by clang compiler
+   and have been fixed.
+
+ * The documentation has been updated to hint the connection between
+   the '--signoff' option and DCO.
+
+ * "git reflog" incorrectly assumed that all objects that used to be
+   at the tip of a ref must be commits, which caused it to segfault.
+
+ * The ignore mechanism saw a few regressions around untracked file
+   listing and sparse checkout selection areas in 2.7.0; the change
+   that is responsible for the regression has been reverted.
+
+ * Some codepaths used fopen(3) when opening a fixed path in $GIT_DIR
+   (e.g. COMMIT_EDITMSG) that is meant to be left after the command is
+   done.  This however did not work well if the repository is set to
+   be shared with core.sharedRepository and the umask of the previous
+   user is tighter.  They have been made to work better by calling
+   unlink(2) and retrying after fopen(3) fails with EPERM.
+
+ * Asking gitweb for a nonexistent commit left a warning in the server
+   log.
+
+ * "git rebase", unlike all other callers of "gc --auto", did not
+   ignore the exit code from "gc --auto".
+
+ * Many codepaths that run "gc --auto" before exiting kept packfiles
+   mapped and left the file descriptors to them open, which was not
+   friendly to systems that cannot remove files that are open.  They
+   now close the packs before doing so.
+
+ * A recent optimization to filter-branch in v2.7.0 introduced a
+   regression when --prune-empty filter is used, which has been
+   corrected.
+
+ * The description for SANITY prerequisite the test suite uses has
+   been clarified both in the comment and in the implementation.
+
+ * "git tag" started listing a tag "foo" as "tags/foo" when a branch
+   named "foo" exists in the same repository; remove this unnecessary
+   disambiguation, which is a regression introduced in v2.7.0.
+
+ * The way "git svn" uses auth parameter was broken by Subversion
+   1.9.0 and later.
+
+ * The "split" subcommand of "git subtree" (in contrib/) incorrectly
+   skipped merges when it shouldn't, which was corrected.
+
+ * A few options of "git diff" did not work well when the command was
+   run from a subdirectory.
+
+ * dirname() emulation has been added, as Msys2 lacks it.
+
+ * The underlying machinery used by "ls-files -o" and other commands
+   have been taught not to create empty submodule ref cache for a
+   directory that is not a submodule.  This removes a ton of wasted
+   CPU cycles.
+
+ * Drop a few old "todo" items by deciding that the change one of them
+   suggests is not such a good idea, and doing the change the other
+   one suggested to do.
+
+ * Documentation for "git fetch --depth" has been updated for clarity.
+
+ * The command line completion learned a handful of additional options
+   and command specific syntax.
+
+Also includes a handful of documentation and test updates.
index 1a0fcb2027ba9fe67bbb3c434443fc3c41f7f952..17e904cf4d18d8b42a863e0d3a0369e2a104455d 100644 (file)
@@ -7,7 +7,6 @@ Updates since v2.7
 UI, Workflows & Features
 
  * "branch --delete" has "branch -d" but "push --delete" does not.
-   (merge 38a2559 ps/push-delete-option later to maint).
 
  * "git blame" learned to produce the progress eye-candy when it takes
    too much time before emitting the first line of the result.
@@ -42,6 +41,48 @@ UI, Workflows & Features
  * "interpret-trailers" has been taught to optionally update a file in
    place, instead of always writing the result to the standard output.
 
+ * Many commands that read files that are expected to contain text
+   that is generated (or can be edited) by the end user to control
+   their behaviour (e.g. "git grep -f <filename>") have been updated
+   to be more tolerant to lines that are terminated with CRLF (they
+   used to treat such a line to contain payload that ends with CR,
+   which is usually not what the users expect).
+
+ * "git notes merge" used to limit the source of the merged notes tree
+   to somewhere under refs/notes/ hierarchy, which was too limiting
+   when inventing a workflow to exchange notes with remote
+   repositories using remote-tracking notes trees (located in e.g.
+   refs/remote-notes/ or somesuch).
+
+ * "git ls-files" learned a new "--eol" option to help diagnose
+   end-of-line problems.
+
+ * "ls-remote" learned an option to show which branch the remote
+   repository advertises as its primary by pointing its HEAD at.
+
+ * New http.proxyAuthMethod configuration variable can be used to
+   specify what authentication method to use, as a way to work around
+   proxies that do not give error response expected by libcurl when
+   CURLAUTH_ANY is used.  Also, the codepath for proxy authentication
+   has been taught to use credential API to store the authentication
+   material in user's keyrings.
+
+ * Update the untracked cache subsystem and change its primary UI from
+   "git update-index" to "git config".
+
+ * There were a few "now I am doing this thing" progress messages in
+   the TCP connection code that can be triggered by setting a verbose
+   option internally in the code, but "git fetch -v" and friends never
+   passed the verbose option down to that codepath.
+
+ * Clean/smudge filters defined in a configuration file of lower
+   precedence can now be overridden to be a pass-through no-op by
+   setting the variable to an empty string.
+
+ * A new "<branch>^{/!-<pattern>}" notation can be used to name a
+   commit that is reachable from <branch> that does not match the
+   given <pattern>.
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -77,6 +118,14 @@ Performance, Internal Implementation, Development Support etc.
    (e.g. there is no need to collect the log messages when showing
    only the number of changes).
 
+ * "git checkout $branch" (and other operations that share the same
+   underlying machinery) has been optimized.
+
+ * Automated tests in Travis CI environment has been optimized by
+   persisting runtime statistics of previous "prove" run, executing
+   tests that take longer before other ones; this reduces the total
+   wallclock time.
+
 
 Also contains various documentation updates and code clean-ups.
 
@@ -170,8 +219,57 @@ notes for details).
    1.9.0 and later.
    (merge 0b66415 ew/svn-1.9.0-auth later to maint).
 
+ * The "split" subcommand of "git subtree" (in contrib/) incorrectly
+   skipped merges when it shouldn't, which was corrected.
+   (merge 933cfeb dw/subtree-split-do-not-drop-merge later to maint).
+
+ * A few options of "git diff" did not work well when the command was
+   run from a subdirectory.
+   (merge a97262c nd/diff-with-path-params later to maint).
+
+ * The command line completion learned a handful of additional options
+   and command specific syntax.
+   (merge fa4b5e3 jk/completion-rebase later to maint).
+   (merge f7c2e1a pw/completion-show-branch later to maint).
+   (merge d7d4ca8 pw/completion-stash later to maint).
+   (merge e6414b4 tb/complete-word-diff-regex later to maint).
+
+ * dirname() emulation has been added, as Msys2 lacks it.
+   (merge e7d5ce8 js/dirname-basename later to maint).
+
+ * The underlying machinery used by "ls-files -o" and other commands
+   have been taught not to create empty submodule ref cache for a
+   directory that is not a submodule.  This removes a ton of wasted
+   CPU cycles.
+   (merge a2d5156 jk/ref-cache-non-repository-optim later to maint).
+
+ * "git worktree" had a broken code that attempted to auto-fix
+   possible inconsistency that results from end-users moving a
+   worktree to different places without telling Git (the original
+   repository needs to maintain backpointers to its worktrees, but
+   "mv" run by end-users who are not familiar with that fact will
+   obviously not adjust them), which actually made things worse
+   when triggered.
+   (merge 618244e nd/do-not-move-worktree-manually later to maint).
+
+ * The low-level merge machinery has been taught to use CRLF line
+   termination when inserting conflict markers to merged contents that
+   are themselves CRLF line-terminated.
+   (merge 15980de js/xmerge-marker-eol later to maint).
+
+ * "git push --force-with-lease" has been taught to report if the push
+   needed to force (or fast-forwarded).
+   (merge b2e93f8 aw/push-force-with-lease-reporting later to maint).
+
+ * The emulated "yes" command used in our test scripts has been
+   tweaked not to spend too much time generating unnecessary output
+   that is not used, to help those who test on Windows where it would
+   not stop until it fills the pipe buffer due to lack of SIGPIPE.
+   (merge 6129c93 js/test-lib-windows-emulated-yes later to maint).
+
  * Other minor clean-ups and documentation updates
    (merge 99487cf ss/user-manual later to maint).
    (merge e914ef0 ew/for-each-ref-doc later to maint).
    (merge 36fc7d8 sg/t6050-failing-editor-test-fix later to maint).
    (merge 60253a6 ss/clone-depth-single-doc later to maint).
+   (merge bd02e97 lv/add-doc-working-tree later to maint).
index 877cbc875ec38ef7dca9f3e2a2c860ea9a2f1790..01cca0a70177091f4580a06ea53e498d3e5be4e4 100644 (file)
@@ -308,6 +308,15 @@ core.trustctime::
        crawlers and some backup systems).
        See linkgit:git-update-index[1]. True by default.
 
+core.untrackedCache::
+       Determines what to do about the untracked cache feature of the
+       index. It will be kept, if this variable is unset or set to
+       `keep`. It will automatically be added if set to `true`. And
+       it will automatically be removed, if set to `false`. Before
+       setting it to `true`, you should check that mtime is working
+       properly on your system.
+       See linkgit:git-update-index[1]. `keep` by default.
+
 core.checkStat::
        Determines which stat fields to match between the index
        and work tree. The user can set this to 'default' or
@@ -1610,9 +1619,34 @@ help.htmlPath::
 
 http.proxy::
        Override the HTTP proxy, normally configured using the 'http_proxy',
-       'https_proxy', and 'all_proxy' environment variables (see
-       `curl(1)`).  This can be overridden on a per-remote basis; see
-       remote.<name>.proxy
+       'https_proxy', and 'all_proxy' environment variables (see `curl(1)`). In
+       addition to the syntax understood by curl, it is possible to specify a
+       proxy string with a user name but no password, in which case git will
+       attempt to acquire one in the same way it does for other credentials. See
+       linkgit:gitcredentials[7] for more information. The syntax thus is
+       '[protocol://][user[:password]@]proxyhost[:port]'. This can be overridden
+       on a per-remote basis; see remote.<name>.proxy
+
+http.proxyAuthMethod::
+       Set the method with which to authenticate against the HTTP proxy. This
+       only takes effect if the configured proxy string contains a user name part
+       (i.e. is of the form 'user@host' or 'user@host:port'). This can be
+       overridden on a per-remote basis; see `remote.<name>.proxyAuthMethod`.
+       Both can be overridden by the 'GIT_HTTP_PROXY_AUTHMETHOD' environment
+       variable.  Possible values are:
++
+--
+* `anyauth` - Automatically pick a suitable authentication method. It is
+  assumed that the proxy answers an unauthenticated request with a 407
+  status code and one or more Proxy-authenticate headers with supported
+  authentication methods. This is the default.
+* `basic` - HTTP Basic authentication
+* `digest` - HTTP Digest authentication; this prevents the password from being
+  transmitted to the proxy in clear text
+* `negotiate` - GSS-Negotiate authentication (compare the --negotiate option
+  of `curl(1)`)
+* `ntlm` - NTLM authentication (compare the --ntlm option of `curl(1)`)
+--
 
 http.cookieFile::
        File containing previously stored cookie lines which should be used
@@ -2088,7 +2122,7 @@ pack.indexVersion::
        larger than 2 GB.
 +
 If you have an old Git that does not understand the version 2 `*.idx` file,
-cloning or fetching over a non native protocol (e.g. "http" and "rsync")
+cloning or fetching over a non native protocol (e.g. "http")
 that will copy both `*.pack` file and corresponding `*.idx` file from the
 other side may give you a repository that cannot be accessed with your
 older version of Git. If the `*.pack` file is smaller than 2 GB, however,
@@ -2423,6 +2457,11 @@ remote.<name>.proxy::
        the proxy to use for that remote.  Set to the empty string to
        disable proxying for that remote.
 
+remote.<name>.proxyAuthMethod::
+       For remotes that require curl (http, https and ftp), the method to use for
+       authenticating against the proxy in use (probably set in
+       `remote.<name>.proxy`). See `http.proxyAuthMethod`.
+
 remote.<name>.fetch::
        The default set of "refspec" for linkgit:git-fetch[1]. See
        linkgit:git-fetch[1].
@@ -2791,6 +2830,16 @@ user.name::
        Can be overridden by the 'GIT_AUTHOR_NAME' and 'GIT_COMMITTER_NAME'
        environment variables.  See linkgit:git-commit-tree[1].
 
+user.useConfigOnly::
+       Instruct Git to avoid trying to guess defaults for 'user.email'
+       and 'user.name', and instead retrieve the values only from the
+       configuration. For example, if you have multiple email addresses
+       and would like to use a different one for each repository, then
+       with this configuration option set to `true` in the global config
+       along with a name, Git will prompt you to set up an email before
+       making new commits in a newly cloned repository.
+       Defaults to `false`.
+
 user.signingKey::
        If linkgit:git-tag[1] or linkgit:git-commit[1] is not selecting the
        key you want it to automatically when creating a signed tag or
index 0417562eb736f8a3b919bfa4deeb372164451bab..3a8120c3b3795784cb05211bcde959a224f0a867 100644 (file)
@@ -20,7 +20,7 @@ DESCRIPTION
 Some workflows require that one or more branches of development on one
 machine be replicated on another machine, but the two machines cannot
 be directly connected, and therefore the interactive Git protocols (git,
-ssh, rsync, http) cannot be used.  This command provides support for
+ssh, http) cannot be used.  This command provides support for
 'git fetch' and 'git pull' to operate by packaging objects and references
 in an archive at the originating machine, then importing those into
 another repository using 'git fetch' and 'git pull'
index 789b668f7732957d71f42f98d361abd0b34305a7..b7c467a001ad47de0bebd8c985df769fe4e63adc 100644 (file)
@@ -115,8 +115,7 @@ objects from the source repository into a pack in the cloned repository.
 --quiet::
 -q::
        Operate quietly.  Progress is not reported to the standard
-       error stream. This flag is also passed to the `rsync'
-       command when given.
+       error stream.
 
 --verbose::
 -v::
index 0e0bd363d6773bd2652287e12aff62bcf6ea09f4..af230d06475eedf99ee4a27eab5f1cc204f71aa1 100644 (file)
@@ -133,7 +133,7 @@ By default, the command passes `--delta-base-offset` option to
 'git pack-objects'; this typically results in slightly smaller packs,
 but the generated packs are incompatible with versions of Git older than
 version 1.4.4. If you need to share your repository with such ancient Git
-versions, either directly or via the dumb http or rsync protocol, then you
+versions, either directly or via the dumb http protocol, then you
 need to set the configuration variable `repack.UseDeltaBaseOffset` to
 "false" and repack. Access from old Git versions over the native protocol
 is unaffected by this option as the conversion is performed on the fly
index f4e5a85351d7a7fdda24ac497560f59ccdb6ef7b..c6cbed189ceddd294361502b861f37c29a8adbf1 100644 (file)
@@ -18,7 +18,7 @@ SYNOPSIS
             [--[no-]skip-worktree]
             [--ignore-submodules]
             [--[no-]split-index]
-            [--[no-|force-]untracked-cache]
+            [--[no-|test-|force-]untracked-cache]
             [--really-refresh] [--unresolve] [--again | -g]
             [--info-only] [--index-info]
             [-z] [--stdin] [--index-version <n>]
@@ -174,17 +174,30 @@ may not support it yet.
 
 --untracked-cache::
 --no-untracked-cache::
-       Enable or disable untracked cache extension. This could speed
-       up for commands that involve determining untracked files such
-       as `git status`. The underlying operating system and file
-       system must change `st_mtime` field of a directory if files
-       are added or deleted in that directory.
+       Enable or disable untracked cache feature. Please use
+       `--test-untracked-cache` before enabling it.
++
+These options take effect whatever the value of the `core.untrackedCache`
+configuration variable (see linkgit:git-config[1]). But a warning is
+emitted when the change goes against the configured value, as the
+configured value will take effect next time the index is read and this
+will remove the intended effect of the option.
+
+--test-untracked-cache::
+       Only perform tests on the working directory to make sure
+       untracked cache can be used. You have to manually enable
+       untracked cache using `--untracked-cache` or
+       `--force-untracked-cache` or the `core.untrackedCache`
+       configuration variable afterwards if you really want to use
+       it. If a test fails the exit code is 1 and a message
+       explains what is not working as needed, otherwise the exit
+       code is 0 and OK is printed.
 
 --force-untracked-cache::
-       For safety, `--untracked-cache` performs tests on the working
-       directory to make sure untracked cache can be used. These
-       tests can take a few seconds. `--force-untracked-cache` can be
-       used to skip the tests.
+       Same as `--untracked-cache`. Provided for backwards
+       compatibility with older versions of Git where
+       `--untracked-cache` used to imply `--test-untracked-cache` but
+       this option would enable the extension unconditionally.
 
 \--::
        Do not interpret any more arguments as options.
@@ -375,6 +388,37 @@ Although this bit looks similar to assume-unchanged bit, its goal is
 different from assume-unchanged bit's. Skip-worktree also takes
 precedence over assume-unchanged bit when both are set.
 
+Untracked cache
+---------------
+
+This cache is meant to speed up commands that involve determining
+untracked files such as `git status`.
+
+This feature works by recording the mtime of the working tree
+directories and then omitting reading directories and stat calls
+against files in those directories whose mtime hasn't changed. For
+this to work the underlying operating system and file system must
+change the `st_mtime` field of directories if files in the directory
+are added, modified or deleted.
+
+You can test whether the filesystem supports that with the
+`--test-untracked-cache` option. The `--untracked-cache` option used
+to implicitly perform that test in older versions of Git, but that's
+no longer the case.
+
+If you want to enable (or disable) this feature, it is easier to use
+the `core.untrackedCache` configuration variable (see
+linkgit:git-config[1]) than using the `--untracked-cache` option to
+`git update-index` in each repository, especially if you want to do so
+across all repositories you use, because you can set the configuration
+variable to `true` (or `false`) in your `$HOME/.gitconfig` just once
+and have it affect all repositories you touch.
+
+When the `core.untrackedCache` configuration variable is changed, the
+untracked cache is added to or removed from the index the next time a
+command reads the index; while when `--[no-|force-]untracked-cache`
+are used, the untracked cache is immediately added to or removed from
+the index.
 
 Configuration
 -------------
@@ -400,6 +444,9 @@ It can be useful when the inode change time is regularly modified by
 something outside Git (file system crawlers and backup systems use
 ctime for marking files processed) (see linkgit:git-config[1]).
 
+The untracked cache extension can be enabled by the
+`core.untrackedCache` configuration variable (see
+linkgit:git-config[1]).
 
 SEE ALSO
 --------
index 5b9ad0429c84d2f11b0569f6d979858c833b3768..62c76c1c8945512009c6d0ca1179cf71ec50d04e 100644 (file)
@@ -32,11 +32,9 @@ The working tree's administrative files in the repository (see
 `git worktree prune` in the main or any linked working tree to
 clean up any stale administrative files.
 
-If you move a linked working tree to another file system, or
-within a file system that does not support hard links, you need to run
-at least one git command inside the linked working tree
-(e.g. `git status`) in order to update its administrative files in the
-repository so that they do not get automatically pruned.
+If you move a linked working tree, you need to manually update the
+administrative files so that they do not get pruned automatically. See
+section "DETAILS" for more information.
 
 If a linked working tree is stored on a portable device or network share
 which is not always mounted, you can prevent its administrative files from
@@ -137,6 +135,13 @@ thumb is do not make any assumption about whether a path belongs to
 $GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
 inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
 
+If you move a linked working tree, you need to update the 'gitdir' file
+in the entry's directory. For example, if a linked working tree is moved
+to `/newpath/test-next` and its `.git` file points to
+`/path/main/.git/worktrees/test-next`, then update
+`/path/main/.git/worktrees/test-next/gitdir` to reference `/newpath/test-next`
+instead.
+
 To prevent a $GIT_DIR/worktrees entry from being pruned (which
 can be useful in some situations, such as when the
 entry's working tree is stored on a portable device), add a file named
index bff6302c0dec6d18454439c4423189a86beee396..a48c1e802413713122f2f9e4f9dc410950163aef 100644 (file)
@@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v2.7.0/git.html[documentation for release 2.7]
+* link:v2.7.1/git.html[documentation for release 2.7.1]
 
 * release notes for
+  link:RelNotes/2.7.1.txt[2.7.1],
   link:RelNotes/2.7.0.txt[2.7].
 
 * link:v2.6.5/git.html[documentation for release 2.6.5]
@@ -1123,8 +1124,6 @@ of clones and fetches.
          - `ssh`: git over ssh (including `host:path` syntax,
            `git+ssh://`, etc).
 
-         - `rsync`: git over rsync
-
          - `http`: git over http, both "smart http" and "dumb http".
            Note that this does _not_ include `https`; if you want both,
            you should specify both as `http:https`.
index 36e9ab3e16860be21e6bcdc6e2f7c6ff44aa4757..15b3bfa8db143948629405a2ea9a72b7a83b31d5 100644 (file)
@@ -710,7 +710,7 @@ files).
 Again, this can all be simplified with
 
 ----------------
-$ git clone rsync://rsync.kernel.org/pub/scm/git/git.git/ my-git
+$ git clone git://git.kernel.org/pub/scm/git/git.git/ my-git
 $ cd my-git
 $ git checkout
 ----------------
@@ -1011,20 +1011,6 @@ $ git fetch <remote-repository>
 One of the following transports can be used to name the
 repository to download from:
 
-Rsync::
-       `rsync://remote.machine/path/to/repo.git/`
-+
-Rsync transport is usable for both uploading and downloading,
-but is completely unaware of what git does, and can produce
-unexpected results when you download from the public repository
-while the repository owner is uploading into it via `rsync`
-transport.  Most notably, it could update the files under
-`refs/` which holds the object name of the topmost commits
-before uploading the files in `objects/` -- the downloader would
-obtain head commit object name while that object itself is still
-not available in the repository.  For this reason, it is
-considered deprecated.
-
 SSH::
        `remote.machine:/path/to/repo.git/` or
 +
@@ -1430,7 +1416,7 @@ while, depending on how active your project is.
 
 When a repository is synchronized via `git push` and `git pull`
 objects packed in the source repository are usually stored
-unpacked in the destination, unless rsync transport is used.
+unpacked in the destination.
 While this allows you to use different packing strategies on
 both ends, it also means you may need to repack both
 repositories every once in a while.
index b00c67df46dad4efe93dddc7ead0a7422aa47c32..b3b58d324e4b7c254c54531bbab979064f3ced4a 100644 (file)
@@ -451,7 +451,7 @@ perform clones and pulls using the ssh protocol:
 bob$ git clone alice.org:/home/alice/project myrepo
 -------------------------------------
 
-Alternatively, Git has a native protocol, or can use rsync or http;
+Alternatively, Git has a native protocol, or can use http;
 see linkgit:git-pull[1] for details.
 
 Git can also be used in a CVS-like mode, with a central repository
index fa4bdb208cd86c603e1d7e430e753d5fe4768a13..19314e3b7f3eb7616be5ab88580020206285f880 100644 (file)
@@ -176,11 +176,12 @@ existing tag object.
   A colon, followed by a slash, followed by a text, names
   a commit whose commit message matches the specified regular expression.
   This name returns the youngest matching commit which is
-  reachable from any ref.  If the commit message starts with a
-  '!' you have to repeat that;  the special sequence ':/!',
-  followed by something else than '!', is reserved for now.
-  The regular expression can match any part of the commit message. To
-  match messages starting with a string, one can use e.g. ':/^foo'.
+  reachable from any ref. The regular expression can match any part of the
+  commit message. To match messages starting with a string, one can use
+  e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to what
+  is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a
+  literal '!' character, followed by 'foo'. Any other sequence beginning with
+  ':/!' is reserved for now.
 
 '<rev>:<path>', e.g. 'HEAD:README', ':README', 'master:./README'::
   A suffix ':' followed by a path names the blob or tree
index 2cfdd224a83710f32e344b76c131181527caf98c..f10941b2e816142e9659ec3982105360f79070fd 100644 (file)
@@ -51,6 +51,10 @@ struct remote
 
        The proxy to use for curl (http, https, ftp, etc.) URLs.
 
+`http_proxy_authmethod`::
+
+       The method used for authenticating against `http_proxy`.
+
 struct remotes can be found by name with remote_get(), and iterated
 through with for_each_remote(). remote_get(NULL) will return the
 default remote, given the current branch and configuration.
index 9ccb24677e95b8aff605c9020bc7a0537e23f751..b05da95788f7b1294be6b2733ca55b58111b7607 100644 (file)
@@ -7,9 +7,8 @@ Depending on the transport protocol, some of this information may be
 absent.
 
 Git supports ssh, git, http, and https protocols (in addition, ftp,
-and ftps can be used for fetching and rsync can be used for fetching
-and pushing, but these are inefficient and deprecated; do not use
-them).
+and ftps can be used for fetching, but this is inefficient and
+deprecated; do not use it).
 
 The native transport (i.e. git:// URL) does no authentication and
 should be used with caution on unsecured networks.
@@ -20,7 +19,6 @@ The following syntaxes may be used with them:
 - git://host.xz{startsb}:port{endsb}/path/to/repo.git/
 - http{startsb}s{endsb}://host.xz{startsb}:port{endsb}/path/to/repo.git/
 - ftp{startsb}s{endsb}://host.xz{startsb}:port{endsb}/path/to/repo.git/
-- rsync://host.xz/path/to/repo.git/
 
 An alternative scp-like syntax may also be used with the ssh protocol:
 
index fc2f1ab2c31820513758514cd445fc63521b1d19..10566d648175fc561fde6a1498996e2bb43b880d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -583,6 +583,7 @@ TEST_PROGRAMS_NEED_X += test-delta
 TEST_PROGRAMS_NEED_X += test-dump-cache-tree
 TEST_PROGRAMS_NEED_X += test-dump-split-index
 TEST_PROGRAMS_NEED_X += test-dump-untracked-cache
+TEST_PROGRAMS_NEED_X += test-fake-ssh
 TEST_PROGRAMS_NEED_X += test-genrandom
 TEST_PROGRAMS_NEED_X += test-hashmap
 TEST_PROGRAMS_NEED_X += test-index-version
index deb1364fa81452d236a224109a99b28a034f9a9a..d61ac65dab28a766a13782bdef572431e20e80ff 100644 (file)
@@ -4464,16 +4464,6 @@ static int option_parse_p(const struct option *opt,
        return 0;
 }
 
-static int option_parse_z(const struct option *opt,
-                         const char *arg, int unset)
-{
-       if (unset)
-               line_termination = '\n';
-       else
-               line_termination = 0;
-       return 0;
-}
-
 static int option_parse_space_change(const struct option *opt,
                          const char *arg, int unset)
 {
@@ -4546,9 +4536,9 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
                         N_( "attempt three-way merge if a patch does not apply")),
                OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
                        N_("build a temporary index based on embedded index information")),
-               { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
-                       N_("paths are separated with NUL character"),
-                       PARSE_OPT_NOARG, option_parse_z },
+               /* Think twice before adding "--nul" synonym to this */
+               OPT_SET_INT('z', NULL, &line_termination,
+                       N_("paths are separated with NUL character"), '\0'),
                OPT_INTEGER('C', NULL, &p_context,
                                N_("ensure at least <n> lines of context match")),
                { OPTION_CALLBACK, 0, "whitespace", &whitespace_option, N_("action"),
index 087325ef6954e4a2364d194f8d7ac27fedb7fc67..53a5a18c1681f5f13f6ddd4fd4d7d30c0ea14ce6 100644 (file)
@@ -72,24 +72,23 @@ static void check_attr(const char *prefix, int cnt,
 static void check_attr_stdin_paths(const char *prefix, int cnt,
        struct git_attr_check *check)
 {
-       struct strbuf buf, nbuf;
+       struct strbuf buf = STRBUF_INIT;
+       struct strbuf unquoted = STRBUF_INIT;
        strbuf_getline_fn getline_fn;
 
        getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
-       strbuf_init(&buf, 0);
-       strbuf_init(&nbuf, 0);
        while (getline_fn(&buf, stdin) != EOF) {
                if (!nul_term_line && buf.buf[0] == '"') {
-                       strbuf_reset(&nbuf);
-                       if (unquote_c_style(&nbuf, buf.buf, NULL))
+                       strbuf_reset(&unquoted);
+                       if (unquote_c_style(&unquoted, buf.buf, NULL))
                                die("line is badly quoted");
-                       strbuf_swap(&buf, &nbuf);
+                       strbuf_swap(&buf, &unquoted);
                }
                check_attr(prefix, cnt, check, buf.buf);
                maybe_flush_or_die(stdout, "attribute to stdout");
        }
        strbuf_release(&buf);
-       strbuf_release(&nbuf);
+       strbuf_release(&unquoted);
 }
 
 static NORETURN void error_with_usage(const char *msg)
index 4f0b09e2db5c0e0bc4665b06dc543b7f8ea1d467..1d73d3ca3d0509d71b927d685f3239cdab3cc885 100644 (file)
@@ -115,20 +115,19 @@ static int check_ignore(struct dir_struct *dir,
 
 static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)
 {
-       struct strbuf buf, nbuf;
+       struct strbuf buf = STRBUF_INIT;
+       struct strbuf unquoted = STRBUF_INIT;
        char *pathspec[2] = { NULL, NULL };
        strbuf_getline_fn getline_fn;
        int num_ignored = 0;
 
        getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
-       strbuf_init(&buf, 0);
-       strbuf_init(&nbuf, 0);
        while (getline_fn(&buf, stdin) != EOF) {
                if (!nul_term_line && buf.buf[0] == '"') {
-                       strbuf_reset(&nbuf);
-                       if (unquote_c_style(&nbuf, buf.buf, NULL))
+                       strbuf_reset(&unquoted);
+                       if (unquote_c_style(&unquoted, buf.buf, NULL))
                                die("line is badly quoted");
-                       strbuf_swap(&buf, &nbuf);
+                       strbuf_swap(&buf, &unquoted);
                }
                pathspec[0] = buf.buf;
                num_ignored += check_ignore(dir, prefix,
@@ -136,7 +135,7 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)
                maybe_flush_or_die(stdout, "check-ignore to stdout");
        }
        strbuf_release(&buf);
-       strbuf_release(&nbuf);
+       strbuf_release(&unquoted);
        return num_ignored;
 }
 
index ed888a5b9e8a2978369c404ab050b237ab5c7b4d..92c69672e96f6e7fc6bbe7b783c551474224f18b 100644 (file)
@@ -130,33 +130,6 @@ static const char * const builtin_checkout_index_usage[] = {
 
 static struct lock_file lock_file;
 
-static int option_parse_u(const struct option *opt,
-                             const char *arg, int unset)
-{
-       int *newfd = opt->value;
-
-       state.refresh_cache = 1;
-       state.istate = &the_index;
-       if (*newfd < 0)
-               *newfd = hold_locked_index(&lock_file, 1);
-       return 0;
-}
-
-static int option_parse_z(const struct option *opt,
-                         const char *arg, int unset)
-{
-       nul_term_line = !unset;
-       return 0;
-}
-
-static int option_parse_prefix(const struct option *opt,
-                              const char *arg, int unset)
-{
-       state.base_dir = arg;
-       state.base_dir_len = strlen(arg);
-       return 0;
-}
-
 static int option_parse_stage(const struct option *opt,
                              const char *arg, int unset)
 {
@@ -168,7 +141,7 @@ static int option_parse_stage(const struct option *opt,
                if ('1' <= ch && ch <= '3')
                        checkout_stage = arg[0] - '0';
                else
-                       die("stage should be between 1 and 3 or all");
+                       die(_("stage should be between 1 and 3 or all"));
        }
        return 0;
 }
@@ -181,6 +154,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
        int read_from_stdin = 0;
        int prefix_length;
        int force = 0, quiet = 0, not_new = 0;
+       int index_opt = 0;
        struct option builtin_checkout_index_options[] = {
                OPT_BOOL('a', "all", &all,
                        N_("check out all files in the index")),
@@ -189,22 +163,19 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
                        N_("no warning for existing files and files not in index")),
                OPT_BOOL('n', "no-create", &not_new,
                        N_("don't checkout new files")),
-               { OPTION_CALLBACK, 'u', "index", &newfd, NULL,
-                       N_("update stat information in the index file"),
-                       PARSE_OPT_NOARG, option_parse_u },
-               { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
-                       N_("paths are separated with NUL character"),
-                       PARSE_OPT_NOARG, option_parse_z },
+               OPT_BOOL('u', "index", &index_opt,
+                        N_("update stat information in the index file")),
+               OPT_BOOL('z', NULL, &nul_term_line,
+                       N_("paths are separated with NUL character")),
                OPT_BOOL(0, "stdin", &read_from_stdin,
                        N_("read list of paths from the standard input")),
                OPT_BOOL(0, "temp", &to_tempfile,
                        N_("write the content to temporary files")),
-               OPT_CALLBACK(0, "prefix", NULL, N_("string"),
-                       N_("when creating files, prepend <string>"),
-                       option_parse_prefix),
-               OPT_CALLBACK(0, "stage", NULL, NULL,
+               OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
+                       N_("when creating files, prepend <string>")),
+               { OPTION_CALLBACK, 0, "stage", NULL, "1-3|all",
                        N_("copy out the files from named stage"),
-                       option_parse_stage),
+                       PARSE_OPT_NONEG, option_parse_stage },
                OPT_END()
        };
 
@@ -212,7 +183,6 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
                usage_with_options(builtin_checkout_index_usage,
                                   builtin_checkout_index_options);
        git_config(git_default_config, NULL);
-       state.base_dir = "";
        prefix_length = prefix ? strlen(prefix) : 0;
 
        if (read_cache() < 0) {
@@ -225,15 +195,17 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
        state.quiet = quiet;
        state.not_new = not_new;
 
-       if (state.base_dir_len || to_tempfile) {
-               /* when --prefix is specified we do not
-                * want to update cache.
-                */
-               if (state.refresh_cache) {
-                       rollback_lock_file(&lock_file);
-                       newfd = -1;
-               }
-               state.refresh_cache = 0;
+       if (!state.base_dir)
+               state.base_dir = "";
+       state.base_dir_len = strlen(state.base_dir);
+
+       /*
+        * when --prefix is specified we do not want to update cache.
+        */
+       if (index_opt && !state.base_dir_len && !to_tempfile) {
+               state.refresh_cache = 1;
+               state.istate = &the_index;
+               newfd = hold_locked_index(&lock_file, 1);
        }
 
        /* Check out named files first */
@@ -251,7 +223,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
        }
 
        if (read_from_stdin) {
-               struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
+               struct strbuf buf = STRBUF_INIT;
+               struct strbuf unquoted = STRBUF_INIT;
                strbuf_getline_fn getline_fn;
 
                if (all)
@@ -261,16 +234,16 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
                while (getline_fn(&buf, stdin) != EOF) {
                        char *p;
                        if (!nul_term_line && buf.buf[0] == '"') {
-                               strbuf_reset(&nbuf);
-                               if (unquote_c_style(&nbuf, buf.buf, NULL))
+                               strbuf_reset(&unquoted);
+                               if (unquote_c_style(&unquoted, buf.buf, NULL))
                                        die("line is badly quoted");
-                               strbuf_swap(&buf, &nbuf);
+                               strbuf_swap(&buf, &unquoted);
                        }
                        p = prefix_path(prefix, prefix_length, buf.buf);
                        checkout_file(p, prefix);
                        free(p);
                }
-               strbuf_release(&nbuf);
+               strbuf_release(&unquoted);
                strbuf_release(&buf);
        }
 
index cc5f9723dead24b528c676ae06af4ed152c9d2e6..7b08237480fde101640ce361b3b95106e7ffa930 100644 (file)
@@ -147,30 +147,6 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)
        return 0;
 }
 
-/*
- * Return 1 if the given path is the root of a git repository or
- * submodule else 0. Will not return 1 for bare repositories with the
- * exception of creating a bare repository in "foo/.git" and calling
- * is_git_repository("foo").
- */
-static int is_git_repository(struct strbuf *path)
-{
-       int ret = 0;
-       int gitfile_error;
-       size_t orig_path_len = path->len;
-       assert(orig_path_len != 0);
-       strbuf_complete(path, '/');
-       strbuf_addstr(path, ".git");
-       if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))
-               ret = 1;
-       if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||
-           gitfile_error == READ_GITFILE_ERR_READ_FAILED)
-               ret = 1;  /* This could be a real .git file, take the
-                          * safe option and avoid cleaning */
-       strbuf_setlen(path, orig_path_len);
-       return ret;
-}
-
 static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
                int dry_run, int quiet, int *dir_gone)
 {
@@ -182,7 +158,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 
        *dir_gone = 1;
 
-       if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_git_repository(path)) {
+       if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_nonbare_repository_dir(path)) {
                if (!quiet) {
                        quote_path_relative(path->buf, prefix, &quoted);
                        printf(dry_run ?  _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
index ff20395c69780cb5869300af83084d6cac1bbd4d..f7d3567dd0ce2d75778d6cf011961c0f203432b4 100644 (file)
@@ -58,20 +58,21 @@ static void hash_object(const char *path, const char *type, const char *vpath,
 static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
                             int literally)
 {
-       struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
+       struct strbuf buf = STRBUF_INIT;
+       struct strbuf unquoted = STRBUF_INIT;
 
        while (strbuf_getline(&buf, stdin) != EOF) {
                if (buf.buf[0] == '"') {
-                       strbuf_reset(&nbuf);
-                       if (unquote_c_style(&nbuf, buf.buf, NULL))
+                       strbuf_reset(&unquoted);
+                       if (unquote_c_style(&unquoted, buf.buf, NULL))
                                die("line is badly quoted");
-                       strbuf_swap(&buf, &nbuf);
+                       strbuf_swap(&buf, &unquoted);
                }
                hash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags,
                            literally);
        }
        strbuf_release(&buf);
-       strbuf_release(&nbuf);
+       strbuf_release(&unquoted);
 }
 
 int cmd_hash_object(int argc, const char **argv, const char *prefix)
index dedf02dc702d1cc94399f45869e5d01d2f0eecb9..f02e3d23bb71a39dfd9f6eddf40aa84da896b650 100644 (file)
@@ -379,14 +379,6 @@ static const char * const ls_files_usage[] = {
        NULL
 };
 
-static int option_parse_z(const struct option *opt,
-                         const char *arg, int unset)
-{
-       line_terminator = unset ? '\n' : '\0';
-
-       return 0;
-}
-
 static int option_parse_exclude(const struct option *opt,
                                const char *arg, int unset)
 {
@@ -428,9 +420,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
        struct exclude_list *el;
        struct string_list exclude_list = STRING_LIST_INIT_NODUP;
        struct option builtin_ls_files_options[] = {
-               { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
-                       N_("paths are separated with NUL character"),
-                       PARSE_OPT_NOARG, option_parse_z },
+               /* Think twice before adding "--nul" synonym to this */
+               OPT_SET_INT('z', NULL, &line_terminator,
+                       N_("paths are separated with NUL character"), '\0'),
                OPT_BOOL('t', NULL, &show_tag,
                        N_("identify the file status with tags")),
                OPT_BOOL('v', NULL, &show_valid_bit,
index 7c5c143de5dc74dda2b17832037268fc4e4b9d60..1c94ca59bfcd756c94d86ef46592528e8fbfdcb1 100644 (file)
@@ -35,6 +35,15 @@ static int mark_skip_worktree_only;
 #define UNMARK_FLAG 2
 static struct strbuf mtime_dir = STRBUF_INIT;
 
+/* Untracked cache mode */
+enum uc_mode {
+       UC_UNSPECIFIED = -1,
+       UC_DISABLE = 0,
+       UC_ENABLE,
+       UC_TEST,
+       UC_FORCE
+};
+
 __attribute__((format (printf, 1, 2)))
 static void report(const char *fmt, ...)
 {
@@ -121,7 +130,7 @@ static int test_if_untracked_cache_is_supported(void)
        if (!mkdtemp(mtime_dir.buf))
                die_errno("Could not make temporary directory");
 
-       fprintf(stderr, _("Testing "));
+       fprintf(stderr, _("Testing mtime in '%s' "), xgetcwd());
        atexit(remove_test_directory);
        xstat_mtime_dir(&st);
        fill_stat_data(&base, &st);
@@ -904,7 +913,7 @@ static int reupdate_callback(struct parse_opt_ctx_t *ctx,
 int cmd_update_index(int argc, const char **argv, const char *prefix)
 {
        int newfd, entries, has_errors = 0, nul_term_line = 0;
-       int untracked_cache = -1;
+       enum uc_mode untracked_cache = UC_UNSPECIFIED;
        int read_from_stdin = 0;
        int prefix_length = prefix ? strlen(prefix) : 0;
        int preferred_index_format = 0;
@@ -999,8 +1008,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
                        N_("enable or disable split index")),
                OPT_BOOL(0, "untracked-cache", &untracked_cache,
                        N_("enable/disable untracked cache")),
+               OPT_SET_INT(0, "test-untracked-cache", &untracked_cache,
+                           N_("test if the filesystem supports untracked cache"), UC_TEST),
                OPT_SET_INT(0, "force-untracked-cache", &untracked_cache,
-                           N_("enable untracked cache without testing the filesystem"), 2),
+                           N_("enable untracked cache without testing the filesystem"), UC_FORCE),
                OPT_END()
        };
 
@@ -1075,16 +1086,17 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
        }
 
        if (read_from_stdin) {
-               struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
+               struct strbuf buf = STRBUF_INIT;
+               struct strbuf unquoted = STRBUF_INIT;
 
                setup_work_tree();
                while (getline_fn(&buf, stdin) != EOF) {
                        char *p;
                        if (!nul_term_line && buf.buf[0] == '"') {
-                               strbuf_reset(&nbuf);
-                               if (unquote_c_style(&nbuf, buf.buf, NULL))
+                               strbuf_reset(&unquoted);
+                               if (unquote_c_style(&unquoted, buf.buf, NULL))
                                        die("line is badly quoted");
-                               strbuf_swap(&buf, &nbuf);
+                               strbuf_swap(&buf, &unquoted);
                        }
                        p = prefix_path(prefix, prefix_length, buf.buf);
                        update_one(p);
@@ -1092,7 +1104,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
                                chmod_path(set_executable_bit, p);
                        free(p);
                }
-               strbuf_release(&nbuf);
+               strbuf_release(&unquoted);
                strbuf_release(&buf);
        }
 
@@ -1109,27 +1121,32 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
                the_index.split_index = NULL;
                the_index.cache_changed |= SOMETHING_CHANGED;
        }
-       if (untracked_cache > 0) {
-               struct untracked_cache *uc;
 
-               if (untracked_cache < 2) {
-                       setup_work_tree();
-                       if (!test_if_untracked_cache_is_supported())
-                               return 1;
-               }
-               if (!the_index.untracked) {
-                       uc = xcalloc(1, sizeof(*uc));
-                       strbuf_init(&uc->ident, 100);
-                       uc->exclude_per_dir = ".gitignore";
-                       /* should be the same flags used by git-status */
-                       uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
-                       the_index.untracked = uc;
-               }
-               add_untracked_ident(the_index.untracked);
-               the_index.cache_changed |= UNTRACKED_CHANGED;
-       } else if (!untracked_cache && the_index.untracked) {
-               the_index.untracked = NULL;
-               the_index.cache_changed |= UNTRACKED_CHANGED;
+       switch (untracked_cache) {
+       case UC_UNSPECIFIED:
+               break;
+       case UC_DISABLE:
+               if (git_config_get_untracked_cache() == 1)
+                       warning("core.untrackedCache is set to true; "
+                               "remove or change it, if you really want to "
+                               "disable the untracked cache");
+               remove_untracked_cache(&the_index);
+               report(_("Untracked cache disabled"));
+               break;
+       case UC_TEST:
+               setup_work_tree();
+               return !test_if_untracked_cache_is_supported();
+       case UC_ENABLE:
+       case UC_FORCE:
+               if (git_config_get_untracked_cache() == 0)
+                       warning("core.untrackedCache is set to false; "
+                               "remove or change it, if you really want to "
+                               "enable the untracked cache");
+               add_untracked_cache(&the_index);
+               report(_("Untracked cache enabled for '%s'"), get_git_work_tree());
+               break;
+       default:
+               die("Bug: bad untracked_cache value: %d", untracked_cache);
        }
 
        if (active_cache_changed) {
diff --git a/cache.h b/cache.h
index dfc459c0637ff2ff94adba27ec40df84bd82b709..26640b421d938a215236935d35c2d6b4f37fee6d 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -458,7 +458,6 @@ extern char *git_work_tree_cfg;
 extern int is_inside_work_tree(void);
 extern const char *get_git_dir(void);
 extern const char *get_git_common_dir(void);
-extern int is_git_directory(const char *path);
 extern char *get_object_directory(void);
 extern char *get_index_file(void);
 extern char *get_graft_file(void);
@@ -469,6 +468,25 @@ extern const char *get_git_namespace(void);
 extern const char *strip_namespace(const char *namespaced_ref);
 extern const char *get_git_work_tree(void);
 
+/*
+ * Return true if the given path is a git directory; note that this _just_
+ * looks at the directory itself. If you want to know whether "foo/.git"
+ * is a repository, you must feed that path, not just "foo".
+ */
+extern int is_git_directory(const char *path);
+
+/*
+ * Return 1 if the given path is the root of a git repository or
+ * submodule, else 0. Will not return 1 for bare repositories with the
+ * exception of creating a bare repository in "foo/.git" and calling
+ * is_git_repository("foo").
+ *
+ * If we run into read errors, we err on the side of saying "yes, it is",
+ * as we usually consider sub-repos precious, and would prefer to err on the
+ * side of not disrupting or deleting them.
+ */
+extern int is_nonbare_repository_dir(struct strbuf *path);
+
 #define READ_GITFILE_ERR_STAT_FAILED 1
 #define READ_GITFILE_ERR_NOT_A_FILE 2
 #define READ_GITFILE_ERR_OPEN_FAILED 3
@@ -1606,6 +1624,14 @@ extern int git_config_get_bool(const char *key, int *dest);
 extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
 extern int git_config_get_maybe_bool(const char *key, int *dest);
 extern int git_config_get_pathname(const char *key, const char **dest);
+extern int git_config_get_untracked_cache(void);
+
+/*
+ * This is a hack for test programs like test-dump-untracked-cache to
+ * ensure that they do not modify the untracked cache when reading it.
+ * Do not use it otherwise!
+ */
+extern int ignore_untracked_cache_config;
 
 struct key_value_info {
        const char *filename;
index 77a51d3f72ebf8a3fa53b72e93b26f4e60c710b8..fbe69b874b06259e1d699572ace7dd8d2c4667c6 100644 (file)
@@ -454,6 +454,39 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
        return (time_t)(filetime_to_hnsec(ft) / 10000000);
 }
 
+/**
+ * Verifies that safe_create_leading_directories() would succeed.
+ */
+static int has_valid_directory_prefix(wchar_t *wfilename)
+{
+       int n = wcslen(wfilename);
+
+       while (n > 0) {
+               wchar_t c = wfilename[--n];
+               DWORD attributes;
+
+               if (!is_dir_sep(c))
+                       continue;
+
+               wfilename[n] = L'\0';
+               attributes = GetFileAttributesW(wfilename);
+               wfilename[n] = c;
+               if (attributes == FILE_ATTRIBUTE_DIRECTORY ||
+                               attributes == FILE_ATTRIBUTE_DEVICE)
+                       return 1;
+               if (attributes == INVALID_FILE_ATTRIBUTES)
+                       switch (GetLastError()) {
+                       case ERROR_PATH_NOT_FOUND:
+                               continue;
+                       case ERROR_FILE_NOT_FOUND:
+                               /* This implies parent directory exists. */
+                               return 1;
+                       }
+               return 0;
+       }
+       return 1;
+}
+
 /* We keep the do_lstat code in a separate function to avoid recursion.
  * When a path ends with a slash, the stat will fail with ENOENT. In
  * this case, we strip the trailing slashes and stat again.
@@ -514,6 +547,12 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
        case ERROR_NOT_ENOUGH_MEMORY:
                errno = ENOMEM;
                break;
+       case ERROR_PATH_NOT_FOUND:
+               if (!has_valid_directory_prefix(wfilename)) {
+                       errno = ENOTDIR;
+                       break;
+               }
+               /* fallthru */
        default:
                errno = ENOENT;
                break;
@@ -1603,7 +1642,12 @@ int mingw_rename(const char *pold, const char *pnew)
        if (gle == ERROR_ACCESS_DENIED &&
            (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
                if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
-                       errno = EISDIR;
+                       DWORD attrsold = GetFileAttributesW(wpold);
+                       if (attrsold == INVALID_FILE_ATTRIBUTES ||
+                           !(attrsold & FILE_ATTRIBUTE_DIRECTORY))
+                               errno = EISDIR;
+                       else if (!_wrmdir(wpnew))
+                               goto repeat;
                        return -1;
                }
                if ((attrs & FILE_ATTRIBUTE_READONLY) &&
@@ -2047,6 +2091,37 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
        return -1;
 }
 
+static void setup_windows_environment()
+{
+       char *tmp = getenv("TMPDIR");
+
+       /* on Windows it is TMP and TEMP */
+       if (!tmp) {
+               if (!(tmp = getenv("TMP")))
+                       tmp = getenv("TEMP");
+               if (tmp) {
+                       setenv("TMPDIR", tmp, 1);
+                       tmp = getenv("TMPDIR");
+               }
+       }
+
+       if (tmp) {
+               /*
+                * Convert all dir separators to forward slashes,
+                * to help shell commands called from the Git
+                * executable (by not mistaking the dir separators
+                * for escape characters).
+                */
+               for (; *tmp; tmp++)
+                       if (*tmp == '\\')
+                               *tmp = '/';
+       }
+
+       /* simulate TERM to enable auto-color (see color.c) */
+       if (!getenv("TERM"))
+               setenv("TERM", "cygwin", 1);
+}
+
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
@@ -2125,19 +2200,7 @@ void mingw_startup()
        qsort(environ, i, sizeof(char*), compareenv);
 
        /* fix Windows specific environment settings */
-
-       /* on Windows it is TMP and TEMP */
-       if (!mingw_getenv("TMPDIR")) {
-               const char *tmp = mingw_getenv("TMP");
-               if (!tmp)
-                       tmp = mingw_getenv("TEMP");
-               if (tmp)
-                       setenv("TMPDIR", tmp, 1);
-       }
-
-       /* simulate TERM to enable auto-color (see color.c) */
-       if (!getenv("TERM"))
-               setenv("TERM", "cygwin", 1);
+       setup_windows_environment();
 
        /* initialize critical section for waitpid pinfo_t list */
        InitializeCriticalSection(&pinfo_cs);
index 86a5eb2571fb282a1d7bad9e6d097b2374b550dc..b95ac3a9cd5ca4fef392a2202f0a5722d15b8dde 100644 (file)
--- a/config.c
+++ b/config.c
@@ -1594,6 +1594,30 @@ int git_config_get_pathname(const char *key, const char **dest)
        return ret;
 }
 
+int git_config_get_untracked_cache(void)
+{
+       int val = -1;
+       const char *v;
+
+       /* Hack for test programs like test-dump-untracked-cache */
+       if (ignore_untracked_cache_config)
+               return -1;
+
+       if (!git_config_get_maybe_bool("core.untrackedcache", &val))
+               return val;
+
+       if (!git_config_get_value("core.untrackedcache", &v)) {
+               if (!strcasecmp(v, "keep"))
+                       return -1;
+
+               error("unknown core.untrackedCache value '%s'; "
+                     "using 'keep' default value", v);
+               return -1;
+       }
+
+       return -1; /* default value */
+}
+
 NORETURN
 void git_die_config_linenr(const char *key, const char *filename, int linenr)
 {
index 4b2e1b807fc4e6f4467f0da891afe9aa8dad6310..d6f7980bb91ab7d1e4a02a91407bd8e38461671b 100644 (file)
@@ -560,7 +560,8 @@ else
                NO_R_TO_GCC_LINKER = YesPlease
                INTERNAL_QSORT = YesPlease
                HAVE_LIBCHARSET_H = YesPlease
-               NO_GETTEXT = YesPlease
+               NO_GETTEXT =
+               USE_GETTEXT_SCHEME = fallthrough
                USE_LIBPCRE= YesPlease
                NO_CURL =
                USE_NED_ALLOCATOR = YesPlease
index 15ebba51dc11ec28f98f6c759719125f155aa5d3..45ec47f2b1b45e346290e7bbad143519b1ad91a6 100644 (file)
@@ -2060,6 +2060,7 @@ _git_config ()
                core.sparseCheckout
                core.symlinks
                core.trustctime
+               core.untrackedCache
                core.warnAmbiguousRefs
                core.whitespace
                core.worktree
index 4bb4ec1d836e695a86f309b276fd07e300885c57..8cd6222a263ac99a63335bf7080a3fb4dd797ff7 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -434,7 +434,7 @@ static int apply_filter(const char *path, const char *src, size_t len, int fd,
        struct async async;
        struct filter_params params;
 
-       if (!cmd)
+       if (!cmd || !*cmd)
                return 0;
 
        if (!dst)
diff --git a/dir.c b/dir.c
index 29aec124871e44972de70cb05f1c6023e514fcc2..f0b6d0a3eab704311ed2c93a3da5db0683b3125c 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -1839,31 +1839,67 @@ static const char *get_ident_string(void)
                return sb.buf;
        if (uname(&uts) < 0)
                die_errno(_("failed to get kernel name and information"));
-       strbuf_addf(&sb, "Location %s, system %s %s %s", get_git_work_tree(),
-                   uts.sysname, uts.release, uts.version);
+       strbuf_addf(&sb, "Location %s, system %s", get_git_work_tree(),
+                   uts.sysname);
        return sb.buf;
 }
 
 static int ident_in_untracked(const struct untracked_cache *uc)
 {
-       const char *end = uc->ident.buf + uc->ident.len;
-       const char *p   = uc->ident.buf;
+       /*
+        * Previous git versions may have saved many NUL separated
+        * strings in the "ident" field, but it is insane to manage
+        * many locations, so just take care of the first one.
+        */
 
-       for (p = uc->ident.buf; p < end; p += strlen(p) + 1)
-               if (!strcmp(p, get_ident_string()))
-                       return 1;
-       return 0;
+       return !strcmp(uc->ident.buf, get_ident_string());
 }
 
-void add_untracked_ident(struct untracked_cache *uc)
+static void set_untracked_ident(struct untracked_cache *uc)
 {
-       if (ident_in_untracked(uc))
-               return;
+       strbuf_reset(&uc->ident);
        strbuf_addstr(&uc->ident, get_ident_string());
-       /* this strbuf contains a list of strings, save NUL too */
+
+       /*
+        * This strbuf used to contain a list of NUL separated
+        * strings, so save NUL too for backward compatibility.
+        */
        strbuf_addch(&uc->ident, 0);
 }
 
+static void new_untracked_cache(struct index_state *istate)
+{
+       struct untracked_cache *uc = xcalloc(1, sizeof(*uc));
+       strbuf_init(&uc->ident, 100);
+       uc->exclude_per_dir = ".gitignore";
+       /* should be the same flags used by git-status */
+       uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
+       set_untracked_ident(uc);
+       istate->untracked = uc;
+       istate->cache_changed |= UNTRACKED_CHANGED;
+}
+
+void add_untracked_cache(struct index_state *istate)
+{
+       if (!istate->untracked) {
+               new_untracked_cache(istate);
+       } else {
+               if (!ident_in_untracked(istate->untracked)) {
+                       free_untracked_cache(istate->untracked);
+                       new_untracked_cache(istate);
+               }
+       }
+}
+
+void remove_untracked_cache(struct index_state *istate)
+{
+       if (istate->untracked) {
+               free_untracked_cache(istate->untracked);
+               istate->untracked = NULL;
+               istate->cache_changed |= UNTRACKED_CHANGED;
+       }
+}
+
 static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *dir,
                                                      int base_len,
                                                      const struct pathspec *pathspec)
@@ -1921,7 +1957,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
                return NULL;
 
        if (!ident_in_untracked(dir->untracked)) {
-               warning(_("Untracked cache is disabled on this system."));
+               warning(_("Untracked cache is disabled on this system or location."));
                return NULL;
        }
 
diff --git a/dir.h b/dir.h
index 7b5855dd80eda02973a55c827d79826a25937880..cd46f30017ce239720926afdad4301b2ac402ccf 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -307,5 +307,6 @@ void untracked_cache_add_to_index(struct index_state *, const char *);
 void free_untracked_cache(struct untracked_cache *);
 struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz);
 void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked);
-void add_untracked_ident(struct untracked_cache *);
+void add_untracked_cache(struct index_state *istate);
+void remove_untracked_cache(struct index_state *istate);
 #endif
index 1cc4aab4eacb629f8fe147c2e20b53c4141587aa..6dec9d0403f11579a7ab316db87a1dbbc58e71b2 100644 (file)
@@ -87,6 +87,13 @@ int auto_comment_line_char;
 /* Parallel index stat data preload? */
 int core_preload_index = 1;
 
+/*
+ * This is a hack for test programs like test-dump-untracked-cache to
+ * ensure that they do not modify the untracked cache when reading it.
+ * Do not use it otherwise!
+ */
+int ignore_untracked_cache_config;
+
 /* This is set by setup_git_dir_gently() and/or git_default_config() */
 char *git_work_tree_cfg;
 static char *work_tree;
diff --git a/git.c b/git.c
index da278c3d41ed308581ffec46e3487e7670898d41..6c64c9430e8e5ae3130b0c97e90bcbad29625b1e 100644 (file)
--- a/git.c
+++ b/git.c
@@ -25,14 +25,14 @@ static const char *env_names[] = {
        GIT_PREFIX_ENVIRONMENT
 };
 static char *orig_env[4];
-static int saved_env_before_alias;
+static int save_restore_env_balance;
 
 static void save_env_before_alias(void)
 {
        int i;
-       if (saved_env_before_alias)
-               return;
-       saved_env_before_alias = 1;
+
+       assert(save_restore_env_balance == 0);
+       save_restore_env_balance = 1;
        orig_cwd = xgetcwd();
        for (i = 0; i < ARRAY_SIZE(env_names); i++) {
                orig_env[i] = getenv(env_names[i]);
@@ -44,6 +44,9 @@ static void save_env_before_alias(void)
 static void restore_env(int external_alias)
 {
        int i;
+
+       assert(save_restore_env_balance == 1);
+       save_restore_env_balance = 0;
        if (!external_alias && orig_cwd && chdir(orig_cwd))
                die_errno("could not move to %s", orig_cwd);
        free(orig_cwd);
@@ -51,10 +54,12 @@ static void restore_env(int external_alias)
                if (external_alias &&
                    !strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT))
                        continue;
-               if (orig_env[i])
+               if (orig_env[i]) {
                        setenv(env_names[i], orig_env[i], 1);
-               else
+                       free(orig_env[i]);
+               } else {
                        unsetenv(env_names[i]);
+               }
        }
 }
 
@@ -531,16 +536,8 @@ static void handle_builtin(int argc, const char **argv)
        }
 
        builtin = get_builtin(cmd);
-       if (builtin) {
-               /*
-                * XXX: if we can figure out cases where it is _safe_
-                * to do, we can avoid spawning a new process when
-                * saved_env_before_alias is true
-                * (i.e. setup_git_dir* has been run once)
-                */
-               if (!saved_env_before_alias)
-                       exit(run_builtin(builtin, argc, argv));
-       }
+       if (builtin)
+               exit(run_builtin(builtin, argc, argv));
 }
 
 static void execv_dashed_external(const char **argv)
@@ -584,8 +581,17 @@ static int run_argv(int *argcp, const char ***argv)
        int done_alias = 0;
 
        while (1) {
-               /* See if it's a builtin */
-               handle_builtin(*argcp, *argv);
+               /*
+                * If we tried alias and futzed with our environment,
+                * it no longer is safe to invoke builtins directly in
+                * general.  We have to spawn them as dashed externals.
+                *
+                * NEEDSWORK: if we can figure out cases
+                * where it is safe to do, we can avoid spawning a new
+                * process.
+                */
+               if (!done_alias)
+                       handle_builtin(*argcp, *argv);
 
                /* .. then try the external ones */
                execv_dashed_external(*argv);
diff --git a/http.c b/http.c
index 0da9e6639832a493f932e3ba332683d3d4ae73ae..dfc53c1e2554e76126459d6cb1f098facac28593 100644 (file)
--- a/http.c
+++ b/http.c
@@ -62,6 +62,26 @@ static long curl_low_speed_limit = -1;
 static long curl_low_speed_time = -1;
 static int curl_ftp_no_epsv;
 static const char *curl_http_proxy;
+static const char *http_proxy_authmethod;
+static struct {
+       const char *name;
+       long curlauth_param;
+} proxy_authmethods[] = {
+       { "basic", CURLAUTH_BASIC },
+       { "digest", CURLAUTH_DIGEST },
+       { "negotiate", CURLAUTH_GSSNEGOTIATE },
+       { "ntlm", CURLAUTH_NTLM },
+#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
+       { "anyauth", CURLAUTH_ANY },
+#endif
+       /*
+        * CURLAUTH_DIGEST_IE has no corresponding command-line option in
+        * curl(1) and is not included in CURLAUTH_ANY, so we leave it out
+        * here, too
+        */
+};
+static struct credential proxy_auth = CREDENTIAL_INIT;
+static const char *curl_proxyuserpwd;
 static const char *curl_cookie_file;
 static int curl_save_cookies;
 struct credential http_auth = CREDENTIAL_INIT;
@@ -159,6 +179,9 @@ static void finish_active_slot(struct active_request_slot *slot)
 #else
                slot->results->auth_avail = 0;
 #endif
+
+               curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CONNECTCODE,
+                       &slot->results->http_connectcode);
        }
 
        /* Run callback if appropriate */
@@ -256,6 +279,9 @@ static int http_options(const char *var, const char *value, void *cb)
        if (!strcmp("http.proxy", var))
                return git_config_string(&curl_http_proxy, var, value);
 
+       if (!strcmp("http.proxyauthmethod", var))
+               return git_config_string(&http_proxy_authmethod, var, value);
+
        if (!strcmp("http.cookiefile", var))
                return git_config_string(&curl_cookie_file, var, value);
        if (!strcmp("http.savecookies", var)) {
@@ -304,6 +330,64 @@ static void init_curl_http_auth(CURL *result)
 #endif
 }
 
+/* *var must be free-able */
+static void var_override(const char **var, char *value)
+{
+       if (value) {
+               free((void *)*var);
+               *var = xstrdup(value);
+       }
+}
+
+static void set_proxyauth_name_password(CURL *result)
+{
+#if LIBCURL_VERSION_NUM >= 0x071301
+               curl_easy_setopt(result, CURLOPT_PROXYUSERNAME,
+                       proxy_auth.username);
+               curl_easy_setopt(result, CURLOPT_PROXYPASSWORD,
+                       proxy_auth.password);
+#else
+               struct strbuf s = STRBUF_INIT;
+
+               strbuf_addstr_urlencode(&s, proxy_auth.username, 1);
+               strbuf_addch(&s, ':');
+               strbuf_addstr_urlencode(&s, proxy_auth.password, 1);
+               curl_proxyuserpwd = strbuf_detach(&s, NULL);
+               curl_easy_setopt(result, CURLOPT_PROXYUSERPWD, curl_proxyuserpwd);
+#endif
+}
+
+static void init_curl_proxy_auth(CURL *result)
+{
+       if (proxy_auth.username) {
+               if (!proxy_auth.password)
+                       credential_fill(&proxy_auth);
+               set_proxyauth_name_password(result);
+       }
+
+       var_override(&http_proxy_authmethod, getenv("GIT_HTTP_PROXY_AUTHMETHOD"));
+
+#if LIBCURL_VERSION_NUM >= 0x070a07 /* CURLOPT_PROXYAUTH and CURLAUTH_ANY */
+       if (http_proxy_authmethod) {
+               int i;
+               for (i = 0; i < ARRAY_SIZE(proxy_authmethods); i++) {
+                       if (!strcmp(http_proxy_authmethod, proxy_authmethods[i].name)) {
+                               curl_easy_setopt(result, CURLOPT_PROXYAUTH,
+                                               proxy_authmethods[i].curlauth_param);
+                               break;
+                       }
+               }
+               if (i == ARRAY_SIZE(proxy_authmethods)) {
+                       warning("unsupported proxy authentication method %s: using anyauth",
+                                       http_proxy_authmethod);
+                       curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+               }
+       }
+       else
+               curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+#endif
+}
+
 static int has_cert_password(void)
 {
        if (ssl_cert == NULL || ssl_cert_password_required != 1)
@@ -462,6 +546,31 @@ static CURL *get_curl_handle(void)
                curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY);
 #endif
 
+       /*
+        * CURL also examines these variables as a fallback; but we need to query
+        * them here in order to decide whether to prompt for missing password (cf.
+        * init_curl_proxy_auth()).
+        *
+        * Unlike many other common environment variables, these are historically
+        * lowercase only. It appears that CURL did not know this and implemented
+        * only uppercase variants, which was later corrected to take both - with
+        * the exception of http_proxy, which is lowercase only also in CURL. As
+        * the lowercase versions are the historical quasi-standard, they take
+        * precedence here, as in CURL.
+        */
+       if (!curl_http_proxy) {
+               if (!strcmp(http_auth.protocol, "https")) {
+                       var_override(&curl_http_proxy, getenv("HTTPS_PROXY"));
+                       var_override(&curl_http_proxy, getenv("https_proxy"));
+               } else {
+                       var_override(&curl_http_proxy, getenv("http_proxy"));
+               }
+               if (!curl_http_proxy) {
+                       var_override(&curl_http_proxy, getenv("ALL_PROXY"));
+                       var_override(&curl_http_proxy, getenv("all_proxy"));
+               }
+       }
+
        if (curl_http_proxy) {
                curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
 #if LIBCURL_VERSION_NUM >= 0x071800
@@ -475,10 +584,18 @@ static CURL *get_curl_handle(void)
                        curl_easy_setopt(result,
                                CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
 #endif
+               if (strstr(curl_http_proxy, "://"))
+                       credential_from_url(&proxy_auth, curl_http_proxy);
+               else {
+                       struct strbuf url = STRBUF_INIT;
+                       strbuf_addf(&url, "http://%s", curl_http_proxy);
+                       credential_from_url(&proxy_auth, url.buf);
+                       strbuf_release(&url);
+               }
+
+               curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host);
        }
-#if LIBCURL_VERSION_NUM >= 0x070a07
-       curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
-#endif
+       init_curl_proxy_auth(result);
 
        set_curl_keepalive(result);
 
@@ -519,6 +636,9 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
        if (remote && remote->http_proxy)
                curl_http_proxy = xstrdup(remote->http_proxy);
 
+       if (remote)
+               var_override(&http_proxy_authmethod, remote->http_proxy_authmethod);
+
        pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache");
        no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
 
@@ -617,6 +737,18 @@ void http_cleanup(void)
                curl_http_proxy = NULL;
        }
 
+       if (proxy_auth.password) {
+               memset(proxy_auth.password, 0, strlen(proxy_auth.password));
+               free(proxy_auth.password);
+               proxy_auth.password = NULL;
+       }
+
+       free((void *)curl_proxyuserpwd);
+       curl_proxyuserpwd = NULL;
+
+       free((void *)http_proxy_authmethod);
+       http_proxy_authmethod = NULL;
+
        if (cert_auth.password != NULL) {
                memset(cert_auth.password, 0, strlen(cert_auth.password));
                free(cert_auth.password);
@@ -946,6 +1078,8 @@ static int handle_curl_result(struct slot_results *results)
 
        if (results->curl_result == CURLE_OK) {
                credential_approve(&http_auth);
+               if (proxy_auth.password)
+                       credential_approve(&proxy_auth);
                return HTTP_OK;
        } else if (missing_target(results))
                return HTTP_MISSING_TARGET;
@@ -960,6 +1094,8 @@ static int handle_curl_result(struct slot_results *results)
                        return HTTP_REAUTH;
                }
        } else {
+               if (results->http_connectcode == 407)
+                       credential_reject(&proxy_auth);
 #if LIBCURL_VERSION_NUM >= 0x070c00
                if (!curl_errorstr[0])
                        strlcpy(curl_errorstr,
diff --git a/http.h b/http.h
index 4f97b60b5c8abdf5ab0610382a6d6fa289df2605..f83cfa686823728587b2a803c3e84a8cd4669220 100644 (file)
--- a/http.h
+++ b/http.h
@@ -54,6 +54,7 @@ struct slot_results {
        CURLcode curl_result;
        long http_code;
        long auth_avail;
+       long http_connectcode;
 };
 
 struct active_request_slot {
diff --git a/ident.c b/ident.c
index 3da555634290f1812702e2d6da15e5a6806fe635..6e125821f0563c46eaf8253f31e19d9d97a94e7e 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -13,11 +13,14 @@ static struct strbuf git_default_date = STRBUF_INIT;
 static int default_email_is_bogus;
 static int default_name_is_bogus;
 
+static int ident_use_config_only;
+
 #define IDENT_NAME_GIVEN 01
 #define IDENT_MAIL_GIVEN 02
 #define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN)
 static int committer_ident_explicitly_given;
 static int author_ident_explicitly_given;
+static int ident_config_given;
 
 #ifdef NO_GECOS_IN_PWENT
 #define get_gecos(ignored) "&"
@@ -345,32 +348,40 @@ const char *fmt_ident(const char *name, const char *email,
        int want_date = !(flag & IDENT_NO_DATE);
        int want_name = !(flag & IDENT_NO_NAME);
 
-       if (want_name && !name)
-               name = ident_default_name();
-       if (!email)
-               email = ident_default_email();
-
-       if (want_name && !*name) {
-               struct passwd *pw;
-
-               if (strict) {
-                       if (name == git_default_name.buf)
+       if (want_name) {
+               int using_default = 0;
+               if (!name) {
+                       name = ident_default_name();
+                       using_default = 1;
+                       if (strict && default_name_is_bogus) {
                                fputs(env_hint, stderr);
-                       die("empty ident name (for <%s>) not allowed", email);
+                               die("unable to auto-detect name (got '%s')", name);
+                       }
+                       if (strict && ident_use_config_only
+                           && !(ident_config_given & IDENT_NAME_GIVEN))
+                               die("user.useConfigOnly set but no name given");
+               }
+               if (!*name) {
+                       struct passwd *pw;
+                       if (strict) {
+                               if (using_default)
+                                       fputs(env_hint, stderr);
+                               die("empty ident name (for <%s>) not allowed", email);
+                       }
+                       pw = xgetpwuid_self(NULL);
+                       name = pw->pw_name;
                }
-               pw = xgetpwuid_self(NULL);
-               name = pw->pw_name;
-       }
-
-       if (want_name && strict &&
-           name == git_default_name.buf && default_name_is_bogus) {
-               fputs(env_hint, stderr);
-               die("unable to auto-detect name (got '%s')", name);
        }
 
-       if (strict && email == git_default_email.buf && default_email_is_bogus) {
-               fputs(env_hint, stderr);
-               die("unable to auto-detect email address (got '%s')", email);
+       if (!email) {
+               email = ident_default_email();
+               if (strict && default_email_is_bogus) {
+                       fputs(env_hint, stderr);
+                       die("unable to auto-detect email address (got '%s')", email);
+               }
+               if (strict && ident_use_config_only
+                   && !(ident_config_given & IDENT_MAIL_GIVEN))
+                       die("user.useConfigOnly set but no mail given");
        }
 
        strbuf_reset(&ident);
@@ -444,6 +455,11 @@ int author_ident_sufficiently_given(void)
 
 int git_ident_config(const char *var, const char *value, void *data)
 {
+       if (!strcmp(var, "user.useconfigonly")) {
+               ident_use_config_only = git_config_bool(var, value);
+               return 0;
+       }
+
        if (!strcmp(var, "user.name")) {
                if (!value)
                        return config_error_nonbool(var);
@@ -451,6 +467,7 @@ int git_ident_config(const char *var, const char *value, void *data)
                strbuf_addstr(&git_default_name, value);
                committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
                author_ident_explicitly_given |= IDENT_NAME_GIVEN;
+               ident_config_given |= IDENT_NAME_GIVEN;
                return 0;
        }
 
@@ -461,6 +478,7 @@ int git_ident_config(const char *var, const char *value, void *data)
                strbuf_addstr(&git_default_email, value);
                committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
                author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
+               ident_config_given |= IDENT_MAIL_GIVEN;
                return 0;
        }
 
index 19ef081103a56e3c723749dc172ccc356a9b795c..49eb88af8d052e2bd71b83576034f8d338290013 100644 (file)
@@ -188,7 +188,8 @@ sub repository {
                };
 
                if ($dir) {
-                       $dir =~ m#^/# or $dir = $opts{Directory} . '/' . $dir;
+                       _verify_require();
+                       File::Spec->file_name_is_absolute($dir) or $dir = $opts{Directory} . '/' . $dir;
                        $opts{Repository} = abs_path($dir);
 
                        # If --git-dir went ok, this shouldn't die either.
index 5be7cd1dbf50c850ee5e02dcfde69d7611c181b5..d9fb78bc559ac9de642833df5af63e33481cad52 100644 (file)
@@ -1519,6 +1519,28 @@ static void check_ce_order(struct index_state *istate)
        }
 }
 
+static void tweak_untracked_cache(struct index_state *istate)
+{
+       switch (git_config_get_untracked_cache()) {
+       case -1: /* keep: do nothing */
+               break;
+       case 0: /* false */
+               remove_untracked_cache(istate);
+               break;
+       case 1: /* true */
+               add_untracked_cache(istate);
+               break;
+       default: /* unknown value: do nothing */
+               break;
+       }
+}
+
+static void post_read_index_from(struct index_state *istate)
+{
+       check_ce_order(istate);
+       tweak_untracked_cache(istate);
+}
+
 /* remember to discard_cache() before reading a different cache! */
 int do_read_index(struct index_state *istate, const char *path, int must_exist)
 {
@@ -1622,9 +1644,10 @@ int read_index_from(struct index_state *istate, const char *path)
                return istate->cache_nr;
 
        ret = do_read_index(istate, path, 0);
+
        split_index = istate->split_index;
        if (!split_index || is_null_sha1(split_index->base_sha1)) {
-               check_ce_order(istate);
+               post_read_index_from(istate);
                return ret;
        }
 
@@ -1642,7 +1665,7 @@ int read_index_from(struct index_state *istate, const char *path)
                             sha1_to_hex(split_index->base_sha1)),
                    sha1_to_hex(split_index->base->sha1));
        merge_base_index(istate);
-       check_ce_order(istate);
+       post_read_index_from(istate);
        return ret;
 }
 
index 81c92b410eb76cd11dd56f6b82afec6668745dd1..b56976288819c87307c03e4e5abf9b9458d09970 100644 (file)
@@ -933,6 +933,10 @@ static void clear_loose_ref_cache(struct ref_cache *refs)
        }
 }
 
+/*
+ * Create a new submodule ref cache and add it to the internal
+ * set of caches.
+ */
 static struct ref_cache *create_ref_cache(const char *submodule)
 {
        int len;
@@ -942,16 +946,12 @@ static struct ref_cache *create_ref_cache(const char *submodule)
        len = strlen(submodule) + 1;
        refs = xcalloc(1, sizeof(struct ref_cache) + len);
        memcpy(refs->name, submodule, len);
+       refs->next = submodule_ref_caches;
+       submodule_ref_caches = refs;
        return refs;
 }
 
-/*
- * Return a pointer to a ref_cache for the specified submodule. For
- * the main repository, use submodule==NULL. The returned structure
- * will be allocated and initialized but not necessarily populated; it
- * should not be freed.
- */
-static struct ref_cache *get_ref_cache(const char *submodule)
+static struct ref_cache *lookup_ref_cache(const char *submodule)
 {
        struct ref_cache *refs;
 
@@ -961,10 +961,20 @@ static struct ref_cache *get_ref_cache(const char *submodule)
        for (refs = submodule_ref_caches; refs; refs = refs->next)
                if (!strcmp(submodule, refs->name))
                        return refs;
+       return NULL;
+}
 
-       refs = create_ref_cache(submodule);
-       refs->next = submodule_ref_caches;
-       submodule_ref_caches = refs;
+/*
+ * Return a pointer to a ref_cache for the specified submodule. For
+ * the main repository, use submodule==NULL. The returned structure
+ * will be allocated and initialized but not necessarily populated; it
+ * should not be freed.
+ */
+static struct ref_cache *get_ref_cache(const char *submodule)
+{
+       struct ref_cache *refs = lookup_ref_cache(submodule);
+       if (!refs)
+               refs = create_ref_cache(submodule);
        return refs;
 }
 
@@ -1336,16 +1346,24 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
 int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)
 {
        int len = strlen(path), retval;
-       char *submodule;
+       struct strbuf submodule = STRBUF_INIT;
        struct ref_cache *refs;
 
        while (len && path[len-1] == '/')
                len--;
        if (!len)
                return -1;
-       submodule = xstrndup(path, len);
-       refs = get_ref_cache(submodule);
-       free(submodule);
+
+       strbuf_add(&submodule, path, len);
+       refs = lookup_ref_cache(submodule.buf);
+       if (!refs) {
+               if (!is_nonbare_repository_dir(&submodule)) {
+                       strbuf_release(&submodule);
+                       return -1;
+               }
+               refs = create_ref_cache(submodule.buf);
+       }
+       strbuf_release(&submodule);
 
        retval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0);
        return retval;
index 7d61dabebb3727e2e70cc282053d3138be5ead9d..02e698a5e05a02f8905ec511851eea15e86d746f 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -428,6 +428,9 @@ static int handle_config(const char *key, const char *value, void *cb)
        } else if (!strcmp(subkey, ".proxy")) {
                return git_config_string((const char **)&remote->http_proxy,
                                         key, value);
+       } else if (!strcmp(subkey, ".proxyauthmethod")) {
+               return git_config_string((const char **)&remote->http_proxy_authmethod,
+                                        key, value);
        } else if (!strcmp(subkey, ".vcs")) {
                return git_config_string(&remote->foreign_vcs, key, value);
        }
@@ -1545,11 +1548,8 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                }
 
                /*
-                * Bypass the usual "must fast-forward" check but
-                * replace it with a weaker "the old value must be
-                * this value we observed".  If the remote ref has
-                * moved and is now different from what we expect,
-                * reject any push.
+                * If the remote ref has moved and is now different
+                * from what we expect, reject any push.
                 *
                 * It also is an error if the user told us to check
                 * with the remote-tracking branch to find the value
@@ -1560,10 +1560,14 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                        if (ref->expect_old_no_trackback ||
                            oidcmp(&ref->old_oid, &ref->old_oid_expect))
                                reject_reason = REF_STATUS_REJECT_STALE;
+                       else
+                               /* If the ref isn't stale then force the update. */
+                               force_ref_update = 1;
                }
 
                /*
-                * The usual "must fast-forward" rules.
+                * If the update isn't already rejected then check
+                * the usual "must fast-forward" rules.
                 *
                 * Decide whether an individual refspec A:B can be
                 * pushed.  The push will succeed if any of the
@@ -1582,7 +1586,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                 *     passing the --force argument
                 */
 
-               else if (!ref->deletion && !is_null_oid(&ref->old_oid)) {
+               if (!reject_reason && !ref->deletion && !is_null_oid(&ref->old_oid)) {
                        if (starts_with(ref->name, "refs/tags/"))
                                reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
                        else if (!has_object_file(&ref->old_oid))
index 4a039bae0b15d6d28aace0c62287c3f3bb11befa..4fd7a0f9b2764d3de935f6387f6a93bfd7ab13b0 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -54,6 +54,7 @@ struct remote {
         * for curl remotes only
         */
        char *http_proxy;
+       char *http_proxy_authmethod;
 };
 
 struct remote *remote_get(const char *name);
diff --git a/setup.c b/setup.c
index d34372520b05a2acee36f02ddc2ef68dde4b65fd..0deb02238ba426144e0b7b077c9f2ad5c7993d23 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -312,6 +312,23 @@ int is_git_directory(const char *suspect)
        return ret;
 }
 
+int is_nonbare_repository_dir(struct strbuf *path)
+{
+       int ret = 0;
+       int gitfile_error;
+       size_t orig_path_len = path->len;
+       assert(orig_path_len != 0);
+       strbuf_complete(path, '/');
+       strbuf_addstr(path, ".git");
+       if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))
+               ret = 1;
+       if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||
+           gitfile_error == READ_GITFILE_ERR_READ_FAILED)
+               ret = 1;
+       strbuf_setlen(path, orig_path_len);
+       return ret;
+}
+
 int is_inside_git_dir(void)
 {
        if (inside_git_dir < 0)
@@ -434,17 +451,6 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
        return ret;
 }
 
-static void update_linked_gitdir(const char *gitfile, const char *gitdir)
-{
-       struct strbuf path = STRBUF_INIT;
-       struct stat st;
-
-       strbuf_addf(&path, "%s/gitdir", gitdir);
-       if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL))
-               write_file(path.buf, "%s", gitfile);
-       strbuf_release(&path);
-}
-
 /*
  * Try to read the location of the git directory from the .git file,
  * return path to git directory if found.
@@ -514,7 +520,6 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
                error_code = READ_GITFILE_ERR_NOT_A_REPO;
                goto cleanup_return;
        }
-       update_linked_gitdir(path, dir);
        path = real_path(dir);
 
 cleanup_return:
index 892db21813bc484628e940274e742d103629b0ed..89918ca158379a02368b0604b14465fa14855c8e 100644 (file)
@@ -848,8 +848,12 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l
  * through history and returning the first commit whose message starts
  * the given regular expression.
  *
- * For future extension, ':/!' is reserved. If you want to match a message
- * beginning with a '!', you have to repeat the exclamation mark.
+ * For negative-matching, prefix the pattern-part with '!-', like: ':/!-WIP'.
+ *
+ * For a literal '!' character at the beginning of a pattern, you have to repeat
+ * that, like: ':/!!foo'
+ *
+ * For future extension, all other sequences beginning with ':/!' are reserved.
  */
 
 /* Remember to update object flag allocation in object.h */
@@ -878,12 +882,18 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
 {
        struct commit_list *backup = NULL, *l;
        int found = 0;
+       int negative = 0;
        regex_t regex;
 
        if (prefix[0] == '!') {
-               if (prefix[1] != '!')
-                       die ("Invalid search pattern: %s", prefix);
                prefix++;
+
+               if (prefix[0] == '-') {
+                       prefix++;
+                       negative = 1;
+               } else if (prefix[0] != '!') {
+                       die ("Invalid search pattern: %s", prefix);
+               }
        }
 
        if (regcomp(&regex, prefix, REG_EXTENDED))
@@ -903,7 +913,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
                        continue;
                buf = get_commit_buffer(commit, NULL);
                p = strstr(buf, "\n\n");
-               matches = p && !regexec(&regex, p + 2, 0, NULL, 0);
+               matches = negative ^ (p && !regexec(&regex, p + 2, 0, NULL, 0));
                unuse_commit_buffer(commit, buf);
 
                if (matches) {
index bc4b3412fbca1f545ebdcaf23d3ef83d124ddc71..340534c0644eb46782c0a95103bd2a3ef60da9f7 100644 (file)
@@ -23,6 +23,11 @@ then
        test_done
 fi
 
+if test_have_prereq !PIPE
+then
+       test_skip_or_die $GIT_TEST_GIT_DAEMON "file system does not support FIFOs"
+fi
+
 LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-${this_test#t}}
 
 GIT_DAEMON_PID=
index ec94cdd657f838020b3bea32ac8b81caf481a4a9..7c1888a27e7fcf090698ec5ac60db72c76fbb807 100755 (executable)
@@ -28,4 +28,8 @@ test_perf 'clean many untracked sub dirs, ignore nested git' '
        git clean -n -q -f -f -d 100000_sub_dirs/
 '
 
+test_perf 'ls-files -o' '
+       git ls-files -o
+'
+
 test_done
index 4ef5ed484c12a4509b9bc66f2cc41118f7254431..89544dd8332793af7c792a45e6566f207ef57e38 100755 (executable)
@@ -5,7 +5,7 @@ test_description=check-ignore
 . ./test-lib.sh
 
 init_vars () {
-       global_excludes="$(pwd)/global-excludes"
+       global_excludes="global-excludes"
 }
 
 enable_global_excludes () {
index 718efa04d34df1f867a37d7b3073f1463457455b..7bac2bcf260794bbfeb795b210ed0c9eceb45937 100755 (executable)
@@ -252,4 +252,20 @@ test_expect_success "filter: smudge empty file" '
        test_cmp expected filtered-empty-in-repo
 '
 
+test_expect_success 'disable filter with empty override' '
+       test_config_global filter.disable.smudge false &&
+       test_config_global filter.disable.clean false &&
+       test_config filter.disable.smudge false &&
+       test_config filter.disable.clean false &&
+
+       echo "*.disable filter=disable" >.gitattributes &&
+
+       echo test >test.disable &&
+       git -c filter.disable.clean= add test.disable 2>err &&
+       test_must_be_empty err &&
+       rm -f test.disable &&
+       git -c filter.disable.smudge= checkout -- test.disable 2>err &&
+       test_must_be_empty err
+'
+
 test_done
index f0152a7ab4aabd4f47f546c038efcd8503adc9a4..8532a028e7c814057fe0bb7fd87addbd5dc90392 100755 (executable)
@@ -36,12 +36,21 @@ if test $rootoff = 2; then
        rootoff=        # we are on Unix
 else
        rootoff=$(($rootoff-1))
+       # In MSYS2, the root directory "/" is translated into a Windows
+       # directory *with* trailing slash. Let's test for that and adjust
+       # our expected longest ancestor length accordingly.
+       case "$(test-path-utils print_path /)" in
+       */) rootslash=1;;
+       *) rootslash=0;;
+       esac
 fi
 
 ancestor() {
        # We do some math with the expected ancestor length.
        expected=$3
        if test -n "$rootoff" && test "x$expected" != x-1; then
+               expected=$(($expected-$rootslash))
+               test $expected -lt 0 ||
                expected=$(($expected+$rootoff))
        fi
        test_expect_success "longest ancestor: $1 $2 => $expected" \
index 078e1195dfa1625796fdbbf1b054ebf8a1ba2621..4a9964e9dc4e0437b703a35a727e7e1971cf06fd 100755 (executable)
@@ -35,7 +35,10 @@ test_expect_success 'setup' '
        git checkout -b upstream-branch &&
        test_commit upstream-one &&
        test_commit upstream-two &&
-       git checkout -b @/at-test &&
+       if test_have_prereq !MINGW
+       then
+               git checkout -b @/at-test
+       fi &&
        git checkout -b @@/at-test &&
        git checkout -b @at-test &&
        git checkout -b old-branch &&
@@ -64,6 +67,7 @@ check "@{-1}@{u}@{1}" commit master-one
 check "@" commit new-two
 check "@@{u}" ref refs/heads/upstream-branch
 check "@@/at-test" ref refs/heads/@@/at-test
+test_have_prereq MINGW ||
 check "@/at-test" ref refs/heads/@/at-test
 check "@at-test" ref refs/heads/@at-test
 nonsense "@{u}@{-1}"
index 7043ba7947933644f15d086d8bdd95d377c4d265..e0a49a651fdd3b3f7d9e0f24e00439c9642f896c 100755 (executable)
@@ -18,7 +18,18 @@ test_expect_success 'setup' '
        git checkout master &&
        echo modified >>a-blob &&
        git add -u &&
-       git commit -m Modified
+       git commit -m Modified &&
+       git branch modref &&
+       echo changed! >>a-blob &&
+       git add -u &&
+       git commit -m !Exp &&
+       git branch expref &&
+       echo changed >>a-blob &&
+       git add -u &&
+       git commit -m Changed &&
+       echo changed-again >>a-blob &&
+       git add -u &&
+       git commit -m Changed-again
 '
 
 test_expect_success 'ref^{non-existent}' '
@@ -77,4 +88,44 @@ test_expect_success 'ref^{/Initial}' '
        test_cmp expected actual
 '
 
+test_expect_success 'ref^{/!Exp}' '
+       test_must_fail git rev-parse master^{/!Exp}
+'
+
+test_expect_success 'ref^{/!}' '
+       test_must_fail git rev-parse master^{/!}
+'
+
+test_expect_success 'ref^{/!!Exp}' '
+       git rev-parse expref >expected &&
+       git rev-parse master^{/!!Exp} >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'ref^{/!-}' '
+       test_must_fail git rev-parse master^{/!-}
+'
+
+test_expect_success 'ref^{/!-.}' '
+       test_must_fail git rev-parse master^{/!-.}
+'
+
+test_expect_success 'ref^{/!-non-existent}' '
+       git rev-parse master >expected &&
+       git rev-parse master^{/!-non-existent} >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'ref^{/!-Changed}' '
+       git rev-parse expref >expected &&
+       git rev-parse master^{/!-Changed} >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'ref^{/!-!Exp}' '
+       git rev-parse modref >expected &&
+       git rev-parse expref^{/!-!Exp} >actual &&
+       test_cmp expected actual
+'
+
 test_done
index 88be904c09214586b18f867306f7a8dcf1170cb7..c525656b2c04f8999482496688a0bd47ae8da9e2 100755 (executable)
@@ -65,6 +65,13 @@ test_expect_success '--no-empty-directory hides empty directory' '
        test_cmp expected3 output
 '
 
+test_expect_success 'ls-files --others handles non-submodule .git' '
+       mkdir not-a-submodule &&
+       echo foo >not-a-submodule/.git &&
+       git ls-files -o >output &&
+       test_cmp expected1 output
+'
+
 test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' '
        git init super &&
        git init sub &&
index 9a146f133539387a8cbc70fb4f5095eca5cd288e..04de03cad0a7466106a125205742b5feea1b1e2f 100755 (executable)
@@ -13,6 +13,7 @@ tree, index, and tree objects.
 
 HT='   '
 
+test_have_prereq MINGW ||
 echo 2>/dev/null > "Name with an${HT}HT"
 if ! test -f "Name with an${HT}HT"
 then
index 2e47a2bfd8c99988d536483a0c01d8b81396c5b5..d046d98aec61748ad936515807f28f77600f630e 100755 (executable)
@@ -14,7 +14,7 @@ test_expect_success \
      git add -- foo bar baz 'space embedded' -q &&
      git commit -m 'add normal files'"
 
-if touch -- 'tab       embedded' 'newline
+if test_have_prereq !MINGW && touch -- 'tab    embedded' 'newline
 embedded' 2>/dev/null
 then
        test_set_prereq FUNNYNAMES
index 5115de7036c38a9464dfdab0e13519a872902991..3ef525a559d91b115a3dbe4a1373c8c51fb1fc98 100755 (executable)
@@ -38,7 +38,7 @@ cat >expected <<EOF
 add 'sub/foo'
 EOF
 
-if mkdir ":" 2>/dev/null
+if test_have_prereq !MINGW && mkdir ":" 2>/dev/null
 then
        test_set_prereq COLON_DIR
 fi
index 892f5678441b3c9065f743d9fe9f071334420831..f528008c363c68f40da3b88a34ae8ec931d0c1ac 100755 (executable)
@@ -12,6 +12,7 @@ GN='純'
 HT='   '
 DQ='"'
 
+test_have_prereq MINGW ||
 echo foo 2>/dev/null > "Name and an${HT}HT"
 if ! test -f "Name and an${HT}HT"
 then
index cd543ecc5429dc175750971f4b593e327ab3fcee..9c48e5c2c99ad1eafc343a2cf6b9eeda54f644d4 100755 (executable)
@@ -13,6 +13,7 @@ P1='pathname  with HT'
 P2='pathname with SP'
 P3='pathname
 with LF'
+test_have_prereq !MINGW &&
 echo 2>/dev/null >"$P1" && test -f "$P1" && rm -f "$P1" || {
        skip_all='Your filesystem does not allow tabs in filenames'
        test_done
index bf5dc57286493b0b94caf927304e92db11e54f2c..27cb0009fb1ed52b749785c31081b3097fef0022 100755 (executable)
@@ -19,7 +19,8 @@ test_expect_success 'setup' '
 
        test_when_finished "rm -f \"tab embedded.txt\"" &&
        test_when_finished "rm -f '\''\"quoteembedded\".txt'\''" &&
-       if touch -- "tab        embedded.txt" '\''"quoteembedded".txt'\''
+       if test_have_prereq !MINGW &&
+               touch -- "tab   embedded.txt" '\''"quoteembedded".txt'\''
        then
                test_set_prereq FUNNYNAMES
        fi
index 9203a6507fa8df75ef187c129f750921caf19951..0c10c856a96072a1b0c37530a9f5c8605d8833b5 100755 (executable)
@@ -314,42 +314,6 @@ test_expect_success 'bundle should be able to create a full history' '
 
 '
 
-! rsync --help > /dev/null 2> /dev/null &&
-say 'Skipping rsync tests because rsync was not found' || {
-test_expect_success 'fetch via rsync' '
-       git pack-refs &&
-       mkdir rsynced &&
-       (cd rsynced &&
-        git init --bare &&
-        git fetch "rsync:../.git" master:refs/heads/master &&
-        git gc --prune &&
-        test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
-        git fsck --full)
-'
-
-test_expect_success 'push via rsync' '
-       mkdir rsynced2 &&
-       (cd rsynced2 &&
-        git init) &&
-       (cd rsynced &&
-        git push "rsync:../rsynced2/.git" master) &&
-       (cd rsynced2 &&
-        git gc --prune &&
-        test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
-        git fsck --full)
-'
-
-test_expect_success 'push via rsync' '
-       mkdir rsynced3 &&
-       (cd rsynced3 &&
-        git init) &&
-       git push --all "rsync:rsynced3/.git" &&
-       (cd rsynced3 &&
-        test $(git rev-parse master) = $(cd .. && git rev-parse master) &&
-        git fsck --full)
-'
-}
-
 test_expect_success 'fetch with a non-applying branch.<name>.merge' '
        git config branch.master.remote yeti &&
        git config branch.master.merge refs/heads/bigfoot &&
index c402d8d3d7c7e053373ffd98491ae0160481f3ba..c7320121ecfa74dce8389d3790364501c8bb12b8 100755 (executable)
@@ -25,7 +25,8 @@ test_expect_success 'push to update (protected)' '
        (
                cd dst &&
                test_commit D &&
-               test_must_fail git push --force-with-lease=master:master origin master
+               test_must_fail git push --force-with-lease=master:master origin master 2>err &&
+               grep "stale info" err
        ) &&
        git ls-remote . refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -37,7 +38,8 @@ test_expect_success 'push to update (protected, forced)' '
        (
                cd dst &&
                test_commit D &&
-               git push --force --force-with-lease=master:master origin master
+               git push --force --force-with-lease=master:master origin master 2>err &&
+               grep "forced update" err
        ) &&
        git ls-remote dst refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -101,7 +103,8 @@ test_expect_success 'push to update (allowed, tracking)' '
        (
                cd dst &&
                test_commit D &&
-               git push --force-with-lease=master origin master
+               git push --force-with-lease=master origin master 2>err &&
+               ! grep "forced update" err
        ) &&
        git ls-remote dst refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -114,7 +117,8 @@ test_expect_success 'push to update (allowed even though no-ff)' '
                cd dst &&
                git reset --hard HEAD^ &&
                test_commit D &&
-               git push --force-with-lease=master origin master
+               git push --force-with-lease=master origin master 2>err &&
+               grep "forced update" err
        ) &&
        git ls-remote dst refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -147,7 +151,8 @@ test_expect_success 'push to delete (allowed)' '
        setup_srcdst_basic &&
        (
                cd dst &&
-               git push --force-with-lease=master origin :master
+               git push --force-with-lease=master origin :master 2>err &&
+               grep deleted err
        ) &&
        >expect &&
        git ls-remote src refs/heads/master >actual &&
index 669ec9ba811fedeca820c4454b490e975b03bfca..c1efb8e445402cccdddda987e1eafad4d4bb75f9 100755 (executable)
@@ -4,6 +4,9 @@ test_description=clone
 
 . ./test-lib.sh
 
+X=
+test_have_prereq !MINGW || X=.exe
+
 test_expect_success setup '
 
        rm -fr .git &&
@@ -305,14 +308,9 @@ test_expect_success 'clone checking out a tag' '
 
 setup_ssh_wrapper () {
        test_expect_success 'setup ssh wrapper' '
-               write_script "$TRASH_DIRECTORY/ssh-wrapper" <<-\EOF &&
-               echo >>"$TRASH_DIRECTORY/ssh-output" "ssh: $*" &&
-               # throw away all but the last argument, which should be the
-               # command
-               while test $# -gt 1; do shift; done
-               eval "$1"
-               EOF
-               GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper" &&
+               cp "$GIT_BUILD_DIR/test-fake-ssh$X" \
+                       "$TRASH_DIRECTORY/ssh-wrapper$X" &&
+               GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper$X" &&
                export GIT_SSH &&
                export TRASH_DIRECTORY &&
                >"$TRASH_DIRECTORY"/ssh-output
@@ -320,8 +318,8 @@ setup_ssh_wrapper () {
 }
 
 copy_ssh_wrapper_as () {
-       cp "$TRASH_DIRECTORY/ssh-wrapper" "$1" &&
-       GIT_SSH="$1" &&
+       cp "$TRASH_DIRECTORY/ssh-wrapper$X" "${1%$X}$X" &&
+       GIT_SSH="${1%$X}$X" &&
        export GIT_SSH
 }
 
index 190ee903cf6269071809e82d61d6065f1de679c6..20aee43f95ab3cc38b8671a233089873fe374777 100755 (executable)
@@ -346,4 +346,17 @@ test_expect_success 'conflict at EOF without LF resolved by --union' \
         printf "line1\nline2\nline3x\nline3y" >expect.txt &&
         test_cmp expect.txt output.txt'
 
+test_expect_success 'conflict sections match existing line endings' '
+       printf "1\\r\\n2\\r\\n3" >crlf-orig.txt &&
+       printf "1\\r\\n2\\r\\n4" >crlf-diff1.txt &&
+       printf "1\\r\\n2\\r\\n5" >crlf-diff2.txt &&
+       test_must_fail git -c core.eol=crlf merge-file -p \
+               crlf-diff1.txt crlf-orig.txt crlf-diff2.txt >crlf.txt &&
+       test $(tr "\015" Q <crlf.txt | grep "^[<=>].*Q$" | wc -l) = 3 &&
+       test $(tr "\015" Q <crlf.txt | grep "[345]Q$" | wc -l) = 3 &&
+       test_must_fail git -c core.eol=crlf merge-file -p \
+               nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >nolf.txt &&
+       test $(tr "\015" Q <nolf.txt | grep "^[<=>].*Q$" | wc -l) = 0
+'
+
 test_done
index 0e8d0d42f2f5b1edbc18d46da77c956cd99dadec..a971884cfd8f03de29c978734812ab295fcbb08f 100755 (executable)
@@ -8,10 +8,8 @@ avoid_racy() {
        sleep 1
 }
 
-# It's fine if git update-index returns an error code other than one,
-# it'll be caught in the first test.
 test_lazy_prereq UNTRACKED_CACHE '
-       { git update-index --untracked-cache; ret=$?; } &&
+       { git update-index --test-untracked-cache; ret=$?; } &&
        test $ret -ne 1
 '
 
@@ -20,6 +18,10 @@ if ! test_have_prereq UNTRACKED_CACHE; then
        test_done
 fi
 
+test_expect_success 'core.untrackedCache is unset' '
+       test_must_fail git config --get core.untrackedCache
+'
+
 test_expect_success 'setup' '
        git init worktree &&
        cd worktree &&
@@ -32,13 +34,13 @@ test_expect_success 'setup' '
 
 test_expect_success 'untracked cache is empty' '
        test-dump-untracked-cache >../actual &&
-       cat >../expect <<EOF &&
+       cat >../expect-empty <<EOF &&
 info/exclude 0000000000000000000000000000000000000000
 core.excludesfile 0000000000000000000000000000000000000000
 exclude_per_dir .gitignore
 flags 00000006
 EOF
-       test_cmp ../expect ../actual
+       test_cmp ../expect-empty ../actual
 '
 
 cat >../status.expect <<EOF &&
@@ -508,7 +510,7 @@ EOF
 
 test_expect_success 'verify untracked cache dump (sparse/subdirs)' '
        test-dump-untracked-cache >../actual &&
-       cat >../expect <<EOF &&
+       cat >../expect-from-test-dump <<EOF &&
 info/exclude 13263c0978fb9fad16b2d580fb800b6d811c3ff0
 core.excludesfile 0000000000000000000000000000000000000000
 exclude_per_dir .gitignore
@@ -527,7 +529,7 @@ file
 /dtwo/ 0000000000000000000000000000000000000000 recurse check_only valid
 two
 EOF
-       test_cmp ../expect ../actual
+       test_cmp ../expect-from-test-dump ../actual
 '
 
 test_expect_success 'test sparse status again with untracked cache and subdir' '
@@ -571,4 +573,77 @@ EOF
        test_cmp ../status.expect ../status.actual
 '
 
+test_expect_success '--no-untracked-cache removes the cache' '
+       git update-index --no-untracked-cache &&
+       test-dump-untracked-cache >../actual &&
+       echo "no untracked cache" >../expect-no-uc &&
+       test_cmp ../expect-no-uc ../actual
+'
+
+test_expect_success 'git status does not change anything' '
+       git status &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-no-uc ../actual
+'
+
+test_expect_success 'setting core.untrackedCache to true and using git status creates the cache' '
+       git config core.untrackedCache true &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-no-uc ../actual &&
+       git status &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-from-test-dump ../actual
+'
+
+test_expect_success 'using --no-untracked-cache does not fail when core.untrackedCache is true' '
+       git update-index --no-untracked-cache &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-no-uc ../actual &&
+       git update-index --untracked-cache &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-empty ../actual
+'
+
+test_expect_success 'setting core.untrackedCache to false and using git status removes the cache' '
+       git config core.untrackedCache false &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-empty ../actual &&
+       git status &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-no-uc ../actual
+'
+
+test_expect_success 'using --untracked-cache does not fail when core.untrackedCache is false' '
+       git update-index --untracked-cache &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-empty ../actual
+'
+
+test_expect_success 'setting core.untrackedCache to keep' '
+       git config core.untrackedCache keep &&
+       git update-index --untracked-cache &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-empty ../actual &&
+       git status &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-from-test-dump ../actual &&
+       git update-index --no-untracked-cache &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-no-uc ../actual &&
+       git update-index --force-untracked-cache &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-empty ../actual &&
+       git status &&
+       test-dump-untracked-cache >../actual &&
+       test_cmp ../expect-from-test-dump ../actual
+'
+
+test_expect_success 'test ident field is working' '
+       mkdir ../other_worktree &&
+       cp -R done dthree dtwo four three ../other_worktree &&
+       GIT_WORK_TREE=../other_worktree git status 2>../err &&
+       echo "warning: Untracked cache is disabled on this system or location." >../expect &&
+       test_cmp ../expect ../err
+'
+
 test_done
diff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh
new file mode 100755 (executable)
index 0000000..337e6e3
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# Copyright (c) 2016 Dan Aloni
+# Copyright (c) 2016 Jeff King
+#
+
+test_description='per-repo forced setting of email address'
+
+. ./test-lib.sh
+
+test_expect_success 'setup a likely user.useConfigOnly use case' '
+       # we want to make sure a reflog is written, since that needs
+       # a non-strict ident. So be sure we have an actual commit.
+       test_commit foo &&
+
+       sane_unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL &&
+       sane_unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL &&
+       git config user.name "test" &&
+       git config --global user.useConfigOnly true
+'
+
+test_expect_success 'fails committing if clone email is not set' '
+       test_must_fail git commit --allow-empty -m msg
+'
+
+test_expect_success 'fails committing if clone email is not set, but EMAIL set' '
+       test_must_fail env EMAIL=test@fail.com git commit --allow-empty -m msg
+'
+
+test_expect_success 'succeeds committing if clone email is set' '
+       test_config user.email "test@ok.com" &&
+       git commit --allow-empty -m msg
+'
+
+test_expect_success 'succeeds cloning if global email is not set' '
+       git clone . clone
+'
+
+test_done
index ec8bc8c7656fd7f0fd03226b5491f5bc9d532dd7..4e713f7aa54d4713cfd74978460ec9aa144fc773 100755 (executable)
@@ -430,11 +430,11 @@ EOF
 test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
        cat >expect <<-EOF &&
        file
-       $(pwd)/file
+       $PWD/file
        file2
-       $(pwd)/file2
+       $PWD/file2
        sub/sub
-       $(pwd)/sub/sub
+       $PWD/sub/sub
        EOF
        git difftool --dir-diff --symlink \
                --extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
@@ -448,14 +448,14 @@ EOF
 run_dir_diff_test 'difftool --dir-diff syncs worktree with unstaged change' '
        test_when_finished git reset --hard &&
        echo "orig content" >file &&
-       git difftool -d $symlinks --extcmd "$(pwd)/modify-right-file" branch &&
+       git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
        echo "new content" >expect &&
        test_cmp expect file
 '
 
 run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '
        test_when_finished git reset --hard &&
-       git difftool -d $symlinks --extcmd "$(pwd)/modify-right-file" branch &&
+       git difftool -d $symlinks --extcmd "$PWD/modify-right-file" branch &&
        echo "new content" >expect &&
        test_cmp expect file
 '
@@ -466,7 +466,7 @@ EOF
 
 test_expect_success PERL 'difftool --no-symlinks does not overwrite working tree file ' '
        echo "orig content" >file &&
-       git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-file" branch &&
+       git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-file" branch &&
        echo "new content" >expect &&
        test_cmp expect file
 '
@@ -482,7 +482,7 @@ test_expect_success PERL 'difftool --no-symlinks detects conflict ' '
                TMPDIR=$TRASH_DIRECTORY &&
                export TMPDIR &&
                echo "orig content" >file &&
-               test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-both-files" branch &&
+               test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$PWD/modify-both-files" branch &&
                echo "wt content" >expect &&
                test_cmp expect file &&
                echo "tmp content" >expect &&
diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh
new file mode 100755 (executable)
index 0000000..dfe95c9
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+test_description='help.autocorrect finding a match'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       # An alias
+       git config alias.lgf "log --format=%s --first-parent" &&
+
+       # A random user-defined command
+       write_script git-distimdistim <<-EOF &&
+               echo distimdistim was called
+       EOF
+
+       PATH="$PATH:." &&
+       export PATH &&
+
+       git commit --allow-empty -m "a single log entry" &&
+
+       # Sanity check
+       git lgf >actual &&
+       echo "a single log entry" >expect &&
+       test_cmp expect actual &&
+
+       git distimdistim >actual &&
+       echo "distimdistim was called" >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'autocorrect showing candidates' '
+       git config help.autocorrect 0 &&
+
+       test_must_fail git lfg 2>actual &&
+       sed -e "1,/^Did you mean this/d" actual | grep lgf &&
+
+       test_must_fail git distimdist 2>actual &&
+       sed -e "1,/^Did you mean this/d" actual | grep distimdistim
+'
+
+test_expect_success 'autocorrect running commands' '
+       git config help.autocorrect -1 &&
+
+       git lfg >actual &&
+       echo "a single log entry" >expect &&
+       test_cmp expect actual &&
+
+       git distimdist >actual &&
+       echo "distimdistim was called" >expect &&
+       test_cmp expect actual
+'
+
+test_done
index 258d9b8cefb6bbf81a64098d57db03f7c1da90c6..22d8367ff397fc68683ff1084ce4914cfbfa9d89 100755 (executable)
@@ -117,7 +117,7 @@ test_expect_success "$name" '
 
 
 name='remove executable bit from a file'
-test_expect_success "$name" '
+test_expect_success POSIXPERM "$name" '
        rm -f "$GIT_DIR"/index &&
        git checkout -f -b mybranch5 ${remotes_git_svn} &&
        chmod -x exec.sh &&
@@ -130,7 +130,7 @@ test_expect_success "$name" '
 
 
 name='add executable bit back file'
-test_expect_success "$name" '
+test_expect_success POSIXPERM "$name" '
        chmod +x exec.sh &&
        git update-index exec.sh &&
        git commit -m "$name" &&
@@ -141,7 +141,7 @@ test_expect_success "$name" '
 
 
 name='executable file becomes a symlink to file'
-test_expect_success "$name" '
+test_expect_success SYMLINKS "$name" '
        rm exec.sh &&
        ln -s file exec.sh &&
        git update-index exec.sh &&
@@ -153,7 +153,7 @@ test_expect_success "$name" '
 
 name='new symlink is added to a file that was also just made executable'
 
-test_expect_success "$name" '
+test_expect_success POSIXPERM,SYMLINKS "$name" '
        chmod +x file &&
        ln -s file exec-2.sh &&
        git update-index --add file exec-2.sh &&
@@ -165,7 +165,7 @@ test_expect_success "$name" '
        test -h "$SVN_TREE"/exec-2.sh'
 
 name='modify a symlink to become a file'
-test_expect_success "$name" '
+test_expect_success POSIXPERM,SYMLINKS "$name" '
        echo git help >help &&
        rm exec-2.sh &&
        cp help exec-2.sh &&
@@ -181,7 +181,8 @@ test_expect_success "$name" '
 name="commit with UTF-8 message: locale: $GIT_SVN_LC_ALL"
 LC_ALL="$GIT_SVN_LC_ALL"
 export LC_ALL
-test_expect_success UTF8 "$name" "
+# This test relies on the previous test, hence requires POSIXPERM,SYMLINKS
+test_expect_success UTF8,POSIXPERM,SYMLINKS "$name" "
        echo '# hello' >> exec-2.sh &&
        git update-index exec-2.sh &&
        git commit -m 'éï∏' &&
@@ -214,7 +215,7 @@ tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e
 tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4
 EOF
 
-test_expect_success "$name" "test_cmp a expected"
+test_expect_success POSIXPERM,SYMLINKS "$name" "test_cmp a expected"
 
 test_expect_success 'exit if remote refs are ambigious' "
         git config --add svn-remote.svn.fetch \
index a2219154b89393effa51f87b3be56706728b6572..ecb1fed147d206c7d1a3ac43f9d82110e9514e66 100755 (executable)
@@ -23,8 +23,11 @@ test_expect_success 'setup svnrepo' '
                      "$svnrepo/pr ject/branches/$scary_uri" &&
        svn_cmd cp -m "leading dot" "$svnrepo/pr ject/trunk" \
                        "$svnrepo/pr ject/branches/.leading_dot" &&
-       svn_cmd cp -m "trailing dot" "$svnrepo/pr ject/trunk" \
-                       "$svnrepo/pr ject/branches/trailing_dot." &&
+       if test_have_prereq !MINGW
+       then
+               svn_cmd cp -m "trailing dot" "$svnrepo/pr ject/trunk" \
+                       "$svnrepo/pr ject/branches/trailing_dot."
+       fi &&
        svn_cmd cp -m "trailing .lock" "$svnrepo/pr ject/trunk" \
                        "$svnrepo/pr ject/branches/trailing_dotlock.lock" &&
        svn_cmd cp -m "reflog" "$svnrepo/pr ject/trunk" \
@@ -45,7 +48,10 @@ test_expect_success 'test clone with funky branch names' '
                git rev-parse "refs/remotes/origin/more%20fun%20plugin!" &&
                git rev-parse "refs/remotes/origin/$scary_ref" &&
                git rev-parse "refs/remotes/origin/%2Eleading_dot" &&
-               git rev-parse "refs/remotes/origin/trailing_dot%2E" &&
+               if test_have_prereq !MINGW
+               then
+                       git rev-parse "refs/remotes/origin/trailing_dot%2E"
+               fi &&
                git rev-parse "refs/remotes/origin/trailing_dotlock%2Elock" &&
                git rev-parse "refs/remotes/origin/$non_reflog"
        )
index aa841e12996aad8cd7284eea56c47f0d89c79c56..9f7231d5b7dae28b55316e9e24968f4e5fe06664 100755 (executable)
@@ -34,8 +34,7 @@ test_expect_success 'enable auto-props config' '
 '
 
 test_expect_success 'add files matching auto-props' '
-       echo "#!$SHELL_PATH" >exec1.sh &&
-       chmod +x exec1.sh &&
+       write_script exec1.sh </dev/null &&
        echo "hello" >hello.txt &&
        echo bar >bar &&
        git add exec1.sh hello.txt bar &&
@@ -48,8 +47,7 @@ test_expect_success 'disable auto-props config' '
 '
 
 test_expect_success 'add files matching disabled auto-props' '
-       echo "#$SHELL_PATH" >exec2.sh &&
-       chmod +x exec2.sh &&
+       write_script exec2.sh </dev/null &&
        echo "world" >world.txt &&
        echo zot >zot &&
        git add exec2.sh world.txt zot &&
@@ -65,7 +63,10 @@ test_expect_success 'check resulting svn repository' '
        cd svnrepo &&
 
        # Check properties from first commit.
-       test "x$(svn_cmd propget svn:executable exec1.sh)" = "x*" &&
+       if test_have_prereq POSIXPERM
+       then
+               test "x$(svn_cmd propget svn:executable exec1.sh)" = "x*"
+       fi &&
        test "x$(svn_cmd propget svn:mime-type exec1.sh)" = \
             "xapplication/x-shellscript" &&
        test "x$(svn_cmd propget svn:mime-type hello.txt)" = "xtext/plain" &&
@@ -73,7 +74,10 @@ test_expect_success 'check resulting svn repository' '
        test "x$(svn_cmd propget svn:mime-type bar)" = "x" &&
 
        # Check properties from second commit.
-       test "x$(svn_cmd propget svn:executable exec2.sh)" = "x*" &&
+       if test_have_prereq POSIXPERM
+       then
+               test "x$(svn_cmd propget svn:executable exec2.sh)" = "x*"
+       fi &&
        test "x$(svn_cmd propget svn:mime-type exec2.sh)" = "x" &&
        test "x$(svn_cmd propget svn:mime-type world.txt)" = "x" &&
        test "x$(svn_cmd propget svn:eol-style world.txt)" = "x" &&
index d306b77c31e6a73cc777b71eba1f69090093c0dc..41264818ccdd85abb4b0a17c8a508d4bcbfe57f5 100755 (executable)
@@ -91,7 +91,7 @@ test_expect_success 'fetch continues after authors-file is fixed' '
        )
        '
 
-test_expect_success 'fresh clone with svn.authors-file in config' '
+test_expect_success !MINGW 'fresh clone with svn.authors-file in config' '
        (
                rm -r "$GIT_DIR" &&
                test x = x"$(git config svn.authorsfile)" &&
index 812c9cd462f58f6fd76e3d339e95137aee598801..5cfb9cfc52e715c916f3ebe922e57263d7c4d7da 100755 (executable)
@@ -197,7 +197,7 @@ if p="Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" &&
 then
 
 # This test contains UTF-8 characters
-test_expect_success \
+test_expect_success !MINGW \
      'File with non-ascii file name' \
      'mkdir -p Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö &&
       echo Foo >Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt &&
index 6146c3fec293915b4599748e7a787539a7715e1a..d708cbf0320abe502d875ae3333eda2501208ca2 100755 (executable)
@@ -25,11 +25,11 @@ perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || {
     test_done
 }
 
-WORKDIR=$(pwd)
-SERVERDIR=$(pwd)/gitcvs.git
+WORKDIR=$PWD
+SERVERDIR=$PWD/gitcvs.git
 git_config="$SERVERDIR/config"
 CVSROOT=":fork:$SERVERDIR"
-CVSWORK="$(pwd)/cvswork"
+CVSWORK="$PWD/cvswork"
 CVS_SERVER=git-cvsserver
 export CVSROOT CVS_SERVER
 
index 5a4ed28e4980ea080fc018043527d9c62dd9b5d7..f324b9f010506d5f79388ef454df74156860ec13 100755 (executable)
@@ -74,11 +74,11 @@ perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || {
 }
 
 unset GIT_DIR GIT_CONFIG
-WORKDIR=$(pwd)
-SERVERDIR=$(pwd)/gitcvs.git
+WORKDIR=$PWD
+SERVERDIR=$PWD/gitcvs.git
 git_config="$SERVERDIR/config"
 CVSROOT=":fork:$SERVERDIR"
-CVSWORK="$(pwd)/cvswork"
+CVSWORK="$PWD/cvswork"
 CVS_SERVER=git-cvsserver
 export CVSROOT CVS_SERVER
 
index d00df0873135a8efcf0edb92cd397b92ab7d06f0..6d2d3c8739cbd6978d823e7947d9f95c758ff241 100755 (executable)
@@ -82,11 +82,11 @@ perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || {
 }
 
 unset GIT_DIR GIT_CONFIG
-WORKDIR=$(pwd)
-SERVERDIR=$(pwd)/gitcvs.git
+WORKDIR=$PWD
+SERVERDIR=$PWD/gitcvs.git
 git_config="$SERVERDIR/config"
 CVSROOT=":fork:$SERVERDIR"
-CVSWORK="$(pwd)/cvswork"
+CVSWORK="$PWD/cvswork"
 CVS_SERVER=git-cvsserver
 export CVSROOT CVS_SERVER
 
index 1140767b50706f03b0da5b2c8befdae6898e4136..7e8c40b97b4eecc2347ab2986a97b62148fe5f88 100755 (executable)
@@ -33,7 +33,7 @@ BEGIN
 is($r->config_int("test.nonexistent"), undef, "config_int: nonexistent");
 ok($r->config_bool("test.booltrue"), "config_bool: true");
 ok(!$r->config_bool("test.boolfalse"), "config_bool: false");
-is($r->config_path("test.path"), $r->config("test.pathexpanded"),
+is($r->config_path("test.path") =~ s/\\/\//gr, $r->config("test.pathexpanded"),
    "config_path: ~/foo expansion");
 is_deeply([$r->config_path("test.pathmulti")], ["foo", "bar"],
    "config_path: multiple values");
index af82049f82e89c3275c0f1e6c5da9d7f9c7041f5..ffbfa0efb8712f06cb14adc986ae29c4d1c23bf1 100755 (executable)
@@ -67,7 +67,7 @@ repo_with_newline='repo
 with
 newline'
 
-if mkdir "$repo_with_newline" 2>/dev/null
+if test_have_prereq !MINGW && mkdir "$repo_with_newline" 2>/dev/null
 then
        test_set_prereq FUNNYNAMES
 else
index bd4b02e9dbf9560cf1285bb6607be83964ecc40a..0b47eb6bb299492d31111c94557c216bb3f32c7f 100644 (file)
@@ -907,9 +907,11 @@ yes () {
                y="$*"
        fi
 
-       while echo "$y"
+       i=0
+       while test $i -lt 99
        do
-               :
+               echo "$y"
+               i=$(($i+1))
        done
 }
 
@@ -998,7 +1000,7 @@ test_i18ngrep () {
 test_lazy_prereq PIPE '
        # test whether the filesystem supports FIFOs
        case $(uname -s) in
-       CYGWIN*)
+       CYGWIN*|MINGW*)
                false
                ;;
        *)
index 25d855d98b5cc718a6da63824e1c0f9ae39ab77c..0a1c28524668f02d3aa4d073c0c6991652cbf850 100644 (file)
@@ -44,6 +44,10 @@ int main(int ac, char **av)
 {
        struct untracked_cache *uc;
        struct strbuf base = STRBUF_INIT;
+
+       /* Hack to avoid modifying the untracked cache when we read it */
+       ignore_untracked_cache_config = 1;
+
        setup_git_directory();
        if (read_cache() < 0)
                die("unable to read index file");
diff --git a/test-fake-ssh.c b/test-fake-ssh.c
new file mode 100644 (file)
index 0000000..980de21
--- /dev/null
@@ -0,0 +1,30 @@
+#include "git-compat-util.h"
+#include "run-command.h"
+#include "strbuf.h"
+
+int main(int argc, char **argv)
+{
+       const char *trash_directory = getenv("TRASH_DIRECTORY");
+       struct strbuf buf = STRBUF_INIT;
+       FILE *f;
+       int i;
+       const char *child_argv[] = { NULL, NULL };
+
+       /* First, print all parameters into $TRASH_DIRECTORY/ssh-output */
+       if (!trash_directory)
+               die("Need a TRASH_DIRECTORY!");
+       strbuf_addf(&buf, "%s/ssh-output", trash_directory);
+       f = fopen(buf.buf, "w");
+       if (!f)
+               die("Could not write to %s", buf.buf);
+       for (i = 0; i < argc; i++)
+               fprintf(f, "%s%s", i > 0 ? " " : "", i > 0 ? argv[i] : "ssh:");
+       fprintf(f, "\n");
+       fclose(f);
+
+       /* Now, evaluate the *last* parameter */
+       if (argc < 2)
+               return 0;
+       child_argv[0] = argv[argc - 1];
+       return run_command_v_opt(child_argv, RUN_USING_SHELL);
+}
index 67f366687c7abf2f6bd9cf31faa6f4ed9e6dc69e..c92f8ae7054e3340cf1a40c3f74c70b7aab7303a 100644 (file)
 #include "sha1-array.h"
 #include "sigchain.h"
 
-/* rsync support */
-
-/*
- * We copy packed-refs and refs/ into a temporary file, then read the
- * loose refs recursively (sorting whenever possible), and then inserting
- * those packed refs that are not yet in the list (not validating, but
- * assuming that the file is sorted).
- *
- * Appears refactoring this from refs.c is too cumbersome.
- */
-
-static int str_cmp(const void *a, const void *b)
-{
-       const char *s1 = a;
-       const char *s2 = b;
-
-       return strcmp(s1, s2);
-}
-
-/* path->buf + name_offset is expected to point to "refs/" */
-
-static int read_loose_refs(struct strbuf *path, int name_offset,
-               struct ref **tail)
-{
-       DIR *dir = opendir(path->buf);
-       struct dirent *de;
-       struct {
-               char **entries;
-               int nr, alloc;
-       } list;
-       int i, pathlen;
-
-       if (!dir)
-               return -1;
-
-       memset (&list, 0, sizeof(list));
-
-       while ((de = readdir(dir))) {
-               if (is_dot_or_dotdot(de->d_name))
-                       continue;
-               ALLOC_GROW(list.entries, list.nr + 1, list.alloc);
-               list.entries[list.nr++] = xstrdup(de->d_name);
-       }
-       closedir(dir);
-
-       /* sort the list */
-
-       qsort(list.entries, list.nr, sizeof(char *), str_cmp);
-
-       pathlen = path->len;
-       strbuf_addch(path, '/');
-
-       for (i = 0; i < list.nr; i++, strbuf_setlen(path, pathlen + 1)) {
-               strbuf_addstr(path, list.entries[i]);
-               if (read_loose_refs(path, name_offset, tail)) {
-                       int fd = open(path->buf, O_RDONLY);
-                       char buffer[40];
-                       struct ref *next;
-
-                       if (fd < 0)
-                               continue;
-                       next = alloc_ref(path->buf + name_offset);
-                       if (read_in_full(fd, buffer, 40) != 40 ||
-                                       get_oid_hex(buffer, &next->old_oid)) {
-                               close(fd);
-                               free(next);
-                               continue;
-                       }
-                       close(fd);
-                       (*tail)->next = next;
-                       *tail = next;
-               }
-       }
-       strbuf_setlen(path, pathlen);
-
-       for (i = 0; i < list.nr; i++)
-               free(list.entries[i]);
-       free(list.entries);
-
-       return 0;
-}
-
-/* insert the packed refs for which no loose refs were found */
-
-static void insert_packed_refs(const char *packed_refs, struct ref **list)
-{
-       FILE *f = fopen(packed_refs, "r");
-       static char buffer[PATH_MAX];
-
-       if (!f)
-               return;
-
-       for (;;) {
-               int cmp = 0; /* assigned before used */
-               int len;
-
-               if (!fgets(buffer, sizeof(buffer), f)) {
-                       fclose(f);
-                       return;
-               }
-
-               if (!isxdigit(buffer[0]))
-                       continue;
-               len = strlen(buffer);
-               if (len && buffer[len - 1] == '\n')
-                       buffer[--len] = '\0';
-               if (len < 41)
-                       continue;
-               while ((*list)->next &&
-                               (cmp = strcmp(buffer + 41,
-                                     (*list)->next->name)) > 0)
-                       list = &(*list)->next;
-               if (!(*list)->next || cmp < 0) {
-                       struct ref *next = alloc_ref(buffer + 41);
-                       buffer[40] = '\0';
-                       if (get_oid_hex(buffer, &next->old_oid)) {
-                               warning ("invalid SHA-1: %s", buffer);
-                               free(next);
-                               continue;
-                       }
-                       next->next = (*list)->next;
-                       (*list)->next = next;
-                       list = &(*list)->next;
-               }
-       }
-}
-
 static void set_upstreams(struct transport *transport, struct ref *refs,
        int pretend)
 {
@@ -192,205 +65,6 @@ static void set_upstreams(struct transport *transport, struct ref *refs,
        }
 }
 
-static const char *rsync_url(const char *url)
-{
-       if (!starts_with(url, "rsync://"))
-               skip_prefix(url, "rsync:", &url);
-       return url;
-}
-
-static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
-{
-       struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
-       struct ref dummy = {NULL}, *tail = &dummy;
-       struct child_process rsync = CHILD_PROCESS_INIT;
-       const char *args[5];
-       int temp_dir_len;
-
-       if (for_push)
-               return NULL;
-
-       /* copy the refs to the temporary directory */
-
-       strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
-       if (!mkdtemp(temp_dir.buf))
-               die_errno ("Could not make temporary directory");
-       temp_dir_len = temp_dir.len;
-
-       strbuf_addstr(&buf, rsync_url(transport->url));
-       strbuf_addstr(&buf, "/refs");
-
-       rsync.argv = args;
-       rsync.stdout_to_stderr = 1;
-       args[0] = "rsync";
-       args[1] = (transport->verbose > 1) ? "-rv" : "-r";
-       args[2] = buf.buf;
-       args[3] = temp_dir.buf;
-       args[4] = NULL;
-
-       if (run_command(&rsync))
-               die ("Could not run rsync to get refs");
-
-       strbuf_reset(&buf);
-       strbuf_addstr(&buf, rsync_url(transport->url));
-       strbuf_addstr(&buf, "/packed-refs");
-
-       args[2] = buf.buf;
-
-       if (run_command(&rsync))
-               die ("Could not run rsync to get refs");
-
-       /* read the copied refs */
-
-       strbuf_addstr(&temp_dir, "/refs");
-       read_loose_refs(&temp_dir, temp_dir_len + 1, &tail);
-       strbuf_setlen(&temp_dir, temp_dir_len);
-
-       tail = &dummy;
-       strbuf_addstr(&temp_dir, "/packed-refs");
-       insert_packed_refs(temp_dir.buf, &tail);
-       strbuf_setlen(&temp_dir, temp_dir_len);
-
-       if (remove_dir_recursively(&temp_dir, 0))
-               warning ("Error removing temporary directory %s.",
-                               temp_dir.buf);
-
-       strbuf_release(&buf);
-       strbuf_release(&temp_dir);
-
-       return dummy.next;
-}
-
-static int fetch_objs_via_rsync(struct transport *transport,
-                               int nr_objs, struct ref **to_fetch)
-{
-       struct child_process rsync = CHILD_PROCESS_INIT;
-
-       rsync.stdout_to_stderr = 1;
-       argv_array_push(&rsync.args, "rsync");
-       argv_array_push(&rsync.args, (transport->verbose > 1) ? "-rv" : "-r");
-       argv_array_push(&rsync.args, "--ignore-existing");
-       argv_array_push(&rsync.args, "--exclude");
-       argv_array_push(&rsync.args, "info");
-       argv_array_pushf(&rsync.args, "%s/objects/", rsync_url(transport->url));
-       argv_array_push(&rsync.args, get_object_directory());
-
-       /* NEEDSWORK: handle one level of alternates */
-       return run_command(&rsync);
-}
-
-static int write_one_ref(const char *name, const struct object_id *oid,
-                        int flags, void *data)
-{
-       struct strbuf *buf = data;
-       int len = buf->len;
-
-       /* when called via for_each_ref(), flags is non-zero */
-       if (flags && !starts_with(name, "refs/heads/") &&
-                       !starts_with(name, "refs/tags/"))
-               return 0;
-
-       strbuf_addstr(buf, name);
-       if (safe_create_leading_directories(buf->buf) ||
-           write_file_gently(buf->buf, "%s", oid_to_hex(oid)))
-               return error("problems writing temporary file %s: %s",
-                            buf->buf, strerror(errno));
-       strbuf_setlen(buf, len);
-       return 0;
-}
-
-static int write_refs_to_temp_dir(struct strbuf *temp_dir,
-                                 int refspec_nr, const char **refspec)
-{
-       int i;
-
-       for (i = 0; i < refspec_nr; i++) {
-               struct object_id oid;
-               char *ref;
-
-               if (dwim_ref(refspec[i], strlen(refspec[i]), oid.hash, &ref) != 1)
-                       return error("Could not get ref %s", refspec[i]);
-
-               if (write_one_ref(ref, &oid, 0, temp_dir)) {
-                       free(ref);
-                       return -1;
-               }
-               free(ref);
-       }
-       return 0;
-}
-
-static int rsync_transport_push(struct transport *transport,
-               int refspec_nr, const char **refspec, int flags)
-{
-       struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
-       int result = 0, i;
-       struct child_process rsync = CHILD_PROCESS_INIT;
-       const char *args[10];
-
-       if (flags & TRANSPORT_PUSH_MIRROR)
-               return error("rsync transport does not support mirror mode");
-
-       /* first push the objects */
-
-       strbuf_addstr(&buf, rsync_url(transport->url));
-       strbuf_addch(&buf, '/');
-
-       rsync.argv = args;
-       rsync.stdout_to_stderr = 1;
-       i = 0;
-       args[i++] = "rsync";
-       args[i++] = "-a";
-       if (flags & TRANSPORT_PUSH_DRY_RUN)
-               args[i++] = "--dry-run";
-       if (transport->verbose > 1)
-               args[i++] = "-v";
-       args[i++] = "--ignore-existing";
-       args[i++] = "--exclude";
-       args[i++] = "info";
-       args[i++] = get_object_directory();
-       args[i++] = buf.buf;
-       args[i++] = NULL;
-
-       if (run_command(&rsync))
-               return error("Could not push objects to %s",
-                               rsync_url(transport->url));
-
-       /* copy the refs to the temporary directory; they could be packed. */
-
-       strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
-       if (!mkdtemp(temp_dir.buf))
-               die_errno ("Could not make temporary directory");
-       strbuf_addch(&temp_dir, '/');
-
-       if (flags & TRANSPORT_PUSH_ALL) {
-               if (for_each_ref(write_one_ref, &temp_dir))
-                       return -1;
-       } else if (write_refs_to_temp_dir(&temp_dir, refspec_nr, refspec))
-               return -1;
-
-       i = 2;
-       if (flags & TRANSPORT_PUSH_DRY_RUN)
-               args[i++] = "--dry-run";
-       if (!(flags & TRANSPORT_PUSH_FORCE))
-               args[i++] = "--ignore-existing";
-       args[i++] = temp_dir.buf;
-       args[i++] = rsync_url(transport->url);
-       args[i++] = NULL;
-       if (run_command(&rsync))
-               result = error("Could not push to %s",
-                               rsync_url(transport->url));
-
-       if (remove_dir_recursively(&temp_dir, 0))
-               warning ("Could not remove temporary directory %s.",
-                               temp_dir.buf);
-
-       strbuf_release(&buf);
-       strbuf_release(&temp_dir);
-
-       return result;
-}
-
 struct bundle_transport_data {
        int fd;
        struct bundle_header header;
@@ -481,9 +155,10 @@ static int set_git_option(struct git_transport_options *opts,
        return 1;
 }
 
-static int connect_setup(struct transport *transport, int for_push, int verbose)
+static int connect_setup(struct transport *transport, int for_push)
 {
        struct git_transport_data *data = transport->data;
+       int flags = transport->verbose > 0 ? CONNECT_VERBOSE : 0;
 
        if (data->conn)
                return 0;
@@ -491,7 +166,7 @@ static int connect_setup(struct transport *transport, int for_push, int verbose)
        data->conn = git_connect(data->fd, transport->url,
                                 for_push ? data->options.receivepack :
                                 data->options.uploadpack,
-                                verbose ? CONNECT_VERBOSE : 0);
+                                flags);
 
        return 0;
 }
@@ -501,7 +176,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
        struct git_transport_data *data = transport->data;
        struct ref *refs;
 
-       connect_setup(transport, for_push, 0);
+       connect_setup(transport, for_push);
        get_remote_heads(data->fd[0], NULL, 0, &refs,
                         for_push ? REF_NORMAL : 0,
                         &data->extra_have,
@@ -536,7 +211,7 @@ static int fetch_refs_via_pack(struct transport *transport,
        args.update_shallow = data->options.update_shallow;
 
        if (!data->got_remote_heads) {
-               connect_setup(transport, 0, 0);
+               connect_setup(transport, 0);
                get_remote_heads(data->fd[0], NULL, 0, &refs_tmp, 0,
                                 NULL, &data->shallow);
                data->got_remote_heads = 1;
@@ -812,7 +487,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
 
        if (!data->got_remote_heads) {
                struct ref *tmp_refs;
-               connect_setup(transport, 1, 0);
+               connect_setup(transport, 1);
 
                get_remote_heads(data->fd[0], NULL, 0, &tmp_refs, REF_NORMAL,
                                 NULL, &data->shallow);
@@ -984,11 +659,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
        if (helper) {
                transport_helper_init(ret, helper);
        } else if (starts_with(url, "rsync:")) {
-               transport_check_allowed("rsync");
-               ret->get_refs_list = get_refs_via_rsync;
-               ret->fetch = fetch_objs_via_rsync;
-               ret->push = rsync_transport_push;
-               ret->smart_options = NULL;
+               die("git-over-rsync is no longer supported");
        } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
                struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
                transport_check_allowed("file");
index 6dccd2d5dd78e0ee71c1ebc771a99010a56db157..cd4bb2c38bdf40f497ece781ce3a9e61de6b4399 100644 (file)
@@ -320,6 +320,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
        struct tree_desc_x *tx = xcalloc(n, sizeof(*tx));
        struct strbuf base = STRBUF_INIT;
        int interesting = 1;
+       char *traverse_path;
 
        for (i = 0; i < n; i++)
                tx[i].d = t[i];
@@ -329,7 +330,11 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
                make_traverse_path(base.buf, info->prev, &info->name);
                base.buf[info->pathlen-1] = '/';
                strbuf_setlen(&base, info->pathlen);
+               traverse_path = xstrndup(base.buf, info->pathlen);
+       } else {
+               traverse_path = xstrndup(info->name.path, info->pathlen);
        }
+       info->traverse_path = traverse_path;
        for (;;) {
                int trees_used;
                unsigned long mask, dirmask;
@@ -411,6 +416,8 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
        for (i = 0; i < n; i++)
                free_extended_entry(tx + i);
        free(tx);
+       free(traverse_path);
+       info->traverse_path = NULL;
        strbuf_release(&base);
        return error;
 }
index 3b2f7bf17d37de5b475c415b41c6abb4281d5469..174eb617dfb9d6a85bcf1e309227c8b724089765 100644 (file)
@@ -59,6 +59,7 @@ enum follow_symlinks_result {
 enum follow_symlinks_result get_tree_entry_follow_symlinks(unsigned char *tree_sha1, const char *name, unsigned char *result, struct strbuf *result_path, unsigned *mode);
 
 struct traverse_info {
+       const char *traverse_path;
        struct traverse_info *prev;
        struct name_entry name;
        int pathlen;
index 8e2032f4e592910d6f3336f95019647992113877..9f55cc28b9dd41231644053b49875671f5a505fa 100644 (file)
@@ -498,13 +498,14 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
  * itself - the caller needs to do the final check for the cache
  * entry having more data at the end!
  */
-static int do_compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
+static int do_compare_entry_piecewise(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
 {
        int len, pathlen, ce_len;
        const char *ce_name;
 
        if (info->prev) {
-               int cmp = do_compare_entry(ce, info->prev, &info->name);
+               int cmp = do_compare_entry_piecewise(ce, info->prev,
+                                                    &info->name);
                if (cmp)
                        return cmp;
        }
@@ -522,6 +523,39 @@ static int do_compare_entry(const struct cache_entry *ce, const struct traverse_
        return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
 }
 
+static int do_compare_entry(const struct cache_entry *ce,
+                           const struct traverse_info *info,
+                           const struct name_entry *n)
+{
+       int len, pathlen, ce_len;
+       const char *ce_name;
+       int cmp;
+
+       /*
+        * If we have not precomputed the traverse path, it is quicker
+        * to avoid doing so.  But if we have precomputed it,
+        * it is quicker to use the precomputed version.
+        */
+       if (!info->traverse_path)
+               return do_compare_entry_piecewise(ce, info, n);
+
+       cmp = strncmp(ce->name, info->traverse_path, info->pathlen);
+       if (cmp)
+               return cmp;
+
+       pathlen = info->pathlen;
+       ce_len = ce_namelen(ce);
+
+       if (ce_len < pathlen)
+               return -1;
+
+       ce_len -= pathlen;
+       ce_name = ce->name + pathlen;
+
+       len = tree_entry_len(n);
+       return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
+}
+
 static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
 {
        int cmp = do_compare_entry(ce, info, n);
@@ -661,8 +695,19 @@ static int find_cache_pos(struct traverse_info *info,
                                ++o->cache_bottom;
                        continue;
                }
-               if (!ce_in_traverse_path(ce, info))
+               if (!ce_in_traverse_path(ce, info)) {
+                       /*
+                        * Check if we can skip future cache checks
+                        * (because we're already past all possible
+                        * entries in the traverse path).
+                        */
+                       if (info->traverse_path) {
+                               if (strncmp(ce->name, info->traverse_path,
+                                           info->pathlen) > 0)
+                                       break;
+                       }
                        continue;
+               }
                ce_name = ce->name + pfxlen;
                ce_slash = strchr(ce_name, '/');
                if (ce_slash)
index 981f810e80008d878d6a5af1331c89dc093c5927..6181a66f1ee2e1e45d7d8b2c88d312746473661f 100644 (file)
@@ -176,10 +176,10 @@ struct worktree **get_worktrees(void)
                        if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                                continue;
 
-                               if ((linked = get_linked_worktree(d->d_name))) {
-                                       ALLOC_GROW(list, counter + 1, alloc);
-                                       list[counter++] = linked;
-                               }
+                       if ((linked = get_linked_worktree(d->d_name))) {
+                               ALLOC_GROW(list, counter + 1, alloc);
+                               list[counter++] = linked;
+                       }
                }
                closedir(dir);
        }
index 625198e0585c52c20c778790c82126efd1b57009..d98f430c912bead3ee5381eafd195dde4d709c47 100644 (file)
@@ -109,7 +109,7 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,
        return 0;
 }
 
-static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
 {
        xrecord_t **recs;
        int size = 0;
@@ -125,6 +125,12 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add
        if (add_nl) {
                i = recs[count - 1]->size;
                if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') {
+                       if (needs_cr) {
+                               if (dest)
+                                       dest[size] = '\r';
+                               size++;
+                       }
+
                        if (dest)
                                dest[size] = '\n';
                        size++;
@@ -133,14 +139,58 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add
        return size;
 }
 
-static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
+{
+       return xdl_recs_copy_0(0, xe, i, count, needs_cr, add_nl, dest);
+}
+
+static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
+{
+       return xdl_recs_copy_0(1, xe, i, count, needs_cr, add_nl, dest);
+}
+
+/*
+ * Returns 1 if the i'th line ends in CR/LF (if it is the last line and
+ * has no eol, the preceding line, if any), 0 if it ends in LF-only, and
+ * -1 if the line ending cannot be determined.
+ */
+static int is_eol_crlf(xdfile_t *file, int i)
 {
-       return xdl_recs_copy_0(0, xe, i, count, add_nl, dest);
+       long size;
+
+       if (i < file->nrec - 1)
+               /* All lines before the last *must* end in LF */
+               return (size = file->recs[i]->size) > 1 &&
+                       file->recs[i]->ptr[size - 2] == '\r';
+       if (!file->nrec)
+               /* Cannot determine eol style from empty file */
+               return -1;
+       if ((size = file->recs[i]->size) &&
+                       file->recs[i]->ptr[size - 1] == '\n')
+               /* Last line; ends in LF; Is it CR/LF? */
+               return size > 1 &&
+                       file->recs[i]->ptr[size - 2] == '\r';
+       if (!i)
+               /* The only line has no eol */
+               return -1;
+       /* Determine eol from second-to-last line */
+       return (size = file->recs[i - 1]->size) > 1 &&
+               file->recs[i - 1]->ptr[size - 2] == '\r';
 }
 
-static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m)
 {
-       return xdl_recs_copy_0(1, xe, i, count, add_nl, dest);
+       int needs_cr;
+
+       /* Match post-images' preceding, or first, lines' end-of-line style */
+       needs_cr = is_eol_crlf(&xe1->xdf2, m->i1 ? m->i1 - 1 : 0);
+       if (needs_cr)
+               needs_cr = is_eol_crlf(&xe2->xdf2, m->i2 ? m->i2 - 1 : 0);
+       /* Look at pre-image's first line, unless we already settled on LF */
+       if (needs_cr)
+               needs_cr = is_eol_crlf(&xe1->xdf1, 0);
+       /* If still undecided, use LF-only */
+       return needs_cr < 0 ? 0 : needs_cr;
 }
 
 static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
@@ -152,16 +202,17 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
        int marker1_size = (name1 ? strlen(name1) + 1 : 0);
        int marker2_size = (name2 ? strlen(name2) + 1 : 0);
        int marker3_size = (name3 ? strlen(name3) + 1 : 0);
+       int needs_cr = is_cr_needed(xe1, xe2, m);
 
        if (marker_size <= 0)
                marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
 
        /* Before conflicting part */
-       size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
+       size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,
                              dest ? dest + size : NULL);
 
        if (!dest) {
-               size += marker_size + 1 + marker1_size;
+               size += marker_size + 1 + needs_cr + marker1_size;
        } else {
                memset(dest + size, '<', marker_size);
                size += marker_size;
@@ -170,17 +221,19 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                        memcpy(dest + size + 1, name1, marker1_size - 1);
                        size += marker1_size;
                }
+               if (needs_cr)
+                       dest[size++] = '\r';
                dest[size++] = '\n';
        }
 
        /* Postimage from side #1 */
-       size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
+       size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, 1,
                              dest ? dest + size : NULL);
 
        if (style == XDL_MERGE_DIFF3) {
                /* Shared preimage */
                if (!dest) {
-                       size += marker_size + 1 + marker3_size;
+                       size += marker_size + 1 + needs_cr + marker3_size;
                } else {
                        memset(dest + size, '|', marker_size);
                        size += marker_size;
@@ -189,25 +242,29 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                                memcpy(dest + size + 1, name3, marker3_size - 1);
                                size += marker3_size;
                        }
+                       if (needs_cr)
+                               dest[size++] = '\r';
                        dest[size++] = '\n';
                }
-               size += xdl_orig_copy(xe1, m->i0, m->chg0, 1,
+               size += xdl_orig_copy(xe1, m->i0, m->chg0, needs_cr, 1,
                                      dest ? dest + size : NULL);
        }
 
        if (!dest) {
-               size += marker_size + 1;
+               size += marker_size + 1 + needs_cr;
        } else {
                memset(dest + size, '=', marker_size);
                size += marker_size;
+               if (needs_cr)
+                       dest[size++] = '\r';
                dest[size++] = '\n';
        }
 
        /* Postimage from side #2 */
-       size += xdl_recs_copy(xe2, m->i2, m->chg2, 1,
+       size += xdl_recs_copy(xe2, m->i2, m->chg2, needs_cr, 1,
                              dest ? dest + size : NULL);
        if (!dest) {
-               size += marker_size + 1 + marker2_size;
+               size += marker_size + 1 + needs_cr + marker2_size;
        } else {
                memset(dest + size, '>', marker_size);
                size += marker_size;
@@ -216,6 +273,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                        memcpy(dest + size + 1, name2, marker2_size - 1);
                        size += marker2_size;
                }
+               if (needs_cr)
+                       dest[size++] = '\r';
                dest[size++] = '\n';
        }
        return size;
@@ -241,21 +300,24 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
                                                  marker_size);
                else if (m->mode & 3) {
                        /* Before conflicting part */
-                       size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
+                       size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,
                                              dest ? dest + size : NULL);
                        /* Postimage from side #1 */
-                       if (m->mode & 1)
-                               size += xdl_recs_copy(xe1, m->i1, m->chg1, (m->mode & 2),
+                       if (m->mode & 1) {
+                               int needs_cr = is_cr_needed(xe1, xe2, m);
+
+                               size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, (m->mode & 2),
                                                      dest ? dest + size : NULL);
+                       }
                        /* Postimage from side #2 */
                        if (m->mode & 2)
-                               size += xdl_recs_copy(xe2, m->i2, m->chg2, 0,
+                               size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, 0,
                                                      dest ? dest + size : NULL);
                } else
                        continue;
                i = m->i1 + m->chg1;
        }
-       size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0,
+       size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, 0,
                              dest ? dest + size : NULL);
        return size;
 }