Merge branch 'nd/worktree-add-B'
authorJunio C Hamano <gitster@pobox.com>
Wed, 24 Feb 2016 21:26:00 +0000 (13:26 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 24 Feb 2016 21:26:00 +0000 (13:26 -0800)
"git worktree add -B <branchname>" did not work.

* nd/worktree-add-B:
worktree add -B: do the checkout test before update branch
worktree: fix "add -B"

95 files changed:
.gitignore
Documentation/RelNotes/2.7.2.txt [new file with mode: 0644]
Documentation/RelNotes/2.8.0.txt
Documentation/config.txt
Documentation/fetch-options.txt
Documentation/git-bundle.txt
Documentation/git-check-ignore.txt
Documentation/git-clean.txt
Documentation/git-clone.txt
Documentation/git-config.txt
Documentation/git-push.txt
Documentation/git-repack.txt
Documentation/git.txt
Documentation/gitcore-tutorial.txt
Documentation/gitignore.txt
Documentation/gittutorial.txt
Documentation/urls.txt
Makefile
builtin/checkout.c
builtin/clone.c
builtin/fetch.c
builtin/pack-objects.c
builtin/push.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/stripspace.c
compat/mingw.c
config.mak.uname
connect.c
connect.h
contrib/completion/git-completion.bash
dir.c
dir.h
git-cvsserver.perl
git.c
http-push.c
http.c
http.h
ident.c
list-objects.c
list-objects.h
mergetools/vimdiff
pack-bitmap-write.c
pack-bitmap.c
perl/Git.pm
perl/Git/SVN/Editor.pm
reachable.c
remote-curl.c
rerere.c
revision.c
revision.h
setup.c
sha1_name.c
t/Makefile
t/lib-git-daemon.sh
t/lib-git-svn.sh
t/t0008-ignores.sh
t/t0060-path-utils.sh
t/t1508-at-combinations.sh
t/t2019-checkout-ambiguous-ref.sh
t/t2027-worktree-list.sh
t/t3001-ls-files-others-exclude.sh
t/t3007-ls-files-other-negative.sh [new file with mode: 0755]
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/t5505-remote.sh
t/t5510-fetch.sh
t/t5570-git-daemon.sh
t/t5601-clone.sh
t/t6133-pathspec-rev-dwim.sh [new file with mode: 0755]
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/t9115-git-svn-dcommit-funky-renames.sh
t/t9118-git-svn-funky-branch-names.sh
t/t9124-git-svn-dcommit-auto-props.sh
t/t9129-git-svn-i18n-commitencoding.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-fake-ssh.c [new file with mode: 0644]
test-path-utils.c
transport-helper.c
transport.c
transport.h
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
diff --git a/Documentation/RelNotes/2.7.2.txt b/Documentation/RelNotes/2.7.2.txt
new file mode 100644 (file)
index 0000000..4feef76
--- /dev/null
@@ -0,0 +1,41 @@
+Git v2.7.2 Release Notes
+========================
+
+Fixes since v2.7.1
+------------------
+
+ * 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.
+
+ * "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.
+
+ * "git push --force-with-lease" has been taught to report if the push
+   needed to force (or fast-forwarded).
+
+ * 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.
+
+ * The vimdiff backend for "git mergetool" has been tweaked to arrange
+   and number buffers in the order that would match the expectation of
+   majority of people who read left to right, then top down and assign
+   buffers 1 2 3 4 "mentally" to local base remote merge windows based
+   on that order.
+
+ * The documentation for "git clean" has been corrected; it mentioned
+   that .git/modules/* are removed by giving two "-f", which has never
+   been the case.
+
+ * Paths that have been told the index about with "add -N" are not
+   quite yet in the index, but a few commands behaved as if they
+   already are in a harmful way.
+
+Also includes tiny documentation and test updates.
index 17e904cf4d18d8b42a863e0d3a0369e2a104455d..dd540d032738eb372ef4c774b4e767f2c09da6ad 100644 (file)
@@ -1,11 +1,21 @@
 Git 2.8 Release Notes
 =====================
 
+Backward compatibility note
+---------------------------
+
+The rsync:// transport has been removed.
+
+
 Updates since v2.7
 ------------------
 
 UI, Workflows & Features
 
+ * It turns out "git clone" over rsync transport has been broken when
+   the source repository has packed references for a long time, and
+   nobody noticed nor complained about it.
+
  * "branch --delete" has "branch -d" but "push --delete" does not.
 
  * "git blame" learned to produce the progress eye-candy when it takes
@@ -83,6 +93,11 @@ UI, Workflows & Features
    commit that is reachable from <branch> that does not match the
    given <pattern>.
 
+ * The "user.useConfigOnly" configuration variable can be used to
+   force the user to always set user.email & user.name configuration
+   variables, serving as a reminder for those who work on multiple
+   projects and do not want to put these in their $HOME/.gitconfig.
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -126,6 +141,21 @@ Performance, Internal Implementation, Development Support etc.
    tests that take longer before other ones; this reduces the total
    wallclock time.
 
+ * Test scripts have been updated to remove assumptions that are not
+   portable between Git for POSIX and Git for Windows, or to skip ones
+   with expectations that are not satisfiable on Git for Windows.
+
+ * 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.
+
+ * 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 "git rerere" that are already safe has been
+   rewritten to avoid false wanings.
 
 Also contains various documentation updates and code clean-ups.
 
@@ -267,9 +297,22 @@ notes for details).
    not stop until it fills the pipe buffer due to lack of SIGPIPE.
    (merge 6129c93 js/test-lib-windows-emulated-yes later to maint).
 
+ * The documentation for "git clean" has been corrected; it mentioned
+   that .git/modules/* are removed by giving two "-f", which has never
+   been the case.
+   (merge 31e3c2d mm/clean-doc-fix later to maint).
+
+ * The vimdiff backend for "git mergetool" has been tweaked to arrange
+   and number buffers in the order that would match the expectation of
+   majority of people who read left to right, then top down and assign
+   buffers 1 2 3 4 "mentally" to local base remote merge windows based
+   on that order.
+   (merge 2300328 dw/mergetool-vim-window-shuffle 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).
+   (merge f562d7d ah/stripspace-optstring later to maint).
index 27f02be35ed2aebedab93281814b1f4e0fea4f35..2cd6bdd7d2bc2816c1a9aed1c6a26bbd3285777c 100644 (file)
@@ -1648,6 +1648,12 @@ http.proxyAuthMethod::
 * `ntlm` - NTLM authentication (compare the --ntlm option of `curl(1)`)
 --
 
+http.emptyAuth::
+       Attempt authentication without seeking a username or password.  This
+       can be used to attempt GSS-Negotiate authentication without specifying
+       a username in the URL, as libcurl normally requires a username for
+       authentication.
+
 http.cookieFile::
        File containing previously stored cookie lines which should be used
        in the Git http session, if they match the server. The file format
@@ -1727,6 +1733,14 @@ http.sslCAPath::
        with when fetching or pushing over HTTPS. Can be overridden
        by the 'GIT_SSL_CAPATH' environment variable.
 
+http.pinnedpubkey::
+       Public key of the https service. It may either be the filename of
+       a PEM or DER encoded public key file or a string starting with
+       'sha256//' followed by the base64 encoded sha256 hash of the
+       public key. See also libcurl 'CURLOPT_PINNEDPUBLICKEY'. git will
+       exit with an error if this option is set but not supported by
+       cURL.
+
 http.sslTry::
        Attempt to use AUTH SSL/TLS and encrypted data transfers
        when connecting via regular FTP protocol. This might be needed
@@ -2122,7 +2136,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,
@@ -2830,6 +2844,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 952dfdfef098ca00b7976ef9d549401f171514f6..036edfb099c367262f34d2c1275ac5079a1e0914 100644 (file)
@@ -158,3 +158,11 @@ endif::git-pull[]
        by default when it is attached to a terminal, unless -q
        is specified. This flag forces progress status even if the
        standard error stream is not directed to a terminal.
+
+-4::
+--ipv4::
+       Use IPv4 addresses only, ignoring IPv6 addresses.
+
+-6::
+--ipv6::
+       Use IPv6 addresses only, ignoring IPv4 addresses.
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 e94367a5ed8e8b94bca7036ff7616bc3cfa9ca97..f60ee051f8c0e930e790add0bd1be39f49c82785 100644 (file)
@@ -114,6 +114,7 @@ SEE ALSO
 linkgit:gitignore[5]
 linkgit:gitconfig[5]
 linkgit:git-ls-files[1]
+GIT_TRACE_EXCLUDE in linkgit:git[1]
 
 GIT
 ---
index 641681f61ad360fcfd5aa98f81a9e3d49c44c8a7..51a7e26a8ec178e7e9fd0b78c00bb7ce518cd049 100644 (file)
@@ -37,9 +37,7 @@ OPTIONS
        to false, 'git clean' will refuse to delete files or directories
        unless given -f, -n or -i. Git will refuse to delete directories
        with .git sub directory or file unless a second -f
-       is given. This affects also git submodules where the storage area
-       of the removed submodule under .git/modules/ is not removed until
-       -f is given twice.
+       is given.
 
 -i::
 --interactive::
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 2608ca74ac82f7e18531dc0d49a81c84e3155a5c..242fa5d1bb2b7eff9645e140613640d94d28852f 100644 (file)
@@ -219,7 +219,9 @@ See also <<FILES>>.
 
 --[no-]includes::
        Respect `include.*` directives in config files when looking up
-       values. Defaults to on.
+       values. Defaults to `off` when a specific file is given (e.g.,
+       using `--file`, `--global`, etc) and `on` when searching all
+       config files.
 
 [[FILES]]
 FILES
index 32482cec42d3ea5661813097919ff38657c2e01c..669a357c81fbba17c245adc3660cdd07479e564e 100644 (file)
@@ -277,6 +277,13 @@ origin +master` to force a push to the `master` branch). See the
        default is --verify, giving the hook a chance to prevent the
        push.  With --no-verify, the hook is bypassed completely.
 
+-4::
+--ipv4::
+       Use IPv4 addresses only, ignoring IPv6 addresses.
+
+-6::
+--ipv6::
+       Use IPv6 addresses only, ignoring IPv4 addresses.
 
 include::urls-remotes.txt[]
 
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 d987ad20c90a05932733c09812324c3d176ebbbe..2754af8f7782d4a13fce4f5752737e3106491f22 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.1/git.html[documentation for release 2.7.1]
+* link:v2.7.2/git.html[documentation for release 2.7.2]
 
 * release notes for
+  link:RelNotes/2.7.2.txt[2.7.2],
   link:RelNotes/2.7.1.txt[2.7.1],
   link:RelNotes/2.7.0.txt[2.7].
 
@@ -1064,6 +1065,11 @@ of clones and fetches.
        cloning of shallow repositories.
        See 'GIT_TRACE' for available trace output options.
 
+'GIT_TRACE_EXCLUDE'::
+       Enables trace messages that can help debugging .gitignore
+       processing. See 'GIT_TRACE' for available trace output
+       options.
+
 'GIT_LITERAL_PATHSPECS'::
        Setting this variable to `1` will cause Git to treat all
        pathspecs literally, rather than as glob patterns. For example,
@@ -1124,8 +1130,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 473623d6318a859c9ed2cf600222ea6cb4a25d4c..3ded6fdc9972bb72a0efea73f0a2c73ae3e9906d 100644 (file)
@@ -82,12 +82,12 @@ PATTERN FORMAT
 
  - An optional prefix "`!`" which negates the pattern; any
    matching file excluded by a previous pattern will become
-   included again. It is not possible to re-include a file if a parent
-   directory of that file is excluded. Git doesn't list excluded
-   directories for performance reasons, so any patterns on contained
-   files have no effect, no matter where they are defined.
+   included again.
    Put a backslash ("`\`") in front of the first "`!`" for patterns
    that begin with a literal "`!`", for example, "`\!important!.txt`".
+   It is possible to re-include a file if a parent directory of that
+   file is excluded if certain conditions are met. See section NOTES
+   for detail.
 
  - If the pattern ends with a slash, it is removed for the
    purpose of the following description, but it would only find
@@ -141,6 +141,15 @@ not tracked by Git remain untracked.
 To stop tracking a file that is currently tracked, use
 'git rm --cached'.
 
+To re-include files or directories when their parent directory is
+excluded, the following conditions must be met:
+
+ - The rules to exclude a directory and re-include a subset back must
+   be in the same .gitignore file.
+
+ - The directory part in the re-include rules must be literal (i.e. no
+   wildcards)
+
 EXAMPLES
 --------
 
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 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 5af84a3118d20da437d3e08c1667f76dc2f57845..cfa66e25eb0838ba70d87d3008c6d3c57e363bd1 100644 (file)
@@ -982,7 +982,8 @@ static int parse_branchname_arg(int argc, const char **argv,
                 */
                int recover_with_dwim = dwim_new_local_branch_ok;
 
-               if (check_filename(NULL, arg) && !has_dash_dash)
+               if (!has_dash_dash &&
+                   (check_filename(NULL, arg) || !no_wildcard(arg)))
                        recover_with_dwim = 0;
                /*
                 * Accept "git checkout foo" and "git checkout foo --"
index bcba0805e1c9c5691c2e876f9748a2cf492b1c70..b8c39aa701d6fd53f5bbb121ef9b9f0e77ca9d6d 100644 (file)
@@ -47,6 +47,7 @@ static const char *real_git_dir;
 static char *option_upload_pack = "git-upload-pack";
 static int option_verbosity;
 static int option_progress = -1;
+static enum transport_family family;
 static struct string_list option_config;
 static struct string_list option_reference;
 static int option_dissociate;
@@ -92,6 +93,10 @@ static struct option builtin_clone_options[] = {
                   N_("separate git dir from working tree")),
        OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
                        N_("set config inside the new repository")),
+       OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
+                       TRANSPORT_FAMILY_IPV4),
+       OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
+                       TRANSPORT_FAMILY_IPV6),
        OPT_END()
 };
 
@@ -970,6 +975,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        remote = remote_get(option_origin);
        transport = transport_get(remote, remote->url[0]);
        transport_set_verbosity(transport, option_verbosity, option_progress);
+       transport->family = family;
 
        path = get_repo_path(remote->url[0], &is_bundle);
        is_local = option_local != 0 && path && !is_bundle;
index 8e742135f049c2792bfc5a20299dac88518929cc..55919a9e4fb8e2fd538b6c111bfdacf83acf62ed 100644 (file)
@@ -38,6 +38,7 @@ static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosit
 static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 static int tags = TAGS_DEFAULT, unshallow, update_shallow;
 static int max_children = 1;
+static enum transport_family family;
 static const char *depth;
 static const char *upload_pack;
 static struct strbuf default_rla = STRBUF_INIT;
@@ -127,6 +128,10 @@ static struct option builtin_fetch_options[] = {
                 N_("accept refs that update .git/shallow")),
        { OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"),
          N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg },
+       OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
+                       TRANSPORT_FAMILY_IPV4),
+       OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
+                       TRANSPORT_FAMILY_IPV6),
        OPT_END()
 };
 
@@ -864,6 +869,7 @@ static struct transport *prepare_transport(struct remote *remote)
        struct transport *transport;
        transport = transport_get(remote, NULL);
        transport_set_verbosity(transport, verbosity, progress);
+       transport->family = family;
        if (upload_pack)
                set_option(transport, TRANS_OPT_UPLOADPACK, upload_pack);
        if (keep)
index 4dae5b11c28deb3c296cbd89753cafe3ca7a1e90..a6609f19ffa2c5320eee3e2994eda1d13e922729 100644 (file)
@@ -2284,21 +2284,11 @@ static void show_commit(struct commit *commit, void *data)
                index_commit_for_bitmap(commit);
 }
 
-static void show_object(struct object *obj,
-                       const struct name_path *path, const char *last,
-                       void *data)
+static void show_object(struct object *obj, const char *name, void *data)
 {
-       char *name = path_name(path, last);
-
        add_preferred_base_object(name);
        add_object_entry(obj->oid.hash, obj->type, name, 0);
        obj->flags |= OBJECT_ADDED;
-
-       /*
-        * We will have generated the hash from the name,
-        * but not saved a pointer to it - we can free it
-        */
-       free((char *)name);
 }
 
 static void show_edge(struct commit *commit)
