summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/lib-httpd/apache.conf9
-rwxr-xr-xt/t0003-attributes.sh26
-rwxr-xr-xt/t1300-repo-config.sh167
-rwxr-xr-xt/t1400-update-ref.sh45
-rwxr-xr-xt/t1500-rev-parse.sh45
-rwxr-xr-xt/t1700-split-index.sh16
-rwxr-xr-xt/t2027-worktree-list.sh10
-rwxr-xr-xt/t3200-branch.sh6
-rwxr-xr-xt/t3203-branch-output.sh16
-rwxr-xr-xt/t3404-rebase-interactive.sh2
-rwxr-xr-xt/t5316-pack-delta-depth.sh93
-rwxr-xr-xt/t5400-send-pack.sh38
-rwxr-xr-xt/t5505-remote.sh21
-rwxr-xr-xt/t5512-ls-remote.sh9
-rwxr-xr-xt/t5550-http-fetch-dumb.sh18
-rwxr-xr-xt/t5601-clone.sh41
-rwxr-xr-xt/t6007-rev-list-cherry-pick-file.sh38
-rwxr-xr-xt/t6040-tracking-info.sh2
-rwxr-xr-xt/t6045-merge-rename-delete.sh23
-rwxr-xr-xt/t6120-describe.sh27
-rwxr-xr-xt/t6132-pathspec-exclude.sh6
-rwxr-xr-xt/t6300-for-each-ref.sh98
-rwxr-xr-xt/t6302-for-each-ref-filter.sh94
-rwxr-xr-xt/t6500-gc.sh15
-rwxr-xr-xt/t7004-tag.sh18
-rwxr-xr-xt/t7518-ident-corner-cases.sh36
-rwxr-xr-xt/t7810-grep.sh66
-rwxr-xr-xt/t9001-send-email.sh7
-rwxr-xr-xt/t9902-completion.sh561
29 files changed, 1454 insertions, 99 deletions
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 69174c6e31..0642ae7e6e 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -133,6 +133,15 @@ RewriteRule ^/ftp-redir/(.*)$ ftp://localhost:1000/$1 [R=302]
RewriteRule ^/loop-redir/x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-(.*) /$1 [R=302]
RewriteRule ^/loop-redir/(.*)$ /loop-redir/x-$1 [R=302]
+# redir-to/502/x?y -> really-redir-to?path=502/x&qs=y which returns 502
+# redir-to/x?y -> really-redir-to?path=x&qs=y -> x?y
+RewriteCond %{QUERY_STRING} ^(.*)$
+RewriteRule ^/redir-to/(.*)$ /really-redir-to?path=$1&qs=%1 [R=302]
+RewriteCond %{QUERY_STRING} ^path=502/(.*)&qs=(.*)$
+RewriteRule ^/really-redir-to$ - [R=502,L]
+RewriteCond %{QUERY_STRING} ^path=(.*)&qs=(.*)$
+RewriteRule ^/really-redir-to$ /%1?%2 [R=302]
+
# The first rule issues a client-side redirect to something
# that _doesn't_ look like a git repo. The second rule is a
# server-side rewrite, so that it turns out the odd-looking
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index f0fbb42554..f19ae4f8cc 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -13,10 +13,31 @@ attr_check () {
test_line_count = 0 err
}
+attr_check_quote () {
+
+ path="$1"
+ quoted_path="$2"
+ expect="$3"
+
+ git check-attr test -- "$path" >actual &&
+ echo "\"$quoted_path\": test: $expect" >expect &&
+ test_cmp expect actual
+
+}
+
+test_expect_success 'open-quoted pathname' '
+ echo "\"a test=a" >.gitattributes &&
+ test_must_fail attr_check a a
+'
+
+
test_expect_success 'setup' '
mkdir -p a/b/d a/c b &&
(
echo "[attr]notest !test"
+ echo "\" d \" test=d"
+ echo " e test=e"
+ echo " e\" test=e"
echo "f test=f"
echo "a/i test=a/i"
echo "onoff test -test"
@@ -69,6 +90,11 @@ test_expect_success 'command line checks' '
'
test_expect_success 'attribute test' '
+
+ attr_check " d " d &&
+ attr_check e e &&
+ attr_check_quote e\" e\\\" e &&
+
attr_check f f &&
attr_check a/f f &&
attr_check a/c/f f &&
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 923bfc5a26..afcca0d52c 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -1097,6 +1097,68 @@ test_expect_success 'multiple git -c appends config' '
test_cmp expect actual
'
+test_expect_success 'last one wins: two level vars' '
+
+ # sec.var and sec.VAR are the same variable, as the first
+ # and the last level of a configuration variable name is
+ # case insensitive.
+
+ echo VAL >expect &&
+
+ git -c sec.var=val -c sec.VAR=VAL config --get sec.var >actual &&
+ test_cmp expect actual &&
+ git -c SEC.var=val -c sec.var=VAL config --get sec.var >actual &&
+ test_cmp expect actual &&
+
+ git -c sec.var=val -c sec.VAR=VAL config --get SEC.var >actual &&
+ test_cmp expect actual &&
+ git -c SEC.var=val -c sec.var=VAL config --get sec.VAR >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'last one wins: three level vars' '
+
+ # v.a.r and v.A.r are not the same variable, as the middle
+ # level of a three-level configuration variable name is
+ # case sensitive.
+
+ echo val >expect &&
+ git -c v.a.r=val -c v.A.r=VAL config --get v.a.r >actual &&
+ test_cmp expect actual &&
+ git -c v.a.r=val -c v.A.r=VAL config --get V.a.R >actual &&
+ test_cmp expect actual &&
+
+ # v.a.r and V.a.R are the same variable, as the first
+ # and the last level of a configuration variable name is
+ # case insensitive.
+
+ echo VAL >expect &&
+ git -c v.a.r=val -c v.a.R=VAL config --get v.a.r >actual &&
+ test_cmp expect actual &&
+ git -c v.a.r=val -c V.a.r=VAL config --get v.a.r >actual &&
+ test_cmp expect actual &&
+ git -c v.a.r=val -c v.a.R=VAL config --get V.a.R >actual &&
+ test_cmp expect actual &&
+ git -c v.a.r=val -c V.a.r=VAL config --get V.a.R >actual &&
+ test_cmp expect actual
+'
+
+for VAR in a .a a. a.0b a."b c". a."b c".0d
+do
+ test_expect_success "git -c $VAR=VAL rejects invalid '$VAR'" '
+ test_must_fail git -c "$VAR=VAL" config -l
+ '
+done
+
+for VAR in a.b a."b c".d
+do
+ test_expect_success "git -c $VAR=VAL works with valid '$VAR'" '
+ echo VAL >expect &&
+ git -c "$VAR=VAL" config --get "$VAR" >actual &&
+ test_cmp expect actual
+ '
+done
+
test_expect_success 'git -c is not confused by empty environment' '
GIT_CONFIG_PARAMETERS="" git -c x.one=1 config --list
'
@@ -1177,6 +1239,111 @@ test_expect_success 'urlmatch' '
test_cmp expect actual
'
+test_expect_success 'urlmatch favors more specific URLs' '
+ cat >.git/config <<-\EOF &&
+ [http "https://example.com/"]
+ cookieFile = /tmp/root.txt
+ [http "https://example.com/subdirectory"]
+ cookieFile = /tmp/subdirectory.txt
+ [http "https://user@example.com/"]
+ cookieFile = /tmp/user.txt
+ [http "https://averylonguser@example.com/"]
+ cookieFile = /tmp/averylonguser.txt
+ [http "https://preceding.example.com"]
+ cookieFile = /tmp/preceding.txt
+ [http "https://*.example.com"]
+ cookieFile = /tmp/wildcard.txt
+ [http "https://*.example.com/wildcardwithsubdomain"]
+ cookieFile = /tmp/wildcardwithsubdomain.txt
+ [http "https://trailing.example.com"]
+ cookieFile = /tmp/trailing.txt
+ [http "https://user@*.example.com/"]
+ cookieFile = /tmp/wildcardwithuser.txt
+ [http "https://sub.example.com/"]
+ cookieFile = /tmp/sub.txt
+ EOF
+
+ echo http.cookiefile /tmp/root.txt >expect &&
+ git config --get-urlmatch HTTP https://example.com >actual &&
+ test_cmp expect actual &&
+
+ echo http.cookiefile /tmp/subdirectory.txt >expect &&
+ git config --get-urlmatch HTTP https://example.com/subdirectory >actual &&
+ test_cmp expect actual &&
+
+ echo http.cookiefile /tmp/subdirectory.txt >expect &&
+ git config --get-urlmatch HTTP https://example.com/subdirectory/nested >actual &&
+ test_cmp expect actual &&
+
+ echo http.cookiefile /tmp/user.txt >expect &&
+ git config --get-urlmatch HTTP https://user@example.com/ >actual &&
+ test_cmp expect actual &&
+
+ echo http.cookiefile /tmp/subdirectory.txt >expect &&
+ git config --get-urlmatch HTTP https://averylonguser@example.com/subdirectory >actual &&
+ test_cmp expect actual &&
+
+ echo http.cookiefile /tmp/preceding.txt >expect &&
+ git config --get-urlmatch HTTP https://preceding.example.com >actual &&
+ test_cmp expect actual &&
+
+ echo http.cookiefile /tmp/wildcard.txt >expect &&
+ git config --get-urlmatch HTTP https://wildcard.example.com >actual &&
+ test_cmp expect actual &&
+
+ echo http.cookiefile /tmp/sub.txt >expect &&
+ git config --get-urlmatch HTTP https://sub.example.com/wildcardwithsubdomain >actual &&
+ test_cmp expect actual &&
+
+ echo http.cookiefile /tmp/trailing.txt >expect &&
+ git config --get-urlmatch HTTP https://trailing.example.com >actual &&
+ test_cmp expect actual &&
+
+ echo http.cookiefile /tmp/sub.txt >expect &&
+ git config --get-urlmatch HTTP https://user@sub.example.com >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'urlmatch with wildcard' '
+ cat >.git/config <<-\EOF &&
+ [http]
+ sslVerify
+ [http "https://*.example.com"]
+ sslVerify = false
+ cookieFile = /tmp/cookie.txt
+ EOF
+
+ test_expect_code 1 git config --bool --get-urlmatch doesnt.exist https://good.example.com >actual &&
+ test_must_be_empty actual &&
+
+ echo true >expect &&
+ git config --bool --get-urlmatch http.SSLverify https://example.com >actual &&
+ test_cmp expect actual &&
+
+ echo true >expect &&
+ git config --bool --get-urlmatch http.SSLverify https://good-example.com >actual &&
+ test_cmp expect actual &&
+
+ echo true >expect &&
+ git config --bool --get-urlmatch http.sslverify https://deep.nested.example.com >actual &&
+ test_cmp expect actual &&
+
+ echo false >expect &&
+ git config --bool --get-urlmatch http.sslverify https://good.example.com >actual &&
+ test_cmp expect actual &&
+
+ {
+ echo http.cookiefile /tmp/cookie.txt &&
+ echo http.sslverify false
+ } >expect &&
+ git config --get-urlmatch HTTP https://good.example.com >actual &&
+ test_cmp expect actual &&
+
+ echo http.sslverify >expect &&
+ git config --get-urlmatch HTTP https://more.example.com.au >actual &&
+ test_cmp expect actual
+'
+
# good section hygiene
test_expect_failure 'unsetting the last key in a section removes header' '
cat >.git/config <<-\EOF &&
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index b0ffc0b573..825422341d 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -85,6 +85,24 @@ test_expect_success "delete $m (by HEAD)" '
'
rm -f .git/$m
+test_expect_success "deleting current branch adds message to HEAD's log" '
+ git update-ref $m $A &&
+ git symbolic-ref HEAD $m &&
+ git update-ref -m delete-$m -d $m &&
+ ! test -f .git/$m &&
+ grep "delete-$m$" .git/logs/HEAD
+'
+rm -f .git/$m
+
+test_expect_success "deleting by HEAD adds message to HEAD's log" '
+ git update-ref $m $A &&
+ git symbolic-ref HEAD $m &&
+ git update-ref -m delete-by-head -d HEAD &&
+ ! test -f .git/$m &&
+ grep "delete-by-head$" .git/logs/HEAD
+'
+rm -f .git/$m
+
test_expect_success 'update-ref does not create reflogs by default' '
test_when_finished "git update-ref -d $outside" &&
git update-ref $outside $A &&
@@ -256,6 +274,33 @@ test_expect_success \
git update-ref HEAD'" $A &&
test $A"' = $(cat .git/'"$m"')'
+test_expect_success "empty directory removal" '
+ git branch d1/d2/r1 HEAD &&
+ git branch d1/r2 HEAD &&
+ test -f .git/refs/heads/d1/d2/r1 &&
+ test -f .git/logs/refs/heads/d1/d2/r1 &&
+ git branch -d d1/d2/r1 &&
+ ! test -e .git/refs/heads/d1/d2 &&
+ ! test -e .git/logs/refs/heads/d1/d2 &&
+ test -f .git/refs/heads/d1/r2 &&
+ test -f .git/logs/refs/heads/d1/r2
+'
+
+test_expect_success "symref empty directory removal" '
+ git branch e1/e2/r1 HEAD &&
+ git branch e1/r2 HEAD &&
+ git checkout e1/e2/r1 &&
+ test_when_finished "git checkout master" &&
+ test -f .git/refs/heads/e1/e2/r1 &&
+ test -f .git/logs/refs/heads/e1/e2/r1 &&
+ git update-ref -d HEAD &&
+ ! test -e .git/refs/heads/e1/e2 &&
+ ! test -e .git/logs/refs/heads/e1/e2 &&
+ test -f .git/refs/heads/e1/r2 &&
+ test -f .git/logs/refs/heads/e1/r2 &&
+ test -f .git/logs/HEAD
+'
+
cat >expect <<EOF
$Z $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 Initial Creation
$A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150260 +0000 Switch
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index 038e24c401..9ed8b8ccba 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -3,7 +3,7 @@
test_description='test git rev-parse'
. ./test-lib.sh
-# usage: [options] label is-bare is-inside-git is-inside-work prefix git-dir
+# usage: [options] label is-bare is-inside-git is-inside-work prefix git-dir absolute-git-dir
test_rev_parse () {
d=
bare=
@@ -29,7 +29,8 @@ test_rev_parse () {
--is-inside-git-dir \
--is-inside-work-tree \
--show-prefix \
- --git-dir
+ --git-dir \
+ --absolute-git-dir
do
test $# -eq 0 && break
expect="$1"
@@ -62,29 +63,57 @@ test_expect_success 'setup' '
cp -R .git repo.git
'
-test_rev_parse toplevel false false true '' .git
+test_rev_parse toplevel false false true '' .git "$ROOT/.git"
-test_rev_parse -C .git .git/ false true false '' .
-test_rev_parse -C .git/objects .git/objects/ false true false '' "$ROOT/.git"
+test_rev_parse -C .git .git/ false true false '' . "$ROOT/.git"
+test_rev_parse -C .git/objects .git/objects/ false true false '' "$ROOT/.git" "$ROOT/.git"
-test_rev_parse -C sub/dir subdirectory false false true sub/dir/ "$ROOT/.git"
+test_rev_parse -C sub/dir subdirectory false false true sub/dir/ "$ROOT/.git" "$ROOT/.git"
test_rev_parse -b t 'core.bare = true' true false false
test_rev_parse -b u 'core.bare undefined' false false true
-test_rev_parse -C work -g ../.git -b f 'GIT_DIR=../.git, core.bare = false' false false true ''
+test_rev_parse -C work -g ../.git -b f 'GIT_DIR=../.git, core.bare = false' false false true '' "../.git" "$ROOT/.git"
test_rev_parse -C work -g ../.git -b t 'GIT_DIR=../.git, core.bare = true' true false false ''
test_rev_parse -C work -g ../.git -b u 'GIT_DIR=../.git, core.bare undefined' false false true ''
-test_rev_parse -C work -g ../repo.git -b f 'GIT_DIR=../repo.git, core.bare = false' false false true ''
+test_rev_parse -C work -g ../repo.git -b f 'GIT_DIR=../repo.git, core.bare = false' false false true '' "../repo.git" "$ROOT/repo.git"
test_rev_parse -C work -g ../repo.git -b t 'GIT_DIR=../repo.git, core.bare = true' true false false ''
test_rev_parse -C work -g ../repo.git -b u 'GIT_DIR=../repo.git, core.bare undefined' false false true ''
+test_expect_success 'git-common-dir from worktree root' '
+ echo .git >expect &&
+ git rev-parse --git-common-dir >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git-common-dir inside sub-dir' '
+ mkdir -p path/to/child &&
+ test_when_finished "rm -rf path" &&
+ echo "$(git -C path/to/child rev-parse --show-cdup).git" >expect &&
+ git -C path/to/child rev-parse --git-common-dir >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git-path from worktree root' '
+ echo .git/objects >expect &&
+ git rev-parse --git-path objects >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git-path inside sub-dir' '
+ mkdir -p path/to/child &&
+ test_when_finished "rm -rf path" &&
+ echo "$(git -C path/to/child rev-parse --show-cdup).git/objects" >expect &&
+ git -C path/to/child rev-parse --git-path objects >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1700-split-index.sh b/t/t1700-split-index.sh
index 292a0720fc..6096f2c630 100755
--- a/t/t1700-split-index.sh
+++ b/t/t1700-split-index.sh
@@ -200,4 +200,20 @@ EOF
test_cmp expect actual
'
+test_expect_success 'rev-parse --shared-index-path' '
+ test_create_repo split-index &&
+ (
+ cd split-index &&
+ git update-index --split-index &&
+ echo .git/sharedindex* >expect &&
+ git rev-parse --shared-index-path >actual &&
+ test_cmp expect actual &&
+ mkdir subdirectory &&
+ cd subdirectory &&
+ echo ../.git/sharedindex* >expect &&
+ git rev-parse --shared-index-path >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
diff --git a/t/t2027-worktree-list.sh b/t/t2027-worktree-list.sh
index 465eeeacd3..848da5f368 100755
--- a/t/t2027-worktree-list.sh
+++ b/t/t2027-worktree-list.sh
@@ -14,10 +14,18 @@ test_expect_success 'rev-parse --git-common-dir on main worktree' '
test_cmp expected actual &&
mkdir sub &&
git -C sub rev-parse --git-common-dir >actual2 &&
- echo sub/.git >expected2 &&
+ echo ../.git >expected2 &&
test_cmp expected2 actual2
'
+test_expect_success 'rev-parse --git-path objects linked worktree' '
+ echo "$(git rev-parse --show-toplevel)/.git/objects" >expect &&
+ test_when_finished "rm -rf linked-tree && git worktree prune" &&
+ git worktree add --detach linked-tree master &&
+ git -C linked-tree rev-parse --git-path objects >actual &&
+ test_cmp expect actual
+'
+
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" &&
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 8a833f354e..e36ed3b4e1 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -139,6 +139,12 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
test $(git rev-parse --abbrev-ref HEAD) = bam
'
+test_expect_success 'git branch -M baz bam should add entries to .git/logs/HEAD' '
+ msg="Branch: renamed refs/heads/baz to refs/heads/bam" &&
+ grep " 0\{40\}.*$msg$" .git/logs/HEAD &&
+ grep "^0\{40\}.*$msg$" .git/logs/HEAD
+'
+
test_expect_success 'git branch -M baz bam should succeed when baz is checked out as linked working tree' '
git checkout master &&
git worktree add -b baz bazdir &&
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 52283dfc8c..5778c0afe1 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -194,7 +194,7 @@ test_expect_success 'local-branch symrefs shortened properly' '
git symbolic-ref refs/heads/ref-to-remote refs/remotes/origin/branch-one &&
cat >expect <<-\EOF &&
ref-to-branch -> branch-one
- ref-to-remote -> refs/remotes/origin/branch-one
+ ref-to-remote -> origin/branch-one
EOF
git branch >actual.raw &&
grep ref-to <actual.raw >actual &&
@@ -225,4 +225,18 @@ test_expect_success 'sort branches, ignore case' '
)
'
+test_expect_success 'git branch --format option' '
+ cat >expect <<-\EOF &&
+ Refname is (HEAD detached from fromtag)
+ Refname is refs/heads/ambiguous
+ Refname is refs/heads/branch-one
+ Refname is refs/heads/branch-two
+ Refname is refs/heads/master
+ Refname is refs/heads/ref-to-branch
+ Refname is refs/heads/ref-to-remote
+ EOF
+ git branch --format="Refname is %(refname)" >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index e2f18d11f6..33d392ba11 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -556,7 +556,7 @@ test_expect_success 'clean error after failed "exec"' '
echo "edited again" > file7 &&
git add file7 &&
test_must_fail git rebase --continue 2>error &&
- test_i18ngrep "You have staged changes in your working tree." error
+ test_i18ngrep "you have staged changes in your working tree" error
'
test_expect_success 'rebase a detached HEAD' '
diff --git a/t/t5316-pack-delta-depth.sh b/t/t5316-pack-delta-depth.sh
new file mode 100755
index 0000000000..37143ea0ac
--- /dev/null
+++ b/t/t5316-pack-delta-depth.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+test_description='pack-objects breaks long cross-pack delta chains'
+. ./test-lib.sh
+
+# This mirrors a repeated push setup:
+#
+# 1. A client repeatedly modifies some files, makes a
+# commit, and pushes the result. It does this N times
+# before we get around to repacking.
+#
+# 2. Each push generates a thin pack with the new version of
+# various objects. Let's consider some file in the root tree
+# which is updated in each commit.
+#
+# When generating push number X, we feed commit X-1 (and
+# thus blob X-1) as a preferred base. The resulting pack has
+# blob X as a thin delta against blob X-1.
+#
+# On the receiving end, "index-pack --fix-thin" will
+# complete the pack with a base copy of blob X-1.
+#
+# 3. In older versions of git, if we used the delta from
+# pack X, then we'd always find blob X-1 as a base in the
+# same pack (and generate a fresh delta).
+#
+# But with the pack mru, we jump from delta to delta
+# following the traversal order:
+#
+# a. We grab blob X from pack X as a delta, putting it at
+# the tip of our mru list.
+#
+# b. Eventually we move onto commit X-1. We need other
+# objects which are only in pack X-1 (in the test code
+# below, it's the containing tree). That puts pack X-1
+# at the tip of our mru list.
+#
+# c. Eventually we look for blob X-1, and we find the
+# version in pack X-1 (because it's the mru tip).
+#
+# Now we have blob X as a delta against X-1, which is a delta
+# against X-2, and so forth.
+#
+# In the real world, these small pushes would get exploded by
+# unpack-objects rather than "index-pack --fix-thin", but the
+# same principle applies to larger pushes (they only need one
+# repeatedly-modified file to generate the delta chain).
+
+test_expect_success 'create series of packs' '
+ test-genrandom foo 4096 >content &&
+ prev= &&
+ for i in $(test_seq 1 10)
+ do
+ cat content >file &&
+ echo $i >>file &&
+ git add file &&
+ git commit -m $i &&
+ cur=$(git rev-parse HEAD^{tree}) &&
+ {
+ test -n "$prev" && echo "-$prev"
+ echo $cur
+ echo "$(git rev-parse :file) file"
+ } | git pack-objects --stdout >tmp &&
+ git index-pack --stdin --fix-thin <tmp || return 1
+ prev=$cur
+ done
+'
+
+max_chain() {
+ git index-pack --verify-stat-only "$1" >output &&
+ perl -lne '
+ /chain length = (\d+)/ and $len = $1;
+ END { print $len }
+ ' output
+}
+
+# Note that this whole setup is pretty reliant on the current
+# packing heuristics. We double-check that our test case
+# actually produces a long chain. If it doesn't, it should be
+# adjusted (or scrapped if the heuristics have become too unreliable)
+test_expect_success 'packing produces a long delta' '
+ # Use --window=0 to make sure we are seeing reused deltas,
+ # not computing a new long chain.
+ pack=$(git pack-objects --all --window=0 </dev/null pack) &&
+ test 9 = "$(max_chain pack-$pack.pack)"
+'
+
+test_expect_success '--depth limits depth' '
+ pack=$(git pack-objects --all --depth=5 </dev/null pack) &&
+ test 5 = "$(max_chain pack-$pack.pack)"
+'
+
+test_done
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 305ca7a930..3331e0f534 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -255,4 +255,42 @@ test_expect_success 'deny pushing to delete current branch' '
)
'
+extract_ref_advertisement () {
+ perl -lne '
+ # \\ is there to skip capabilities after \0
+ /push< ([^\\]+)/ or next;
+ exit 0 if $1 eq "0000";
+ print $1;
+ '
+}
+
+test_expect_success 'receive-pack de-dupes .have lines' '
+ git init shared &&
+ git -C shared commit --allow-empty -m both &&
+ git clone -s shared fork &&
+ (
+ cd shared &&
+ git checkout -b only-shared &&
+ git commit --allow-empty -m only-shared &&
+ git update-ref refs/heads/foo HEAD
+ ) &&
+
+ # Notable things in this expectation:
+ # - local refs are not de-duped
+ # - .have does not duplicate locals
+ # - .have does not duplicate itself
+ local=$(git -C fork rev-parse HEAD) &&
+ shared=$(git -C shared rev-parse only-shared) &&
+ cat >expect <<-EOF &&
+ $local refs/heads/master
+ $local refs/remotes/origin/HEAD
+ $local refs/remotes/origin/master
+ $shared .have
+ EOF
+
+ GIT_TRACE_PACKET=$(pwd)/trace git push fork HEAD:foo &&
+ extract_ref_advertisement <trace >refs &&
+ test_cmp expect refs
+'
+
test_done
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index ba46e86de0..a6c0178f3a 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -153,6 +153,25 @@ test_expect_success 'remove errors out early when deleting non-existent branch'
)
'
+test_expect_success 'remove remote with a branch without configured merge' '
+ test_when_finished "(
+ git -C test checkout master;
+ git -C test branch -D two;
+ git -C test config --remove-section remote.two;
+ git -C test config --remove-section branch.second;
+ true
+ )" &&
+ (
+ cd test &&
+ git remote add two ../two &&
+ git fetch two &&
+ git checkout -b second two/master^0 &&
+ git config branch.second.remote two &&
+ git checkout master &&
+ git remote rm two
+ )
+'
+
test_expect_success 'rename errors out early when deleting non-existent branch' '
(
cd test &&
@@ -725,7 +744,7 @@ test_expect_success 'rename a remote' '
(
cd four &&
git remote rename origin upstream &&
- rmdir .git/refs/remotes/origin &&
+ test -z "$(git for-each-ref refs/remotes/origin)" &&
test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/master" &&
test "$(git rev-parse upstream/master)" = "$(git rev-parse master)" &&
test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" &&
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 55fc83fc06..94fc9be9ce 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -248,4 +248,13 @@ test_expect_success PIPE,JGIT,GIT_DAEMON 'indicate no refs in standards-complian
test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git
'
+test_expect_success 'ls-remote works outside repository' '
+ # It is important for this repo to be inside the nongit
+ # area, as we want a repo name that does not include
+ # slashes (because those inhibit some of our configuration
+ # lookups).
+ nongit git init --bare dst.git &&
+ nongit git ls-remote dst.git
+'
+
test_done
diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh
index aeb3a63f7c..87308cdced 100755
--- a/t/t5550-http-fetch-dumb.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -34,6 +34,15 @@ test_expect_success 'clone http repository' '
test_cmp file clone/file
'
+test_expect_success 'list refs from outside any repository' '
+ cat >expect <<-EOF &&
+ $(git rev-parse master) HEAD
+ $(git rev-parse master) refs/heads/master
+ EOF
+ nongit git ls-remote "$HTTPD_URL/dumb/repo.git" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'create password-protected repository' '
mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/" &&
cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
@@ -378,5 +387,14 @@ test_expect_success 'http-alternates triggers not-from-user protocol check' '
clone $HTTPD_URL/dumb/evil.git evil-user
'
+test_expect_success 'can redirect through non-"info/refs?service=git-upload-pack" URL' '
+ git clone "$HTTPD_URL/redir-to/dumb/repo.git"
+'
+
+test_expect_success 'print HTTP error when any intermediate redirect throws error' '
+ test_must_fail git clone "$HTTPD_URL/redir-to/502" 2> stderr &&
+ test_i18ngrep "unable to access.*/redir-to/502" stderr
+'
+
stop_httpd
test_done
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 4241ea5b32..b52b8acf98 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -386,6 +386,47 @@ test_expect_success 'tortoiseplink is like putty, with extra arguments' '
expect_ssh "-batch -P 123" myhost src
'
+test_expect_success 'double quoted plink.exe in GIT_SSH_COMMAND' '
+ copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink.exe" &&
+ GIT_SSH_COMMAND="\"$TRASH_DIRECTORY/plink.exe\" -v" \
+ git clone "[myhost:123]:src" ssh-bracket-clone-plink-3 &&
+ expect_ssh "-v -P 123" myhost src
+'
+
+SQ="'"
+test_expect_success 'single quoted plink.exe in GIT_SSH_COMMAND' '
+ copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink.exe" &&
+ GIT_SSH_COMMAND="$SQ$TRASH_DIRECTORY/plink.exe$SQ -v" \
+ git clone "[myhost:123]:src" ssh-bracket-clone-plink-4 &&
+ expect_ssh "-v -P 123" myhost src
+'
+
+test_expect_success 'GIT_SSH_VARIANT overrides plink detection' '
+ copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink" &&
+ GIT_SSH_VARIANT=ssh \
+ git clone "[myhost:123]:src" ssh-bracket-clone-variant-1 &&
+ expect_ssh "-p 123" myhost src
+'
+
+test_expect_success 'ssh.variant overrides plink detection' '
+ copy_ssh_wrapper_as "$TRASH_DIRECTORY/plink" &&
+ git -c ssh.variant=ssh \
+ clone "[myhost:123]:src" ssh-bracket-clone-variant-2 &&
+ expect_ssh "-p 123" myhost src
+'
+
+test_expect_success 'GIT_SSH_VARIANT overrides plink detection to plink' '
+ GIT_SSH_VARIANT=plink \
+ git clone "[myhost:123]:src" ssh-bracket-clone-variant-3 &&
+ expect_ssh "-P 123" myhost src
+'
+
+test_expect_success 'GIT_SSH_VARIANT overrides plink to tortoiseplink' '
+ GIT_SSH_VARIANT=tortoiseplink \
+ git clone "[myhost:123]:src" ssh-bracket-clone-variant-4 &&
+ expect_ssh "-batch -P 123" myhost src
+'
+
# Reset the GIT_SSH environment variable for clone tests.
setup_ssh_wrapper
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index 1408b608eb..2959745196 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -99,6 +99,44 @@ test_expect_success '--cherry-pick bar does not come up empty (II)' '
test_cmp actual.named expect
'
+test_expect_success 'name-rev multiple --refs combine inclusive' '
+ git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+ git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" \
+ <actual >actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+EOF
+
+test_expect_success 'name-rev --refs excludes non-matched patterns' '
+ git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
+ git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+ git name-rev --stdin --name-only --refs="*tags/F" \
+ <actual >actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+EOF
+
+test_expect_success 'name-rev --exclude excludes matched patterns' '
+ git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
+ git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" --exclude="*E" \
+ <actual >actual.named &&
+ test_cmp actual.named expect
+'
+
+test_expect_success 'name-rev --no-refs clears the refs list' '
+ git rev-list --left-right --cherry-pick F...E -- bar >expect &&
+ git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
+ <expect >actual &&
+ test_cmp actual expect
+'
+
cat >expect <<EOF
+tags/F
=tags/D
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 3d5c238c81..97a07655a0 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -44,7 +44,7 @@ b1 [ahead 1, behind 1] d
b2 [ahead 1, behind 1] d
b3 [behind 1] b
b4 [ahead 2] f
-b5 g
+b5 [gone] g
b6 c
EOF
diff --git a/t/t6045-merge-rename-delete.sh b/t/t6045-merge-rename-delete.sh
new file mode 100755
index 0000000000..5d33577d2f
--- /dev/null
+++ b/t/t6045-merge-rename-delete.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+test_description='Merge-recursive rename/delete conflict message'
+. ./test-lib.sh
+
+test_expect_success 'rename/delete' '
+ echo foo >A &&
+ git add A &&
+ git commit -m "initial" &&
+
+ git checkout -b rename &&
+ git mv A B &&
+ git commit -m "rename" &&
+
+ git checkout master &&
+ git rm A &&
+ git commit -m "delete" &&
+
+ test_must_fail git merge --strategy=recursive rename >output &&
+ test_i18ngrep "CONFLICT (rename/delete): A deleted in HEAD and renamed to B in rename. Version rename of B left in tree." output
+'
+
+test_done
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 85f269411c..167491fd5b 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -182,6 +182,10 @@ check_describe "test2-lightweight-*" --tags --match="test2-*"
check_describe "test2-lightweight-*" --long --tags --match="test2-*" HEAD^
+check_describe "test1-lightweight-*" --long --tags --match="test1-*" --match="test2-*" HEAD^
+
+check_describe "test2-lightweight-*" --long --tags --match="test1-*" --no-match --match="test2-*" HEAD^
+
test_expect_success 'name-rev with exact tags' '
echo A >expect &&
tag_object=$(git rev-parse refs/tags/A) &&
@@ -206,4 +210,27 @@ test_expect_success 'describe --contains with the exact tags' '
test_cmp expect actual
'
+test_expect_success 'describe --contains and --match' '
+ echo "A^0" >expect &&
+ tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+ test_must_fail git describe --contains --match="B" $tagged_commit &&
+ git describe --contains --match="B" --match="A" $tagged_commit >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'describe --exclude' '
+ echo "c~1" >expect &&
+ tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+ test_must_fail git describe --contains --match="B" $tagged_commit &&
+ git describe --contains --match="?" --exclude="A" $tagged_commit >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'describe --contains and --no-match' '
+ echo "A^0" >expect &&
+ tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+ git describe --contains --match="B" --no-match $tagged_commit >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh
index d51595cf6b..9dd5cde5fc 100755
--- a/t/t6132-pathspec-exclude.sh
+++ b/t/t6132-pathspec-exclude.sh
@@ -25,8 +25,10 @@ EOF
test_cmp expect actual
'
-test_expect_success 'exclude only should error out' '
- test_must_fail git log --oneline --format=%s -- ":(exclude)sub"
+test_expect_success 'exclude only no longer errors out' '
+ git log --oneline --format=%s -- . ":(exclude)sub" >expect &&
+ git log --oneline --format=%s -- ":(exclude)sub" >actual &&
+ test_cmp expect actual
'
test_expect_success 't_e_i() exclude sub' '
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index aea1dfc714..834a9ed168 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -38,6 +38,7 @@ test_atom() {
case "$1" in
head) ref=refs/heads/master ;;
tag) ref=refs/tags/testtag ;;
+ sym) ref=refs/heads/sym ;;
*) ref=$1 ;;
esac
printf '%s\n' "$3" >expected
@@ -50,16 +51,40 @@ test_atom() {
test_atom head refname refs/heads/master
test_atom head refname:short master
+test_atom head refname:lstrip=1 heads/master
+test_atom head refname:lstrip=2 master
+test_atom head refname:lstrip=-1 master
+test_atom head refname:lstrip=-2 heads/master
+test_atom head refname:rstrip=1 refs/heads
+test_atom head refname:rstrip=2 refs
+test_atom head refname:rstrip=-1 refs
+test_atom head refname:rstrip=-2 refs/heads
test_atom head refname:strip=1 heads/master
test_atom head refname:strip=2 master
+test_atom head refname:strip=-1 master
+test_atom head refname:strip=-2 heads/master
test_atom head upstream refs/remotes/origin/master
test_atom head upstream:short origin/master
+test_atom head upstream:lstrip=2 origin/master
+test_atom head upstream:lstrip=-2 origin/master
+test_atom head upstream:rstrip=2 refs/remotes
+test_atom head upstream:rstrip=-2 refs/remotes
+test_atom head upstream:strip=2 origin/master
+test_atom head upstream:strip=-2 origin/master
test_atom head push refs/remotes/myfork/master
test_atom head push:short myfork/master
+test_atom head push:lstrip=1 remotes/myfork/master
+test_atom head push:lstrip=-1 master
+test_atom head push:rstrip=1 refs/remotes/myfork
+test_atom head push:rstrip=-1 refs
+test_atom head push:strip=1 remotes/myfork/master
+test_atom head push:strip=-1 master
test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master)
test_atom head objectname:short $(git rev-parse --short refs/heads/master)
+test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/master)
+test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/master)
test_atom head tree $(git rev-parse refs/heads/master^{tree})
test_atom head parent ''
test_atom head numparent 0
@@ -99,6 +124,8 @@ test_atom tag objecttype tag
test_atom tag objectsize 154
test_atom tag objectname $(git rev-parse refs/tags/testtag)
test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag)
+test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/master)
+test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/master)
test_atom tag tree ''
test_atom tag parent ''
test_atom tag numparent ''
@@ -134,16 +161,6 @@ test_expect_success 'Check invalid atoms names are errors' '
test_must_fail git for-each-ref --format="%(INVALID)" refs/heads
'
-test_expect_success 'arguments to :strip must be positive integers' '
- test_must_fail git for-each-ref --format="%(refname:strip=0)" &&
- test_must_fail git for-each-ref --format="%(refname:strip=-1)" &&
- test_must_fail git for-each-ref --format="%(refname:strip=foo)"
-'
-
-test_expect_success 'stripping refnames too far gives an error' '
- test_must_fail git for-each-ref --format="%(refname:strip=3)"
-'
-
test_expect_success 'Check format specifiers are ignored in naming date atoms' '
git for-each-ref --format="%(authordate)" refs/heads &&
git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads &&
@@ -164,6 +181,12 @@ test_expect_success 'Check invalid format specifiers are errors' '
test_must_fail git for-each-ref --format="%(authordate:INVALID)" refs/heads
'
+test_expect_success 'arguments to %(objectname:short=) must be positive integers' '
+ test_must_fail git for-each-ref --format="%(objectname:short=0)" &&
+ test_must_fail git for-each-ref --format="%(objectname:short=-1)" &&
+ test_must_fail git for-each-ref --format="%(objectname:short=foo)"
+'
+
test_date () {
f=$1 &&
committer_date=$2 &&
@@ -362,6 +385,8 @@ test_expect_success 'setup for upstream:track[short]' '
test_atom head upstream:track '[ahead 1]'
test_atom head upstream:trackshort '>'
+test_atom head upstream:track,nobracket 'ahead 1'
+test_atom head upstream:nobracket,track 'ahead 1'
test_atom head push:track '[ahead 1]'
test_atom head push:trackshort '>'
@@ -372,7 +397,7 @@ test_expect_success 'Check that :track[short] cannot be used with other atoms' '
test_expect_success 'Check that :track[short] works when upstream is invalid' '
cat >expected <<-\EOF &&
-
+ [gone]
EOF
test_when_finished "git config branch.master.merge refs/heads/master" &&
@@ -554,11 +579,12 @@ test_expect_success 'Verify sort with multiple keys' '
test_cmp expected actual
'
+
test_expect_success 'do not dereference NULL upon %(HEAD) on unborn branch' '
test_when_finished "git checkout master" &&
git for-each-ref --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
sed -e "s/^\* / /" actual >expect &&
- git checkout --orphan HEAD &&
+ git checkout --orphan orphaned-branch &&
git for-each-ref --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
test_cmp expect actual
'
@@ -588,4 +614,52 @@ test_expect_success 'basic atom: head contents:trailers' '
test_cmp expect actual.clean
'
+test_expect_success 'Add symbolic ref for the following tests' '
+ git symbolic-ref refs/heads/sym refs/heads/master
+'
+
+cat >expected <<EOF
+refs/heads/master
+EOF
+
+test_expect_success 'Verify usage of %(symref) atom' '
+ git for-each-ref --format="%(symref)" refs/heads/sym >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+heads/master
+EOF
+
+test_expect_success 'Verify usage of %(symref:short) atom' '
+ git for-each-ref --format="%(symref:short)" refs/heads/sym >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+master
+heads/master
+EOF
+
+test_expect_success 'Verify usage of %(symref:lstrip) atom' '
+ git for-each-ref --format="%(symref:lstrip=2)" refs/heads/sym > actual &&
+ git for-each-ref --format="%(symref:lstrip=-2)" refs/heads/sym >> actual &&
+ test_cmp expected actual &&
+
+ git for-each-ref --format="%(symref:strip=2)" refs/heads/sym > actual &&
+ git for-each-ref --format="%(symref:strip=-2)" refs/heads/sym >> actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+refs
+refs/heads
+EOF
+
+test_expect_success 'Verify usage of %(symref:rstrip) atom' '
+ git for-each-ref --format="%(symref:rstrip=2)" refs/heads/sym > actual &&
+ git for-each-ref --format="%(symref:rstrip=-2)" refs/heads/sym >> actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index d0ab09f4bd..a09a1a46ef 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -327,4 +327,98 @@ test_expect_success 'reverse version sort' '
test_cmp expect actual
'
+test_expect_success 'improper usage of %(if), %(then), %(else) and %(end) atoms' '
+ test_must_fail git for-each-ref --format="%(if)" &&
+ test_must_fail git for-each-ref --format="%(then) %(end)" &&
+ test_must_fail git for-each-ref --format="%(else) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(else) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(then) %(then) %(end)" &&
+ test_must_fail git for-each-ref --format="%(then) %(else) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(else) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(then) %(else)" &&
+ test_must_fail git for-each-ref --format="%(if) %(else) %(then) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(then) %(else) %(else) %(end)" &&
+ test_must_fail git for-each-ref --format="%(if) %(end)"
+'
+
+test_expect_success 'check %(if)...%(then)...%(end) atoms' '
+ git for-each-ref --format="%(refname)%(if)%(authorname)%(then) Author: %(authorname)%(end)" >actual &&
+ cat >expect <<-\EOF &&
+ refs/heads/master Author: A U Thor
+ refs/heads/side Author: A U Thor
+ refs/odd/spot Author: A U Thor
+ refs/tags/annotated-tag
+ refs/tags/doubly-annotated-tag
+ refs/tags/doubly-signed-tag
+ refs/tags/foo1.10 Author: A U Thor
+ refs/tags/foo1.3 Author: A U Thor
+ refs/tags/foo1.6 Author: A U Thor
+ refs/tags/four Author: A U Thor
+ refs/tags/one Author: A U Thor
+ refs/tags/signed-tag
+ refs/tags/three Author: A U Thor
+ refs/tags/two Author: A U Thor
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'check %(if)...%(then)...%(else)...%(end) atoms' '
+ git for-each-ref --format="%(if)%(authorname)%(then)%(authorname)%(else)No author%(end): %(refname)" >actual &&
+ cat >expect <<-\EOF &&
+ A U Thor: refs/heads/master
+ A U Thor: refs/heads/side
+ A U Thor: refs/odd/spot
+ No author: refs/tags/annotated-tag
+ No author: refs/tags/doubly-annotated-tag
+ No author: refs/tags/doubly-signed-tag
+ A U Thor: refs/tags/foo1.10
+ A U Thor: refs/tags/foo1.3
+ A U Thor: refs/tags/foo1.6
+ A U Thor: refs/tags/four
+ A U Thor: refs/tags/one
+ No author: refs/tags/signed-tag
+ A U Thor: refs/tags/three
+ A U Thor: refs/tags/two
+ EOF
+ test_cmp expect actual
+'
+test_expect_success 'ignore spaces in %(if) atom usage' '
+ git for-each-ref --format="%(refname:short): %(if)%(HEAD)%(then)Head ref%(else)Not Head ref%(end)" >actual &&
+ cat >expect <<-\EOF &&
+ master: Head ref
+ side: Not Head ref
+ odd/spot: Not Head ref
+ annotated-tag: Not Head ref
+ doubly-annotated-tag: Not Head ref
+ doubly-signed-tag: Not Head ref
+ foo1.10: Not Head ref
+ foo1.3: Not Head ref
+ foo1.6: Not Head ref
+ four: Not Head ref
+ one: Not Head ref
+ signed-tag: Not Head ref
+ three: Not Head ref
+ two: Not Head ref
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'check %(if:equals=<string>)' '
+ git for-each-ref --format="%(if:equals=master)%(refname:short)%(then)Found master%(else)Not master%(end)" refs/heads/ >actual &&
+ cat >expect <<-\EOF &&
+ Found master
+ Not master
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'check %(if:notequals=<string>)' '
+ git for-each-ref --format="%(if:notequals=master)%(refname:short)%(then)Not master%(else)Found master%(end)" refs/heads/ >actual &&
+ cat >expect <<-\EOF &&
+ Found master
+ Not master
+ EOF
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh
index 1762dfa6a3..08de2e8ab0 100755
--- a/t/t6500-gc.sh
+++ b/t/t6500-gc.sh
@@ -67,5 +67,20 @@ test_expect_success 'auto gc with too many loose objects does not attempt to cre
test_line_count = 2 new # There is one new pack and its .idx
'
+test_expect_success 'background auto gc does not run if gc.log is present and recent but does if it is old' '
+ test_commit foo &&
+ test_commit bar &&
+ git repack &&
+ test_config gc.autopacklimit 1 &&
+ test_config gc.autodetach true &&
+ echo fleem >.git/gc.log &&
+ test_must_fail git gc --auto 2>err &&
+ test_i18ngrep "^error:" err &&
+ test_config gc.logexpiry 5.days &&
+ test-chmtime =-345600 .git/gc.log &&
+ test_must_fail git gc --auto &&
+ test_config gc.logexpiry 2.days &&
+ git gc --auto
+'
test_done
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 072e6c6b88..b4698ab5f5 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -81,9 +81,25 @@ test_expect_success 'creating a tag using default HEAD should succeed' '
'
test_expect_success 'creating a tag with --create-reflog should create reflog' '
+ git log -1 \
+ --format="format:tag: tagging %h (%s, %cd)%n" \
+ --date=format:%Y-%m-%d >expected &&
test_when_finished "git tag -d tag_with_reflog" &&
git tag --create-reflog tag_with_reflog &&
- git reflog exists refs/tags/tag_with_reflog
+ git reflog exists refs/tags/tag_with_reflog &&
+ sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'annotated tag with --create-reflog has correct message' '
+ git log -1 \
+ --format="format:tag: tagging %h (%s, %cd)%n" \
+ --date=format:%Y-%m-%d >expected &&
+ test_when_finished "git tag -d tag_with_reflog" &&
+ git tag -m "annotated tag" --create-reflog tag_with_reflog &&
+ git reflog exists refs/tags/tag_with_reflog &&
+ sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual &&
+ test_cmp expected actual
'
test_expect_success '--create-reflog does not create reflog on failure' '
diff --git a/t/t7518-ident-corner-cases.sh b/t/t7518-ident-corner-cases.sh
new file mode 100755
index 0000000000..b22f631261
--- /dev/null
+++ b/t/t7518-ident-corner-cases.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+test_description='corner cases in ident strings'
+. ./test-lib.sh
+
+# confirm that we do not segfault _and_ that we do not say "(null)", as
+# glibc systems will quietly handle our NULL pointer
+#
+# Note also that we can't use "env" here because we need to unset a variable,
+# and "-u" is not portable.
+test_expect_success 'empty name and missing email' '
+ (
+ sane_unset GIT_AUTHOR_EMAIL &&
+ GIT_AUTHOR_NAME= &&
+ test_must_fail git commit --allow-empty -m foo 2>err &&
+ test_i18ngrep ! null err
+ )
+'
+
+test_expect_success 'commit rejects all-crud name' '
+ test_must_fail env GIT_AUTHOR_NAME=" .;<>" \
+ git commit --allow-empty -m foo
+'
+
+# We must test the actual error message here, as an unwanted
+# auto-detection could fail for other reasons.
+test_expect_success 'empty configured name does not auto-detect' '
+ (
+ sane_unset GIT_AUTHOR_NAME &&
+ test_must_fail \
+ git -c user.name= commit --allow-empty -m foo 2>err &&
+ test_i18ngrep "empty ident name" err
+ )
+'
+
+test_done
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 19f0108f8a..cee42097b0 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -982,6 +982,72 @@ test_expect_success 'grep -e -- -- path' '
test_cmp expected actual
'
+test_expect_success 'dashdash disambiguates rev as rev' '
+ test_when_finished "rm -f master" &&
+ echo content >master &&
+ echo master:hello.c >expect &&
+ git grep -l o master -- hello.c >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'dashdash disambiguates pathspec as pathspec' '
+ test_when_finished "git rm -f master" &&
+ echo content >master &&
+ git add master &&
+ echo master:content >expect &&
+ git grep o -- master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'report bogus arg without dashdash' '
+ test_must_fail git grep o does-not-exist
+'
+
+test_expect_success 'report bogus rev with dashdash' '
+ test_must_fail git grep o hello.c --
+'
+
+test_expect_success 'allow non-existent path with dashdash' '
+ # We need a real match so grep exits with success.
+ tree=$(git ls-tree HEAD |
+ sed s/hello.c/not-in-working-tree/ |
+ git mktree) &&
+ git grep o "$tree" -- not-in-working-tree
+'
+
+test_expect_success 'grep --no-index pattern -- path' '
+ rm -fr non &&
+ mkdir -p non/git &&
+ (
+ GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
+ export GIT_CEILING_DIRECTORIES &&
+ cd non/git &&
+ echo hello >hello &&
+ echo goodbye >goodbye &&
+ echo hello:hello >expect &&
+ git grep --no-index o -- hello >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'grep --no-index complains of revs' '
+ test_must_fail git grep --no-index o master -- 2>err &&
+ test_i18ngrep "cannot be used with revs" err
+'
+
+test_expect_success 'grep --no-index prefers paths to revs' '
+ test_when_finished "rm -f master" &&
+ echo content >master &&
+ echo master:content >expect &&
+ git grep --no-index o master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep --no-index does not "diagnose" revs' '
+ test_must_fail git grep --no-index o :1:hello.c 2>err &&
+ test_i18ngrep ! -i "did you mean" err
+'
+
cat >expected <<EOF
hello.c:int main(int argc, const char **argv)
hello.c: printf("Hello world.\n");
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 0f398dd160..60a80f60b2 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -148,7 +148,6 @@ cat >expected-cc <<\EOF
!two@example.com!
!three@example.com!
!four@example.com!
-!five@example.com!
EOF
"
@@ -159,9 +158,9 @@ test_expect_success $PREREQ 'cc trailer with various syntax' '
Test Cc: trailers.
Cc: one@example.com
- Cc: <two@example.com> # this is part of the name
- Cc: <three@example.com>, <four@example.com> # not.five@example.com
- Cc: "Some # Body" <five@example.com> [part.of.name.too]
+ Cc: <two@example.com> # trailing comments are ignored
+ Cc: <three@example.com>, <not.four@example.com> one address per line
+ Cc: "Some # Body" <four@example.com> [ <also.a.comment> ]
EOF
clean_fake_sendmail &&
git send-email -1 --to=recipient@example.com \
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index a34e55f874..d711bef240 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -98,7 +98,7 @@ test_gitcomp ()
{
local -a COMPREPLY &&
sed -e 's/Z$//' >expected &&
- cur="$1" &&
+ local cur="$1" &&
shift &&
__gitcomp "$@" &&
print_comp &&
@@ -113,7 +113,7 @@ test_gitcomp_nl ()
{
local -a COMPREPLY &&
sed -e 's/Z$//' >expected &&
- cur="$1" &&
+ local cur="$1" &&
shift &&
__gitcomp_nl "$@" &&
print_comp &&
@@ -124,140 +124,280 @@ invalid_variable_name='${foo.bar}'
actual="$TRASH_DIRECTORY/actual"
-test_expect_success 'setup for __gitdir tests' '
+if test_have_prereq MINGW
+then
+ ROOT="$(pwd -W)"
+else
+ ROOT="$(pwd)"
+fi
+
+test_expect_success 'setup for __git_find_repo_path/__gitdir tests' '
mkdir -p subdir/subsubdir &&
+ mkdir -p non-repo &&
git init otherrepo
'
-test_expect_success '__gitdir - from command line (through $__git_dir)' '
- echo "$TRASH_DIRECTORY/otherrepo/.git" >expected &&
+test_expect_success '__git_find_repo_path - from command line (through $__git_dir)' '
+ echo "$ROOT/otherrepo/.git" >expected &&
(
- __git_dir="$TRASH_DIRECTORY/otherrepo/.git" &&
- __gitdir >"$actual"
+ __git_dir="$ROOT/otherrepo/.git" &&
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
-test_expect_success '__gitdir - repo as argument' '
- echo "otherrepo/.git" >expected &&
- __gitdir "otherrepo" >"$actual" &&
- test_cmp expected "$actual"
-'
-
-test_expect_success '__gitdir - remote as argument' '
- echo "remote" >expected &&
- __gitdir "remote" >"$actual" &&
- test_cmp expected "$actual"
-'
-
-test_expect_success '__gitdir - .git directory in cwd' '
+test_expect_success '__git_find_repo_path - .git directory in cwd' '
echo ".git" >expected &&
- __gitdir >"$actual" &&
+ (
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
+ ) &&
test_cmp expected "$actual"
'
-test_expect_success '__gitdir - .git directory in parent' '
- echo "$(pwd -P)/.git" >expected &&
+test_expect_success '__git_find_repo_path - .git directory in parent' '
+ echo "$ROOT/.git" >expected &&
(
cd subdir/subsubdir &&
- __gitdir >"$actual"
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
-test_expect_success '__gitdir - cwd is a .git directory' '
+test_expect_success '__git_find_repo_path - cwd is a .git directory' '
echo "." >expected &&
(
cd .git &&
- __gitdir >"$actual"
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
-test_expect_success '__gitdir - parent is a .git directory' '
- echo "$(pwd -P)/.git" >expected &&
+test_expect_success '__git_find_repo_path - parent is a .git directory' '
+ echo "$ROOT/.git" >expected &&
(
cd .git/refs/heads &&
- __gitdir >"$actual"
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
-test_expect_success '__gitdir - $GIT_DIR set while .git directory in cwd' '
- echo "$TRASH_DIRECTORY/otherrepo/.git" >expected &&
+test_expect_success '__git_find_repo_path - $GIT_DIR set while .git directory in cwd' '
+ echo "$ROOT/otherrepo/.git" >expected &&
(
- GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" &&
+ GIT_DIR="$ROOT/otherrepo/.git" &&
export GIT_DIR &&
- __gitdir >"$actual"
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
-test_expect_success '__gitdir - $GIT_DIR set while .git directory in parent' '
- echo "$TRASH_DIRECTORY/otherrepo/.git" >expected &&
+test_expect_success '__git_find_repo_path - $GIT_DIR set while .git directory in parent' '
+ echo "$ROOT/otherrepo/.git" >expected &&
(
- GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" &&
+ GIT_DIR="$ROOT/otherrepo/.git" &&
export GIT_DIR &&
cd subdir &&
- __gitdir >"$actual"
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_find_repo_path - from command line while "git -C"' '
+ echo "$ROOT/.git" >expected &&
+ (
+ __git_dir="$ROOT/.git" &&
+ __git_C_args=(-C otherrepo) &&
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
-test_expect_success '__gitdir - non-existing $GIT_DIR' '
+test_expect_success '__git_find_repo_path - relative dir from command line and "git -C"' '
+ echo "$ROOT/otherrepo/.git" >expected &&
(
- GIT_DIR="$TRASH_DIRECTORY/non-existing" &&
+ cd subdir &&
+ __git_dir="otherrepo/.git" &&
+ __git_C_args=(-C ..) &&
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_find_repo_path - $GIT_DIR set while "git -C"' '
+ echo "$ROOT/.git" >expected &&
+ (
+ GIT_DIR="$ROOT/.git" &&
export GIT_DIR &&
- test_must_fail __gitdir
- )
+ __git_C_args=(-C otherrepo) &&
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
'
-function pwd_P_W () {
- if test_have_prereq MINGW
- then
- pwd -W
- else
- pwd -P
- fi
-}
+test_expect_success '__git_find_repo_path - relative dir in $GIT_DIR and "git -C"' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ (
+ cd subdir &&
+ GIT_DIR="otherrepo/.git" &&
+ export GIT_DIR &&
+ __git_C_args=(-C ..) &&
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
-test_expect_success '__gitdir - gitfile in cwd' '
- echo "$(pwd_P_W)/otherrepo/.git" >expected &&
- echo "gitdir: $(pwd_P_W)/otherrepo/.git" >subdir/.git &&
+test_expect_success '__git_find_repo_path - "git -C" while .git directory in cwd' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ (
+ __git_C_args=(-C otherrepo) &&
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_find_repo_path - "git -C" while cwd is a .git directory' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ (
+ cd .git &&
+ __git_C_args=(-C .. -C otherrepo) &&
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_find_repo_path - "git -C" while .git directory in parent' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ (
+ cd subdir &&
+ __git_C_args=(-C .. -C otherrepo) &&
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_find_repo_path - non-existing path in "git -C"' '
+ (
+ __git_C_args=(-C non-existing) &&
+ test_must_fail __git_find_repo_path &&
+ printf "$__git_repo_path" >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
+test_expect_success '__git_find_repo_path - non-existing path in $__git_dir' '
+ (
+ __git_dir="non-existing" &&
+ test_must_fail __git_find_repo_path &&
+ printf "$__git_repo_path" >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
+test_expect_success '__git_find_repo_path - non-existing $GIT_DIR' '
+ (
+ GIT_DIR="$ROOT/non-existing" &&
+ export GIT_DIR &&
+ test_must_fail __git_find_repo_path &&
+ printf "$__git_repo_path" >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
+test_expect_success '__git_find_repo_path - gitfile in cwd' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ echo "gitdir: $ROOT/otherrepo/.git" >subdir/.git &&
test_when_finished "rm -f subdir/.git" &&
(
cd subdir &&
- __gitdir >"$actual"
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
-test_expect_success '__gitdir - gitfile in parent' '
- echo "$(pwd_P_W)/otherrepo/.git" >expected &&
- echo "gitdir: $(pwd_P_W)/otherrepo/.git" >subdir/.git &&
+test_expect_success '__git_find_repo_path - gitfile in parent' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ echo "gitdir: $ROOT/otherrepo/.git" >subdir/.git &&
test_when_finished "rm -f subdir/.git" &&
(
cd subdir/subsubdir &&
- __gitdir >"$actual"
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
-test_expect_success SYMLINKS '__gitdir - resulting path avoids symlinks' '
- echo "$(pwd -P)/otherrepo/.git" >expected &&
+test_expect_success SYMLINKS '__git_find_repo_path - resulting path avoids symlinks' '
+ echo "$ROOT/otherrepo/.git" >expected &&
mkdir otherrepo/dir &&
test_when_finished "rm -rf otherrepo/dir" &&
ln -s otherrepo/dir link &&
test_when_finished "rm -f link" &&
(
cd link &&
+ __git_find_repo_path &&
+ echo "$__git_repo_path" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_find_repo_path - not a git repository' '
+ (
+ cd non-repo &&
+ GIT_CEILING_DIRECTORIES="$ROOT" &&
+ export GIT_CEILING_DIRECTORIES &&
+ test_must_fail __git_find_repo_path &&
+ printf "$__git_repo_path" >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
+test_expect_success '__gitdir - finds repo' '
+ echo "$ROOT/.git" >expected &&
+ (
+ cd subdir/subsubdir &&
__gitdir >"$actual"
) &&
test_cmp expected "$actual"
'
-test_expect_success '__gitdir - not a git repository' '
- nongit test_must_fail __gitdir
+
+test_expect_success '__gitdir - returns error when cant find repo' '
+ (
+ __git_dir="non-existing" &&
+ test_must_fail __gitdir >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
+test_expect_success '__gitdir - repo as argument' '
+ echo "otherrepo/.git" >expected &&
+ (
+ __gitdir "otherrepo" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__gitdir - remote as argument' '
+ echo "remote" >expected &&
+ (
+ __gitdir "remote" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
'
test_expect_success '__gitcomp - trailing space - options' '
@@ -361,10 +501,286 @@ test_expect_success '__git_remotes - list remotes from $GIT_DIR/remotes and from
git remote add remote_in_config_1 git://remote_1 &&
test_when_finished "git remote remove remote_in_config_2" &&
git remote add remote_in_config_2 git://remote_2 &&
- __git_remotes >actual &&
+ (
+ __git_remotes >actual
+ ) &&
test_cmp expect actual
'
+test_expect_success '__git_is_configured_remote' '
+ test_when_finished "git remote remove remote_1" &&
+ git remote add remote_1 git://remote_1 &&
+ test_when_finished "git remote remove remote_2" &&
+ git remote add remote_2 git://remote_2 &&
+ (
+ verbose __git_is_configured_remote remote_2 &&
+ test_must_fail __git_is_configured_remote non-existent
+ )
+'
+
+test_expect_success 'setup for ref completion' '
+ git commit --allow-empty -m initial &&
+ git branch matching-branch &&
+ git tag matching-tag &&
+ (
+ cd otherrepo &&
+ git commit --allow-empty -m initial &&
+ git branch -m master master-in-other &&
+ git branch branch-in-other &&
+ git tag tag-in-other
+ ) &&
+ git remote add other "$ROOT/otherrepo/.git" &&
+ git fetch --no-tags other &&
+ rm -f .git/FETCH_HEAD &&
+ git init thirdrepo
+'
+
+test_expect_success '__git_refs - simple' '
+ cat >expected <<-EOF &&
+ HEAD
+ master
+ matching-branch
+ other/branch-in-other
+ other/master-in-other
+ matching-tag
+ EOF
+ (
+ cur= &&
+ __git_refs >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - full refs' '
+ cat >expected <<-EOF &&
+ refs/heads/master
+ refs/heads/matching-branch
+ EOF
+ (
+ cur=refs/heads/ &&
+ __git_refs >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - repo given on the command line' '
+ cat >expected <<-EOF &&
+ HEAD
+ branch-in-other
+ master-in-other
+ tag-in-other
+ EOF
+ (
+ __git_dir="$ROOT/otherrepo/.git" &&
+ cur= &&
+ __git_refs >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - remote on local file system' '
+ cat >expected <<-EOF &&
+ HEAD
+ branch-in-other
+ master-in-other
+ tag-in-other
+ EOF
+ (
+ cur= &&
+ __git_refs otherrepo >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - remote on local file system - full refs' '
+ cat >expected <<-EOF &&
+ refs/heads/branch-in-other
+ refs/heads/master-in-other
+ refs/tags/tag-in-other
+ EOF
+ (
+ cur=refs/ &&
+ __git_refs otherrepo >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - configured remote' '
+ cat >expected <<-EOF &&
+ HEAD
+ branch-in-other
+ master-in-other
+ EOF
+ (
+ cur= &&
+ __git_refs other >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - configured remote - full refs' '
+ cat >expected <<-EOF &&
+ refs/heads/branch-in-other
+ refs/heads/master-in-other
+ refs/tags/tag-in-other
+ EOF
+ (
+ cur=refs/ &&
+ __git_refs other >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - configured remote - repo given on the command line' '
+ cat >expected <<-EOF &&
+ HEAD
+ branch-in-other
+ master-in-other
+ EOF
+ (
+ cd thirdrepo &&
+ __git_dir="$ROOT/.git" &&
+ cur= &&
+ __git_refs other >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - configured remote - full refs - repo given on the command line' '
+ cat >expected <<-EOF &&
+ refs/heads/branch-in-other
+ refs/heads/master-in-other
+ refs/tags/tag-in-other
+ EOF
+ (
+ cd thirdrepo &&
+ __git_dir="$ROOT/.git" &&
+ cur=refs/ &&
+ __git_refs other >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - configured remote - remote name matches a directory' '
+ cat >expected <<-EOF &&
+ HEAD
+ branch-in-other
+ master-in-other
+ EOF
+ mkdir other &&
+ test_when_finished "rm -rf other" &&
+ (
+ cur= &&
+ __git_refs other >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - URL remote' '
+ cat >expected <<-EOF &&
+ HEAD
+ branch-in-other
+ master-in-other
+ tag-in-other
+ EOF
+ (
+ cur= &&
+ __git_refs "file://$ROOT/otherrepo/.git" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - URL remote - full refs' '
+ cat >expected <<-EOF &&
+ refs/heads/branch-in-other
+ refs/heads/master-in-other
+ refs/tags/tag-in-other
+ EOF
+ (
+ cur=refs/ &&
+ __git_refs "file://$ROOT/otherrepo/.git" >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__git_refs - non-existing remote' '
+ (
+ cur= &&
+ __git_refs non-existing >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
+test_expect_success '__git_refs - non-existing remote - full refs' '
+ (
+ cur=refs/ &&
+ __git_refs non-existing >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
+test_expect_success '__git_refs - non-existing URL remote' '
+ (
+ cur= &&
+ __git_refs "file://$ROOT/non-existing" >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
+test_expect_success '__git_refs - non-existing URL remote - full refs' '
+ (
+ cur=refs/ &&
+ __git_refs "file://$ROOT/non-existing" >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
+test_expect_success '__git_refs - not in a git repository' '
+ (
+ GIT_CEILING_DIRECTORIES="$ROOT" &&
+ export GIT_CEILING_DIRECTORIES &&
+ cd subdir &&
+ cur= &&
+ __git_refs >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
+test_expect_success '__git_refs - unique remote branches for git checkout DWIMery' '
+ cat >expected <<-EOF &&
+ HEAD
+ master
+ matching-branch
+ other/ambiguous
+ other/branch-in-other
+ other/master-in-other
+ remote/ambiguous
+ remote/branch-in-remote
+ matching-tag
+ branch-in-other
+ branch-in-remote
+ master-in-other
+ EOF
+ for remote_ref in refs/remotes/other/ambiguous \
+ refs/remotes/remote/ambiguous \
+ refs/remotes/remote/branch-in-remote
+ do
+ git update-ref $remote_ref master &&
+ test_when_finished "git update-ref -d $remote_ref"
+ done &&
+ (
+ cur= &&
+ __git_refs "" 1 >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success 'teardown after ref completion' '
+ git branch -d matching-branch &&
+ git tag -d matching-tag &&
+ git remote remove other
+'
+
test_expect_success '__git_get_config_variables' '
cat >expect <<-EOF &&
name-1
@@ -475,7 +891,12 @@ test_expect_success 'general options plus command' '
test_completion "git --namespace=foo check" "checkout " &&
test_completion "git --paginate check" "checkout " &&
test_completion "git --info-path check" "checkout " &&
- test_completion "git --no-replace-objects check" "checkout "
+ test_completion "git --no-replace-objects check" "checkout " &&
+ test_completion "git --git-dir some/path check" "checkout " &&
+ test_completion "git -c conf.var=value check" "checkout " &&
+ test_completion "git -C some/path check" "checkout " &&
+ test_completion "git --work-tree some/path check" "checkout " &&
+ test_completion "git --namespace name/space check" "checkout "
'
test_expect_success 'git --help completion' '
@@ -483,10 +904,10 @@ test_expect_success 'git --help completion' '
test_completion "git --help core" "core-tutorial "
'
-test_expect_success 'setup for ref completion' '
+test_expect_success 'setup for integration tests' '
echo content >file1 &&
echo more >file2 &&
- git add . &&
+ git add file1 file2 &&
git commit -m one &&
git branch mybranch &&
git tag mytag
@@ -500,6 +921,12 @@ test_expect_success 'checkout completes ref names' '
EOF
'
+test_expect_success 'git -C <path> checkout uses the right repo' '
+ test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
+ branch-in-other Z
+ EOF
+'
+
test_expect_success 'show completes all refs' '
test_completion "git show m" <<-\EOF
master Z
@@ -517,7 +944,7 @@ test_expect_success '<ref>: completes paths' '
test_expect_success 'complete tree filename with spaces' '
echo content >"name with spaces" &&
- git add . &&
+ git add "name with spaces" &&
git commit -m spaces &&
test_completion "git show HEAD:nam" <<-\EOF
name with spaces Z
@@ -526,7 +953,7 @@ test_expect_success 'complete tree filename with spaces' '
test_expect_success 'complete tree filename with metacharacters' '
echo content >"name with \${meta}" &&
- git add . &&
+ git add "name with \${meta}" &&
git commit -m meta &&
test_completion "git show HEAD:nam" <<-\EOF
name with ${meta} Z