summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/helper/test-config.c3
-rw-r--r--t/helper/test-dump-split-index.c2
-rw-r--r--t/helper/test-dump-untracked-cache.c6
-rw-r--r--t/helper/test-sha1-array.c3
-rwxr-xr-xt/perf/p0003-delta-base-cache.sh31
-rwxr-xr-xt/perf/p5310-pack-bitmaps.sh14
-rwxr-xr-xt/t0001-init.sh26
-rwxr-xr-xt/t0012-help.sh52
-rwxr-xr-xt/t1007-hash-object.sh68
-rwxr-xr-xt/t1301-shared-repo.sh41
-rwxr-xr-xt/t1302-repo-version.sh32
-rwxr-xr-xt/t1450-fsck.sh16
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh70
-rwxr-xr-xt/t3310-notes-merge-manual-resolve.sh2
-rwxr-xr-xt/t3320-notes-merge-worktrees.sh2
-rwxr-xr-xt/t3900-i18n-commit.sh8
-rwxr-xr-xt/t3901-i18n-patch.sh2
-rwxr-xr-xt/t4012-diff-binary.sh4
-rwxr-xr-xt/t4013-diff-various.sh6
-rw-r--r--t/t4013/diff.diff_--line-prefix=abc_master_master^_side29
-rw-r--r--t/t4013/diff.diff_--line-prefix_--cached_--_file015
-rwxr-xr-xt/t4014-format-patch.sh9
-rwxr-xr-xt/t4021-format-patch-numbered.sh17
-rwxr-xr-xt/t4053-diff-no-index.sh38
-rwxr-xr-xt/t4059-diff-submodule-not-initialized.sh127
-rwxr-xr-xt/t4060-diff-submodule-option-diff-format.sh749
-rwxr-xr-xt/t4061-diff-indent.sh216
-rwxr-xr-xt/t4150-am.sh23
-rwxr-xr-xt/t4202-log.sh323
-rwxr-xr-xt/t4204-patch-id.sh14
-rwxr-xr-xt/t4254-am-corrupt.sh2
-rwxr-xr-xt/t5100-mailinfo.sh2
-rw-r--r--t/t5100/info00185
-rw-r--r--t/t5100/info0018--no-inbody-headers5
-rw-r--r--t/t5100/msg00152
-rw-r--r--t/t5100/msg00182
-rw-r--r--t/t5100/msg0018--no-inbody-headers8
-rw-r--r--t/t5100/patch00186
-rw-r--r--t/t5100/patch0018--no-inbody-headers6
-rw-r--r--t/t5100/sample.mbox19
-rwxr-xr-xt/t5310-pack-bitmaps.sh108
-rwxr-xr-xt/t5314-pack-cycle-detection.sh113
-rwxr-xr-xt/t5500-fetch-pack.sh68
-rwxr-xr-xt/t5512-ls-remote.sh42
-rwxr-xr-xt/t5539-fetch-http-shallow.sh73
-rwxr-xr-xt/t5546-receive-limits.sh55
-rwxr-xr-xt/t6101-rev-parse-parents.sh94
-rwxr-xr-xt/t7060-wtstatus.sh21
-rwxr-xr-xt/t7064-wtstatus-pv2.sh593
-rwxr-xr-xt/t7408-submodule-reference.sh185
-rwxr-xr-xt/t8003-blame-corner-cases.sh4
-rwxr-xr-xt/t8010-cat-file-filters.sh64
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh8
-rw-r--r--t/test-lib-functions.sh4
-rw-r--r--t/test-lib.sh4
55 files changed, 3291 insertions, 150 deletions
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index 3c6d08cd09..83a4f2ab86 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -72,6 +72,9 @@ int cmd_main(int argc, const char **argv)
const char *v;
const struct string_list *strptr;
struct config_set cs;
+
+ setup_git_directory();
+
git_configset_init(&cs);
if (argc < 2) {
diff --git a/t/helper/test-dump-split-index.c b/t/helper/test-dump-split-index.c
index d1689248b4..e44430b699 100644
--- a/t/helper/test-dump-split-index.c
+++ b/t/helper/test-dump-split-index.c
@@ -23,7 +23,7 @@ int cmd_main(int ac, const char **av)
for (i = 0; i < the_index.cache_nr; i++) {
struct cache_entry *ce = the_index.cache[i];
printf("%06o %s %d\t%s\n", ce->ce_mode,
- sha1_to_hex(ce->sha1), ce_stage(ce), ce->name);
+ oid_to_hex(&ce->oid), ce_stage(ce), ce->name);
}
printf("replacements:");
if (si->replace_bitmap)
diff --git a/t/helper/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c
index 50112cc858..f752532ffb 100644
--- a/t/helper/test-dump-untracked-cache.c
+++ b/t/helper/test-dump-untracked-cache.c
@@ -18,10 +18,8 @@ static int compare_dir(const void *a_, const void *b_)
static void dump(struct untracked_cache_dir *ucd, struct strbuf *base)
{
int i, len;
- qsort(ucd->untracked, ucd->untracked_nr, sizeof(*ucd->untracked),
- compare_untracked);
- qsort(ucd->dirs, ucd->dirs_nr, sizeof(*ucd->dirs),
- compare_dir);
+ QSORT(ucd->untracked, ucd->untracked_nr, compare_untracked);
+ QSORT(ucd->dirs, ucd->dirs_nr, compare_dir);
len = base->len;
strbuf_addf(base, "%s/", ucd->name);
printf("%s %s", base->buf,
diff --git a/t/helper/test-sha1-array.c b/t/helper/test-sha1-array.c
index 09f7790971..f7a53c4ad6 100644
--- a/t/helper/test-sha1-array.c
+++ b/t/helper/test-sha1-array.c
@@ -1,9 +1,10 @@
#include "cache.h"
#include "sha1-array.h"
-static void print_sha1(const unsigned char sha1[20], void *data)
+static int print_sha1(const unsigned char sha1[20], void *data)
{
puts(sha1_to_hex(sha1));
+ return 0;
}
int cmd_main(int argc, const char **argv)
diff --git a/t/perf/p0003-delta-base-cache.sh b/t/perf/p0003-delta-base-cache.sh
new file mode 100755
index 0000000000..62369eaaf0
--- /dev/null
+++ b/t/perf/p0003-delta-base-cache.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+test_description='Test operations that emphasize the delta base cache.
+
+We look at both "log --raw", which should put only trees into the delta cache,
+and "log -Sfoo --raw", which should look at both trees and blobs.
+
+Any effects will be emphasized if the test repository is fully packed (loose
+objects obviously do not use the delta base cache at all). It is also
+emphasized if the pack has long delta chains (e.g., as produced by "gc
+--aggressive"), though cache is still quite noticeable even with the default
+depth of 50.
+
+The setting of core.deltaBaseCacheLimit in the source repository is also
+relevant (depending on the size of your test repo), so be sure it is consistent
+between runs.
+'
+. ./perf-lib.sh
+
+test_perf_large_repo
+
+# puts mostly trees into the delta base cache
+test_perf 'log --raw' '
+ git log --raw >/dev/null
+'
+
+test_perf 'log -S' '
+ git log --raw -Sfoo >/dev/null
+'
+
+test_done
diff --git a/t/perf/p5310-pack-bitmaps.sh b/t/perf/p5310-pack-bitmaps.sh
index de2a224a36..bb91dbb173 100755
--- a/t/perf/p5310-pack-bitmaps.sh
+++ b/t/perf/p5310-pack-bitmaps.sh
@@ -32,6 +32,14 @@ test_perf 'simulated fetch' '
} | git pack-objects --revs --stdout >/dev/null
'
+test_perf 'pack to file' '
+ git pack-objects --all pack1 </dev/null >/dev/null
+'
+
+test_perf 'pack to file (bitmap)' '
+ git pack-objects --use-bitmap-index --all pack1b </dev/null >/dev/null
+'
+
test_expect_success 'create partial bitmap state' '
# pick a commit to represent the repo tip in the past
cutoff=$(git rev-list HEAD~100 -1) &&
@@ -53,8 +61,12 @@ test_expect_success 'create partial bitmap state' '
git update-ref HEAD $orig_tip
'
-test_perf 'partial bitmap' '
+test_perf 'clone (partial bitmap)' '
git pack-objects --stdout --all </dev/null >/dev/null
'
+test_perf 'pack to file (partial bitmap)' '
+ git pack-objects --use-bitmap-index --all pack2b </dev/null >/dev/null
+'
+
test_done
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index a6fdd5ef3a..b8fc588b19 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -384,4 +384,30 @@ test_expect_success MINGW 'bare git dir not hidden' '
! is_hidden newdir
'
+test_expect_success 'remote init from does not use config from cwd' '
+ rm -rf newdir &&
+ test_config core.logallrefupdates true &&
+ git init newdir &&
+ echo true >expect &&
+ git -C newdir config --bool core.logallrefupdates >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 're-init from a linked worktree' '
+ git init main-worktree &&
+ (
+ cd main-worktree &&
+ test_commit first &&
+ git worktree add ../linked-worktree &&
+ mv .git/info/exclude expected-exclude &&
+ cp .git/config expected-config &&
+ find .git/worktrees -print | sort >expected &&
+ git -C ../linked-worktree init &&
+ test_cmp expected-exclude .git/info/exclude &&
+ test_cmp expected-config .git/config &&
+ find .git/worktrees -print | sort >actual &&
+ test_cmp expected actual
+ )
+'
+
test_done
diff --git a/t/t0012-help.sh b/t/t0012-help.sh
new file mode 100755
index 0000000000..8faba2e8bc
--- /dev/null
+++ b/t/t0012-help.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+test_description='help'
+
+. ./test-lib.sh
+
+configure_help () {
+ test_config help.format html &&
+
+ # Unless the path has "://" in it, Git tries to make sure
+ # the documentation directory locally exists. Avoid it as
+ # we are only interested in seeing an attempt to correctly
+ # invoke a help browser in this test.
+ test_config help.htmlpath test://html &&
+
+ # Name a custom browser
+ test_config browser.test.cmd ./test-browser &&
+ test_config help.browser test
+}
+
+test_expect_success "setup" '
+ # Just write out which page gets requested
+ write_script test-browser <<-\EOF
+ echo "$*" >test-browser.log
+ EOF
+'
+
+test_expect_success "works for commands and guides by default" '
+ configure_help &&
+ git help status &&
+ echo "test://html/git-status.html" >expect &&
+ test_cmp expect test-browser.log &&
+ git help revisions &&
+ echo "test://html/gitrevisions.html" >expect &&
+ test_cmp expect test-browser.log
+'
+
+test_expect_success "--exclude-guides does not work for guides" '
+ >test-browser.log &&
+ test_must_fail git help --exclude-guides revisions &&
+ test_must_be_empty test-browser.log
+'
+
+test_expect_success "--help does not work for guides" "
+ cat <<-EOF >expect &&
+ git: 'revisions' is not a git command. See 'git --help'.
+ EOF
+ test_must_fail git revisions --help 2>actual &&
+ test_i18ncmp expect actual
+"
+
+test_done
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index 7d2baa15bb..c5245c5cb4 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -101,7 +101,7 @@ test_expect_success 'git hash-object --stdin file1 <file0 first operates on file
test "$obname1" = "$obname1new"
'
-test_expect_success 'check that appropriate filter is invoke when --path is used' '
+test_expect_success 'set up crlf tests' '
echo fooQ | tr Q "\\015" >file0 &&
cp file0 file1 &&
echo "file0 -crlf" >.gitattributes &&
@@ -109,7 +109,10 @@ test_expect_success 'check that appropriate filter is invoke when --path is used
git config core.autocrlf true &&
file0_sha=$(git hash-object file0) &&
file1_sha=$(git hash-object file1) &&
- test "$file0_sha" != "$file1_sha" &&
+ test "$file0_sha" != "$file1_sha"
+'
+
+test_expect_success 'check that appropriate filter is invoke when --path is used' '
path1_sha=$(git hash-object --path=file1 file0) &&
path0_sha=$(git hash-object --path=file0 file1) &&
test "$file0_sha" = "$path0_sha" &&
@@ -117,38 +120,30 @@ test_expect_success 'check that appropriate filter is invoke when --path is used
path1_sha=$(cat file0 | git hash-object --path=file1 --stdin) &&
path0_sha=$(cat file1 | git hash-object --path=file0 --stdin) &&
test "$file0_sha" = "$path0_sha" &&
- test "$file1_sha" = "$path1_sha" &&
- git config --unset core.autocrlf
+ test "$file1_sha" = "$path1_sha"
+'
+
+test_expect_success 'gitattributes also work in a subdirectory' '
+ mkdir subdir &&
+ (
+ cd subdir &&
+ subdir_sha0=$(git hash-object ../file0) &&
+ subdir_sha1=$(git hash-object ../file1) &&
+ test "$file0_sha" = "$subdir_sha0" &&
+ test "$file1_sha" = "$subdir_sha1"
+ )
'
test_expect_success 'check that --no-filters option works' '
- echo fooQ | tr Q "\\015" >file0 &&
- cp file0 file1 &&
- echo "file0 -crlf" >.gitattributes &&
- echo "file1 crlf" >>.gitattributes &&
- git config core.autocrlf true &&
- file0_sha=$(git hash-object file0) &&
- file1_sha=$(git hash-object file1) &&
- test "$file0_sha" != "$file1_sha" &&
nofilters_file1=$(git hash-object --no-filters file1) &&
test "$file0_sha" = "$nofilters_file1" &&
nofilters_file1=$(cat file1 | git hash-object --stdin) &&
- test "$file0_sha" = "$nofilters_file1" &&
- git config --unset core.autocrlf
+ test "$file0_sha" = "$nofilters_file1"
'
test_expect_success 'check that --no-filters option works with --stdin-paths' '
- echo fooQ | tr Q "\\015" >file0 &&
- cp file0 file1 &&
- echo "file0 -crlf" >.gitattributes &&
- echo "file1 crlf" >>.gitattributes &&
- git config core.autocrlf true &&
- file0_sha=$(git hash-object file0) &&
- file1_sha=$(git hash-object file1) &&
- test "$file0_sha" != "$file1_sha" &&
nofilters_file1=$(echo "file1" | git hash-object --stdin-paths --no-filters) &&
- test "$file0_sha" = "$nofilters_file1" &&
- git config --unset core.autocrlf
+ test "$file0_sha" = "$nofilters_file1"
'
pop_repo
@@ -188,9 +183,30 @@ for args in "-w --stdin-paths" "--stdin-paths -w"; do
pop_repo
done
-test_expect_success 'corrupt tree' '
+test_expect_success 'too-short tree' '
echo abc >malformed-tree &&
- test_must_fail git hash-object -t tree malformed-tree
+ test_must_fail git hash-object -t tree malformed-tree 2>err &&
+ test_i18ngrep "too-short tree object" err
+'
+
+hex2oct() {
+ perl -ne 'printf "\\%03o", hex for /../g'
+}
+
+test_expect_success 'malformed mode in tree' '
+ hex_sha1=$(echo foo | git hash-object --stdin -w) &&
+ bin_sha1=$(echo $hex_sha1 | hex2oct) &&
+ printf "9100644 \0$bin_sha1" >tree-with-malformed-mode &&
+ test_must_fail git hash-object -t tree tree-with-malformed-mode 2>err &&
+ test_i18ngrep "malformed mode in tree entry" err
+'
+
+test_expect_success 'empty filename in tree' '
+ hex_sha1=$(echo foo | git hash-object --stdin -w) &&
+ bin_sha1=$(echo $hex_sha1 | hex2oct) &&
+ printf "100644 \0$bin_sha1" >tree-with-empty-filename &&
+ test_must_fail git hash-object -t tree tree-with-empty-filename 2>err &&
+ test_i18ngrep "empty filename in tree entry" err
'
test_expect_success 'corrupt commit' '
diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index ac10875408..1312004f8c 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -172,4 +172,45 @@ test_expect_success POSIXPERM 'forced modes' '
}" actual)"
'
+test_expect_success POSIXPERM 'remote init does not use config from cwd' '
+ git config core.sharedrepository 0666 &&
+ umask 0022 &&
+ git init --bare child.git &&
+ echo "-rw-r--r--" >expect &&
+ modebits child.git/config >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success POSIXPERM 're-init respects core.sharedrepository (local)' '
+ git config core.sharedrepository 0666 &&
+ umask 0022 &&
+ echo whatever >templates/foo &&
+ git init --template=templates &&
+ echo "-rw-rw-rw-" >expect &&
+ modebits .git/foo >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success POSIXPERM 're-init respects core.sharedrepository (remote)' '
+ rm -rf child.git &&
+ umask 0022 &&
+ git init --bare --shared=0666 child.git &&
+ test_path_is_missing child.git/foo &&
+ git init --bare --template=../templates child.git &&
+ echo "-rw-rw-rw-" >expect &&
+ modebits child.git/foo >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success POSIXPERM 'template can set core.sharedrepository' '
+ rm -rf child.git &&
+ umask 0022 &&
+ git config core.sharedrepository 0666 &&
+ cp .git/config templates/config &&
+ git init --bare --template=../templates child.git &&
+ echo "-rw-rw-rw-" >expect &&
+ modebits child.git/HEAD >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh
index 9bcd34969f..ce4cff13bb 100755
--- a/t/t1302-repo-version.sh
+++ b/t/t1302-repo-version.sh
@@ -25,46 +25,26 @@ test_expect_success 'setup' '
test_expect_success 'gitdir selection on normal repos' '
echo 0 >expect &&
git config core.repositoryformatversion >actual &&
- (
- cd test &&
- git config core.repositoryformatversion >../actual2
- ) &&
+ git -C test config core.repositoryformatversion >actual2 &&
test_cmp expect actual &&
test_cmp expect actual2
'
test_expect_success 'gitdir selection on unsupported repo' '
# Make sure it would stop at test2, not trash
- echo 99 >expect &&
- (
- cd test2 &&
- git config core.repositoryformatversion >../actual
- ) &&
- test_cmp expect actual
+ test_expect_code 1 git -C test2 config core.repositoryformatversion >actual
'
test_expect_success 'gitdir not required mode' '
git apply --stat test.patch &&
- (
- cd test &&
- git apply --stat ../test.patch
- ) &&
- (
- cd test2 &&
- git apply --stat ../test.patch
- )
+ git -C test apply --stat ../test.patch &&
+ git -C test2 apply --stat ../test.patch
'
test_expect_success 'gitdir required mode' '
git apply --check --index test.patch &&
- (
- cd test &&
- git apply --check --index ../test.patch
- ) &&
- (
- cd test2 &&
- test_must_fail git apply --check --index ../test.patch
- )
+ git -C test apply --check --index ../test.patch &&
+ test_must_fail git -C test2 apply --check --index ../test.patch
'
check_allow () {
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 8f52da2771..ee7d4736db 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -188,8 +188,7 @@ test_expect_success 'commit with NUL in header' '
grep "error in commit $new.*unterminated header: NUL at offset" out
'
-test_expect_success 'malformatted tree object' '
- test_when_finished "git update-ref -d refs/tags/wrong" &&
+test_expect_success 'tree object with duplicate entries' '
test_when_finished "remove_object \$T" &&
T=$(
GIT_INDEX_FILE=test-index &&
@@ -208,6 +207,19 @@ test_expect_success 'malformatted tree object' '
grep "error in tree .*contains duplicate file entries" out
'
+test_expect_success 'unparseable tree object' '
+ test_when_finished "git update-ref -d refs/heads/wrong" &&
+ test_when_finished "remove_object \$tree_sha1" &&
+ test_when_finished "remove_object \$commit_sha1" &&
+ tree_sha1=$(printf "100644 \0twenty-bytes-of-junk" | git hash-object -t tree --stdin -w --literally) &&
+ commit_sha1=$(git commit-tree $tree_sha1) &&
+ git update-ref refs/heads/wrong $commit_sha1 &&
+ test_must_fail git fsck 2>out &&
+ test_i18ngrep "error: empty filename in tree entry" out &&
+ test_i18ngrep "$tree_sha1" out &&
+ test_i18ngrep ! "fatal: empty filename in tree entry" out
+'
+
test_expect_success 'tag pointing to nonexistent' '
cat >invalid-tag <<-\EOF &&
object ffffffffffffffffffffffffffffffffffffffff
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index e221167cfb..7c659eb585 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -264,6 +264,13 @@ test_expect_success 'ambiguous commit-ish' '
test_must_fail git log 000000000...
'
+# There are three objects with this prefix: a blob, a tree, and a tag. We know
+# the blob will not pass as a treeish, but the tree and tag should (and thus
+# cause an error).
+test_expect_success 'ambiguous tags peel to treeish' '
+ test_must_fail git rev-parse 0000000000f^{tree}
+'
+
test_expect_success 'rev-parse --disambiguate' '
# The test creates 16 objects that share the prefix and two
# commits created by commit-tree in earlier tests share a
@@ -273,6 +280,13 @@ test_expect_success 'rev-parse --disambiguate' '
test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
'
+test_expect_success 'rev-parse --disambiguate drops duplicates' '
+ git rev-parse --disambiguate=000000000 >expect &&
+ git pack-objects .git/objects/pack/pack <expect &&
+ git rev-parse --disambiguate=000000000 >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'ambiguous 40-hex ref' '
TREE=$(git mktree </dev/null) &&
REF=$(git rev-parse HEAD) &&
@@ -291,4 +305,60 @@ test_expect_success 'ambiguous short sha1 ref' '
grep "refname.*${REF}.*ambiguous" err
'
+test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (raw)' '
+ test_must_fail git rev-parse 00000 2>stderr &&
+ grep "is ambiguous" stderr >errors &&
+ test_line_count = 1 errors
+'
+
+test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (treeish)' '
+ test_must_fail git rev-parse 00000:foo 2>stderr &&
+ grep "is ambiguous" stderr >errors &&
+ test_line_count = 1 errors
+'
+
+test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (peel)' '
+ test_must_fail git rev-parse 00000^{commit} 2>stderr &&
+ grep "is ambiguous" stderr >errors &&
+ test_line_count = 1 errors
+'
+
+test_expect_success C_LOCALE_OUTPUT 'ambiguity hints' '
+ test_must_fail git rev-parse 000000000 2>stderr &&
+ grep ^hint: stderr >hints &&
+ # 16 candidates, plus one intro line
+ test_line_count = 17 hints
+'
+
+test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '
+ test_must_fail git rev-parse 000000000^{commit} 2>stderr &&
+ grep ^hint: stderr >hints &&
+ # 5 commits, 1 tag (which is a commitish), plus intro line
+ test_line_count = 7 hints
+'
+
+test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '
+ # these two blobs share the same prefix "ee3d", but neither
+ # will pass for a commit
+ echo 851 | git hash-object --stdin -w &&
+ echo 872 | git hash-object --stdin -w &&
+ test_must_fail git rev-parse ee3d^{commit} 2>stderr &&
+ grep ^hint: stderr >hints &&
+ test_line_count = 3 hints
+'
+
+test_expect_success 'core.disambiguate config can prefer types' '
+ # ambiguous between tree and tag
+ sha1=0000000000f &&
+ test_must_fail git rev-parse $sha1 &&
+ git rev-parse $sha1^{commit} &&
+ git -c core.disambiguate=committish rev-parse $sha1
+'
+
+test_expect_success 'core.disambiguate does not override context' '
+ # treeish ambiguous between tag and tree
+ test_must_fail \
+ git -c core.disambiguate=committish rev-parse $sha1^{tree}
+'
+
test_done
diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh
index 6967436327..baef2d6924 100755
--- a/t/t3310-notes-merge-manual-resolve.sh
+++ b/t/t3310-notes-merge-manual-resolve.sh
@@ -225,7 +225,7 @@ test_expect_success 'cannot do merge w/conflicts when previous merge is unfinish
test -d .git/NOTES_MERGE_WORKTREE &&
test_must_fail git notes merge z >output 2>&1 &&
# Output should indicate what is wrong
- grep -q "\\.git/NOTES_MERGE_\\* exists" output
+ test_i18ngrep -q "\\.git/NOTES_MERGE_\\* exists" output
'
# Setup non-conflicting merge between x and new notes ref w
diff --git a/t/t3320-notes-merge-worktrees.sh b/t/t3320-notes-merge-worktrees.sh
index 6e0511596b..b9c3bc2487 100755
--- a/t/t3320-notes-merge-worktrees.sh
+++ b/t/t3320-notes-merge-worktrees.sh
@@ -52,7 +52,7 @@ test_expect_success 'merge z into y while mid-merge in another workdir fails' '
cd worktree &&
git config core.notesRef refs/notes/y &&
test_must_fail git notes merge z 2>err &&
- test_i18ngrep "A notes merge into refs/notes/y is already in-progress at" err
+ test_i18ngrep "a notes merge into refs/notes/y is already in-progress at" err
) &&
test_path_is_missing .git/worktrees/worktree/NOTES_MERGE_REF
'
diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh
index 4bf1dbe9c9..3b94283e35 100755
--- a/t/t3900-i18n-commit.sh
+++ b/t/t3900-i18n-commit.sh
@@ -45,7 +45,7 @@ test_expect_success 'UTF-8 invalid characters refused' '
printf "Commit message\n\nInvalid surrogate:\355\240\200\n" \
>"$HOME/invalid" &&
git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
- grep "did not conform" "$HOME"/stderr
+ test_i18ngrep "did not conform" "$HOME"/stderr
'
test_expect_success 'UTF-8 overlong sequences rejected' '
@@ -55,7 +55,7 @@ test_expect_success 'UTF-8 overlong sequences rejected' '
printf "\340\202\251ommit message\n\nThis is not a space:\300\240\n" \
>"$HOME/invalid" &&
git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
- grep "did not conform" "$HOME"/stderr
+ test_i18ngrep "did not conform" "$HOME"/stderr
'
test_expect_success 'UTF-8 non-characters refused' '
@@ -64,7 +64,7 @@ test_expect_success 'UTF-8 non-characters refused' '
printf "Commit message\n\nNon-character:\364\217\277\276\n" \
>"$HOME/invalid" &&
git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
- grep "did not conform" "$HOME"/stderr
+ test_i18ngrep "did not conform" "$HOME"/stderr
'
test_expect_success 'UTF-8 non-characters refused' '
@@ -73,7 +73,7 @@ test_expect_success 'UTF-8 non-characters refused' '
printf "Commit message\n\nNon-character:\357\267\220\n" \
>"$HOME/invalid" &&
git commit -a -F "$HOME/invalid" 2>"$HOME"/stderr &&
- grep "did not conform" "$HOME"/stderr
+ test_i18ngrep "did not conform" "$HOME"/stderr
'
for H in ISO8859-1 eucJP ISO-2022-JP
diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 509084e1a7..f663d567c8 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -295,7 +295,7 @@ test_expect_success 'am --no-utf8 (U/L)' '
# commit-tree will warn that the commit message does not contain valid UTF-8
# as mailinfo did not convert it
- grep "did not conform" err &&
+ test_i18ngrep "did not conform" err &&
check_encoding 2
'
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index 643d729157..0a8af76aab 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -68,7 +68,7 @@ test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
sed -e "s/-CIT/xCIT/" <output >broken &&
test_must_fail git apply --stat --summary broken 2>detected &&
detected=$(cat detected) &&
- detected=$(expr "$detected" : "fatal.*at line \\([0-9]*\\)\$") &&
+ detected=$(expr "$detected" : "error.*at line \\([0-9]*\\)\$") &&
detected=$(sed -ne "${detected}p" broken) &&
test "$detected" = xCIT
'
@@ -77,7 +77,7 @@ test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
git diff --binary | sed -e "s/-CIT/xCIT/" >broken &&
test_must_fail git apply --stat --summary broken 2>detected &&
detected=$(cat detected) &&
- detected=$(expr "$detected" : "fatal.*at line \\([0-9]*\\)\$") &&
+ detected=$(expr "$detected" : "error.*at line \\([0-9]*\\)\$") &&
detected=$(sed -ne "${detected}p" broken) &&
test "$detected" = xCIT
'
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 94ef5000e7..566817e2ef 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -306,6 +306,8 @@ diff --no-index --name-status dir2 dir
diff --no-index --name-status -- dir2 dir
diff --no-index dir dir3
diff master master^ side
+# Can't use spaces...
+diff --line-prefix=abc master master^ side
diff --dirstat master~1 master~2
diff --dirstat initial rearrange
diff --dirstat-by-file initial rearrange
@@ -325,6 +327,10 @@ test_expect_success 'diff --cached -- file on unborn branch' '
git diff --cached -- file0 >result &&
test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--cached_--_file0" result
'
+test_expect_success 'diff --line-prefix with spaces' '
+ git diff --line-prefix="| | | " --cached -- file0 >result &&
+ test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--line-prefix_--cached_--_file0" result
+'
test_expect_success 'diff-tree --stdin with log formatting' '
cat >expect <<-\EOF &&
diff --git a/t/t4013/diff.diff_--line-prefix=abc_master_master^_side b/t/t4013/diff.diff_--line-prefix=abc_master_master^_side
new file mode 100644
index 0000000000..99f91e7f0e
--- /dev/null
+++ b/t/t4013/diff.diff_--line-prefix=abc_master_master^_side
@@ -0,0 +1,29 @@
+$ git diff --line-prefix=abc master master^ side
+abcdiff --cc dir/sub
+abcindex cead32e,7289e35..992913c
+abc--- a/dir/sub
+abc+++ b/dir/sub
+abc@@@ -1,6 -1,4 +1,8 @@@
+abc A
+abc B
+abc +C
+abc +D
+abc +E
+abc +F
+abc+ 1
+abc+ 2
+abcdiff --cc file0
+abcindex b414108,f4615da..10a8a9f
+abc--- a/file0
+abc+++ b/file0
+abc@@@ -1,6 -1,6 +1,9 @@@
+abc 1
+abc 2
+abc 3
+abc +4
+abc +5
+abc +6
+abc+ A
+abc+ B
+abc+ C
+$
diff --git a/t/t4013/diff.diff_--line-prefix_--cached_--_file0 b/t/t4013/diff.diff_--line-prefix_--cached_--_file0
new file mode 100644
index 0000000000..f41ba4d36a
--- /dev/null
+++ b/t/t4013/diff.diff_--line-prefix_--cached_--_file0
@@ -0,0 +1,15 @@
+| | | diff --git a/file0 b/file0
+| | | new file mode 100644
+| | | index 0000000..10a8a9f
+| | | --- /dev/null
+| | | +++ b/file0
+| | | @@ -0,0 +1,9 @@
+| | | +1
+| | | +2
+| | | +3
+| | | +4
+| | | +5
+| | | +6
+| | | +A
+| | | +B
+| | | +C
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 8d90a6e500..ba4902df2b 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -1086,6 +1086,15 @@ test_expect_success 'empty subject prefix does not have extra space' '
test_cmp expect actual
'
+test_expect_success '--rfc' '
+ cat >expect <<-\EOF &&
+ Subject: [RFC PATCH 1/1] header with . in it
+ EOF
+ git format-patch -n -1 --stdout --rfc >patch &&
+ grep ^Subject: patch >actual &&
+ test_cmp expect actual
+'
+
test_expect_success '--from=ident notices bogus ident' '
test_must_fail git format-patch -1 --stdout --from=foo >patch
'
diff --git a/t/t4021-format-patch-numbered.sh b/t/t4021-format-patch-numbered.sh
index 886494b58f..9be65fd444 100755
--- a/t/t4021-format-patch-numbered.sh
+++ b/t/t4021-format-patch-numbered.sh
@@ -36,6 +36,11 @@ test_no_numbered() {
test_num_no_numbered $1 2
}
+test_single_cover_letter_numbered() {
+ grep "^Subject: \[PATCH 0/1\]" $1 &&
+ grep "^Subject: \[PATCH 1/1\]" $1
+}
+
test_single_numbered() {
grep "^Subject: \[PATCH 1/1\]" $1
}
@@ -121,4 +126,16 @@ test_expect_success '--start-number && --numbered' '
grep "^Subject: \[PATCH 3/3\]" patch8
'
+test_expect_success 'single patch with cover-letter defaults to numbers' '
+ git format-patch --cover-letter --stdout HEAD~1 >patch9.single &&
+ test_single_cover_letter_numbered patch9.single
+'
+
+test_expect_success 'Use --no-numbered and --cover-letter single patch' '
+ git format-patch --no-numbered --stdout --cover-letter HEAD~1 >patch10 &&
+ test_no_numbered patch10
+'
+
+
+
test_done
diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 6eb83211b5..453e6c35eb 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -89,4 +89,42 @@ test_expect_success 'turning a file into a directory' '
)
'
+test_expect_success 'diff from repo subdir shows real paths (explicit)' '
+ echo "diff --git a/../../non/git/a b/../../non/git/b" >expect &&
+ test_expect_code 1 \
+ git -C repo/sub \
+ diff --no-index ../../non/git/a ../../non/git/b >actual &&
+ head -n 1 <actual >actual.head &&
+ test_cmp expect actual.head
+'
+
+test_expect_success 'diff from repo subdir shows real paths (implicit)' '
+ echo "diff --git a/../../non/git/a b/../../non/git/b" >expect &&
+ test_expect_code 1 \
+ git -C repo/sub \
+ diff ../../non/git/a ../../non/git/b >actual &&
+ head -n 1 <actual >actual.head &&
+ test_cmp expect actual.head
+'
+
+test_expect_success 'diff --no-index from repo subdir respects config (explicit)' '
+ echo "diff --git ../../non/git/a ../../non/git/b" >expect &&
+ test_config -C repo diff.noprefix true &&
+ test_expect_code 1 \
+ git -C repo/sub \
+ diff --no-index ../../non/git/a ../../non/git/b >actual &&
+ head -n 1 <actual >actual.head &&
+ test_cmp expect actual.head
+'
+
+test_expect_success 'diff --no-index from repo subdir respects config (implicit)' '
+ echo "diff --git ../../non/git/a ../../non/git/b" >expect &&
+ test_config -C repo diff.noprefix true &&
+ test_expect_code 1 \
+ git -C repo/sub \
+ diff ../../non/git/a ../../non/git/b >actual &&
+ head -n 1 <actual >actual.head &&
+ test_cmp expect actual.head
+'
+
test_done
diff --git a/t/t4059-diff-submodule-not-initialized.sh b/t/t4059-diff-submodule-not-initialized.sh
new file mode 100755
index 0000000000..cd70fd5192
--- /dev/null
+++ b/t/t4059-diff-submodule-not-initialized.sh
@@ -0,0 +1,127 @@
+#!/bin/sh
+#
+# Copyright (c) 2016 Jacob Keller, based on t4041 by Jens Lehmann
+#
+
+test_description='Test for submodule diff on non-checked out submodule
+
+This test tries to verify that add_submodule_odb works when the submodule was
+initialized previously but the checkout has since been removed.
+'
+
+. ./test-lib.sh
+
+# Tested non-UTF-8 encoding
+test_encoding="ISO8859-1"
+
+# String "added" in German (translated with Google Translate), encoded in UTF-8,
+# used in sample commit log messages in add_file() function below.
+added=$(printf "hinzugef\303\274gt")
+
+add_file () {
+ (
+ cd "$1" &&
+ shift &&
+ for name
+ do
+ echo "$name" >"$name" &&
+ git add "$name" &&
+ test_tick &&
+ # "git commit -m" would break MinGW, as Windows refuse to pass
+ # $test_encoding encoded parameter to git.
+ echo "Add $name ($added $name)" | iconv -f utf-8 -t $test_encoding |
+ git -c "i18n.commitEncoding=$test_encoding" commit -F -
+ done >/dev/null &&
+ git rev-parse --short --verify HEAD
+ )
+}
+
+commit_file () {
+ test_tick &&
+ git commit "$@" -m "Commit $*" >/dev/null
+}
+
+test_expect_success 'setup - submodules' '
+ test_create_repo sm2 &&
+ add_file . foo &&
+ add_file sm2 foo1 foo2 &&
+ smhead1=$(git -C sm2 rev-parse --short --verify HEAD)
+'
+
+test_expect_success 'setup - git submodule add' '
+ git submodule add ./sm2 sm1 &&
+ commit_file sm1 .gitmodules &&
+ git diff-tree -p --no-commit-id --submodule=log HEAD -- sm1 >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 0000000...$smhead1 (new submodule)
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'submodule directory removed' '
+ rm -rf sm1 &&
+ git diff-tree -p --no-commit-id --submodule=log HEAD -- sm1 >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 0000000...$smhead1 (new submodule)
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'setup - submodule multiple commits' '
+ git submodule update --checkout sm1 &&
+ smhead2=$(add_file sm1 foo3 foo4) &&
+ commit_file sm1 &&
+ git diff-tree -p --no-commit-id --submodule=log HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $smhead1..$smhead2:
+ > Add foo4 ($added foo4)
+ > Add foo3 ($added foo3)
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'submodule removed multiple commits' '
+ rm -rf sm1 &&
+ git diff-tree -p --no-commit-id --submodule=log HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $smhead1..$smhead2:
+ > Add foo4 ($added foo4)
+ > Add foo3 ($added foo3)
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'submodule not initialized in new clone' '
+ git clone . sm3 &&
+ git -C sm3 diff-tree -p --no-commit-id --submodule=log HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $smhead1...$smhead2 (not initialized)
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'setup submodule moved' '
+ git submodule update --checkout sm1 &&
+ git mv sm1 sm4 &&
+ commit_file sm4 &&
+ git diff-tree -p --no-commit-id --submodule=log HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm4 0000000...$smhead2 (new submodule)
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'submodule moved then removed' '
+ smhead3=$(add_file sm4 foo6 foo7) &&
+ commit_file sm4 &&
+ rm -rf sm4 &&
+ git diff-tree -p --no-commit-id --submodule=log HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm4 $smhead2..$smhead3:
+ > Add foo7 ($added foo7)
+ > Add foo6 ($added foo6)
+ EOF
+ test_cmp expected actual
+'
+
+test_done
diff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh
new file mode 100755
index 0000000000..7e23b55ea4
--- /dev/null
+++ b/t/t4060-diff-submodule-option-diff-format.sh
@@ -0,0 +1,749 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Jens Lehmann, based on t7401 by Ping Yin
+# Copyright (c) 2011 Alexey Shumkin (+ non-UTF-8 commit encoding tests)
+# Copyright (c) 2016 Jacob Keller (copy + convert to --submodule=diff)
+#
+
+test_description='Support for diff format verbose submodule difference in git diff
+
+This test tries to verify the sanity of --submodule=diff option of git diff.
+'
+
+. ./test-lib.sh
+
+# Tested non-UTF-8 encoding
+test_encoding="ISO8859-1"
+
+# String "added" in German (translated with Google Translate), encoded in UTF-8,
+# used in sample commit log messages in add_file() function below.
+added=$(printf "hinzugef\303\274gt")
+
+add_file () {
+ (
+ cd "$1" &&
+ shift &&
+ for name
+ do
+ echo "$name" >"$name" &&
+ git add "$name" &&
+ test_tick &&
+ # "git commit -m" would break MinGW, as Windows refuse to pass
+ # $test_encoding encoded parameter to git.
+ echo "Add $name ($added $name)" | iconv -f utf-8 -t $test_encoding |
+ git -c "i18n.commitEncoding=$test_encoding" commit -F -
+ done >/dev/null &&
+ git rev-parse --short --verify HEAD
+ )
+}
+
+commit_file () {
+ test_tick &&
+ git commit "$@" -m "Commit $*" >/dev/null
+}
+
+test_expect_success 'setup repository' '
+ test_create_repo sm1 &&
+ add_file . foo &&
+ head1=$(add_file sm1 foo1 foo2) &&
+ fullhead1=$(git -C sm1 rev-parse --verify HEAD)
+'
+
+test_expect_success 'added submodule' '
+ git add sm1 &&
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 0000000...$head1 (new submodule)
+ diff --git a/sm1/foo1 b/sm1/foo1
+ new file mode 100644
+ index 0000000..1715acd
+ --- /dev/null
+ +++ b/sm1/foo1
+ @@ -0,0 +1 @@
+ +foo1
+ diff --git a/sm1/foo2 b/sm1/foo2
+ new file mode 100644
+ index 0000000..54b060e
+ --- /dev/null
+ +++ b/sm1/foo2
+ @@ -0,0 +1 @@
+ +foo2
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'added submodule, set diff.submodule' '
+ test_config diff.submodule log &&
+ git add sm1 &&
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 0000000...$head1 (new submodule)
+ diff --git a/sm1/foo1 b/sm1/foo1
+ new file mode 100644
+ index 0000000..1715acd
+ --- /dev/null
+ +++ b/sm1/foo1
+ @@ -0,0 +1 @@
+ +foo1
+ diff --git a/sm1/foo2 b/sm1/foo2
+ new file mode 100644
+ index 0000000..54b060e
+ --- /dev/null
+ +++ b/sm1/foo2
+ @@ -0,0 +1 @@
+ +foo2
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success '--submodule=short overrides diff.submodule' '
+ test_config diff.submodule log &&
+ git add sm1 &&
+ git diff --submodule=short --cached >actual &&
+ cat >expected <<-EOF &&
+ diff --git a/sm1 b/sm1
+ new file mode 160000
+ index 0000000..$head1
+ --- /dev/null
+ +++ b/sm1
+ @@ -0,0 +1 @@
+ +Subproject commit $fullhead1
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'diff.submodule does not affect plumbing' '
+ test_config diff.submodule log &&
+ git diff-index -p HEAD >actual &&
+ cat >expected <<-EOF &&
+ diff --git a/sm1 b/sm1
+ new file mode 160000
+ index 0000000..$head1
+ --- /dev/null
+ +++ b/sm1
+ @@ -0,0 +1 @@
+ +Subproject commit $fullhead1
+ EOF
+ test_cmp expected actual
+'
+
+commit_file sm1 &&
+head2=$(add_file sm1 foo3)
+
+test_expect_success 'modified submodule(forward)' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $head1..$head2:
+ diff --git a/sm1/foo3 b/sm1/foo3
+ new file mode 100644
+ index 0000000..c1ec6c6
+ --- /dev/null
+ +++ b/sm1/foo3
+ @@ -0,0 +1 @@
+ +foo3
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'modified submodule(forward)' '
+ git diff --submodule=diff >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $head1..$head2:
+ diff --git a/sm1/foo3 b/sm1/foo3
+ new file mode 100644
+ index 0000000..c1ec6c6
+ --- /dev/null
+ +++ b/sm1/foo3
+ @@ -0,0 +1 @@
+ +foo3
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'modified submodule(forward) --submodule' '
+ git diff --submodule >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $head1..$head2:
+ > Add foo3 ($added foo3)
+ EOF
+ test_cmp expected actual
+'
+
+fullhead2=$(cd sm1; git rev-parse --verify HEAD)
+test_expect_success 'modified submodule(forward) --submodule=short' '
+ git diff --submodule=short >actual &&
+ cat >expected <<-EOF &&
+ diff --git a/sm1 b/sm1
+ index $head1..$head2 160000
+ --- a/sm1
+ +++ b/sm1
+ @@ -1 +1 @@
+ -Subproject commit $fullhead1
+ +Subproject commit $fullhead2
+ EOF
+ test_cmp expected actual
+'
+
+commit_file sm1 &&
+head3=$(
+ cd sm1 &&
+ git reset --hard HEAD~2 >/dev/null &&
+ git rev-parse --short --verify HEAD
+)
+
+test_expect_success 'modified submodule(backward)' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $head2..$head3 (rewind):
+ diff --git a/sm1/foo2 b/sm1/foo2
+ deleted file mode 100644
+ index 54b060e..0000000
+ --- a/sm1/foo2
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo2
+ diff --git a/sm1/foo3 b/sm1/foo3
+ deleted file mode 100644
+ index c1ec6c6..0000000
+ --- a/sm1/foo3
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo3
+ EOF
+ test_cmp expected actual
+'
+
+head4=$(add_file sm1 foo4 foo5)
+test_expect_success 'modified submodule(backward and forward)' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $head2...$head4:
+ diff --git a/sm1/foo2 b/sm1/foo2
+ deleted file mode 100644
+ index 54b060e..0000000
+ --- a/sm1/foo2
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo2
+ diff --git a/sm1/foo3 b/sm1/foo3
+ deleted file mode 100644
+ index c1ec6c6..0000000
+ --- a/sm1/foo3
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo3
+ diff --git a/sm1/foo4 b/sm1/foo4
+ new file mode 100644
+ index 0000000..a0016db
+ --- /dev/null
+ +++ b/sm1/foo4
+ @@ -0,0 +1 @@
+ +foo4
+ diff --git a/sm1/foo5 b/sm1/foo5
+ new file mode 100644
+ index 0000000..d6f2413
+ --- /dev/null
+ +++ b/sm1/foo5
+ @@ -0,0 +1 @@
+ +foo5
+ EOF
+ test_cmp expected actual
+'
+
+commit_file sm1 &&
+mv sm1 sm1-bak &&
+echo sm1 >sm1 &&
+head5=$(git hash-object sm1 | cut -c1-7) &&
+git add sm1 &&
+rm -f sm1 &&
+mv sm1-bak sm1
+
+test_expect_success 'typechanged submodule(submodule->blob), --cached' '
+ git diff --submodule=diff --cached >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $head4...0000000 (submodule deleted)
+ diff --git a/sm1/foo1 b/sm1/foo1
+ deleted file mode 100644
+ index 1715acd..0000000
+ --- a/sm1/foo1
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo1
+ diff --git a/sm1/foo4 b/sm1/foo4
+ deleted file mode 100644
+ index a0016db..0000000
+ --- a/sm1/foo4
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo4
+ diff --git a/sm1/foo5 b/sm1/foo5
+ deleted file mode 100644
+ index d6f2413..0000000
+ --- a/sm1/foo5
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -foo5
+ diff --git a/sm1 b/sm1
+ new file mode 100644
+ index 0000000..9da5fb8
+ --- /dev/null
+ +++ b/sm1
+ @@ -0,0 +1 @@
+ +sm1
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'typechanged submodule(submodule->blob)' '
+ git diff --submodule=diff >actual &&
+ cat >expected <<-EOF &&
+ diff --git a/sm1 b/sm1
+ deleted file mode 100644
+ index 9da5fb8..0000000
+ --- a/sm1
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -sm1
+ Submodule sm1 0000000...$head4 (new submodule)
+ diff --git a/sm1/foo1 b/sm1/foo1
+ new file mode 100644
+ index 0000000..1715acd
+ --- /dev/null
+ +++ b/sm1/foo1
+ @@ -0,0 +1 @@
+ +foo1
+ diff --git a/sm1/foo4 b/sm1/foo4
+ new file mode 100644
+ index 0000000..a0016db
+ --- /dev/null
+ +++ b/sm1/foo4
+ @@ -0,0 +1 @@
+ +foo4
+ diff --git a/sm1/foo5 b/sm1/foo5
+ new file mode 100644
+ index 0000000..d6f2413
+ --- /dev/null
+ +++ b/sm1/foo5
+ @@ -0,0 +1 @@
+ +foo5
+ EOF
+ test_cmp expected actual
+'
+
+rm -rf sm1 &&
+git checkout-index sm1
+test_expect_success 'typechanged submodule(submodule->blob)' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $head4...0000000 (submodule deleted)
+ diff --git a/sm1 b/sm1
+ new file mode 100644
+ index 0000000..9da5fb8
+ --- /dev/null
+ +++ b/sm1
+ @@ -0,0 +1 @@
+ +sm1
+ EOF
+ test_cmp expected actual
+'
+
+rm -f sm1 &&
+test_create_repo sm1 &&
+head6=$(add_file sm1 foo6 foo7)
+fullhead6=$(cd sm1; git rev-parse --verify HEAD)
+test_expect_success 'nonexistent commit' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 $head4...$head6 (commits not present)
+ EOF
+ test_cmp expected actual
+'
+
+commit_file
+test_expect_success 'typechanged submodule(blob->submodule)' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ diff --git a/sm1 b/sm1
+ deleted file mode 100644
+ index 9da5fb8..0000000
+ --- a/sm1
+ +++ /dev/null
+ @@ -1 +0,0 @@
+ -sm1
+ Submodule sm1 0000000...$head6 (new submodule)
+ diff --git a/sm1/foo6 b/sm1/foo6
+ new file mode 100644
+ index 0000000..462398b
+ --- /dev/null
+ +++ b/sm1/foo6
+ @@ -0,0 +1 @@
+ +foo6
+ diff --git a/sm1/foo7 b/sm1/foo7
+ new file mode 100644
+ index 0000000..6e9262c
+ --- /dev/null
+ +++ b/sm1/foo7
+ @@ -0,0 +1 @@
+ +foo7
+ EOF
+ test_cmp expected actual
+'
+
+commit_file sm1 &&
+test_expect_success 'submodule is up to date' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'submodule contains untracked content' '
+ echo new > sm1/new-file &&
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 contains untracked content
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'submodule contains untracked content (untracked ignored)' '
+ git diff-index -p --ignore-submodules=untracked --submodule=diff HEAD >actual &&
+ ! test -s actual
+'
+
+test_expect_success 'submodule contains untracked content (dirty ignored)' '
+ git diff-index -p --ignore-submodules=dirty --submodule=diff HEAD >actual &&
+ ! test -s actual
+'
+
+test_expect_success 'submodule contains untracked content (all ignored)' '
+ git diff-index -p --ignore-submodules=all --submodule=diff HEAD >actual &&
+ ! test -s actual
+'
+
+test_expect_success 'submodule contains untracked and modified content' '
+ echo new > sm1/foo6 &&
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 contains untracked content
+ Submodule sm1 contains modified content
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..3e75765 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1 @@
+ -foo6
+ +new
+ EOF
+ test_cmp expected actual
+'
+
+# NOT OK
+test_expect_success 'submodule contains untracked and modified content (untracked ignored)' '
+ echo new > sm1/foo6 &&
+ git diff-index -p --ignore-submodules=untracked --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 contains modified content
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..3e75765 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1 @@
+ -foo6
+ +new
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'submodule contains untracked and modified content (dirty ignored)' '
+ echo new > sm1/foo6 &&
+ git diff-index -p --ignore-submodules=dirty --submodule=diff HEAD >actual &&
+ ! test -s actual
+'
+
+test_expect_success 'submodule contains untracked and modified content (all ignored)' '
+ echo new > sm1/foo6 &&
+ git diff-index -p --ignore-submodules --submodule=diff HEAD >actual &&
+ ! test -s actual
+'
+
+test_expect_success 'submodule contains modified content' '
+ rm -f sm1/new-file &&
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 contains modified content
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..3e75765 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1 @@
+ -foo6
+ +new
+ EOF
+ test_cmp expected actual
+'
+
+(cd sm1; git commit -mchange foo6 >/dev/null) &&
+head8=$(cd sm1; git rev-parse --short --verify HEAD) &&
+test_expect_success 'submodule is modified' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 17243c9..$head8:
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..3e75765 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1 @@
+ -foo6
+ +new
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'modified submodule contains untracked content' '
+ echo new > sm1/new-file &&
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 contains untracked content
+ Submodule sm1 17243c9..$head8:
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..3e75765 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1 @@
+ -foo6
+ +new
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'modified submodule contains untracked content (untracked ignored)' '
+ git diff-index -p --ignore-submodules=untracked --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 17243c9..$head8:
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..3e75765 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1 @@
+ -foo6
+ +new
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'modified submodule contains untracked content (dirty ignored)' '
+ git diff-index -p --ignore-submodules=dirty --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 17243c9..cfce562:
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..3e75765 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1 @@
+ -foo6
+ +new
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'modified submodule contains untracked content (all ignored)' '
+ git diff-index -p --ignore-submodules=all --submodule=diff HEAD >actual &&
+ ! test -s actual
+'
+
+test_expect_success 'modified submodule contains untracked and modified content' '
+ echo modification >> sm1/foo6 &&
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 contains untracked content
+ Submodule sm1 contains modified content
+ Submodule sm1 17243c9..cfce562:
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..dfda541 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1,2 @@
+ -foo6
+ +new
+ +modification
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'modified submodule contains untracked and modified content (untracked ignored)' '
+ echo modification >> sm1/foo6 &&
+ git diff-index -p --ignore-submodules=untracked --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 contains modified content
+ Submodule sm1 17243c9..cfce562:
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..e20e2d9 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1,3 @@
+ -foo6
+ +new
+ +modification
+ +modification
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'modified submodule contains untracked and modified content (dirty ignored)' '
+ echo modification >> sm1/foo6 &&
+ git diff-index -p --ignore-submodules=dirty --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 17243c9..cfce562:
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..3e75765 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1 @@
+ -foo6
+ +new
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'modified submodule contains untracked and modified content (all ignored)' '
+ echo modification >> sm1/foo6 &&
+ git diff-index -p --ignore-submodules --submodule=diff HEAD >actual &&
+ ! test -s actual
+'
+
+# NOT OK
+test_expect_success 'modified submodule contains modified content' '
+ rm -f sm1/new-file &&
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 contains modified content
+ Submodule sm1 17243c9..cfce562:
+ diff --git a/sm1/foo6 b/sm1/foo6
+ index 462398b..ac466ca 100644
+ --- a/sm1/foo6
+ +++ b/sm1/foo6
+ @@ -1 +1,5 @@
+ -foo6
+ +new
+ +modification
+ +modification
+ +modification
+ +modification
+ EOF
+ test_cmp expected actual
+'
+
+rm -rf sm1
+test_expect_success 'deleted submodule' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 17243c9...0000000 (submodule deleted)
+ EOF
+ test_cmp expected actual
+'
+
+test_create_repo sm2 &&
+head7=$(add_file sm2 foo8 foo9) &&
+git add sm2
+
+test_expect_success 'multiple submodules' '
+ git diff-index -p --submodule=diff HEAD >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 17243c9...0000000 (submodule deleted)
+ Submodule sm2 0000000...a5a65c9 (new submodule)
+ diff --git a/sm2/foo8 b/sm2/foo8
+ new file mode 100644
+ index 0000000..db9916b
+ --- /dev/null
+ +++ b/sm2/foo8
+ @@ -0,0 +1 @@
+ +foo8
+ diff --git a/sm2/foo9 b/sm2/foo9
+ new file mode 100644
+ index 0000000..9c3b4f6
+ --- /dev/null
+ +++ b/sm2/foo9
+ @@ -0,0 +1 @@
+ +foo9
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'path filter' '
+ git diff-index -p --submodule=diff HEAD sm2 >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm2 0000000...a5a65c9 (new submodule)
+ diff --git a/sm2/foo8 b/sm2/foo8
+ new file mode 100644
+ index 0000000..db9916b
+ --- /dev/null
+ +++ b/sm2/foo8
+ @@ -0,0 +1 @@
+ +foo8
+ diff --git a/sm2/foo9 b/sm2/foo9
+ new file mode 100644
+ index 0000000..9c3b4f6
+ --- /dev/null
+ +++ b/sm2/foo9
+ @@ -0,0 +1 @@
+ +foo9
+ EOF
+ test_cmp expected actual
+'
+
+commit_file sm2
+test_expect_success 'given commit' '
+ git diff-index -p --submodule=diff HEAD^ >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 17243c9...0000000 (submodule deleted)
+ Submodule sm2 0000000...a5a65c9 (new submodule)
+ diff --git a/sm2/foo8 b/sm2/foo8
+ new file mode 100644
+ index 0000000..db9916b
+ --- /dev/null
+ +++ b/sm2/foo8
+ @@ -0,0 +1 @@
+ +foo8
+ diff --git a/sm2/foo9 b/sm2/foo9
+ new file mode 100644
+ index 0000000..9c3b4f6
+ --- /dev/null
+ +++ b/sm2/foo9
+ @@ -0,0 +1 @@
+ +foo9
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'setup .git file for sm2' '
+ (cd sm2 &&
+ REAL="$(pwd)/../.real" &&
+ mv .git "$REAL"
+ echo "gitdir: $REAL" >.git)
+'
+
+test_expect_success 'diff --submodule=diff with .git file' '
+ git diff --submodule=diff HEAD^ >actual &&
+ cat >expected <<-EOF &&
+ Submodule sm1 17243c9...0000000 (submodule deleted)
+ Submodule sm2 0000000...a5a65c9 (new submodule)
+ diff --git a/sm2/foo8 b/sm2/foo8
+ new file mode 100644
+ index 0000000..db9916b
+ --- /dev/null
+ +++ b/sm2/foo8
+ @@ -0,0 +1 @@
+ +foo8
+ diff --git a/sm2/foo9 b/sm2/foo9
+ new file mode 100644
+ index 0000000..9c3b4f6
+ --- /dev/null
+ +++ b/sm2/foo9
+ @@ -0,0 +1 @@
+ +foo9
+ EOF
+ test_cmp expected actual
+'
+
+test_done
diff --git a/t/t4061-diff-indent.sh b/t/t4061-diff-indent.sh
new file mode 100755
index 0000000000..556450609b
--- /dev/null
+++ b/t/t4061-diff-indent.sh
@@ -0,0 +1,216 @@
+#!/bin/sh
+
+test_description='Test diff indent heuristic.
+
+'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/diff-lib.sh
+
+# Compare two diff outputs. Ignore "index" lines, because we don't
+# care about SHA-1s or file modes.
+compare_diff () {
+ sed -e "/^index /d" <"$1" >.tmp-1
+ sed -e "/^index /d" <"$2" >.tmp-2
+ test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
+}
+
+# Compare blame output using the expectation for a diff as reference.
+# Only look for the lines coming from non-boundary commits.
+compare_blame () {
+ sed -n -e "1,4d" -e "s/^\+//p" <"$1" >.tmp-1
+ sed -ne "s/^[^^][^)]*) *//p" <"$2" >.tmp-2
+ test_cmp .tmp-1 .tmp-2 && rm -f .tmp-1 .tmp-2
+}
+
+test_expect_success 'prepare' '
+ cat <<-\EOF >spaces.txt &&
+ 1
+ 2
+ a
+
+ b
+ 3
+ 4
+ EOF
+
+ cat <<-\EOF >functions.c &&
+ 1
+ 2
+ /* function */
+ foo() {
+ foo
+ }
+
+ 3
+ 4
+ EOF
+
+ git add spaces.txt functions.c &&
+ test_tick &&
+ git commit -m initial &&
+ git branch old &&
+
+ cat <<-\EOF >spaces.txt &&
+ 1
+ 2
+ a
+
+ b
+ a
+
+ b
+ 3
+ 4
+ EOF
+
+ cat <<-\EOF >functions.c &&
+ 1
+ 2
+ /* function */
+ bar() {
+ foo
+ }
+
+ /* function */
+ foo() {
+ foo
+ }
+
+ 3
+ 4
+ EOF
+
+ git add spaces.txt functions.c &&
+ test_tick &&
+ git commit -m initial &&
+ git branch new &&
+
+ tr "_" " " <<-\EOF >spaces-expect &&
+ diff --git a/spaces.txt b/spaces.txt
+ --- a/spaces.txt
+ +++ b/spaces.txt
+ @@ -3,5 +3,8 @@
+ a
+ _
+ b
+ +a
+ +
+ +b
+ 3
+ 4
+ EOF
+
+ tr "_" " " <<-\EOF >spaces-compacted-expect &&
+ diff --git a/spaces.txt b/spaces.txt
+ --- a/spaces.txt
+ +++ b/spaces.txt
+ @@ -2,6 +2,9 @@
+ 2
+ a
+ _
+ +b
+ +a
+ +
+ b
+ 3
+ 4
+ EOF
+
+ tr "_" " " <<-\EOF >functions-expect &&
+ diff --git a/functions.c b/functions.c
+ --- a/functions.c
+ +++ b/functions.c
+ @@ -1,6 +1,11 @@
+ 1
+ 2
+ /* function */
+ +bar() {
+ + foo
+ +}
+ +
+ +/* function */
+ foo() {
+ foo
+ }
+ EOF
+
+ tr "_" " " <<-\EOF >functions-compacted-expect
+ diff --git a/functions.c b/functions.c
+ --- a/functions.c
+ +++ b/functions.c
+ @@ -1,5 +1,10 @@
+ 1
+ 2
+ +/* function */
+ +bar() {
+ + foo
+ +}
+ +
+ /* function */
+ foo() {
+ foo
+ EOF
+'
+
+test_expect_success 'diff: ugly spaces' '
+ git diff old new -- spaces.txt >out &&
+ compare_diff spaces-expect out
+'
+
+test_expect_success 'diff: nice spaces with --indent-heuristic' '
+ git diff --indent-heuristic old new -- spaces.txt >out-compacted &&
+ compare_diff spaces-compacted-expect out-compacted
+'
+
+test_expect_success 'diff: nice spaces with diff.indentHeuristic' '
+ git -c diff.indentHeuristic=true diff old new -- spaces.txt >out-compacted2 &&
+ compare_diff spaces-compacted-expect out-compacted2
+'
+
+test_expect_success 'diff: --no-indent-heuristic overrides config' '
+ git -c diff.indentHeuristic=true diff --no-indent-heuristic old new -- spaces.txt >out2 &&
+ compare_diff spaces-expect out2
+'
+
+test_expect_success 'diff: --indent-heuristic with --patience' '
+ git diff --indent-heuristic --patience old new -- spaces.txt >out-compacted3 &&
+ compare_diff spaces-compacted-expect out-compacted3
+'
+
+test_expect_success 'diff: --indent-heuristic with --histogram' '
+ git diff --indent-heuristic --histogram old new -- spaces.txt >out-compacted4 &&
+ compare_diff spaces-compacted-expect out-compacted4
+'
+
+test_expect_success 'diff: ugly functions' '
+ git diff old new -- functions.c >out &&
+ compare_diff functions-expect out
+'
+
+test_expect_success 'diff: nice functions with --indent-heuristic' '
+ git diff --indent-heuristic old new -- functions.c >out-compacted &&
+ compare_diff functions-compacted-expect out-compacted
+'
+
+test_expect_success 'blame: ugly spaces' '
+ git blame old..new -- spaces.txt >out-blame &&
+ compare_blame spaces-expect out-blame
+'
+
+test_expect_success 'blame: nice spaces with --indent-heuristic' '
+ git blame --indent-heuristic old..new -- spaces.txt >out-blame-compacted &&
+ compare_blame spaces-compacted-expect out-blame-compacted
+'
+
+test_expect_success 'blame: nice spaces with diff.indentHeuristic' '
+ git -c diff.indentHeuristic=true blame old..new -- spaces.txt >out-blame-compacted2 &&
+ compare_blame spaces-compacted-expect out-blame-compacted2
+'
+
+test_expect_success 'blame: --no-indent-heuristic overrides config' '
+ git -c diff.indentHeuristic=true blame --no-indent-heuristic old..new -- spaces.txt >out-blame2 &&
+ git blame old..new -- spaces.txt >out-blame &&
+ compare_blame spaces-expect out-blame2
+'
+
+test_done
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index 9ce9424d15..89a5bacac5 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -977,4 +977,27 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
test_cmp msg out
'
+test_expect_success 'am works with multi-line in-body headers' '
+ FORTY="String that has a length of more than forty characters" &&
+ LONG="$FORTY $FORTY" &&
+ rm -fr .git/rebase-apply &&
+ git checkout -f first &&
+ echo one >> file &&
+ git commit -am "$LONG" --author="$LONG <long@example.com>" &&
+ git format-patch --stdout -1 >patch &&
+ # bump from, date, and subject down to in-body header
+ perl -lpe "
+ if (/^From:/) {
+ print \"From: x <x\@example.com>\";
+ print \"Date: Sat, 1 Jan 2000 00:00:00 +0000\";
+ print \"Subject: x\n\";
+ }
+ " patch >msg &&
+ git checkout HEAD^ &&
+ git am msg &&
+ # Ensure that the author and full message are present
+ git cat-file commit HEAD | grep "^author.*long@example.com" &&
+ git cat-file commit HEAD | grep "^$LONG"
+'
+
test_done
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index e2db47c36e..1ccbd5948a 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -188,6 +188,16 @@ test_expect_success 'git log --no-walk=sorted <commits> sorts by commit time' '
'
cat > expect << EOF
+=== 804a787 sixth
+=== 394ef78 fifth
+=== 5d31159 fourth
+EOF
+test_expect_success 'git log --line-prefix="=== " --no-walk <commits> sorts by commit time' '
+ git log --line-prefix="=== " --no-walk --oneline 5d31159 804a787 394ef78 > actual &&
+ test_cmp expect actual
+'
+
+cat > expect << EOF
5d31159 fourth
804a787 sixth
394ef78 fifth
@@ -284,6 +294,21 @@ test_expect_success 'simple log --graph' '
test_cmp expect actual
'
+cat > expect <<EOF
+123 * Second
+123 * sixth
+123 * fifth
+123 * fourth
+123 * third
+123 * second
+123 * initial
+EOF
+
+test_expect_success 'simple log --graph --line-prefix="123 "' '
+ git log --graph --line-prefix="123 " --pretty=tformat:%s >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'set up merge history' '
git checkout -b side HEAD~4 &&
test_commit side-1 1 1 &&
@@ -313,6 +338,27 @@ test_expect_success 'log --graph with merge' '
test_cmp expect actual
'
+cat > expect <<\EOF
+| | | * Merge branch 'side'
+| | | |\
+| | | | * side-2
+| | | | * side-1
+| | | * | Second
+| | | * | sixth
+| | | * | fifth
+| | | * | fourth
+| | | |/
+| | | * third
+| | | * second
+| | | * initial
+EOF
+
+test_expect_success 'log --graph --line-prefix="| | | " with merge' '
+ git log --line-prefix="| | | " --graph --date-order --pretty=tformat:%s |
+ sed "s/ *\$//" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'log --raw --graph -m with merge' '
git log --raw --graph --oneline -m master | head -n 500 >actual &&
grep "initial" actual
@@ -867,6 +913,283 @@ test_expect_success 'log --graph with diff and stats' '
test_i18ncmp expect actual.sanitized
'
+cat >expect <<\EOF
+*** * commit COMMIT_OBJECT_NAME
+*** |\ Merge: MERGE_PARENTS
+*** | | Author: A U Thor <author@example.com>
+*** | |
+*** | | Merge HEADS DESCRIPTION
+*** | |
+*** | * commit COMMIT_OBJECT_NAME
+*** | | Author: A U Thor <author@example.com>
+*** | |
+*** | | reach
+*** | | ---
+*** | | reach.t | 1 +
+*** | | 1 file changed, 1 insertion(+)
+*** | |
+*** | | diff --git a/reach.t b/reach.t
+*** | | new file mode 100644
+*** | | index 0000000..10c9591
+*** | | --- /dev/null
+*** | | +++ b/reach.t
+*** | | @@ -0,0 +1 @@
+*** | | +reach
+*** | |
+*** | \
+*** *-. \ commit COMMIT_OBJECT_NAME
+*** |\ \ \ Merge: MERGE_PARENTS
+*** | | | | Author: A U Thor <author@example.com>
+*** | | | |
+*** | | | | Merge HEADS DESCRIPTION
+*** | | | |
+*** | | * | commit COMMIT_OBJECT_NAME
+*** | | |/ Author: A U Thor <author@example.com>
+*** | | |
+*** | | | octopus-b
+*** | | | ---
+*** | | | octopus-b.t | 1 +
+*** | | | 1 file changed, 1 insertion(+)
+*** | | |
+*** | | | diff --git a/octopus-b.t b/octopus-b.t
+*** | | | new file mode 100644
+*** | | | index 0000000..d5fcad0
+*** | | | --- /dev/null
+*** | | | +++ b/octopus-b.t
+*** | | | @@ -0,0 +1 @@
+*** | | | +octopus-b
+*** | | |
+*** | * | commit COMMIT_OBJECT_NAME
+*** | |/ Author: A U Thor <author@example.com>
+*** | |
+*** | | octopus-a
+*** | | ---
+*** | | octopus-a.t | 1 +
+*** | | 1 file changed, 1 insertion(+)
+*** | |
+*** | | diff --git a/octopus-a.t b/octopus-a.t
+*** | | new file mode 100644
+*** | | index 0000000..11ee015
+*** | | --- /dev/null
+*** | | +++ b/octopus-a.t
+*** | | @@ -0,0 +1 @@
+*** | | +octopus-a
+*** | |
+*** * | commit COMMIT_OBJECT_NAME
+*** |/ Author: A U Thor <author@example.com>
+*** |
+*** | seventh
+*** | ---
+*** | seventh.t | 1 +
+*** | 1 file changed, 1 insertion(+)
+*** |
+*** | diff --git a/seventh.t b/seventh.t
+*** | new file mode 100644
+*** | index 0000000..9744ffc
+*** | --- /dev/null
+*** | +++ b/seventh.t
+*** | @@ -0,0 +1 @@
+*** | +seventh
+*** |
+*** * commit COMMIT_OBJECT_NAME
+*** |\ Merge: MERGE_PARENTS
+*** | | Author: A U Thor <author@example.com>
+*** | |
+*** | | Merge branch 'tangle'
+*** | |
+*** | * commit COMMIT_OBJECT_NAME
+*** | |\ Merge: MERGE_PARENTS
+*** | | | Author: A U Thor <author@example.com>
+*** | | |
+*** | | | Merge branch 'side' (early part) into tangle
+*** | | |
+*** | * | commit COMMIT_OBJECT_NAME
+*** | |\ \ Merge: MERGE_PARENTS
+*** | | | | Author: A U Thor <author@example.com>
+*** | | | |
+*** | | | | Merge branch 'master' (early part) into tangle
+*** | | | |
+*** | * | | commit COMMIT_OBJECT_NAME
+*** | | | | Author: A U Thor <author@example.com>
+*** | | | |
+*** | | | | tangle-a
+*** | | | | ---
+*** | | | | tangle-a | 1 +
+*** | | | | 1 file changed, 1 insertion(+)
+*** | | | |
+*** | | | | diff --git a/tangle-a b/tangle-a
+*** | | | | new file mode 100644
+*** | | | | index 0000000..7898192
+*** | | | | --- /dev/null
+*** | | | | +++ b/tangle-a
+*** | | | | @@ -0,0 +1 @@
+*** | | | | +a
+*** | | | |
+*** * | | | commit COMMIT_OBJECT_NAME
+*** |\ \ \ \ Merge: MERGE_PARENTS
+*** | | | | | Author: A U Thor <author@example.com>
+*** | | | | |
+*** | | | | | Merge branch 'side'
+*** | | | | |
+*** | * | | | commit COMMIT_OBJECT_NAME
+*** | | |_|/ Author: A U Thor <author@example.com>
+*** | |/| |
+*** | | | | side-2
+*** | | | | ---
+*** | | | | 2 | 1 +
+*** | | | | 1 file changed, 1 insertion(+)
+*** | | | |
+*** | | | | diff --git a/2 b/2
+*** | | | | new file mode 100644
+*** | | | | index 0000000..0cfbf08
+*** | | | | --- /dev/null
+*** | | | | +++ b/2
+*** | | | | @@ -0,0 +1 @@
+*** | | | | +2
+*** | | | |
+*** | * | | commit COMMIT_OBJECT_NAME
+*** | | | | Author: A U Thor <author@example.com>
+*** | | | |
+*** | | | | side-1
+*** | | | | ---
+*** | | | | 1 | 1 +
+*** | | | | 1 file changed, 1 insertion(+)
+*** | | | |
+*** | | | | diff --git a/1 b/1
+*** | | | | new file mode 100644
+*** | | | | index 0000000..d00491f
+*** | | | | --- /dev/null
+*** | | | | +++ b/1
+*** | | | | @@ -0,0 +1 @@
+*** | | | | +1
+*** | | | |
+*** * | | | commit COMMIT_OBJECT_NAME
+*** | | | | Author: A U Thor <author@example.com>
+*** | | | |
+*** | | | | Second
+*** | | | | ---
+*** | | | | one | 1 +
+*** | | | | 1 file changed, 1 insertion(+)
+*** | | | |
+*** | | | | diff --git a/one b/one
+*** | | | | new file mode 100644
+*** | | | | index 0000000..9a33383
+*** | | | | --- /dev/null
+*** | | | | +++ b/one
+*** | | | | @@ -0,0 +1 @@
+*** | | | | +case
+*** | | | |
+*** * | | | commit COMMIT_OBJECT_NAME
+*** | |_|/ Author: A U Thor <author@example.com>
+*** |/| |
+*** | | | sixth
+*** | | | ---
+*** | | | a/two | 1 -
+*** | | | 1 file changed, 1 deletion(-)
+*** | | |
+*** | | | diff --git a/a/two b/a/two
+*** | | | deleted file mode 100644
+*** | | | index 9245af5..0000000
+*** | | | --- a/a/two
+*** | | | +++ /dev/null
+*** | | | @@ -1 +0,0 @@
+*** | | | -ni
+*** | | |
+*** * | | commit COMMIT_OBJECT_NAME
+*** | | | Author: A U Thor <author@example.com>
+*** | | |
+*** | | | fifth
+*** | | | ---
+*** | | | a/two | 1 +
+*** | | | 1 file changed, 1 insertion(+)
+*** | | |
+*** | | | diff --git a/a/two b/a/two
+*** | | | new file mode 100644
+*** | | | index 0000000..9245af5
+*** | | | --- /dev/null
+*** | | | +++ b/a/two
+*** | | | @@ -0,0 +1 @@
+*** | | | +ni
+*** | | |
+*** * | | commit COMMIT_OBJECT_NAME
+*** |/ / Author: A U Thor <author@example.com>
+*** | |
+*** | | fourth
+*** | | ---
+*** | | ein | 1 +
+*** | | 1 file changed, 1 insertion(+)
+*** | |
+*** | | diff --git a/ein b/ein
+*** | | new file mode 100644
+*** | | index 0000000..9d7e69f
+*** | | --- /dev/null
+*** | | +++ b/ein
+*** | | @@ -0,0 +1 @@
+*** | | +ichi
+*** | |
+*** * | commit COMMIT_OBJECT_NAME
+*** |/ Author: A U Thor <author@example.com>
+*** |
+*** | third
+*** | ---
+*** | ichi | 1 +
+*** | one | 1 -
+*** | 2 files changed, 1 insertion(+), 1 deletion(-)
+*** |
+*** | diff --git a/ichi b/ichi
+*** | new file mode 100644
+*** | index 0000000..9d7e69f
+*** | --- /dev/null
+*** | +++ b/ichi
+*** | @@ -0,0 +1 @@
+*** | +ichi
+*** | diff --git a/one b/one
+*** | deleted file mode 100644
+*** | index 9d7e69f..0000000
+*** | --- a/one
+*** | +++ /dev/null
+*** | @@ -1 +0,0 @@
+*** | -ichi
+*** |
+*** * commit COMMIT_OBJECT_NAME
+*** | Author: A U Thor <author@example.com>
+*** |
+*** | second
+*** | ---
+*** | one | 2 +-
+*** | 1 file changed, 1 insertion(+), 1 deletion(-)
+*** |
+*** | diff --git a/one b/one
+*** | index 5626abf..9d7e69f 100644
+*** | --- a/one
+*** | +++ b/one
+*** | @@ -1 +1 @@
+*** | -one
+*** | +ichi
+*** |
+*** * commit COMMIT_OBJECT_NAME
+*** Author: A U Thor <author@example.com>
+***
+*** initial
+*** ---
+*** one | 1 +
+*** 1 file changed, 1 insertion(+)
+***
+*** diff --git a/one b/one
+*** new file mode 100644
+*** index 0000000..5626abf
+*** --- /dev/null
+*** +++ b/one
+*** @@ -0,0 +1 @@
+*** +one
+EOF
+
+test_expect_success 'log --line-prefix="*** " --graph with diff and stats' '
+ git log --line-prefix="*** " --no-renames --graph --pretty=short --stat -p >actual &&
+ sanitize_output >actual.sanitized <actual &&
+ test_i18ncmp expect actual.sanitized
+'
+
test_expect_success 'dotdot is a parent directory' '
mkdir -p a/b &&
( echo sixth && echo fifth ) >expect &&
diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh
index 84a809690e..0288c17ec6 100755
--- a/t/t4204-patch-id.sh
+++ b/t/t4204-patch-id.sh
@@ -143,6 +143,20 @@ test_expect_success 'patch-id supports git-format-patch MIME output' '
test_cmp patch-id_master patch-id_same
'
+test_expect_success 'patch-id respects config from subdir' '
+ test_config patchid.stable true &&
+ mkdir subdir &&
+
+ # copy these because test_patch_id() looks for them in
+ # the current directory
+ cp bar-then-foo foo-then-bar subdir &&
+
+ (
+ cd subdir &&
+ test_patch_id irrelevant patchid.stable=true
+ )
+'
+
cat >nonl <<\EOF
diff --git i/a w/a
index e69de29..2e65efe 100644
diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh
index 85716dd6ec..9bd7dd2ba1 100755
--- a/t/t4254-am-corrupt.sh
+++ b/t/t4254-am-corrupt.sh
@@ -29,7 +29,7 @@ test_expect_success 'try to apply corrupted patch' '
'
test_expect_success 'compare diagnostic; ensure file is still here' '
- echo "fatal: git diff header lacks filename information (line 4)" >expected &&
+ echo "error: git diff header lacks filename information (line 4)" >expected &&
test_path_is_file f &&
test_cmp expected actual
'
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index 45d228ebc8..e6b995161e 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -13,7 +13,7 @@ test_expect_success 'split sample box' \
'git mailsplit -o. "$DATA/sample.mbox" >last &&
last=$(cat last) &&
echo total is $last &&
- test $(cat last) = 17'
+ test $(cat last) = 18'
check_mailinfo () {
mail=$1 opt=$2
diff --git a/t/t5100/info0018 b/t/t5100/info0018
new file mode 100644
index 0000000000..d53e7491c7
--- /dev/null
+++ b/t/t5100/info0018
@@ -0,0 +1,5 @@
+Author: Another Thor
+Email: a.thor@example.com
+Subject: This one contains a tab and a space
+Date: Fri, 9 Jun 2006 00:44:16 -0700
+
diff --git a/t/t5100/info0018--no-inbody-headers b/t/t5100/info0018--no-inbody-headers
new file mode 100644
index 0000000000..30b17bd913
--- /dev/null
+++ b/t/t5100/info0018--no-inbody-headers
@@ -0,0 +1,5 @@
+Author: A U Thor
+Email: a.u.thor@example.com
+Subject: check multiline inbody headers
+Date: Fri, 9 Jun 2006 00:44:16 -0700
+
diff --git a/t/t5100/msg0015 b/t/t5100/msg0015
index 4abb3d5c6c..e69de29bb2 100644
--- a/t/t5100/msg0015
+++ b/t/t5100/msg0015
@@ -1,2 +0,0 @@
- - a list
- - of stuff
diff --git a/t/t5100/msg0018 b/t/t5100/msg0018
new file mode 100644
index 0000000000..56de83d7fc
--- /dev/null
+++ b/t/t5100/msg0018
@@ -0,0 +1,2 @@
+a commit message
+
diff --git a/t/t5100/msg0018--no-inbody-headers b/t/t5100/msg0018--no-inbody-headers
new file mode 100644
index 0000000000..b1e05d3862
--- /dev/null
+++ b/t/t5100/msg0018--no-inbody-headers
@@ -0,0 +1,8 @@
+From: Another Thor
+ <a.thor@example.com>
+Subject: This one contains
+ a tab
+ and a space
+
+a commit message
+
diff --git a/t/t5100/patch0018 b/t/t5100/patch0018
new file mode 100644
index 0000000000..789df6d030
--- /dev/null
+++ b/t/t5100/patch0018
@@ -0,0 +1,6 @@
+diff --git a/foo b/foo
+index e69de29..d95f3ad 100644
+--- a/foo
++++ b/foo
+@@ -0,0 +1 @@
++content
diff --git a/t/t5100/patch0018--no-inbody-headers b/t/t5100/patch0018--no-inbody-headers
new file mode 100644
index 0000000000..789df6d030
--- /dev/null
+++ b/t/t5100/patch0018--no-inbody-headers
@@ -0,0 +1,6 @@
+diff --git a/foo b/foo
+index e69de29..d95f3ad 100644
+--- a/foo
++++ b/foo
+@@ -0,0 +1 @@
++content
diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox
index 8b2ae064c3..6d4d0e4474 100644
--- a/t/t5100/sample.mbox
+++ b/t/t5100/sample.mbox
@@ -699,3 +699,22 @@ index e69de29..d95f3ad 100644
+++ b/foo
@@ -0,0 +1 @@
+New content
+From nobody Mon Sep 17 00:00:00 2001
+From: A U Thor <a.u.thor@example.com>
+Subject: check multiline inbody headers
+Date: Fri, 9 Jun 2006 00:44:16 -0700
+
+From: Another Thor
+ <a.thor@example.com>
+Subject: This one contains
+ a tab
+ and a space
+
+a commit message
+
+diff --git a/foo b/foo
+index e69de29..d95f3ad 100644
+--- a/foo
++++ b/foo
+@@ -0,0 +1 @@
++content
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 3893afd687..b4c7a6ff6b 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -7,6 +7,18 @@ objpath () {
echo ".git/objects/$(echo "$1" | sed -e 's|\(..\)|\1/|')"
}
+# show objects present in pack ($1 should be associated *.idx)
+list_packed_objects () {
+ git show-index <"$1" | cut -d' ' -f2
+}
+
+# has_any pattern-file content-file
+# tests whether content-file has any entry from pattern-file with entries being
+# whole lines.
+has_any () {
+ grep -Ff "$1" "$2"
+}
+
test_expect_success 'setup repo with moderate-sized history' '
for i in $(test_seq 1 10); do
test_commit $i
@@ -16,6 +28,7 @@ test_expect_success 'setup repo with moderate-sized history' '
test_commit side-$i
done &&
git checkout master &&
+ bitmaptip=$(git rev-parse master) &&
blob=$(echo tagged-blob | git hash-object -w --stdin) &&
git tag tagged-blob $blob &&
git config repack.writebitmaps true &&
@@ -118,6 +131,83 @@ test_expect_success 'incremental repack can disable bitmaps' '
git repack -d --no-write-bitmap-index
'
+test_expect_success 'pack-objects respects --local (non-local loose)' '
+ git init --bare alt.git &&
+ echo $(pwd)/alt.git/objects >.git/objects/info/alternates &&
+ echo content1 >file1 &&
+ # non-local loose object which is not present in bitmapped pack
+ altblob=$(GIT_DIR=alt.git git hash-object -w file1) &&
+ # non-local loose object which is also present in bitmapped pack
+ git cat-file blob $blob | GIT_DIR=alt.git git hash-object -w --stdin &&
+ git add file1 &&
+ test_tick &&
+ git commit -m commit_file1 &&
+ echo HEAD | git pack-objects --local --stdout --revs >1.pack &&
+ git index-pack 1.pack &&
+ list_packed_objects 1.idx >1.objects &&
+ printf "%s\n" "$altblob" "$blob" >nonlocal-loose &&
+ ! has_any nonlocal-loose 1.objects
+'
+
+test_expect_success 'pack-objects respects --honor-pack-keep (local non-bitmapped pack)' '
+ echo content2 >file2 &&
+ blob2=$(git hash-object -w file2) &&
+ git add file2 &&
+ test_tick &&
+ git commit -m commit_file2 &&
+ printf "%s\n" "$blob2" "$bitmaptip" >keepobjects &&
+ pack2=$(git pack-objects pack2 <keepobjects) &&
+ mv pack2-$pack2.* .git/objects/pack/ &&
+ >.git/objects/pack/pack2-$pack2.keep &&
+ rm $(objpath $blob2) &&
+ echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >2a.pack &&
+ git index-pack 2a.pack &&
+ list_packed_objects 2a.idx >2a.objects &&
+ ! has_any keepobjects 2a.objects
+'
+
+test_expect_success 'pack-objects respects --local (non-local pack)' '
+ mv .git/objects/pack/pack2-$pack2.* alt.git/objects/pack/ &&
+ echo HEAD | git pack-objects --local --stdout --revs >2b.pack &&
+ git index-pack 2b.pack &&
+ list_packed_objects 2b.idx >2b.objects &&
+ ! has_any keepobjects 2b.objects
+'
+
+test_expect_success 'pack-objects respects --honor-pack-keep (local bitmapped pack)' '
+ ls .git/objects/pack/ | grep bitmap >output &&
+ test_line_count = 1 output &&
+ packbitmap=$(basename $(cat output) .bitmap) &&
+ list_packed_objects .git/objects/pack/$packbitmap.idx >packbitmap.objects &&
+ test_when_finished "rm -f .git/objects/pack/$packbitmap.keep" &&
+ >.git/objects/pack/$packbitmap.keep &&
+ echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >3a.pack &&
+ git index-pack 3a.pack &&
+ list_packed_objects 3a.idx >3a.objects &&
+ ! has_any packbitmap.objects 3a.objects
+'
+
+test_expect_success 'pack-objects respects --local (non-local bitmapped pack)' '
+ mv .git/objects/pack/$packbitmap.* alt.git/objects/pack/ &&
+ test_when_finished "mv alt.git/objects/pack/$packbitmap.* .git/objects/pack/" &&
+ echo HEAD | git pack-objects --local --stdout --revs >3b.pack &&
+ git index-pack 3b.pack &&
+ list_packed_objects 3b.idx >3b.objects &&
+ ! has_any packbitmap.objects 3b.objects
+'
+
+test_expect_success 'pack-objects to file can use bitmap' '
+ # make sure we still have 1 bitmap index from previous tests
+ ls .git/objects/pack/ | grep bitmap >output &&
+ test_line_count = 1 output &&
+ # verify equivalent packs are generated with/without using bitmap index
+ packasha1=$(git pack-objects --no-use-bitmap-index --all packa </dev/null) &&
+ packbsha1=$(git pack-objects --use-bitmap-index --all packb </dev/null) &&
+ list_packed_objects <packa-$packasha1.idx >packa.objects &&
+ list_packed_objects <packb-$packbsha1.idx >packb.objects &&
+ test_cmp packa.objects packb.objects
+'
+
test_expect_success 'full repack, reusing previous bitmaps' '
git repack -ad &&
ls .git/objects/pack/ | grep bitmap >output &&
@@ -143,6 +233,20 @@ test_expect_success 'create objects for missing-HAVE tests' '
EOF
'
+test_expect_success 'pack-objects respects --incremental' '
+ cat >revs2 <<-EOF &&
+ HEAD
+ $commit
+ EOF
+ git pack-objects --incremental --stdout --revs <revs2 >4.pack &&
+ git index-pack 4.pack &&
+ list_packed_objects 4.idx >4.objects &&
+ test_line_count = 4 4.objects &&
+ git rev-list --objects $commit >revlist &&
+ cut -d" " -f1 revlist |sort >objects &&
+ test_cmp 4.objects objects
+'
+
test_expect_success 'pack with missing blob' '
rm $(objpath $blob) &&
git pack-objects --stdout --revs <revs >/dev/null
@@ -158,10 +262,6 @@ test_expect_success 'pack with missing parent' '
git pack-objects --stdout --revs <revs >/dev/null
'
-test_lazy_prereq JGIT '
- type jgit
-'
-
test_expect_success JGIT 'we can read jgit bitmaps' '
git clone . compat-jgit &&
(
diff --git a/t/t5314-pack-cycle-detection.sh b/t/t5314-pack-cycle-detection.sh
new file mode 100755
index 0000000000..f7dbdfb412
--- /dev/null
+++ b/t/t5314-pack-cycle-detection.sh
@@ -0,0 +1,113 @@
+#!/bin/sh
+
+test_description='test handling of inter-pack delta cycles during repack
+
+The goal here is to create a situation where we have two blobs, A and B, with A
+as a delta against B in one pack, and vice versa in the other. Then if we can
+persuade a full repack to find A from one pack and B from the other, that will
+give us a cycle when we attempt to reuse those deltas.
+
+The trick is in the "persuade" step, as it depends on the internals of how
+pack-objects picks which pack to reuse the deltas from. But we can assume
+that it does so in one of two general strategies:
+
+ 1. Using a static ordering of packs. In this case, no inter-pack cycles can
+ happen. Any objects with a delta relationship must be present in the same
+ pack (i.e., no "--thin" packs on disk), so we will find all related objects
+ from that pack. So assuming there are no cycles within a single pack (and
+ we avoid generating them via pack-objects or importing them via
+ index-pack), then our result will have no cycles.
+
+ So this case should pass the tests no matter how we arrange things.
+
+ 2. Picking the next pack to examine based on locality (i.e., where we found
+ something else recently).
+
+ In this case, we want to make sure that we find the delta versions of A and
+ B and not their base versions. We can do this by putting two blobs in each
+ pack. The first is a "dummy" blob that can only be found in the pack in
+ question. And then the second is the actual delta we want to find.
+
+ The two blobs must be present in the same tree, not present in other trees,
+ and the dummy pathname must sort before the delta path.
+
+The setup below focuses on case 2. We have two commits HEAD and HEAD^, each
+which has two files: "dummy" and "file". Then we can make two packs which
+contain:
+
+ [pack one]
+ HEAD:dummy
+ HEAD:file (as delta against HEAD^:file)
+ HEAD^:file (as base)
+
+ [pack two]
+ HEAD^:dummy
+ HEAD^:file (as delta against HEAD:file)
+ HEAD:file (as base)
+
+Then no matter which order we start looking at the packs in, we know that we
+will always find a delta for "file", because its lookup will always come
+immediately after the lookup for "dummy".
+'
+. ./test-lib.sh
+
+
+
+# Create a pack containing the the tree $1 and blob $1:file, with
+# the latter stored as a delta against $2:file.
+#
+# We convince pack-objects to make the delta in the direction of our choosing
+# by marking $2 as a preferred-base edge. That results in $1:file as a thin
+# delta, and index-pack completes it by adding $2:file as a base.
+#
+# Note that the two variants of "file" must be similar enough to convince git
+# to create the delta.
+make_pack () {
+ {
+ printf '%s\n' "-$(git rev-parse $2)"
+ printf '%s dummy\n' "$(git rev-parse $1:dummy)"
+ printf '%s file\n' "$(git rev-parse $1:file)"
+ } |
+ git pack-objects --stdout |
+ git index-pack --stdin --fix-thin
+}
+
+test_expect_success 'setup' '
+ test-genrandom base 4096 >base &&
+ for i in one two
+ do
+ # we want shared content here to encourage deltas...
+ cp base file &&
+ echo $i >>file &&
+
+ # ...whereas dummy should be short, because we do not want
+ # deltas that would create duplicates when we --fix-thin
+ echo $i >dummy &&
+
+ git add file dummy &&
+ test_tick &&
+ git commit -m $i ||
+ return 1
+ done &&
+
+ make_pack HEAD^ HEAD &&
+ make_pack HEAD HEAD^
+'
+
+test_expect_success 'repack' '
+ # We first want to check that we do not have any internal errors,
+ # and also that we do not hit the last-ditch cycle-breaking code
+ # in write_object(), which will issue a warning to stderr.
+ >expect &&
+ git repack -ad 2>stderr &&
+ test_cmp expect stderr &&
+
+ # And then double-check that the resulting pack is usable (i.e.,
+ # we did not fail to notice any cycles). We know we are accessing
+ # the objects via the new pack here, because "repack -d" will have
+ # removed the others.
+ git cat-file blob HEAD:file >/dev/null &&
+ git cat-file blob HEAD^:file >/dev/null
+'
+
+test_done
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 82d913a6a8..505e1b4a7f 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -652,4 +652,72 @@ test_expect_success MINGW 'fetch-pack --diag-url c:repo' '
check_prot_path c:repo file c:repo
'
+test_expect_success 'clone shallow since ...' '
+ test_create_repo shallow-since &&
+ (
+ cd shallow-since &&
+ GIT_COMMITTER_DATE="100000000 +0700" git commit --allow-empty -m one &&
+ GIT_COMMITTER_DATE="200000000 +0700" git commit --allow-empty -m two &&
+ GIT_COMMITTER_DATE="300000000 +0700" git commit --allow-empty -m three &&
+ git clone --shallow-since "300000000 +0700" "file://$(pwd)/." ../shallow11 &&
+ git -C ../shallow11 log --pretty=tformat:%s HEAD >actual &&
+ echo three >expected &&
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'fetch shallow since ...' '
+ git -C shallow11 fetch --shallow-since "200000000 +0700" origin &&
+ git -C shallow11 log --pretty=tformat:%s origin/master >actual &&
+ cat >expected <<-\EOF &&
+ three
+ two
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'shallow clone exclude tag two' '
+ test_create_repo shallow-exclude &&
+ (
+ cd shallow-exclude &&
+ test_commit one &&
+ test_commit two &&
+ test_commit three &&
+ git clone --shallow-exclude two "file://$(pwd)/." ../shallow12 &&
+ git -C ../shallow12 log --pretty=tformat:%s HEAD >actual &&
+ echo three >expected &&
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'fetch exclude tag one' '
+ git -C shallow12 fetch --shallow-exclude one origin &&
+ git -C shallow12 log --pretty=tformat:%s origin/master >actual &&
+ test_write_lines three two >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'fetching deepen' '
+ test_create_repo shallow-deepen &&
+ (
+ cd shallow-deepen &&
+ test_commit one &&
+ test_commit two &&
+ test_commit three &&
+ git clone --depth 1 "file://$(pwd)/." deepen &&
+ test_commit four &&
+ git -C deepen log --pretty=tformat:%s master >actual &&
+ echo three >expected &&
+ test_cmp expected actual &&
+ git -C deepen fetch --deepen=1 &&
+ git -C deepen log --pretty=tformat:%s origin/master >actual &&
+ cat >expected <<-\EOF &&
+ four
+ three
+ two
+ EOF
+ test_cmp expected actual
+ )
+'
+
test_done
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 819b9ddd0f..55fc83fc06 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -99,7 +99,7 @@ test_expect_success 'confuses pattern as remote when no remote specified' '
# We could just as easily have used "master"; the "*" emphasizes its
# role as a pattern.
test_must_fail git ls-remote refs*master >actual 2>&1 &&
- test_cmp exp actual
+ test_i18ncmp exp actual
'
test_expect_success 'die with non-2 for wrong repository even with --exit-code' '
@@ -207,5 +207,45 @@ test_expect_success 'ls-remote --symref omits filtered-out matches' '
test_cmp expect actual
'
+test_lazy_prereq GIT_DAEMON '
+ test_tristate GIT_TEST_GIT_DAEMON &&
+ test "$GIT_TEST_GIT_DAEMON" != false
+'
+
+# This test spawns a daemon, so run it only if the user would be OK with
+# testing with git-daemon.
+test_expect_success PIPE,JGIT,GIT_DAEMON 'indicate no refs in standards-compliant empty remote' '
+ JGIT_DAEMON_PORT=${JGIT_DAEMON_PORT-${this_test#t}} &&
+ JGIT_DAEMON_PID= &&
+ git init --bare empty.git &&
+ >empty.git/git-daemon-export-ok &&
+ mkfifo jgit_daemon_output &&
+ {
+ jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output &
+ JGIT_DAEMON_PID=$!
+ } &&
+ test_when_finished kill "$JGIT_DAEMON_PID" &&
+ {
+ read line &&
+ case $line in
+ Exporting*)
+ ;;
+ *)
+ echo "Expected: Exporting" &&
+ false;;
+ esac &&
+ read line &&
+ case $line in
+ "Listening on"*)
+ ;;
+ *)
+ echo "Expected: Listening on" &&
+ false;;
+ esac
+ } <jgit_daemon_output &&
+ # --exit-code asks the command to exit with 2 when no
+ # matching refs are found.
+ test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git
+'
test_done
diff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh
index 37a433504e..5fbf67c446 100755
--- a/t/t5539-fetch-http-shallow.sh
+++ b/t/t5539-fetch-http-shallow.sh
@@ -73,5 +73,78 @@ test_expect_success 'no shallow lines after receiving ACK ready' '
)
'
+test_expect_success 'clone shallow since ...' '
+ test_create_repo shallow-since &&
+ (
+ cd shallow-since &&
+ GIT_COMMITTER_DATE="100000000 +0700" git commit --allow-empty -m one &&
+ GIT_COMMITTER_DATE="200000000 +0700" git commit --allow-empty -m two &&
+ GIT_COMMITTER_DATE="300000000 +0700" git commit --allow-empty -m three &&
+ mv .git "$HTTPD_DOCUMENT_ROOT_PATH/shallow-since.git" &&
+ git clone --shallow-since "300000000 +0700" $HTTPD_URL/smart/shallow-since.git ../shallow11 &&
+ git -C ../shallow11 log --pretty=tformat:%s HEAD >actual &&
+ echo three >expected &&
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'fetch shallow since ...' '
+ git -C shallow11 fetch --shallow-since "200000000 +0700" origin &&
+ git -C shallow11 log --pretty=tformat:%s origin/master >actual &&
+ cat >expected <<-\EOF &&
+ three
+ two
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'shallow clone exclude tag two' '
+ test_create_repo shallow-exclude &&
+ (
+ cd shallow-exclude &&
+ test_commit one &&
+ test_commit two &&
+ test_commit three &&
+ mv .git "$HTTPD_DOCUMENT_ROOT_PATH/shallow-exclude.git" &&
+ git clone --shallow-exclude two $HTTPD_URL/smart/shallow-exclude.git ../shallow12 &&
+ git -C ../shallow12 log --pretty=tformat:%s HEAD >actual &&
+ echo three >expected &&
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'fetch exclude tag one' '
+ git -C shallow12 fetch --shallow-exclude one origin &&
+ git -C shallow12 log --pretty=tformat:%s origin/master >actual &&
+ test_write_lines three two >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'fetching deepen' '
+ test_create_repo shallow-deepen &&
+ (
+ cd shallow-deepen &&
+ test_commit one &&
+ test_commit two &&
+ test_commit three &&
+ mv .git "$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git" &&
+ git clone --depth 1 $HTTPD_URL/smart/shallow-deepen.git deepen &&
+ mv "$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git" .git &&
+ test_commit four &&
+ git -C deepen log --pretty=tformat:%s master >actual &&
+ echo three >expected &&
+ test_cmp expected actual &&
+ mv .git "$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git" &&
+ git -C deepen fetch --deepen=1 &&
+ git -C deepen log --pretty=tformat:%s origin/master >actual &&
+ cat >expected <<-\EOF &&
+ four
+ three
+ two
+ EOF
+ test_cmp expected actual
+ )
+'
+
stop_httpd
test_done
diff --git a/t/t5546-receive-limits.sh b/t/t5546-receive-limits.sh
new file mode 100755
index 0000000000..10cb0be2b7
--- /dev/null
+++ b/t/t5546-receive-limits.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+test_description='check receive input limits'
+. ./test-lib.sh
+
+# Let's run tests with different unpack limits: 1 and 10000
+# When the limit is 1, `git receive-pack` will call `git index-pack`.
+# When the limit is 10000, `git receive-pack` will call `git unpack-objects`.
+
+test_pack_input_limit () {
+ case "$1" in
+ index) unpack_limit=1 ;;
+ unpack) unpack_limit=10000 ;;
+ esac
+
+ test_expect_success 'prepare destination repository' '
+ rm -fr dest &&
+ git --bare init dest
+ '
+
+ test_expect_success "set unpacklimit to $unpack_limit" '
+ git --git-dir=dest config receive.unpacklimit "$unpack_limit"
+ '
+
+ test_expect_success 'setting receive.maxInputSize to 512 rejects push' '
+ git --git-dir=dest config receive.maxInputSize 512 &&
+ test_must_fail git push dest HEAD
+ '
+
+ test_expect_success 'bumping limit to 4k allows push' '
+ git --git-dir=dest config receive.maxInputSize 4k &&
+ git push dest HEAD
+ '
+
+ test_expect_success 'prepare destination repository (again)' '
+ rm -fr dest &&
+ git --bare init dest
+ '
+
+ test_expect_success 'lifting the limit allows push' '
+ git --git-dir=dest config receive.maxInputSize 0 &&
+ git push dest HEAD
+ '
+}
+
+test_expect_success "create known-size (1024 bytes) commit" '
+ test-genrandom foo 1024 >one-k &&
+ git add one-k &&
+ test_commit one-k
+'
+
+test_pack_input_limit index
+test_pack_input_limit unpack
+
+test_done
diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh
index 1c6952d049..64a9850e31 100755
--- a/t/t6101-rev-parse-parents.sh
+++ b/t/t6101-rev-parse-parents.sh
@@ -102,4 +102,98 @@ test_expect_success 'short SHA-1 works' '
test_cmp_rev_output start "git rev-parse ${start%?}"
'
+# rev^- tests; we can use a simpler setup for these
+
+test_expect_success 'setup for rev^- tests' '
+ test_commit one &&
+ test_commit two &&
+ test_commit three &&
+
+ # Merge in a branch for testing rev^-
+ git checkout -b branch &&
+ git checkout HEAD^^ &&
+ git merge -m merge --no-edit --no-ff branch &&
+ git checkout -b merge
+'
+
+# The merged branch has 2 commits + the merge
+test_expect_success 'rev-list --count merge^- = merge^..merge' '
+ git rev-list --count merge^..merge >expect &&
+ echo 3 >actual &&
+ test_cmp expect actual
+'
+
+# All rev^- rev-parse tests
+
+test_expect_success 'rev-parse merge^- = merge^..merge' '
+ git rev-parse merge^..merge >expect &&
+ git rev-parse merge^- >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-parse merge^-1 = merge^..merge' '
+ git rev-parse merge^1..merge >expect &&
+ git rev-parse merge^-1 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-parse merge^-2 = merge^2..merge' '
+ git rev-parse merge^2..merge >expect &&
+ git rev-parse merge^-2 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-parse merge^-0 (invalid parent)' '
+ test_must_fail git rev-parse merge^-0
+'
+
+test_expect_success 'rev-parse merge^-3 (invalid parent)' '
+ test_must_fail git rev-parse merge^-3
+'
+
+test_expect_success 'rev-parse merge^-^ (garbage after ^-)' '
+ test_must_fail git rev-parse merge^-^
+'
+
+test_expect_success 'rev-parse merge^-1x (garbage after ^-1)' '
+ test_must_fail git rev-parse merge^-1x
+'
+
+# All rev^- rev-list tests (should be mostly the same as rev-parse; the reason
+# for the duplication is that rev-parse and rev-list use different parsers).
+
+test_expect_success 'rev-list merge^- = merge^..merge' '
+ git rev-list merge^..merge >expect &&
+ git rev-list merge^- >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list merge^-1 = merge^1..merge' '
+ git rev-list merge^1..merge >expect &&
+ git rev-list merge^-1 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list merge^-2 = merge^2..merge' '
+ git rev-list merge^2..merge >expect &&
+ git rev-list merge^-2 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rev-list merge^-0 (invalid parent)' '
+ test_must_fail git rev-list merge^-0
+'
+
+test_expect_success 'rev-list merge^-3 (invalid parent)' '
+ test_must_fail git rev-list merge^-3
+'
+
+test_expect_success 'rev-list merge^-^ (garbage after ^-)' '
+ test_must_fail git rev-list merge^-^
+'
+
+test_expect_success 'rev-list merge^-1x (garbage after ^-1)' '
+ test_must_fail git rev-list merge^-1x
+'
+
test_done
diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh
index 4d17363a92..53cf42fac1 100755
--- a/t/t7060-wtstatus.sh
+++ b/t/t7060-wtstatus.sh
@@ -232,4 +232,25 @@ test_expect_success 'status --branch with detached HEAD' '
test_i18ncmp expected actual
'
+## Duplicate the above test and verify --porcelain=v1 arg parsing.
+test_expect_success 'status --porcelain=v1 --branch with detached HEAD' '
+ git reset --hard &&
+ git checkout master^0 &&
+ git status --branch --porcelain=v1 >actual &&
+ cat >expected <<-EOF &&
+ ## HEAD (no branch)
+ ?? .gitconfig
+ ?? actual
+ ?? expect
+ ?? expected
+ ?? mdconflict/
+ EOF
+ test_i18ncmp expected actual
+'
+
+## Verify parser error on invalid --porcelain argument.
+test_expect_success 'status --porcelain=bogus' '
+ test_must_fail git status --porcelain=bogus
+'
+
test_done
diff --git a/t/t7064-wtstatus-pv2.sh b/t/t7064-wtstatus-pv2.sh
new file mode 100755
index 0000000000..3012a4d7c0
--- /dev/null
+++ b/t/t7064-wtstatus-pv2.sh
@@ -0,0 +1,593 @@
+#!/bin/sh
+
+test_description='git status --porcelain=v2
+
+This test exercises porcelain V2 output for git status.'
+
+
+. ./test-lib.sh
+
+
+test_expect_success setup '
+ test_tick &&
+ git config core.autocrlf false &&
+ echo x >file_x &&
+ echo y >file_y &&
+ echo z >file_z &&
+ mkdir dir1 &&
+ echo a >dir1/file_a &&
+ echo b >dir1/file_b
+'
+
+test_expect_success 'before initial commit, nothing added, only untracked' '
+ cat >expect <<-EOF &&
+ # branch.oid (initial)
+ # branch.head master
+ ? actual
+ ? dir1/
+ ? expect
+ ? file_x
+ ? file_y
+ ? file_z
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=normal >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'before initial commit, things added' '
+ git add file_x file_y file_z dir1 &&
+ OID_A=$(git hash-object -t blob -- dir1/file_a) &&
+ OID_B=$(git hash-object -t blob -- dir1/file_b) &&
+ OID_X=$(git hash-object -t blob -- file_x) &&
+ OID_Y=$(git hash-object -t blob -- file_y) &&
+ OID_Z=$(git hash-object -t blob -- file_z) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid (initial)
+ # branch.head master
+ 1 A. N... 000000 100644 100644 $_z40 $OID_A dir1/file_a
+ 1 A. N... 000000 100644 100644 $_z40 $OID_B dir1/file_b
+ 1 A. N... 000000 100644 100644 $_z40 $OID_X file_x
+ 1 A. N... 000000 100644 100644 $_z40 $OID_Y file_y
+ 1 A. N... 000000 100644 100644 $_z40 $OID_Z file_z
+ ? actual
+ ? expect
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'before initial commit, things added (-z)' '
+ lf_to_nul >expect <<-EOF &&
+ # branch.oid (initial)
+ # branch.head master
+ 1 A. N... 000000 100644 100644 $_z40 $OID_A dir1/file_a
+ 1 A. N... 000000 100644 100644 $_z40 $OID_B dir1/file_b
+ 1 A. N... 000000 100644 100644 $_z40 $OID_X file_x
+ 1 A. N... 000000 100644 100644 $_z40 $OID_Y file_y
+ 1 A. N... 000000 100644 100644 $_z40 $OID_Z file_z
+ ? actual
+ ? expect
+ EOF
+
+ git status -z --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'make first commit, comfirm HEAD oid and branch' '
+ git commit -m initial &&
+ H0=$(git rev-parse HEAD) &&
+ cat >expect <<-EOF &&
+ # branch.oid $H0
+ # branch.head master
+ ? actual
+ ? expect
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'after first commit, create unstaged changes' '
+ echo x >>file_x &&
+ OID_X1=$(git hash-object -t blob -- file_x) &&
+ rm file_z &&
+ H0=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $H0
+ # branch.head master
+ 1 .M N... 100644 100644 100644 $OID_X $OID_X file_x
+ 1 .D N... 100644 100644 000000 $OID_Z $OID_Z file_z
+ ? actual
+ ? expect
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'after first commit but omit untracked files and branch' '
+ cat >expect <<-EOF &&
+ 1 .M N... 100644 100644 100644 $OID_X $OID_X file_x
+ 1 .D N... 100644 100644 000000 $OID_Z $OID_Z file_z
+ EOF
+
+ git status --porcelain=v2 --untracked-files=no >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'after first commit, stage existing changes' '
+ git add file_x &&
+ git rm file_z &&
+ H0=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $H0
+ # branch.head master
+ 1 M. N... 100644 100644 100644 $OID_X $OID_X1 file_x
+ 1 D. N... 100644 000000 000000 $OID_Z $_z40 file_z
+ ? actual
+ ? expect
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rename causes 2 path lines' '
+ git mv file_y renamed_y &&
+ H0=$(git rev-parse HEAD) &&
+
+ q_to_tab >expect <<-EOF &&
+ # branch.oid $H0
+ # branch.head master
+ 1 M. N... 100644 100644 100644 $OID_X $OID_X1 file_x
+ 1 D. N... 100644 000000 000000 $OID_Z $_z40 file_z
+ 2 R. N... 100644 100644 100644 $OID_Y $OID_Y R100 renamed_yQfile_y
+ ? actual
+ ? expect
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rename causes 2 path lines (-z)' '
+ H0=$(git rev-parse HEAD) &&
+
+ ## Lines use NUL path separator and line terminator, so double transform here.
+ q_to_nul <<-EOF | lf_to_nul >expect &&
+ # branch.oid $H0
+ # branch.head master
+ 1 M. N... 100644 100644 100644 $OID_X $OID_X1 file_x
+ 1 D. N... 100644 000000 000000 $OID_Z $_z40 file_z
+ 2 R. N... 100644 100644 100644 $OID_Y $OID_Y R100 renamed_yQfile_y
+ ? actual
+ ? expect
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all -z >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'make second commit, confirm clean and new HEAD oid' '
+ git commit -m second &&
+ H1=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $H1
+ # branch.head master
+ ? actual
+ ? expect
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'confirm ignored files are not printed' '
+ test_when_finished "rm -f x.ign .gitignore" &&
+ echo x.ign >.gitignore &&
+ echo "ignore me" >x.ign &&
+
+ cat >expect <<-EOF &&
+ ? .gitignore
+ ? actual
+ ? expect
+ EOF
+
+ git status --porcelain=v2 --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'ignored files are printed with --ignored' '
+ test_when_finished "rm -f x.ign .gitignore" &&
+ echo x.ign >.gitignore &&
+ echo "ignore me" >x.ign &&
+
+ cat >expect <<-EOF &&
+ ? .gitignore
+ ? actual
+ ? expect
+ ! x.ign
+ EOF
+
+ git status --porcelain=v2 --ignored --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'create and commit permanent ignore file' '
+ cat >.gitignore <<-EOF &&
+ actual*
+ expect*
+ EOF
+
+ git add .gitignore &&
+ git commit -m ignore_trash &&
+ H1=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $H1
+ # branch.head master
+ EOF
+
+ git status --porcelain=v2 --branch >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'verify --intent-to-add output' '
+ test_when_finished "git rm -f intent1.add intent2.add" &&
+ touch intent1.add &&
+ echo test >intent2.add &&
+
+ git add --intent-to-add intent1.add intent2.add &&
+
+ cat >expect <<-EOF &&
+ 1 AM N... 000000 100644 100644 $_z40 $EMPTY_BLOB intent1.add
+ 1 AM N... 000000 100644 100644 $_z40 $EMPTY_BLOB intent2.add
+ EOF
+
+ git status --porcelain=v2 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'verify AA (add-add) conflict' '
+ test_when_finished "git reset --hard" &&
+
+ git branch AA_A master &&
+ git checkout AA_A &&
+ echo "Branch AA_A" >conflict.txt &&
+ OID_AA_A=$(git hash-object -t blob -- conflict.txt) &&
+ git add conflict.txt &&
+ git commit -m "branch aa_a" &&
+
+ git branch AA_B master &&
+ git checkout AA_B &&
+ echo "Branch AA_B" >conflict.txt &&
+ OID_AA_B=$(git hash-object -t blob -- conflict.txt) &&
+ git add conflict.txt &&
+ git commit -m "branch aa_b" &&
+
+ git branch AA_M AA_B &&
+ git checkout AA_M &&
+ test_must_fail git merge AA_A &&
+
+ HM=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HM
+ # branch.head AA_M
+ u AA N... 000000 100644 100644 100644 $_z40 $OID_AA_B $OID_AA_A conflict.txt
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'verify UU (edit-edit) conflict' '
+ test_when_finished "git reset --hard" &&
+
+ git branch UU_ANC master &&
+ git checkout UU_ANC &&
+ echo "Ancestor" >conflict.txt &&
+ OID_UU_ANC=$(git hash-object -t blob -- conflict.txt) &&
+ git add conflict.txt &&
+ git commit -m "UU_ANC" &&
+
+ git branch UU_A UU_ANC &&
+ git checkout UU_A &&
+ echo "Branch UU_A" >conflict.txt &&
+ OID_UU_A=$(git hash-object -t blob -- conflict.txt) &&
+ git add conflict.txt &&
+ git commit -m "branch uu_a" &&
+
+ git branch UU_B UU_ANC &&
+ git checkout UU_B &&
+ echo "Branch UU_B" >conflict.txt &&
+ OID_UU_B=$(git hash-object -t blob -- conflict.txt) &&
+ git add conflict.txt &&
+ git commit -m "branch uu_b" &&
+
+ git branch UU_M UU_B &&
+ git checkout UU_M &&
+ test_must_fail git merge UU_A &&
+
+ HM=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HM
+ # branch.head UU_M
+ u UU N... 100644 100644 100644 100644 $OID_UU_ANC $OID_UU_B $OID_UU_A conflict.txt
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'verify upstream fields in branch header' '
+ git checkout master &&
+ test_when_finished "rm -rf sub_repo" &&
+ git clone . sub_repo &&
+ (
+ ## Confirm local master tracks remote master.
+ cd sub_repo &&
+ HUF=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HUF
+ # branch.head master
+ # branch.upstream origin/master
+ # branch.ab +0 -0
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual &&
+
+ ## Test ahead/behind.
+ echo xyz >file_xyz &&
+ git add file_xyz &&
+ git commit -m xyz &&
+
+ HUF=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HUF
+ # branch.head master
+ # branch.upstream origin/master
+ # branch.ab +1 -0
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual &&
+
+ ## Repeat the above but without --branch.
+ cat >expect <<-EOF &&
+ EOF
+
+ git status --porcelain=v2 --untracked-files=all >actual &&
+ test_cmp expect actual &&
+
+ ## Test upstream-gone case. Fake this by pointing origin/master at
+ ## a non-existing commit.
+ OLD=$(git rev-parse origin/master) &&
+ NEW=$_z40 &&
+ mv .git/packed-refs .git/old-packed-refs &&
+ sed "s/$OLD/$NEW/g" <.git/old-packed-refs >.git/packed-refs &&
+
+ HUF=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HUF
+ # branch.head master
+ # branch.upstream origin/master
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'create and add submodule, submodule appears clean (A. S...)' '
+ git checkout master &&
+ git clone . sub_repo &&
+ git clone . super_repo &&
+ ( cd super_repo &&
+ git submodule add ../sub_repo sub1 &&
+
+ ## Confirm stage/add of clean submodule.
+ HMOD=$(git hash-object -t blob -- .gitmodules) &&
+ HSUP=$(git rev-parse HEAD) &&
+ HSUB=$HSUP &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HSUP
+ # branch.head master
+ # branch.upstream origin/master
+ # branch.ab +0 -0
+ 1 A. N... 000000 100644 100644 $_z40 $HMOD .gitmodules
+ 1 A. S... 000000 160000 160000 $_z40 $HSUB sub1
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'untracked changes in added submodule (AM S..U)' '
+ ( cd super_repo &&
+ ## create untracked file in the submodule.
+ ( cd sub1 &&
+ echo "xxxx" >file_in_sub
+ ) &&
+
+ HMOD=$(git hash-object -t blob -- .gitmodules) &&
+ HSUP=$(git rev-parse HEAD) &&
+ HSUB=$HSUP &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HSUP
+ # branch.head master
+ # branch.upstream origin/master
+ # branch.ab +0 -0
+ 1 A. N... 000000 100644 100644 $_z40 $HMOD .gitmodules
+ 1 AM S..U 000000 160000 160000 $_z40 $HSUB sub1
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'staged changes in added submodule (AM S.M.)' '
+ ( cd super_repo &&
+ ## stage the changes in the submodule.
+ ( cd sub1 &&
+ git add file_in_sub
+ ) &&
+
+ HMOD=$(git hash-object -t blob -- .gitmodules) &&
+ HSUP=$(git rev-parse HEAD) &&
+ HSUB=$HSUP &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HSUP
+ # branch.head master
+ # branch.upstream origin/master
+ # branch.ab +0 -0
+ 1 A. N... 000000 100644 100644 $_z40 $HMOD .gitmodules
+ 1 AM S.M. 000000 160000 160000 $_z40 $HSUB sub1
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'staged and unstaged changes in added (AM S.M.)' '
+ ( cd super_repo &&
+ ( cd sub1 &&
+ ## make additional unstaged changes (on the same file) in the submodule.
+ ## This does not cause us to get S.MU (because the submodule does not report
+ ## a "?" line for the unstaged changes).
+ echo "more changes" >>file_in_sub
+ ) &&
+
+ HMOD=$(git hash-object -t blob -- .gitmodules) &&
+ HSUP=$(git rev-parse HEAD) &&
+ HSUB=$HSUP &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HSUP
+ # branch.head master
+ # branch.upstream origin/master
+ # branch.ab +0 -0
+ 1 A. N... 000000 100644 100644 $_z40 $HMOD .gitmodules
+ 1 AM S.M. 000000 160000 160000 $_z40 $HSUB sub1
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'staged and untracked changes in added submodule (AM S.MU)' '
+ ( cd super_repo &&
+ ( cd sub1 &&
+ ## stage new changes in tracked file.
+ git add file_in_sub &&
+ ## create new untracked file.
+ echo "yyyy" >>another_file_in_sub
+ ) &&
+
+ HMOD=$(git hash-object -t blob -- .gitmodules) &&
+ HSUP=$(git rev-parse HEAD) &&
+ HSUB=$HSUP &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HSUP
+ # branch.head master
+ # branch.upstream origin/master
+ # branch.ab +0 -0
+ 1 A. N... 000000 100644 100644 $_z40 $HMOD .gitmodules
+ 1 AM S.MU 000000 160000 160000 $_z40 $HSUB sub1
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'commit within the submodule appears as new commit in super (AM SC..)' '
+ ( cd super_repo &&
+ ( cd sub1 &&
+ ## Make a new commit in the submodule.
+ git add file_in_sub &&
+ rm -f another_file_in_sub &&
+ git commit -m "new commit"
+ ) &&
+
+ HMOD=$(git hash-object -t blob -- .gitmodules) &&
+ HSUP=$(git rev-parse HEAD) &&
+ HSUB=$HSUP &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HSUP
+ # branch.head master
+ # branch.upstream origin/master
+ # branch.ab +0 -0
+ 1 A. N... 000000 100644 100644 $_z40 $HMOD .gitmodules
+ 1 AM SC.. 000000 160000 160000 $_z40 $HSUB sub1
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'stage submodule in super and commit' '
+ ( cd super_repo &&
+ ## Stage the new submodule commit in the super.
+ git add sub1 &&
+ ## Commit the super so that the sub no longer appears as added.
+ git commit -m "super commit" &&
+
+ HSUP=$(git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HSUP
+ # branch.head master
+ # branch.upstream origin/master
+ # branch.ab +1 -0
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'make unstaged changes in existing submodule (.M S.M.)' '
+ ( cd super_repo &&
+ ( cd sub1 &&
+ echo "zzzz" >>file_in_sub
+ ) &&
+
+ HSUP=$(git rev-parse HEAD) &&
+ HSUB=$(cd sub1 && git rev-parse HEAD) &&
+
+ cat >expect <<-EOF &&
+ # branch.oid $HSUP
+ # branch.head master
+ # branch.upstream origin/master
+ # branch.ab +1 -0
+ 1 .M S.M. 160000 160000 160000 $HSUB $HSUB sub1
+ EOF
+
+ git status --porcelain=v2 --branch --untracked-files=all >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_done
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index eaea19b8f2..1c1e289ffd 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -8,74 +8,121 @@ test_description='test clone --reference'
base_dir=$(pwd)
-U=$base_dir/UPLOAD_LOG
-
-test_expect_success 'preparing first repository' \
-'test_create_repo A && cd A &&
-echo first > file1 &&
-git add file1 &&
-git commit -m A-initial'
-
-cd "$base_dir"
-
-test_expect_success 'preparing second repository' \
-'git clone A B && cd B &&
-echo second > file2 &&
-git add file2 &&
-git commit -m B-addition &&
-git repack -a -d &&
-git prune'
-
-cd "$base_dir"
-
-test_expect_success 'preparing superproject' \
-'test_create_repo super && cd super &&
-echo file > file &&
-git add file &&
-git commit -m B-super-initial'
-
-cd "$base_dir"
-
-test_expect_success 'submodule add --reference' \
-'cd super && git submodule add --reference ../B "file://$base_dir/A" sub &&
-git commit -m B-super-added'
-
-cd "$base_dir"
-
-test_expect_success 'after add: existence of info/alternates' \
-'test_line_count = 1 super/.git/modules/sub/objects/info/alternates'
-
-cd "$base_dir"
-
-test_expect_success 'that reference gets used with add' \
-'cd super/sub &&
-echo "0 objects, 0 kilobytes" > expected &&
-git count-objects > current &&
-diff expected current'
-
-cd "$base_dir"
-
-test_expect_success 'cloning superproject' \
-'git clone super super-clone'
-
-cd "$base_dir"
-
-test_expect_success 'update with reference' \
-'cd super-clone && git submodule update --init --reference ../B'
-
-cd "$base_dir"
-
-test_expect_success 'after update: existence of info/alternates' \
-'test_line_count = 1 super-clone/.git/modules/sub/objects/info/alternates'
-
-cd "$base_dir"
-
-test_expect_success 'that reference gets used with update' \
-'cd super-clone/sub &&
-echo "0 objects, 0 kilobytes" > expected &&
-git count-objects > current &&
-diff expected current'
-
-cd "$base_dir"
+test_alternate_is_used () {
+ alternates_file="$1" &&
+ working_dir="$2" &&
+ test_line_count = 1 "$alternates_file" &&
+ echo "0 objects, 0 kilobytes" >expect &&
+ git -C "$working_dir" count-objects >actual &&
+ test_cmp expect actual
+}
+
+test_expect_success 'preparing first repository' '
+ test_create_repo A &&
+ (
+ cd A &&
+ echo first >file1 &&
+ git add file1 &&
+ git commit -m A-initial
+ )
+'
+
+test_expect_success 'preparing second repository' '
+ git clone A B &&
+ (
+ cd B &&
+ echo second >file2 &&
+ git add file2 &&
+ git commit -m B-addition &&
+ git repack -a -d &&
+ git prune
+ )
+'
+
+test_expect_success 'preparing superproject' '
+ test_create_repo super &&
+ (
+ cd super &&
+ echo file >file &&
+ git add file &&
+ git commit -m B-super-initial
+ )
+'
+
+test_expect_success 'submodule add --reference uses alternates' '
+ (
+ cd super &&
+ git submodule add --reference ../B "file://$base_dir/A" sub &&
+ git commit -m B-super-added &&
+ git repack -ad
+ ) &&
+ test_alternate_is_used super/.git/modules/sub/objects/info/alternates super/sub
+'
+
+test_expect_success 'that reference gets used with add' '
+ (
+ cd super/sub &&
+ echo "0 objects, 0 kilobytes" >expected &&
+ git count-objects >current &&
+ diff expected current
+ )
+'
+
+# The tests up to this point, and repositories created by them
+# (A, B, super and super/sub), are about setting up the stage
+# for subsequent tests and meant to be kept throughout the
+# remainder of the test.
+# Tests from here on, if they create their own test repository,
+# are expected to clean after themselves.
+
+test_expect_success 'updating superproject keeps alternates' '
+ test_when_finished "rm -rf super-clone" &&
+ git clone super super-clone &&
+ git -C super-clone submodule update --init --reference ../B &&
+ test_alternate_is_used super-clone/.git/modules/sub/objects/info/alternates super-clone/sub
+'
+
+test_expect_success 'submodules use alternates when cloning a superproject' '
+ test_when_finished "rm -rf super-clone" &&
+ git clone --reference super --recursive super super-clone &&
+ (
+ cd super-clone &&
+ # test superproject has alternates setup correctly
+ test_alternate_is_used .git/objects/info/alternates . &&
+ # test submodule has correct setup
+ test_alternate_is_used .git/modules/sub/objects/info/alternates sub
+ )
+'
+
+test_expect_success 'missing submodule alternate fails clone and submodule update' '
+ test_when_finished "rm -rf super-clone" &&
+ git clone super super2 &&
+ test_must_fail git clone --recursive --reference super2 super2 super-clone &&
+ (
+ cd super-clone &&
+ # test superproject has alternates setup correctly
+ test_alternate_is_used .git/objects/info/alternates . &&
+ # update of the submodule succeeds
+ test_must_fail git submodule update --init &&
+ # and we have no alternates:
+ test_must_fail test_alternate_is_used .git/modules/sub/objects/info/alternates sub &&
+ test_must_fail test_path_is_file sub/file1
+ )
+'
+
+test_expect_success 'ignoring missing submodule alternates passes clone and submodule update' '
+ test_when_finished "rm -rf super-clone" &&
+ git clone --reference-if-able super2 --recursive super2 super-clone &&
+ (
+ cd super-clone &&
+ # test superproject has alternates setup correctly
+ test_alternate_is_used .git/objects/info/alternates . &&
+ # update of the submodule succeeds
+ git submodule update --init &&
+ # and we have no alternates:
+ test_must_fail test_alternate_is_used .git/modules/sub/objects/info/alternates sub &&
+ test_path_is_file sub/file1
+ )
+'
test_done
diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh
index e48370dfa0..661f9d430d 100755
--- a/t/t8003-blame-corner-cases.sh
+++ b/t/t8003-blame-corner-cases.sh
@@ -212,12 +212,12 @@ EOF
test_expect_success 'blame -L with invalid start' '
test_must_fail git blame -L5 tres 2>errors &&
- grep "has only 2 lines" errors
+ test_i18ngrep "has only 2 lines" errors
'
test_expect_success 'blame -L with invalid end' '
test_must_fail git blame -L1,5 tres 2>errors &&
- grep "has only 2 lines" errors
+ test_i18ngrep "has only 2 lines" errors
'
test_expect_success 'blame parses <end> part of -L' '
diff --git a/t/t8010-cat-file-filters.sh b/t/t8010-cat-file-filters.sh
new file mode 100755
index 0000000000..d8242e467e
--- /dev/null
+++ b/t/t8010-cat-file-filters.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+test_description='git cat-file filters support'
+. ./test-lib.sh
+
+test_expect_success 'setup ' '
+ echo "*.txt eol=crlf diff=txt" >.gitattributes &&
+ echo "hello" | append_cr >world.txt &&
+ git add .gitattributes world.txt &&
+ test_tick &&
+ git commit -m "Initial commit"
+'
+
+has_cr () {
+ tr '\015' Q <"$1" | grep Q >/dev/null
+}
+
+test_expect_success 'no filters with `git show`' '
+ git show HEAD:world.txt >actual &&
+ ! has_cr actual
+
+'
+
+test_expect_success 'no filters with cat-file' '
+ git cat-file blob HEAD:world.txt >actual &&
+ ! has_cr actual
+'
+
+test_expect_success 'cat-file --filters converts to worktree version' '
+ git cat-file --filters HEAD:world.txt >actual &&
+ has_cr actual
+'
+
+test_expect_success 'cat-file --filters --path=<path> works' '
+ sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
+ git cat-file --filters --path=world.txt $sha1 >actual &&
+ has_cr actual
+'
+
+test_expect_success 'cat-file --textconv --path=<path> works' '
+ sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
+ test_config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <" &&
+ git cat-file --textconv --path=hello.txt $sha1 >rot13 &&
+ test uryyb = "$(cat rot13 | remove_cr)"
+'
+
+test_expect_success '--path=<path> complains without --textconv/--filters' '
+ sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
+ test_must_fail git cat-file --path=hello.txt blob $sha1 >actual 2>err &&
+ test ! -s actual &&
+ grep "path.*needs.*filters" err
+'
+
+test_expect_success 'cat-file --textconv --batch works' '
+ sha1=$(git rev-parse -q --verify HEAD:world.txt) &&
+ test_config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <" &&
+ printf "%s hello.txt\n%s hello\n" $sha1 $sha1 |
+ git cat-file --textconv --batch >actual &&
+ printf "%s blob 6\nuryyb\r\n\n%s blob 6\nhello\n\n" \
+ $sha1 $sha1 >expect &&
+ test_cmp expect actual
+'
+
+test_done
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index e94b2f147a..6d06ed96cb 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -709,6 +709,14 @@ test_expect_success HIGHLIGHT \
git commit -m "Add test.sh" &&
gitweb_run "p=.git;a=blob;f=test.sh"'
+test_expect_success HIGHLIGHT \
+ 'syntax highlighting (highlighter language autodetection)' \
+ 'git config gitweb.highlight yes &&
+ echo "#!/usr/bin/perl" > test &&
+ git add test &&
+ git commit -m "Add test" &&
+ gitweb_run "p=.git;a=blob;f=test"'
+
# ----------------------------------------------------------------------
# forks of projects
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 4f7eadb596..fdaeb3a96b 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -81,6 +81,10 @@ test_decode_color () {
'
}
+lf_to_nul () {
+ perl -pe 'y/\012/\000/'
+}
+
nul_to_q () {
perl -pe 'y/\000/Q/'
}
diff --git a/t/test-lib.sh b/t/test-lib.sh
index ac56512a1c..11562bde10 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1073,6 +1073,10 @@ test_lazy_prereq NOT_ROOT '
test "$uid" != 0
'
+test_lazy_prereq JGIT '
+ type jgit
+'
+
# SANITY is about "can you correctly predict what the filesystem would
# do by only looking at the permission bits of the files and
# directories?" A typical example of !SANITY is running the test