@@ -2480,8 +2470,7 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
 }
 
 static void record_recent_object(struct object *obj,
-                                const struct name_path *path,
-                                const char *last,
+                                const char *name,
                                 void *data)
 {
        sha1_array_append(&recent_objects, obj->oid.hash);
index 960ffc31e1537441a1120dceb120ce584b7edccf..6e13b3c90a08ade04aa7f84b2f3a3c869c0288bd 100644 (file)
@@ -23,6 +23,7 @@ static const char *receivepack;
 static int verbosity;
 static int progress = -1;
 static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+static enum transport_family family;
 
 static struct push_cas_option cas;
 
@@ -346,6 +347,7 @@ static int push_with_options(struct transport *transport, int flags)
        unsigned int reject_reasons;
 
        transport_set_verbosity(transport, verbosity, progress);
+       transport->family = family;
 
        if (receivepack)
                transport_set_option(transport,
@@ -565,6 +567,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                  0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
                  PARSE_OPT_OPTARG, option_parse_push_signed },
                OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
+               OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
+                               TRANSPORT_FAMILY_IPV4),
+               OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
+                               TRANSPORT_FAMILY_IPV6),
                OPT_END()
        };
 
index 3aa89a1a3cd951afdb97cf1fe371404fc96bca8d..275da0d647ebe147386c69683cc75f2d06105d23 100644 (file)
@@ -177,9 +177,7 @@ static void finish_commit(struct commit *commit, void *data)
        free_commit_buffer(commit);
 }
 
-static void finish_object(struct object *obj,
-                         const struct name_path *path, const char *name,
-                         void *cb_data)
+static void finish_object(struct object *obj, const char *name, void *cb_data)
 {
        struct rev_list_info *info = cb_data;
        if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid))
@@ -188,15 +186,13 @@ static void finish_object(struct object *obj,
                parse_object(obj->oid.hash);
 }
 
-static void show_object(struct object *obj,
-                       const struct name_path *path, const char *component,
-                       void *cb_data)
+static void show_object(struct object *obj, const char *name, void *cb_data)
 {
        struct rev_list_info *info = cb_data;
-       finish_object(obj, path, component, cb_data);
+       finish_object(obj, name, cb_data);
        if (info->flags & REV_LIST_QUIET)
                return;
-       show_object_with_name(stdout, obj, path, component);
+       show_object_with_name(stdout, obj, name);
 }
 
 static void show_edge(struct commit *commit)
index bd16876df5ff7bce4fbf348d84a0ebc4ea53e7d7..cf8487b3b95fcca9a8a96a1562646ee8ddd5b354 100644 (file)
@@ -763,7 +763,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                continue;
                        }
                        if (!strcmp(arg, "--git-common-dir")) {
-                               puts(get_git_common_dir());
+                               const char *pfx = prefix ? prefix : "";
+                               puts(prefix_filename(pfx, strlen(pfx), get_git_common_dir()));
                                continue;
                        }
                        if (!strcmp(arg, "--resolve-git-dir")) {
index 7ff8434f7c3cf71dbd77cbf868d5dc56dd943fdb..15e716ef4322bb53428685c349aa489ed84a6dda 100644 (file)
@@ -35,7 +35,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
                            N_("skip and remove all lines starting with comment character"),
                            STRIP_COMMENTS),
                OPT_CMDMODE('c', "comment-lines", &mode,
-                           N_("prepend comment character and blank to each line"),
+                           N_("prepend comment character and space to each line"),
                            COMMENT_LINES),
                OPT_END()
        };
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 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 fd7ffe1840e64417cf94d208840cf97c91e962b7..047863144f3f22fe36d178a00b116ee45c2e9e11 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -357,6 +357,10 @@ static int git_tcp_connect_sock(char *host, int flags)
                port = "<none>";
 
        memset(&hints, 0, sizeof(hints));
+       if (flags & CONNECT_IPV4)
+               hints.ai_family = AF_INET;
+       else if (flags & CONNECT_IPV6)
+               hints.ai_family = AF_INET6;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
 
@@ -783,6 +787,10 @@ struct child_process *git_connect(int fd[2], const char *url,
                        }
 
                        argv_array_push(&conn->args, ssh);
+                       if (flags & CONNECT_IPV4)
+                               argv_array_push(&conn->args, "-4");
+                       else if (flags & CONNECT_IPV6)
+                               argv_array_push(&conn->args, "-6");
                        if (tortoiseplink)
                                argv_array_push(&conn->args, "-batch");
                        if (port) {
index c41a6850f1302e4d27af1066b53b20dd303f0d13..01f14cdf3fa4e6b6c8cd3b4c9ec3c3d55e7fc04f 100644 (file)
--- a/connect.h
+++ b/connect.h
@@ -3,6 +3,8 @@
 
 #define CONNECT_VERBOSE       (1u << 0)
 #define CONNECT_DIAG_URL      (1u << 1)
+#define CONNECT_IPV4          (1u << 2)
+#define CONNECT_IPV6          (1u << 3)
 extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
 extern int finish_connect(struct child_process *conn);
 extern int git_connection_is_socket(struct child_process *conn);
index 45ec47f2b1b45e346290e7bbad143519b1ad91a6..e3918c87e3adf32a9d7a4f0320c92c497376b9b5 100644 (file)
@@ -2415,8 +2415,8 @@ _git_stash ()
                show,--*|branch,--*)
                        ;;
                branch,*)
-                 if [ $cword -eq 3 ]; then
-                       __gitcomp_nl "$(__git_refs)";
+                       if [ $cword -eq 3 ]; then
+                               __gitcomp_nl "$(__git_refs)";
                        else
                                __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \
                                                | sed -n -e 's/:.*//p')"
diff --git a/dir.c b/dir.c
index f0b6d0a3eab704311ed2c93a3da5db0683b3125c..552af237040b3bab95d94f43b169a6278623cea3 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -53,6 +53,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
        int check_only, const struct path_simplify *simplify);
 static int get_dtype(struct dirent *de, const char *path, int len);
 
+static struct trace_key trace_exclude = TRACE_KEY_INIT(EXCLUDE);
+
 /* helper string functions with support for the ignore_case flag */
 int strcmp_icase(const char *a, const char *b)
 {
@@ -519,6 +521,7 @@ void add_exclude(const char *string, const char *base,
        x->baselen = baselen;
        x->flags = flags;
        x->srcpos = srcpos;
+       string_list_init(&x->sticky_paths, 1);
        ALLOC_GROW(el->excludes, el->nr + 1, el->alloc);
        el->excludes[el->nr++] = x;
        x->el = el;
@@ -559,8 +562,10 @@ void clear_exclude_list(struct exclude_list *el)
 {
        int i;
 
-       for (i = 0; i < el->nr; i++)
+       for (i = 0; i < el->nr; i++) {
+               string_list_clear(&el->excludes[i]->sticky_paths, 0);
                free(el->excludes[i]);
+       }
        free(el->excludes);
        free(el->filebuf);
 
@@ -878,7 +883,7 @@ int match_pathname(const char *pathname, int pathlen,
                 * then our prefix match is all we need; we
                 * do not need to call fnmatch at all.
                 */
-               if (!patternlen && !namelen)
+               if (!patternlen && (!namelen || *name == '/'))
                        return 1;
        }
 
@@ -887,6 +892,113 @@ int match_pathname(const char *pathname, int pathlen,
                                 WM_PATHNAME) == 0;
 }
 
+static void add_sticky(struct exclude *exc, const char *pathname, int pathlen)
+{
+       struct strbuf sb = STRBUF_INIT;
+       int i;
+
+       for (i = exc->sticky_paths.nr - 1; i >= 0; i--) {
+               const char *sticky = exc->sticky_paths.items[i].string;
+               int len = strlen(sticky);
+
+               if (pathlen < len && sticky[pathlen] == '/' &&
+                   !strncmp(pathname, sticky, pathlen))
+                       return;
+       }
+
+       strbuf_add(&sb, pathname, pathlen);
+       string_list_append_nodup(&exc->sticky_paths, strbuf_detach(&sb, NULL));
+}
+
+static int match_sticky(struct exclude *exc, const char *pathname, int pathlen, int dtype)
+{
+       int i;
+
+       for (i = exc->sticky_paths.nr - 1; i >= 0; i--) {
+               const char *sticky = exc->sticky_paths.items[i].string;
+               int len = strlen(sticky);
+
+               if (pathlen == len && dtype == DT_DIR &&
+                   !strncmp(pathname, sticky, len))
+                       return 1;
+
+               if (pathlen > len && pathname[len] == '/' &&
+                   !strncmp(pathname, sticky, len))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static inline int different_decisions(const struct exclude *a,
+                                     const struct exclude *b)
+{
+       return (a->flags & EXC_FLAG_NEGATIVE) != (b->flags & EXC_FLAG_NEGATIVE);
+}
+
+/*
+ * Return non-zero if pathname is a directory and an ancestor of the
+ * literal path in a pattern.
+ */
+static int match_directory_part(const char *pathname, int pathlen,
+                               int *dtype, struct exclude *x)
+{
+       const char      *base       = x->base;
+       int              baselen    = x->baselen ? x->baselen - 1 : 0;
+       const char      *pattern    = x->pattern;
+       int              prefix     = x->nowildcardlen;
+       int              patternlen = x->patternlen;
+
+       if (*dtype == DT_UNKNOWN)
+               *dtype = get_dtype(NULL, pathname, pathlen);
+       if (*dtype != DT_DIR)
+               return 0;
+
+       if (*pattern == '/') {
+               pattern++;
+               patternlen--;
+               prefix--;
+       }
+
+       if (baselen) {
+               if (((pathlen < baselen && base[pathlen] == '/') ||
+                    pathlen == baselen) &&
+                   !strncmp_icase(pathname, base, pathlen))
+                       return 1;
+               pathname += baselen + 1;
+               pathlen  -= baselen + 1;
+       }
+
+
+       if (prefix &&
+           (((pathlen < prefix && pattern[pathlen] == '/') ||
+             pathlen == prefix) &&
+            !strncmp_icase(pathname, pattern, pathlen)))
+               return 1;
+
+       return 0;
+}
+
+static struct exclude *should_descend(const char *pathname, int pathlen,
+                                     int *dtype, struct exclude_list *el,
+                                     struct exclude *exc)
+{
+       int i;
+
+       for (i = el->nr - 1; 0 <= i; i--) {
+               struct exclude *x = el->excludes[i];
+
+               if (x == exc)
+                       break;
+
+               if (!(x->flags & EXC_FLAG_NODIR) &&
+                   different_decisions(x, exc) &&
+                   match_directory_part(pathname, pathlen, dtype, x))
+                       return x;
+       }
+       return NULL;
+}
+
 /*
  * Scan the given exclude list in reverse to see whether pathname
  * should be ignored.  The first match (i.e. the last on the list), if
@@ -900,16 +1012,32 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
                                                       struct exclude_list *el)
 {
        struct exclude *exc = NULL; /* undecided */
-       int i;
+       int i, maybe_descend = 0;
 
        if (!el->nr)
                return NULL;    /* undefined */
 
+       trace_printf_key(&trace_exclude, "exclude: from %s\n", el->src);
+
        for (i = el->nr - 1; 0 <= i; i--) {
                struct exclude *x = el->excludes[i];
                const char *exclude = x->pattern;
                int prefix = x->nowildcardlen;
 
+               if (!maybe_descend && i < el->nr - 1 &&
+                   different_decisions(x, el->excludes[i+1]))
+                       maybe_descend = 1;
+
+               if (x->sticky_paths.nr) {
+                       if (*dtype == DT_UNKNOWN)
+                               *dtype = get_dtype(NULL, pathname, pathlen);
+                       if (match_sticky(x, pathname, pathlen, *dtype)) {
+                               exc = x;
+                               break;
+                       }
+                       continue;
+               }
+
                if (x->flags & EXC_FLAG_MUSTBEDIR) {
                        if (*dtype == DT_UNKNOWN)
                                *dtype = get_dtype(NULL, pathname, pathlen);
@@ -936,6 +1064,45 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
                        break;
                }
        }
+
+       if (!exc) {
+               trace_printf_key(&trace_exclude, "exclude: %.*s => n/a\n",
+                                pathlen, pathname);
+               return NULL;
+       }
+
+       /*
+        * We have found a matching pattern "exc" that may exclude whole
+        * directory. We also found that there may be a pattern that matches
+        * something inside the directory and reincludes stuff.
+        *
+        * Go through the patterns again, find that pattern and double check.
+        * If it's true, return "undecided" and keep descending in. "exc" is
+        * marked sticky so that it continues to match inside the directory.
+        */
+       if (!(exc->flags & EXC_FLAG_NEGATIVE) && maybe_descend) {
+               struct exclude *x;
+
+               if (*dtype == DT_UNKNOWN)
+                       *dtype = get_dtype(NULL, pathname, pathlen);
+
+               if (*dtype == DT_DIR &&
+                   (x = should_descend(pathname, pathlen, dtype, el, exc))) {
+                       add_sticky(exc, pathname, pathlen);
+                       trace_printf_key(&trace_exclude,
+                                        "exclude: %.*s vs %s at line %d => %s,"
+                                        " forced open by %s at line %d => n/a\n",
+                                        pathlen, pathname, exc->pattern, exc->srcpos,
+                                        exc->flags & EXC_FLAG_NEGATIVE ? "no" : "yes",
+                                        x->pattern, x->srcpos);
+                       return NULL;
+               }
+       }
+
+       trace_printf_key(&trace_exclude, "exclude: %.*s vs %s at line %d => %s%s\n",
+                        pathlen, pathname, exc->pattern, exc->srcpos,
+                        exc->flags & EXC_FLAG_NEGATIVE ? "no" : "yes",
+                        exc->sticky_paths.nr ? " (stuck)" : "");
        return exc;
 }
 
@@ -1683,9 +1850,13 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
        struct cached_dir cdir;
        enum path_treatment state, subdir_state, dir_state = path_none;
        struct strbuf path = STRBUF_INIT;
+       static int level = 0;
 
        strbuf_add(&path, base, baselen);
 
+       trace_printf_key(&trace_exclude, "exclude: [%d] enter '%.*s'\n",
+                        level++, baselen, base);
+
        if (open_cached_dir(&cdir, dir, untracked, &path, check_only))
                goto out;
 
@@ -1749,6 +1920,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
        }
        close_cached_dir(&cdir);
  out:
+       trace_printf_key(&trace_exclude, "exclude: [%d] leave '%.*s'\n",
+                        --level, baselen, base);
        strbuf_release(&path);
 
        return dir_state;
@@ -1985,6 +2158,25 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
        return root;
 }
 
+static void clear_sticky(struct dir_struct *dir)
+{
+       struct exclude_list_group *g;
+       struct exclude_list *el;
+       struct exclude *x;
+       int i, j, k;
+
+       for (i = EXC_CMDL; i <= EXC_FILE; i++) {
+               g = &dir->exclude_list_group[i];
+               for (j = g->nr - 1; j >= 0; j--) {
+                       el = &g->el[j];
+                       for (k = el->nr - 1; 0 <= k; k--) {
+                               x = el->excludes[k];
+                               string_list_clear(&x->sticky_paths, 0);
+                       }
+               }
+       }
+}
+
 int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)
 {
        struct path_simplify *simplify;
@@ -2005,6 +2197,12 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
        if (has_symlink_leading_path(path, len))
                return dir->nr;
 
+       /*
+        * Stay on the safe side. if read_directory() has run once on
+        * "dir", some sticky flag may have been left. Clear them all.
+        */
+       clear_sticky(dir);
+
        /*
         * exclude patterns are treated like positive ones in
         * create_simplify. Usually exclude patterns should be a
diff --git a/dir.h b/dir.h
index cd46f30017ce239720926afdad4301b2ac402ccf..3ec3fb0dca22164134ea0700094bf63bdc6ad329 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -4,6 +4,7 @@
 /* See Documentation/technical/api-directory-listing.txt */
 
 #include "strbuf.h"
+#include "string-list.h"
 
 struct dir_entry {
        unsigned int len;
@@ -34,6 +35,8 @@ struct exclude {
         * and from -1 decrementing for patterns from CLI args.
         */
        int srcpos;
+
+       struct string_list sticky_paths;
 };
 
 /*
index 95e69b19a70ba63f2055d6a2ec3f9af0092a0832..02c0445be1057619e01e56bd6792f78fc011dc42 100755 (executable)
@@ -2664,7 +2664,7 @@ sub argsfromdir
     #   co  # Obtain list directly.
     #   remove # HERE: TEST: MAYBE client does the recursion for us,
     #          # since it only makes sense to remove stuff already in
-    #          # the sandobx?
+    #          # the sandbox?
     #   ci # HERE: Similar to remove...
     #      # Don't try to implement the confusing/weird
     #      # ci -r bug er.."feature".
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);
index d857b131a8f7b02e3120900c5a4e525d9f8de591..bd60668707b956160edd9fb22767758023571ebb 100644 (file)
@@ -1277,9 +1277,7 @@ static struct object_list **add_one_object(struct object *obj, struct object_lis
 }
 
 static struct object_list **process_blob(struct blob *blob,
-                                        struct object_list **p,
-                                        struct name_path *path,
-                                        const char *name)
+                                        struct object_list **p)
 {
        struct object *obj = &blob->object;
 
@@ -1293,14 +1291,11 @@ static struct object_list **process_blob(struct blob *blob,
 }
 
 static struct object_list **process_tree(struct tree *tree,
-                                        struct object_list **p,
-                                        struct name_path *path,
-                                        const char *name)
+                                        struct object_list **p)
 {
        struct object *obj = &tree->object;
        struct tree_desc desc;
        struct name_entry entry;
-       struct name_path me;
 
        obj->flags |= LOCAL;
 
@@ -1310,21 +1305,17 @@ static struct object_list **process_tree(struct tree *tree,
                die("bad tree object %s", oid_to_hex(&obj->oid));
 
        obj->flags |= SEEN;
-       name = xstrdup(name);
        p = add_one_object(obj, p);
-       me.up = path;
-       me.elem = name;
-       me.elem_len = strlen(name);
 
        init_tree_desc(&desc, tree->buffer, tree->size);
 
        while (tree_entry(&desc, &entry))
                switch (object_type(entry.mode)) {
                case OBJ_TREE:
-                       p = process_tree(lookup_tree(entry.sha1), p, &me, name);
+                       p = process_tree(lookup_tree(entry.sha1), p);
                        break;
                case OBJ_BLOB:
-                       p = process_blob(lookup_blob(entry.sha1), p, &me, name);
+                       p = process_blob(lookup_blob(entry.sha1), p);
                        break;
                default:
                        /* Subproject commit - not in this repository */
@@ -1343,7 +1334,7 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
        int count = 0;
 
        while ((commit = get_revision(revs)) != NULL) {
-               p = process_tree(commit->tree, p, NULL, "");
+               p = process_tree(commit->tree, p);
                commit->object.flags |= LOCAL;
                if (!(commit->object.flags & UNINTERESTING))
                        count += add_send_request(&commit->object, lock);
@@ -1362,11 +1353,11 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
                        continue;
                }
                if (obj->type == OBJ_TREE) {
-                       p = process_tree((struct tree *)obj, p, NULL, name);
+                       p = process_tree((struct tree *)obj, p);
                        continue;
                }
                if (obj->type == OBJ_BLOB) {
-                       p = process_blob((struct blob *)obj, p, NULL, name);
+                       p = process_blob((struct blob *)obj, p);
                        continue;
                }
                die("unknown pending object %s (%s)", oid_to_hex(&obj->oid), name);
diff --git a/http.c b/http.c
index dfc53c1e2554e76126459d6cb1f098facac28593..1d5e3bbd11ae0e7dc0e682d3914e07cc13a0ce14 100644 (file)
--- a/http.c
+++ b/http.c
 #include "gettext.h"
 #include "transport.h"
 
+#if LIBCURL_VERSION_NUM >= 0x070a08
+long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
+#else
+long int git_curl_ipresolve;
+#endif
 int active_requests;
 int http_is_verbose;
 size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
@@ -57,6 +62,9 @@ static const char *ssl_key;
 #if LIBCURL_VERSION_NUM >= 0x070908
 static const char *ssl_capath;
 #endif
+#if LIBCURL_VERSION_NUM >= 0x072c00
+static const char *ssl_pinnedkey;
+#endif
 static const char *ssl_cainfo;
 static long curl_low_speed_limit = -1;
 static long curl_low_speed_time = -1;
@@ -87,6 +95,7 @@ static int curl_save_cookies;
 struct credential http_auth = CREDENTIAL_INIT;
 static int http_proactive_auth;
 static const char *user_agent;
+static int curl_empty_auth;
 
 #if LIBCURL_VERSION_NUM >= 0x071700
 /* Use CURLOPT_KEYPASSWD as is */
@@ -299,14 +308,31 @@ static int http_options(const char *var, const char *value, void *cb)
        if (!strcmp("http.useragent", var))
                return git_config_string(&user_agent, var, value);
 
+       if (!strcmp("http.emptyauth", var)) {
+               curl_empty_auth = git_config_bool(var, value);
+               return 0;
+       }
+
+       if (!strcmp("http.pinnedpubkey", var)) {
+#if LIBCURL_VERSION_NUM >= 0x072c00
+               return git_config_pathname(&ssl_pinnedkey, var, value);
+#else
+               warning(_("Public key pinning not supported with cURL < 7.44.0"));
+               return 0;
+#endif
+       }
+
        /* Fall back on the default ones */
        return git_default_config(var, value, cb);
 }
 
 static void init_curl_http_auth(CURL *result)
 {
-       if (!http_auth.username)
+       if (!http_auth.username) {
+               if (curl_empty_auth)
+                       curl_easy_setopt(result, CURLOPT_USERPWD, ":");
                return;
+       }
 
        credential_fill(&http_auth);
 
@@ -498,6 +524,10 @@ static CURL *get_curl_handle(void)
 #if LIBCURL_VERSION_NUM >= 0x070908
        if (ssl_capath != NULL)
                curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath);
+#endif
+#if LIBCURL_VERSION_NUM >= 0x072c00
+       if (ssl_pinnedkey != NULL)
+               curl_easy_setopt(result, CURLOPT_PINNEDPUBLICKEY, ssl_pinnedkey);
 #endif
        if (ssl_cainfo != NULL)
                curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
@@ -824,10 +854,14 @@ struct active_request_slot *get_active_slot(void)
        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
        curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
        curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL);
+
+#if LIBCURL_VERSION_NUM >= 0x070a08
+       curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve);
+#endif
 #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
        curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
 #endif
-       if (http_auth.password)
+       if (http_auth.password || curl_empty_auth)
                init_curl_http_auth(slot->curl);
 
        return slot;
diff --git a/http.h b/http.h
index f83cfa686823728587b2a803c3e84a8cd4669220..4ef4bbda7d86d8ca5238d45897b277709b30414a 100644 (file)
--- a/http.h
+++ b/http.h
@@ -107,6 +107,7 @@ extern void http_init(struct remote *remote, const char *url,
                      int proactive_auth);
 extern void http_cleanup(void);
 
+extern long int git_curl_ipresolve;
 extern int active_requests;
 extern int http_is_verbose;
 extern size_t http_post_buffer;
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 11732d93883ee6af8990ad311d07f28028af9876..917cc5d7c9ee04d07199f18b78342b84c0375fcd 100644 (file)
 static void process_blob(struct rev_info *revs,
                         struct blob *blob,
                         show_object_fn show,
-                        struct name_path *path,
+                        struct strbuf *path,
                         const char *name,
                         void *cb_data)
 {
        struct object *obj = &blob->object;
+       size_t pathlen;
 
        if (!revs->blob_objects)
                return;
@@ -24,7 +25,11 @@ static void process_blob(struct rev_info *revs,
        if (obj->flags & (UNINTERESTING | SEEN))
                return;
        obj->flags |= SEEN;
-       show(obj, path, name, cb_data);
+
+       pathlen = path->len;
+       strbuf_addstr(path, name);
+       show(obj, path->buf, cb_data);
+       strbuf_setlen(path, pathlen);
 }
 
 /*
@@ -52,7 +57,7 @@ static void process_blob(struct rev_info *revs,
 static void process_gitlink(struct rev_info *revs,
                            const unsigned char *sha1,
                            show_object_fn show,
-                           struct name_path *path,
+                           struct strbuf *path,
                            const char *name,
                            void *cb_data)
 {
@@ -62,7 +67,6 @@ static void process_gitlink(struct rev_info *revs,
 static void process_tree(struct rev_info *revs,
                         struct tree *tree,
                         show_object_fn show,
-                        struct name_path *path,
                         struct strbuf *base,
                         const char *name,
                         void *cb_data)
@@ -70,7 +74,6 @@ static void process_tree(struct rev_info *revs,
        struct object *obj = &tree->object;
        struct tree_desc desc;
        struct name_entry entry;
-       struct name_path me;
        enum interesting match = revs->diffopt.pathspec.nr == 0 ?
                all_entries_interesting: entry_not_interesting;
        int baselen = base->len;
@@ -86,17 +89,12 @@ static void process_tree(struct rev_info *revs,
                        return;
                die("bad tree object %s", oid_to_hex(&obj->oid));
        }
+
        obj->flags |= SEEN;
-       show(obj, path, name, cb_data);
-       me.up = path;
-       me.elem = name;
-       me.elem_len = strlen(name);
-
-       if (!match) {
-               strbuf_addstr(base, name);
-               if (base->len)
-                       strbuf_addch(base, '/');
-       }
+       strbuf_addstr(base, name);
+       show(obj, base->buf, cb_data);
+       if (base->len)
+               strbuf_addch(base, '/');
 
        init_tree_desc(&desc, tree->buffer, tree->size);
 
@@ -113,16 +111,16 @@ static void process_tree(struct rev_info *revs,
                if (S_ISDIR(entry.mode))
                        process_tree(revs,
                                     lookup_tree(entry.sha1),
-                                    show, &me, base, entry.path,
+                                    show, base, entry.path,
                                     cb_data);
                else if (S_ISGITLINK(entry.mode))
                        process_gitlink(revs, entry.sha1,
-                                       show, &me, entry.path,
+                                       show, base, entry.path,
                                        cb_data);
                else
                        process_blob(revs,
                                     lookup_blob(entry.sha1),
-                                    show, &me, entry.path,
+                                    show, base, entry.path,
                                     cb_data);
        }
        strbuf_setlen(base, baselen);
@@ -213,19 +211,19 @@ void traverse_commit_list(struct rev_info *revs,
                        continue;
                if (obj->type == OBJ_TAG) {
                        obj->flags |= SEEN;
-                       show_object(obj, NULL, name, data);
+                       show_object(obj, name, data);
                        continue;
                }
                if (!path)
                        path = "";
                if (obj->type == OBJ_TREE) {
                        process_tree(revs, (struct tree *)obj, show_object,
-                                    NULL, &base, path, data);
+                                    &base, path, data);
                        continue;
                }
                if (obj->type == OBJ_BLOB) {
                        process_blob(revs, (struct blob *)obj, show_object,
-                                    NULL, path, data);
+                                    &base, path, data);
                        continue;
                }
                die("unknown pending object %s (%s)",
index 136a1da5a6f048c0f4645112cdbf29c7b0982526..0cebf8585cb179ae46fd8238eaf2b2162739bbaa 100644 (file)
@@ -2,7 +2,7 @@
 #define LIST_OBJECTS_H
 
 typedef void (*show_commit_fn)(struct commit *, void *);
-typedef void (*show_object_fn)(struct object *, const struct name_path *, const char *, void *);
+typedef void (*show_object_fn)(struct object *, const char *, void *);
 void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *);
 
 typedef void (*show_edge_fn)(struct commit *);
index 1ddfbfcd782d3b8d0e479cb0c5e29abce86e63c9..74ea6d54793f62188cd88e93f1adfe74c5957dda 100644 (file)
@@ -9,8 +9,8 @@ merge_cmd () {
        gvimdiff|vimdiff)
                if $base_present
                then
-                       "$merge_tool_path" -f -d -c 'wincmd J' \
-                               "$MERGED" "$LOCAL" "$BASE" "$REMOTE"
+                       "$merge_tool_path" -f -d -c '4wincmd w | wincmd J' \
+                               "$LOCAL" "$BASE" "$REMOTE" "$MERGED"
                else
                        "$merge_tool_path" -f -d -c 'wincmd l' \
                                "$LOCAL" "$MERGED" "$REMOTE"
index 6bff970c905b6a9c8a04773d64afb164dd124cbe..c30bcd06cbd516eb04e9b55b27b5f091ede61439 100644 (file)
@@ -148,8 +148,7 @@ static uint32_t find_object_pos(const unsigned char *sha1)
        return entry->in_pack_pos;
 }
 
-static void show_object(struct object *object, const struct name_path *path,
-                       const char *last, void *data)
+static void show_object(struct object *object, const char *name, void *data)
 {
        struct bitmap *base = data;
        bitmap_set(base, find_object_pos(object->oid.hash));
index dd8dc16e676fb3e928560002c0cb7e1f36910e1a..b949e517167dbac6c4c347e0a2cbdf8ca2dabbcf 100644 (file)
@@ -414,19 +414,15 @@ static int ext_index_add_object(struct object *object, const char *name)
        return bitmap_pos + bitmap_git.pack->num_objects;
 }
 
-static void show_object(struct object *object, const struct name_path *path,
-                       const char *last, void *data)
+static void show_object(struct object *object, const char *name, void *data)
 {
        struct bitmap *base = data;
        int bitmap_pos;
 
        bitmap_pos = bitmap_position(object->oid.hash);
 
-       if (bitmap_pos < 0) {
-               char *name = path_name(path, last);
+       if (bitmap_pos < 0)
                bitmap_pos = ext_index_add_object(object, name);
-               free(name);
-       }
 
        bitmap_set(base, bitmap_pos);
 }
@@ -894,9 +890,8 @@ struct bitmap_test_data {
        size_t seen;
 };
 
-static void test_show_object(struct object *object,
-                            const struct name_path *path,
-                            const char *last, void *data)
+static void test_show_object(struct object *object, const char *name,
+                            void *data)
 {
        struct bitmap_test_data *tdata = data;
        int bitmap_pos;
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 c50176eec9418c50e5c63921c24e76a87b6123ab..4c4199afecac2c5fc6d918cf0d3b75449504b808 100644 (file)
@@ -41,6 +41,7 @@ sub new {
                               "$self->{svn_path}/" : '';
        $self->{config} = $opts->{config};
        $self->{mergeinfo} = $opts->{mergeinfo};
+       $self->{pathnameencoding} = Git::config('svn.pathnameencoding');
        return $self;
 }
 
@@ -143,11 +144,12 @@ sub repo_path {
 
 sub url_path {
        my ($self, $path) = @_;
+       $path = $self->repo_path($path);
        if ($self->{url} =~ m#^https?://#) {
                # characters are taken from subversion/libsvn_subr/path.c
                $path =~ s#([^~a-zA-Z0-9_./!$&'()*+,-])#sprintf("%%%02X",ord($1))#eg;
        }
-       $self->{url} . '/' . $self->repo_path($path);
+       $self->{url} . '/' . $path;
 }
 
 sub rmdirs {
index 43616d49c7f88166d2fa2f009ca5b926d751ab0b..ed352018964ef2260f5da51239800bbcc816ad1b 100644 (file)
@@ -43,15 +43,14 @@ static int add_one_ref(const char *path, const struct object_id *oid,
  * The traversal will have already marked us as SEEN, so we
  * only need to handle any progress reporting here.
  */
-static void mark_object(struct object *obj, const struct name_path *path,
-                       const char *name, void *data)
+static void mark_object(struct object *obj, const char *name, void *data)
 {
        update_progress(data);
 }
 
 static void mark_commit(struct commit *c, void *data)
 {
-       mark_object(&c->object, NULL, NULL, data);
+       mark_object(&c->object, NULL, data);
 }
 
 struct recent_data {
index c7048575fbdca1bd8dc57c114d0cfdc031e63039..2e2266b856afa920d798f9ae9ee3238c681f9380 100644 (file)
@@ -119,6 +119,19 @@ static int set_option(const char *name, const char *value)
                else
                        return -1;
                return 0;
+
+#if LIBCURL_VERSION_NUM >= 0x070a08
+       } else if (!strcmp(name, "family")) {
+               if (!strcmp(value, "ipv4"))
+                       git_curl_ipresolve = CURL_IPRESOLVE_V4;
+               else if (!strcmp(value, "ipv6"))
+                       git_curl_ipresolve = CURL_IPRESOLVE_V6;
+               else if (!strcmp(value, "all"))
+                       git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
+               else
+                       return -1;
+               return 0;
+#endif /* LIBCURL_VERSION_NUM >= 0x070a08 */
        } else {
                return 1 /* unsupported */;
        }
@@ -439,8 +452,20 @@ static int run_slot(struct active_request_slot *slot,
        err = run_one_slot(slot, results);
 
        if (err != HTTP_OK && err != HTTP_REAUTH) {
-               error("RPC failed; result=%d, HTTP code = %ld",
-                     results->curl_result, results->http_code);
+               struct strbuf msg = STRBUF_INIT;
+               if (results->http_code && results->http_code != 200)
+                       strbuf_addf(&msg, "HTTP %ld", results->http_code);
+               if (results->curl_result != CURLE_OK) {
+                       if (msg.len)
+                               strbuf_addch(&msg, ' ');
+                       strbuf_addf(&msg, "curl %d", results->curl_result);
+                       if (curl_errorstr[0]) {
+                               strbuf_addch(&msg, ' ');
+                               strbuf_addstr(&msg, curl_errorstr);
+                       }
+               }
+               error("RPC failed; %s", msg.buf);
+               strbuf_release(&msg);
        }
 
        return err;
index 403c700c326e4551aea183523af6ed46e1476432..587b7e2717b14748b92a5960f79947b5fba088f0 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -48,7 +48,7 @@ static int has_rerere_resolution(const struct rerere_id *id)
 static struct rerere_id *new_rerere_id_hex(char *hex)
 {
        struct rerere_id *id = xmalloc(sizeof(*id));
-       strcpy(id->hex, hex);
+       xsnprintf(id->hex, sizeof(id->hex), "%s", hex);
        return id;
 }
 
@@ -904,7 +904,7 @@ int rerere_forget(struct pathspec *pathspec)
 static struct rerere_id *dirname_to_id(const char *name)
 {
        static struct rerere_id id;
-       strcpy(id.hex, name);
+       xsnprintf(id.hex, sizeof(id.hex), "%s", name);
        return &id;
 }
 
index f24ead53d537b05d7819ce53b45b05a15ec60a96..82f3ca44b3e3dba8bdd487be04bd66b862fefa4c 100644 (file)
@@ -25,69 +25,13 @@ volatile show_early_output_fn_t show_early_output;
 static const char *term_bad;
 static const char *term_good;
 
-char *path_name(const struct name_path *path, const char *name)
-{
-       const struct name_path *p;
-       char *n, *m;
-       int nlen = strlen(name);
-       int len = nlen + 1;
-
-       for (p = path; p; p = p->up) {
-               if (p->elem_len)
-                       len += p->elem_len + 1;
-       }
-       n = xmalloc(len);
-       m = n + len - (nlen + 1);
-       memcpy(m, name, nlen + 1);
-       for (p = path; p; p = p->up) {
-               if (p->elem_len) {
-                       m -= p->elem_len + 1;
-                       memcpy(m, p->elem, p->elem_len);
-                       m[p->elem_len] = '/';
-               }
-       }
-       return n;
-}
-
-static int show_path_component_truncated(FILE *out, const char *name, int len)
-{
-       int cnt;
-       for (cnt = 0; cnt < len; cnt++) {
-               int ch = name[cnt];
-               if (!ch || ch == '\n')
-                       return -1;
-               fputc(ch, out);
-       }
-       return len;
-}
-
-static int show_path_truncated(FILE *out, const struct name_path *path)
-{
-       int emitted, ours;
-
-       if (!path)
-               return 0;
-       emitted = show_path_truncated(out, path->up);
-       if (emitted < 0)
-               return emitted;
-       if (emitted)
-               fputc('/', out);
-       ours = show_path_component_truncated(out, path->elem, path->elem_len);
-       if (ours < 0)
-               return ours;
-       return ours || emitted;
-}
-
-void show_object_with_name(FILE *out, struct object *obj,
-                          const struct name_path *path, const char *component)
+void show_object_with_name(FILE *out, struct object *obj, const char *name)
 {
-       struct name_path leaf;
-       leaf.up = (struct name_path *)path;
-       leaf.elem = component;
-       leaf.elem_len = strlen(component);
+       const char *p;
 
        fprintf(out, "%s ", oid_to_hex(&obj->oid));
-       show_path_truncated(out, &leaf);
+       for (p = name; *p && *p != '\n'; p++)
+               fputc(*p, out);
        fputc('\n', out);
 }
 
index 23857c0ed1d7a304c848842711a920e678fd506d..dca0d381715cf5bc6888587feaec989012f51252 100644 (file)
@@ -257,16 +257,9 @@ extern void put_revision_mark(const struct rev_info *revs,
 extern void mark_parents_uninteresting(struct commit *commit);
 extern void mark_tree_uninteresting(struct tree *tree);
 
-struct name_path {
-       struct name_path *up;
-       int elem_len;
-       const char *elem;
-};
-
-char *path_name(const struct name_path *path, const char *name);
+char *path_name(struct strbuf *path, const char *name);
 
-extern void show_object_with_name(FILE *, struct object *,
-                                 const struct name_path *, const char *);
+extern void show_object_with_name(FILE *, struct object *, const char *);
 
 extern void add_pending_object(struct rev_info *revs,
                               struct object *obj, const char *name);
diff --git a/setup.c b/setup.c
index 0deb02238ba426144e0b7b077c9f2ad5c7993d23..59ec6587aa7e54b72d7a2f9fe0af51d66b2c8901 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -139,9 +139,7 @@ int check_filename(const char *prefix, const char *arg)
                if (arg[2] == '\0') /* ":/" is root dir, always exists */
                        return 1;
                name = arg + 2;
-       } else if (!no_wildcard(arg))
-               return 1;
-       else if (prefix)
+       } else if (prefix)
                name = prefix_filename(prefix, strlen(prefix), arg);
        else
                name = arg;
@@ -202,7 +200,7 @@ void verify_filename(const char *prefix,
 {
        if (*arg == '-')
                die("bad flag '%s' used after filename", arg);
-       if (check_filename(prefix, arg))
+       if (check_filename(prefix, arg) || !no_wildcard(arg))
                return;
        die_verify_filename(prefix, arg, diagnose_misspelt_rev);
 }
index 89918ca158379a02368b0604b14465fa14855c8e..d0f844db897751adca937578185c7421095bbc1e 100644 (file)
@@ -892,12 +892,12 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
                        prefix++;
                        negative = 1;
                } else if (prefix[0] != '!') {
-                       die ("Invalid search pattern: %s", prefix);
+                       return -1;
                }
        }
 
        if (regcomp(&regex, prefix, REG_EXTENDED))
-               die("Invalid search pattern: %s", prefix);
+               return -1;
 
        for (l = list; l; l = l->next) {
                l->item->object.flags |= ONELINE_SEEN;
index 43b15e36aeeba4ddc48073f8463592efc5216e3c..18e2b28b263682a9eb6902b62535c228be1f36af 100644 (file)
@@ -27,7 +27,6 @@ PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
 TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY))
 
 T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh))
-TSVN = $(sort $(wildcard t91[0-9][0-9]-*.sh))
 TGITWEB = $(sort $(wildcard t95[0-9][0-9]-*.sh))
 THELPERS = $(sort $(filter-out $(T),$(wildcard *.sh)))
 
@@ -77,11 +76,6 @@ aggregate-results:
                echo "$$f"; \
        done | '$(SHELL_PATH_SQ)' ./aggregate-results.sh
 
-# we can test NO_OPTIMIZE_COMMITS independently of LC_ALL
-full-svn-test:
-       $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C
-       $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8
-
 gitweb-test:
        $(MAKE) $(TGITWEB)
 
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 b0ec12ff6cbcdd7352b764db32bc34340b37fc8a..6a50b8793e4ff840e67d20c169159f474cb9d297 100644 (file)
@@ -186,3 +186,15 @@ start_svnserve () {
              --listen-host 127.0.0.1 &
 }
 
+prepare_a_utf8_locale () {
+       a_utf8_locale=$(locale -a | sed -n '/\.[uU][tT][fF]-*8$/{
+       p
+       q
+}')
+       if test -n "$a_utf8_locale"
+       then
+               test_set_prereq UTF8
+       else
+               say "# UTF-8 locale not available, some tests are skipped"
+       fi
+}
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 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 199b22d85e92535f148eaaca4d3856dbdfb6bcec..b99d5192a96ec77ef6a99cb86518375c447b48a9 100755 (executable)
@@ -56,30 +56,4 @@ test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' '
        test_i18ngrep ! "^HEAD is now at" stderr
 '
 
-test_expect_success 'wildcard ambiguation, paths win' '
-       git init ambi &&
-       (
-               cd ambi &&
-               echo a >a.c &&
-               git add a.c &&
-               echo b >a.c &&
-               git checkout "*.c" &&
-               echo a >expect &&
-               test_cmp expect a.c
-       )
-'
-
-test_expect_success !MINGW 'wildcard ambiguation, refs lose' '
-       git init ambi2 &&
-       (
-               cd ambi2 &&
-               echo a >"*.c" &&
-               git add . &&
-               test_must_fail git show :"*.c" &&
-               git show :"*.c" -- >actual &&
-               echo a >expect &&
-               test_cmp expect actual
-       )
-'
-
 test_done
index 75ebb1b4a0f79faa6f92cc9575eeef6b10ae27d3..1b1b65a6b0fc7ace4e18e8642a6c47631d7e6a43 100755 (executable)
@@ -8,6 +8,16 @@ test_expect_success 'setup' '
        test_commit init
 '
 
+test_expect_success 'rev-parse --git-common-dir on main worktree' '
+       git rev-parse --git-common-dir >actual &&
+       echo .git >expected &&
+       test_cmp expected actual &&
+       mkdir sub &&
+       git -C sub rev-parse --git-common-dir >actual2 &&
+       echo sub/.git >expected2 &&
+       test_cmp expected2 actual2
+'
+
 test_expect_success '"list" all worktrees from main' '
        echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
        test_when_finished "rm -rf here && git worktree prune" &&
index 3fc484e8c3f8d910f02e409baf7bf1d5682b4f2f..d043078da526275c3b1505297f5300cf1ad26a22 100755 (executable)
@@ -175,13 +175,10 @@ test_expect_success 'negated exclude matches can override previous ones' '
        grep "^a.1" output
 '
 
-test_expect_success 'excluded directory overrides content patterns' '
+test_expect_success 'excluded directory does not override content patterns' '
 
        git ls-files --others --exclude="one" --exclude="!one/a.1" >output &&
-       if grep "^one/a.1" output
-       then
-               false
-       fi
+       grep "^one/a.1" output
 '
 
 test_expect_success 'negated directory doesn'\''t affect content patterns' '
diff --git a/t/t3007-ls-files-other-negative.sh b/t/t3007-ls-files-other-negative.sh
new file mode 100755 (executable)
index 0000000..0797b86
--- /dev/null
@@ -0,0 +1,153 @@
+#!/bin/sh
+
+test_description='test re-include patterns'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       mkdir -p fooo foo/bar tmp &&
+       touch abc foo/def foo/bar/ghi foo/bar/bar
+'
+
+test_expect_success 'no match, do not enter subdir and waste cycles' '
+       cat >.gitignore <<-\EOF &&
+       /tmp
+       /foo
+       !fooo/bar/bar
+       EOF
+       GIT_TRACE_EXCLUDE="$(pwd)/tmp/trace" git ls-files -o --exclude-standard >tmp/actual &&
+       ! grep "enter .foo/.\$" tmp/trace &&
+       cat >tmp/expected <<-\EOF &&
+       .gitignore
+       abc
+       EOF
+       test_cmp tmp/expected tmp/actual
+'
+
+test_expect_success 'match, excluded by literal pathname pattern' '
+       cat >.gitignore <<-\EOF &&
+       /tmp
+       /fooo
+       /foo
+       !foo/bar/bar
+       EOF
+       cat >fooo/.gitignore <<-\EOF &&
+       !/*
+       EOF     git ls-files -o --exclude-standard >tmp/actual &&
+       cat >tmp/expected <<-\EOF &&
+       .gitignore
+       abc
+       foo/bar/bar
+       EOF
+       test_cmp tmp/expected tmp/actual
+'
+
+test_expect_success 'match, excluded by wildcard pathname pattern' '
+       cat >.gitignore <<-\EOF &&
+       /tmp
+       /fooo
+       /fo?
+       !foo/bar/bar
+       EOF
+       git ls-files -o --exclude-standard >tmp/actual &&
+       cat >tmp/expected <<-\EOF &&
+       .gitignore
+       abc
+       foo/bar/bar
+       EOF
+       test_cmp tmp/expected tmp/actual
+'
+
+test_expect_success 'match, excluded by literal basename pattern' '
+       cat >.gitignore <<-\EOF &&
+       /tmp
+       /fooo
+       foo
+       !foo/bar/bar
+       EOF
+       git ls-files -o --exclude-standard >tmp/actual &&
+       cat >tmp/expected <<-\EOF &&
+       .gitignore
+       abc
+       foo/bar/bar
+       EOF
+       test_cmp tmp/expected tmp/actual
+'
+
+test_expect_success 'match, excluded by wildcard basename pattern' '
+       cat >.gitignore <<-\EOF &&
+       /tmp
+       /fooo
+       fo?
+       !foo/bar/bar
+       EOF
+       git ls-files -o --exclude-standard >tmp/actual &&
+       cat >tmp/expected <<-\EOF &&
+       .gitignore
+       abc
+       foo/bar/bar
+       EOF
+       test_cmp tmp/expected tmp/actual
+'
+
+test_expect_success 'match, excluded by literal mustbedir, basename pattern' '
+       cat >.gitignore <<-\EOF &&
+       /tmp
+       /fooo
+       foo/
+       !foo/bar/bar
+       EOF
+       git ls-files -o --exclude-standard >tmp/actual &&
+       cat >tmp/expected <<-\EOF &&
+       .gitignore
+       abc
+       foo/bar/bar
+       EOF
+       test_cmp tmp/expected tmp/actual
+'
+
+test_expect_success 'match, excluded by literal mustbedir, pathname pattern' '
+       cat >.gitignore <<-\EOF &&
+       /tmp
+       /fooo
+       /foo/
+       !foo/bar/bar
+       EOF
+       git ls-files -o --exclude-standard >tmp/actual &&
+       cat >tmp/expected <<-\EOF &&
+       .gitignore
+       abc
+       foo/bar/bar
+       EOF
+       test_cmp tmp/expected tmp/actual
+'
+
+test_expect_success 'prepare for nested negatives' '
+       cat >.git/info/exclude <<-\EOF &&
+       /.gitignore
+       /tmp
+       /foo
+       /abc
+       EOF
+       git ls-files -o --exclude-standard >tmp/actual &&
+       test_must_be_empty tmp/actual &&
+       mkdir -p 1/2/3/4 &&
+       touch 1/f 1/2/f 1/2/3/f 1/2/3/4/f
+'
+
+test_expect_success 'match, literal pathname, nested negatives' '
+       cat >.gitignore <<-\EOF &&
+       /1
+       !1/2
+       1/2/3
+       !1/2/3/4
+       EOF
+       git ls-files -o --exclude-standard >tmp/actual &&
+       cat >tmp/expected <<-\EOF &&
+       1/2/3/4/f
+       1/2/f
+       EOF
+       test_cmp tmp/expected tmp/actual
+'
+
+test_done
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 1a8e3b81c815cfb92b7025a12d8c703f2ffc54e9..0dcc752076a9e42b0cff982d7b0f42c63f85dee2 100755 (executable)
@@ -51,6 +51,11 @@ test_expect_success setup '
        git clone one test
 '
 
+test_expect_success 'add remote whose URL agrees with url.<...>.insteadOf' '
+       test_config url.git@host.com:team/repo.git.insteadOf myremote &&
+       git remote add myremote git@host.com:team/repo.git
+'
+
 test_expect_success C_LOCALE_OUTPUT 'remote information for the origin' '
        (
                cd test &&
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 d76269a8fc96a874042cd2e070794e2c56577468..225a022e8a8fe063bc9cb8b8b282323f95bb18e3 100755 (executable)
@@ -6,6 +6,12 @@ test_description='test fetching over git protocol'
 . "$TEST_DIRECTORY"/lib-git-daemon.sh
 start_git_daemon
 
+check_verbose_connect () {
+       grep -F "Looking up 127.0.0.1 ..." stderr &&
+       grep -F "Connecting to 127.0.0.1 (port " stderr &&
+       grep -F "done." stderr
+}
+
 test_expect_success 'setup repository' '
        git config push.default matching &&
        echo content >file &&
@@ -24,7 +30,8 @@ test_expect_success 'create git-accessible bare repository' '
 '
 
 test_expect_success 'clone git repository' '
-       git clone "$GIT_DAEMON_URL/repo.git" clone &&
+       git clone -v "$GIT_DAEMON_URL/repo.git" clone 2>stderr &&
+       check_verbose_connect &&
        test_cmp file clone/file
 '
 
@@ -32,10 +39,21 @@ test_expect_success 'fetch changes via git protocol' '
        echo content >>file &&
        git commit -a -m two &&
        git push public &&
-       (cd clone && git pull) &&
+       (cd clone && git pull -v) 2>stderr &&
+       check_verbose_connect &&
        test_cmp file clone/file
 '
 
+test_expect_success 'no-op fetch -v stderr is as expected' '
+       (cd clone && git fetch -v) 2>stderr &&
+       check_verbose_connect
+'
+
+test_expect_success 'no-op fetch without "-v" is quiet' '
+       (cd clone && git fetch) 2>stderr &&
+       ! test -s stderr
+'
+
 test_expect_success 'remote detects correct HEAD' '
        git push public master:other &&
        (cd clone &&
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
 }
 
diff --git a/t/t6133-pathspec-rev-dwim.sh b/t/t6133-pathspec-rev-dwim.sh
new file mode 100755 (executable)
index 0000000..a290ffc
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+test_description='test dwim of revs versus pathspecs in revision parser'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       test_commit base &&
+       echo content >"br[ack]ets" &&
+       git add . &&
+       test_tick &&
+       git commit -m brackets
+'
+
+test_expect_success 'non-rev wildcard dwims to pathspec' '
+       git log -- "*.t" >expect &&
+       git log    "*.t" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'tree:path with metacharacters dwims to rev' '
+       git show "HEAD:br[ack]ets" -- >expect &&
+       git show "HEAD:br[ack]ets"    >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '^{foo} with metacharacters dwims to rev' '
+       git log "HEAD^{/b.*}" -- >expect &&
+       git log "HEAD^{/b.*}"    >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '@{foo} with metacharacters dwims to rev' '
+       git log "HEAD@{now [or thereabouts]}" -- >expect &&
+       git log "HEAD@{now [or thereabouts]}"    >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success ':/*.t from a subdir dwims to a pathspec' '
+       mkdir subdir &&
+       (
+               cd subdir &&
+               git log -- ":/*.t" >expect &&
+               git log    ":/*.t" >actual &&
+               test_cmp expect actual
+       )
+'
+
+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 6a48e4042996549e40843186783e2215beee9cca..0990f8d23571878fccb6e3607caa938590e3f683 100755 (executable)
@@ -77,11 +77,47 @@ test_expect_success 'make a commit to test rebase' '
        '
 
 test_expect_success 'git svn rebase works inside a fresh-cloned repository' '
-       cd test-rebase &&
+       (
+               cd test-rebase &&
                git svn rebase &&
                test -e test-rebase-main &&
                test -e test-rebase
-       '
+       )'
+
+# Without this, LC_ALL=C as set in test-lib.sh, and Cygwin converts
+# non-ASCII characters in filenames unexpectedly, and causes errors.
+# https://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-specialchars
+# > Some characters are disallowed in filenames on Windows filesystems. ...
+# ...
+# > ... All of the above characters, except for the backslash, are converted
+# > to special UNICODE characters in the range 0xf000 to 0xf0ff (the
+# > "Private use area") when creating or accessing files.
+prepare_a_utf8_locale
+test_expect_success UTF8 'svn.pathnameencoding=cp932 new file on dcommit' '
+       LC_ALL=$a_utf8_locale &&
+       export LC_ALL &&
+       neq=$(printf "\201\202") &&
+       git config svn.pathnameencoding cp932 &&
+       echo neq >"$neq" &&
+       git add "$neq" &&
+       git commit -m "neq" &&
+       git svn dcommit
+'
+
+# See the comment on the above test for setting of LC_ALL.
+test_expect_success 'svn.pathnameencoding=cp932 rename on dcommit' '
+       LC_ALL=$a_utf8_locale &&
+       export LC_ALL &&
+       inf=$(printf "\201\207") &&
+       git config svn.pathnameencoding cp932 &&
+       echo inf >"$inf" &&
+       git add "$inf" &&
+       git commit -m "inf" &&
+       git svn dcommit &&
+       git mv "$inf" inf &&
+       git commit -m "inf rename" &&
+       git svn dcommit
+'
 
 stop_httpd
 
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 39b6bcb398fff970184e242bdd51500b84f7d382..8dbd6476fa181dc7a2b3f0b6a9dfff57155c9eea 100755 (executable)
@@ -14,17 +14,7 @@ compare_git_head_with () {
        test_cmp current "$1"
 }
 
-a_utf8_locale=$(locale -a | sed -n '/\.[uU][tT][fF]-*8$/{
-       p
-       q
-}')
-
-if test -n "$a_utf8_locale"
-then
-       test_set_prereq UTF8
-else
-       say "# UTF-8 locale not available, some tests are skipped"
-fi
+prepare_a_utf8_locale
 
 compare_svn_head_with () {
        # extract just the log message and strip out committer info.
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 51e4a88c333463e23957eb07139b01a3de1a1a0e..0b47eb6bb299492d31111c94557c216bb3f32c7f 100644 (file)
@@ -1000,7 +1000,7 @@ test_i18ngrep () {
 test_lazy_prereq PIPE '
        # test whether the filesystem supports FIFOs
        case $(uname -s) in
-       CYGWIN*)
+       CYGWIN*|MINGW*)
                false
                ;;
        *)
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 c3adcd87b8caa2028785483bbc01d85fd0f7a9d6..6232dfe661a53d1eaf17ead5133da5792ae2413f 100644 (file)
@@ -56,7 +56,7 @@ static int test_function(struct test_data *data, char *(*func)(char *input),
                if (!data[i].from)
                        to = func(NULL);
                else {
-                       strcpy(buffer, data[i].from);
+                       xsnprintf(buffer, sizeof(buffer), "%s", data[i].from);
                        to = func(buffer);
                }
                if (!strcmp(to, data[i].to))
index a6bff8b30811c649c82afcdc9e018af1a34ce13c..b934183236ca571093f55818f5018c278150e274 100644 (file)
@@ -321,6 +321,21 @@ static void standard_options(struct transport *t)
        if (n >= sizeof(buf))
                die("impossibly large verbosity value");
        set_helper_option(t, "verbosity", buf);
+
+       switch (t->family) {
+       case TRANSPORT_FAMILY_ALL:
+               /*
+                * this is already the default,
+                * do not break old remote helpers by setting "all" here
+                */
+               break;
+       case TRANSPORT_FAMILY_IPV4:
+               set_helper_option(t, "family", "ipv4");
+               break;
+       case TRANSPORT_FAMILY_IPV6:
+               set_helper_option(t, "family", "ipv6");
+               break;
+       }
 }
 
 static int release_helper(struct transport *transport)
index 9ae71849d622d088a90bfcab81f9053fccfe79ac..e20bb771faaa56aa876f14f73123e14a71731a1b 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;
@@ -489,6 +163,12 @@ static int connect_setup(struct transport *transport, int for_push)
        if (data->conn)
                return 0;
 
+       switch (transport->family) {
+       case TRANSPORT_FAMILY_ALL: break;
+       case TRANSPORT_FAMILY_IPV4: flags |= CONNECT_IPV4; break;
+       case TRANSPORT_FAMILY_IPV6: flags |= CONNECT_IPV6; break;
+       }
+
        data->conn = git_connect(data->fd, transport->url,
                                 for_push ? data->options.receivepack :
                                 data->options.uploadpack,
@@ -985,11 +665,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 8ebaaf2cae054bcdfea491fc464f8bf3180b1e03..c68140892c6258925104f7dda385e635fcf95e20 100644 (file)
@@ -18,6 +18,12 @@ struct git_transport_options {
        struct push_cas_option *cas;
 };
 
+enum transport_family {
+       TRANSPORT_FAMILY_ALL = 0,
+       TRANSPORT_FAMILY_IPV4,
+       TRANSPORT_FAMILY_IPV6
+};
+
 struct transport {
        struct remote *remote;
        const char *url;
@@ -110,6 +116,8 @@ struct transport {
         * actually turns out to be smart.
         */
        struct git_transport_options *smart_options;
+
+       enum transport_family family;
 };
 
 #define TRANSPORT_PUSH_ALL 1