summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rwxr-xr-xt/lib-submodule-update.sh680
-rwxr-xr-xt/t0011-hashmap.sh13
-rwxr-xr-xt/t1013-read-tree-submodule.sh12
-rwxr-xr-xt/t1402-check-ref-format.sh16
-rwxr-xr-xt/t2013-checkout-submodule.sh5
-rwxr-xr-xt/t3400-rebase.sh23
-rwxr-xr-xt/t3426-rebase-submodule.sh46
-rwxr-xr-xt/t3512-cherry-pick-submodule.sh13
-rwxr-xr-xt/t3513-revert-submodule.sh32
-rwxr-xr-xt/t3906-stash-submodule.sh24
-rwxr-xr-xt/t4013-diff-various.sh10
-rwxr-xr-xt/t4041-diff-submodule-option.sh6
-rwxr-xr-xt/t4137-apply-submodule.sh20
-rwxr-xr-xt/t4205-log-pretty-formats.sh2
-rwxr-xr-xt/t4255-am-submodule.sh21
-rwxr-xr-xt/t5539-fetch-http-shallow.sh1
-rwxr-xr-xt/t5572-pull-submodule.sh45
-rwxr-xr-xt/t6006-rev-list-format.sh4
-rwxr-xr-xt/t6041-bisect-submodule.sh32
-rwxr-xr-xt/t6050-replace.sh139
-rwxr-xr-xt/t7004-tag.sh76
-rwxr-xr-xt/t7102-reset.sh8
-rwxr-xr-xt/t7112-reset-submodule.sh14
-rwxr-xr-xt/t7613-merge-submodule.sh19
-rwxr-xr-xt/t7702-repack-cyclic-alternate.sh24
-rwxr-xr-xt/t9814-git-p4-rename.sh10
-rw-r--r--t/test-lib-functions.sh11
-rw-r--r--t/test-lib.sh4
-rw-r--r--t/valgrind/default.supp15
29 files changed, 1241 insertions, 84 deletions
diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
new file mode 100755
index 0000000000..79cdd34a54
--- /dev/null
+++ b/t/lib-submodule-update.sh
@@ -0,0 +1,680 @@
+# Create a submodule layout used for all tests below.
+#
+# The following use cases are covered:
+# - New submodule (no_submodule => add_sub1)
+# - Removed submodule (add_sub1 => remove_sub1)
+# - Updated submodule (add_sub1 => modify_sub1)
+# - Submodule updated to invalid commit (add_sub1 => invalid_sub1)
+# - Submodule updated from invalid commit (invalid_sub1 => valid_sub1)
+# - Submodule replaced by tracked files in directory (add_sub1 =>
+# replace_sub1_with_directory)
+# - Directory containing tracked files replaced by submodule
+# (replace_sub1_with_directory => replace_directory_with_sub1)
+# - Submodule replaced by tracked file with the same name (add_sub1 =>
+# replace_sub1_with_file)
+# - Tracked file replaced by submodule (replace_sub1_with_file =>
+# replace_file_with_sub1)
+#
+# --O-----O
+# / ^ replace_directory_with_sub1
+# / replace_sub1_with_directory
+# /----O
+# / ^
+# / modify_sub1
+# O------O-------O
+# ^ ^\ ^
+# | | \ remove_sub1
+# | | -----O-----O
+# | | \ ^ replace_file_with_sub1
+# | | \ replace_sub1_with_file
+# | add_sub1 --O-----O
+# no_submodule ^ valid_sub1
+# invalid_sub1
+#
+create_lib_submodule_repo () {
+ git init submodule_update_repo &&
+ (
+ cd submodule_update_repo &&
+ echo "expect" >>.gitignore &&
+ echo "actual" >>.gitignore &&
+ echo "x" >file1 &&
+ echo "y" >file2 &&
+ git add .gitignore file1 file2 &&
+ git commit -m "Base" &&
+ git branch "no_submodule" &&
+
+ git checkout -b "add_sub1" &&
+ git submodule add ./. sub1 &&
+ git config -f .gitmodules submodule.sub1.ignore all &&
+ git config submodule.sub1.ignore all &&
+ git add .gitmodules &&
+ git commit -m "Add sub1" &&
+ git checkout -b remove_sub1 &&
+ git revert HEAD &&
+
+ git checkout -b "modify_sub1" "add_sub1" &&
+ git submodule update &&
+ (
+ cd sub1 &&
+ git fetch &&
+ git checkout -b "modifications" &&
+ echo "z" >file2 &&
+ echo "x" >file3 &&
+ git add file2 file3 &&
+ git commit -m "modified file2 and added file3" &&
+ git push origin modifications
+ ) &&
+ git add sub1 &&
+ git commit -m "Modify sub1" &&
+
+ git checkout -b "replace_sub1_with_directory" "add_sub1" &&
+ git submodule update &&
+ (
+ cd sub1 &&
+ git checkout modifications
+ ) &&
+ git rm --cached sub1 &&
+ rm sub1/.git* &&
+ git config -f .gitmodules --remove-section "submodule.sub1" &&
+ git add .gitmodules sub1/* &&
+ git commit -m "Replace sub1 with directory" &&
+ git checkout -b replace_directory_with_sub1 &&
+ git revert HEAD &&
+
+ git checkout -b "replace_sub1_with_file" "add_sub1" &&
+ git rm sub1 &&
+ echo "content" >sub1 &&
+ git add sub1 &&
+ git commit -m "Replace sub1 with file" &&
+ git checkout -b replace_file_with_sub1 &&
+ git revert HEAD &&
+
+ git checkout -b "invalid_sub1" "add_sub1" &&
+ git update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 &&
+ git commit -m "Invalid sub1 commit" &&
+ git checkout -b valid_sub1 &&
+ git revert HEAD &&
+ git checkout master
+ )
+}
+
+# Helper function to replace gitfile with .git directory
+replace_gitfile_with_git_dir () {
+ (
+ cd "$1" &&
+ git_dir="$(git rev-parse --git-dir)" &&
+ rm -f .git &&
+ cp -R "$git_dir" .git &&
+ GIT_WORK_TREE=. git config --unset core.worktree
+ )
+}
+
+# Test that the .git directory in the submodule is unchanged (except for the
+# core.worktree setting, which appears only in $GIT_DIR/modules/$1/config).
+# Call this function before test_submodule_content as the latter might
+# write the index file leading to false positive index differences.
+#
+# Note that this only supports submodules at the root level of the
+# superproject, with the default name, i.e. same as its path.
+test_git_directory_is_unchanged () {
+ (
+ cd ".git/modules/$1" &&
+ # does core.worktree point at the right place?
+ test "$(git config core.worktree)" = "../../../$1" &&
+ # remove it temporarily before comparing, as
+ # "$1/.git/config" lacks it...
+ git config --unset core.worktree
+ ) &&
+ diff -r ".git/modules/$1" "$1/.git" &&
+ (
+ # ... and then restore.
+ cd ".git/modules/$1" &&
+ git config core.worktree "../../../$1"
+ )
+}
+
+# Helper function to be executed at the start of every test below, it sets up
+# the submodule repo if it doesn't exist and configures the most problematic
+# settings for diff.ignoreSubmodules.
+prolog () {
+ (test -d submodule_update_repo || create_lib_submodule_repo) &&
+ test_config_global diff.ignoreSubmodules all &&
+ test_config diff.ignoreSubmodules all
+}
+
+# Helper function to bring work tree back into the state given by the
+# commit. This includes trying to populate sub1 accordingly if it exists and
+# should be updated to an existing commit.
+reset_work_tree_to () {
+ rm -rf submodule_update &&
+ git clone submodule_update_repo submodule_update &&
+ (
+ cd submodule_update &&
+ rm -rf sub1 &&
+ git checkout -f "$1" &&
+ git status -u -s >actual &&
+ test_must_be_empty actual &&
+ sha1=$(git rev-parse --revs-only HEAD:sub1) &&
+ if test -n "$sha1" &&
+ test $(cd "sub1" && git rev-parse --verify "$sha1^{commit}")
+ then
+ git submodule update --init --recursive "sub1"
+ fi
+ )
+}
+
+# Test that the superproject contains the content according to commit "$1"
+# (the work tree must match the index for everything but submodules but the
+# index must exactly match the given commit including any submodule SHA-1s).
+test_superproject_content () {
+ git diff-index --cached "$1" >actual &&
+ test_must_be_empty actual &&
+ git diff-files --ignore-submodules >actual &&
+ test_must_be_empty actual
+}
+
+# Test that the given submodule at path "$1" contains the content according
+# to the submodule commit recorded in the superproject's commit "$2"
+test_submodule_content () {
+ if test $# != 2
+ then
+ echo "test_submodule_content needs two arguments"
+ return 1
+ fi &&
+ submodule="$1" &&
+ commit="$2" &&
+ test -d "$submodule"/ &&
+ if ! test -f "$submodule"/.git && ! test -d "$submodule"/.git
+ then
+ echo "Submodule $submodule is not populated"
+ return 1
+ fi &&
+ sha1=$(git rev-parse --verify "$commit:$submodule") &&
+ if test -z "$sha1"
+ then
+ echo "Couldn't retrieve SHA-1 of $submodule for $commit"
+ return 1
+ fi &&
+ (
+ cd "$submodule" &&
+ git status -u -s >actual &&
+ test_must_be_empty actual &&
+ git diff "$sha1" >actual &&
+ test_must_be_empty actual
+ )
+}
+
+# Test that the following transitions are correctly handled:
+# - Updated submodule
+# - New submodule
+# - Removed submodule
+# - Directory containing tracked files replaced by submodule
+# - Submodule replaced by tracked files in directory
+# - Submodule replaced by tracked file with the same name
+# - tracked file replaced by submodule
+#
+# The default is that submodule contents aren't changed until "git submodule
+# update" is run. And even then that command doesn't delete the work tree of
+# a removed submodule.
+#
+# Removing a submodule containing a .git directory must fail even when forced
+# to protect the history!
+#
+
+# Test that submodule contents are currently not updated when switching
+# between commits that change a submodule.
+test_submodule_switch () {
+ command="$1"
+ ######################### Appearing submodule #########################
+ # Switching to a commit letting a submodule appear creates empty dir ...
+ if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
+ then
+ # Restoring stash fails to restore submodule index entry
+ RESULT="failure"
+ else
+ RESULT="success"
+ fi
+ test_expect_$RESULT "$command: added submodule creates empty directory" '
+ prolog &&
+ reset_work_tree_to no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_dir_is_empty sub1 &&
+ git submodule update --init --recursive &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... and doesn't care if it already exists ...
+ test_expect_$RESULT "$command: added submodule leaves existing empty directory alone" '
+ prolog &&
+ reset_work_tree_to no_submodule &&
+ (
+ cd submodule_update &&
+ mkdir sub1 &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_dir_is_empty sub1 &&
+ git submodule update --init --recursive &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... unless there is an untracked file in its place.
+ test_expect_success "$command: added submodule doesn't remove untracked unignored file with same name" '
+ prolog &&
+ reset_work_tree_to no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ >sub1 &&
+ test_must_fail $command add_sub1 &&
+ test_superproject_content origin/no_submodule &&
+ test_must_be_empty sub1
+ )
+ '
+ # Replacing a tracked file with a submodule produces an empty
+ # directory ...
+ test_expect_$RESULT "$command: replace tracked file with submodule creates empty directory" '
+ prolog &&
+ reset_work_tree_to replace_sub1_with_file &&
+ (
+ cd submodule_update &&
+ git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
+ $command replace_file_with_sub1 &&
+ test_superproject_content origin/replace_file_with_sub1 &&
+ test_dir_is_empty sub1 &&
+ git submodule update --init --recursive &&
+ test_submodule_content sub1 origin/replace_file_with_sub1
+ )
+ '
+ # ... as does removing a directory with tracked files with a
+ # submodule.
+ if test "$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR" = 1
+ then
+ # Non fast-forward merges fail with "Directory sub1 doesn't
+ # exist. sub1" because the empty submodule directory is not
+ # created
+ RESULT="failure"
+ else
+ RESULT="success"
+ fi
+ test_expect_$RESULT "$command: replace directory with submodule" '
+ prolog &&
+ reset_work_tree_to replace_sub1_with_directory &&
+ (
+ cd submodule_update &&
+ git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
+ $command replace_directory_with_sub1 &&
+ test_superproject_content origin/replace_directory_with_sub1 &&
+ test_dir_is_empty sub1 &&
+ git submodule update --init --recursive &&
+ test_submodule_content sub1 origin/replace_directory_with_sub1
+ )
+ '
+
+ ######################## Disappearing submodule #######################
+ # Removing a submodule doesn't remove its work tree ...
+ if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
+ then
+ RESULT="failure"
+ else
+ RESULT="success"
+ fi
+ test_expect_$RESULT "$command: removed submodule leaves submodule directory and its contents in place" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t remove_sub1 origin/remove_sub1 &&
+ $command remove_sub1 &&
+ test_superproject_content origin/remove_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... especially when it contains a .git directory.
+ test_expect_$RESULT "$command: removed submodule leaves submodule containing a .git directory alone" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t remove_sub1 origin/remove_sub1 &&
+ replace_gitfile_with_git_dir sub1 &&
+ $command remove_sub1 &&
+ test_superproject_content origin/remove_sub1 &&
+ test_git_directory_is_unchanged sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # Replacing a submodule with files in a directory must fail as the
+ # submodule work tree isn't removed ...
+ if test "$KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES" = 1
+ then
+ # Non fast-forward merges attempt to merge the former
+ # submodule files with the newly checked out ones in the
+ # directory of the same name while it shouldn't.
+ RESULT="failure"
+ else
+ RESULT="success"
+ fi
+ test_expect_$RESULT "$command: replace submodule with a directory must fail" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+ test_must_fail $command replace_sub1_with_directory &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... especially when it contains a .git directory.
+ test_expect_$RESULT "$command: replace submodule containing a .git directory with a directory must fail" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+ replace_gitfile_with_git_dir sub1 &&
+ test_must_fail $command replace_sub1_with_directory &&
+ test_superproject_content origin/add_sub1 &&
+ test_git_directory_is_unchanged sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # Replacing it with a file must fail as it could throw away any local
+ # work tree changes ...
+ test_expect_failure "$command: replace submodule with a file must fail" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ test_must_fail $command replace_sub1_with_file &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... or even destroy unpushed parts of submodule history if that
+ # still uses a .git directory.
+ test_expect_failure "$command: replace submodule containing a .git directory with a file must fail" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ replace_gitfile_with_git_dir sub1 &&
+ test_must_fail $command replace_sub1_with_file &&
+ test_superproject_content origin/add_sub1 &&
+ test_git_directory_is_unchanged sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+
+ ########################## Modified submodule #########################
+ # Updating a submodule sha1 doesn't update the submodule's work tree
+ if test "$KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT" = 1
+ then
+ # When cherry picking a SHA-1 update for an ignored submodule
+ # the commit incorrectly fails with "The previous cherry-pick
+ # is now empty, possibly due to conflict resolution."
+ RESULT="failure"
+ else
+ RESULT="success"
+ fi
+ test_expect_$RESULT "$command: modified submodule does not update submodule work tree" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t modify_sub1 origin/modify_sub1 &&
+ $command modify_sub1 &&
+ test_superproject_content origin/modify_sub1 &&
+ test_submodule_content sub1 origin/add_sub1 &&
+ git submodule update &&
+ test_submodule_content sub1 origin/modify_sub1
+ )
+ '
+
+ # Updating a submodule to an invalid sha1 doesn't update the
+ # submodule's work tree, subsequent update will fail
+ test_expect_$RESULT "$command: modified submodule does not update submodule work tree to invalid commit" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t invalid_sub1 origin/invalid_sub1 &&
+ $command invalid_sub1 &&
+ test_superproject_content origin/invalid_sub1 &&
+ test_submodule_content sub1 origin/add_sub1 &&
+ test_must_fail git submodule update &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # Updating a submodule from an invalid sha1 doesn't update the
+ # submodule's work tree, subsequent update will succeed
+ test_expect_$RESULT "$command: modified submodule does not update submodule work tree from invalid commit" '
+ prolog &&
+ reset_work_tree_to invalid_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t valid_sub1 origin/valid_sub1 &&
+ $command valid_sub1 &&
+ test_superproject_content origin/valid_sub1 &&
+ test_dir_is_empty sub1 &&
+ git submodule update --init --recursive &&
+ test_submodule_content sub1 origin/valid_sub1
+ )
+ '
+}
+
+# Test that submodule contents are currently not updated when switching
+# between commits that change a submodule, but throwing away local changes in
+# the superproject is allowed.
+test_submodule_forced_switch () {
+ command="$1"
+ ######################### Appearing submodule #########################
+ # Switching to a commit letting a submodule appear creates empty dir ...
+ test_expect_success "$command: added submodule creates empty directory" '
+ prolog &&
+ reset_work_tree_to no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_dir_is_empty sub1 &&
+ git submodule update --init --recursive &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... and doesn't care if it already exists ...
+ test_expect_success "$command: added submodule leaves existing empty directory alone" '
+ prolog &&
+ reset_work_tree_to no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ mkdir sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_dir_is_empty sub1 &&
+ git submodule update --init --recursive &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... unless there is an untracked file in its place.
+ test_expect_success "$command: added submodule does remove untracked unignored file with same name when forced" '
+ prolog &&
+ reset_work_tree_to no_submodule &&
+ (
+ cd submodule_update &&
+ git branch -t add_sub1 origin/add_sub1 &&
+ >sub1 &&
+ $command add_sub1 &&
+ test_superproject_content origin/add_sub1 &&
+ test_dir_is_empty sub1
+ )
+ '
+ # Replacing a tracked file with a submodule produces an empty
+ # directory ...
+ test_expect_success "$command: replace tracked file with submodule creates empty directory" '
+ prolog &&
+ reset_work_tree_to replace_sub1_with_file &&
+ (
+ cd submodule_update &&
+ git branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&
+ $command replace_file_with_sub1 &&
+ test_superproject_content origin/replace_file_with_sub1 &&
+ test_dir_is_empty sub1 &&
+ git submodule update --init --recursive &&
+ test_submodule_content sub1 origin/replace_file_with_sub1
+ )
+ '
+ # ... as does removing a directory with tracked files with a
+ # submodule.
+ test_expect_success "$command: replace directory with submodule" '
+ prolog &&
+ reset_work_tree_to replace_sub1_with_directory &&
+ (
+ cd submodule_update &&
+ git branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&
+ $command replace_directory_with_sub1 &&
+ test_superproject_content origin/replace_directory_with_sub1 &&
+ test_dir_is_empty sub1 &&
+ git submodule update --init --recursive &&
+ test_submodule_content sub1 origin/replace_directory_with_sub1
+ )
+ '
+
+ ######################## Disappearing submodule #######################
+ # Removing a submodule doesn't remove its work tree ...
+ test_expect_success "$command: removed submodule leaves submodule directory and its contents in place" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t remove_sub1 origin/remove_sub1 &&
+ $command remove_sub1 &&
+ test_superproject_content origin/remove_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... especially when it contains a .git directory.
+ test_expect_success "$command: removed submodule leaves submodule containing a .git directory alone" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t remove_sub1 origin/remove_sub1 &&
+ replace_gitfile_with_git_dir sub1 &&
+ $command remove_sub1 &&
+ test_superproject_content origin/remove_sub1 &&
+ test_git_directory_is_unchanged sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # Replacing a submodule with files in a directory must fail as the
+ # submodule work tree isn't removed ...
+ test_expect_failure "$command: replace submodule with a directory must fail" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+ test_must_fail $command replace_sub1_with_directory &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... especially when it contains a .git directory.
+ test_expect_failure "$command: replace submodule containing a .git directory with a directory must fail" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&
+ replace_gitfile_with_git_dir sub1 &&
+ test_must_fail $command replace_sub1_with_directory &&
+ test_superproject_content origin/add_sub1 &&
+ test_git_directory_is_unchanged sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # Replacing it with a file must fail as it could throw away any local
+ # work tree changes ...
+ test_expect_failure "$command: replace submodule with a file must fail" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ test_must_fail $command replace_sub1_with_file &&
+ test_superproject_content origin/add_sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # ... or even destroy unpushed parts of submodule history if that
+ # still uses a .git directory.
+ test_expect_failure "$command: replace submodule containing a .git directory with a file must fail" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t replace_sub1_with_file origin/replace_sub1_with_file &&
+ replace_gitfile_with_git_dir sub1 &&
+ test_must_fail $command replace_sub1_with_file &&
+ test_superproject_content origin/add_sub1 &&
+ test_git_directory_is_unchanged sub1 &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+
+ ########################## Modified submodule #########################
+ # Updating a submodule sha1 doesn't update the submodule's work tree
+ test_expect_success "$command: modified submodule does not update submodule work tree" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t modify_sub1 origin/modify_sub1 &&
+ $command modify_sub1 &&
+ test_superproject_content origin/modify_sub1 &&
+ test_submodule_content sub1 origin/add_sub1 &&
+ git submodule update &&
+ test_submodule_content sub1 origin/modify_sub1
+ )
+ '
+ # Updating a submodule to an invalid sha1 doesn't update the
+ # submodule's work tree, subsequent update will fail
+ test_expect_success "$command: modified submodule does not update submodule work tree to invalid commit" '
+ prolog &&
+ reset_work_tree_to add_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t invalid_sub1 origin/invalid_sub1 &&
+ $command invalid_sub1 &&
+ test_superproject_content origin/invalid_sub1 &&
+ test_submodule_content sub1 origin/add_sub1 &&
+ test_must_fail git submodule update &&
+ test_submodule_content sub1 origin/add_sub1
+ )
+ '
+ # Updating a submodule from an invalid sha1 doesn't update the
+ # submodule's work tree, subsequent update will succeed
+ test_expect_success "$command: modified submodule does not update submodule work tree from invalid commit" '
+ prolog &&
+ reset_work_tree_to invalid_sub1 &&
+ (
+ cd submodule_update &&
+ git branch -t valid_sub1 origin/valid_sub1 &&
+ $command valid_sub1 &&
+ test_superproject_content origin/valid_sub1 &&
+ test_dir_is_empty sub1 &&
+ git submodule update --init --recursive &&
+ test_submodule_content sub1 origin/valid_sub1
+ )
+ '
+}
diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh
index 391e2b6492..f97c80556f 100755
--- a/t/t0011-hashmap.sh
+++ b/t/t0011-hashmap.sh
@@ -237,4 +237,17 @@ test_expect_success 'grow / shrink' '
'
+test_expect_success 'string interning' '
+
+test_hashmap "intern value1
+intern Value1
+intern value2
+intern value2
+" "value1
+Value1
+value2
+value2"
+
+'
+
test_done
diff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh
new file mode 100755
index 0000000000..20526aed34
--- /dev/null
+++ b/t/t1013-read-tree-submodule.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+test_description='read-tree can handle submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+
+test_submodule_switch "git read-tree -u -m"
+
+test_submodule_forced_switch "git read-tree -u --reset"
+
+test_done
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index 9aeb352b3d..4bc7141226 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -48,6 +48,7 @@ invalid_ref './foo/bar'
invalid_ref 'foo/./bar'
invalid_ref 'foo/bar/.'
invalid_ref '.refs/foo'
+invalid_ref 'refs/heads/foo.'
invalid_ref 'heads/foo..bar'
invalid_ref 'heads/foo?bar'
valid_ref 'foo./bar'
@@ -64,7 +65,6 @@ valid_ref "$(printf 'heads/fu\303\237')"
invalid_ref 'heads/*foo/bar' --refspec-pattern
invalid_ref 'heads/foo*/bar' --refspec-pattern
invalid_ref 'heads/f*o/bar' --refspec-pattern
-invalid_ref 'heads/foo*//bar' --refspec-pattern
ref='foo'
invalid_ref "$ref"
@@ -129,20 +129,6 @@ valid_ref NOT_MINGW "$ref" '--allow-onelevel --normalize'
invalid_ref NOT_MINGW "$ref" '--refspec-pattern --normalize'
valid_ref NOT_MINGW "$ref" '--refspec-pattern --allow-onelevel --normalize'
-
-valid_ref 'refs/heads/a-very-long-refname'
-invalid_ref 'refs/heads/.a-very-long-refname'
-invalid_ref 'refs/heads/abcdefgh0123..'
-invalid_ref 'refs/heads/abcdefgh01234..'
-invalid_ref 'refs/heads/abcdefgh012345..'
-invalid_ref 'refs/heads/abcdefgh0123456..'
-invalid_ref 'refs/heads/abcdefgh01234567..'
-valid_ref 'refs/heads/abcdefgh0123.a'
-valid_ref 'refs/heads/abcdefgh01234.a'
-valid_ref 'refs/heads/abcdefgh012345.a'
-valid_ref 'refs/heads/abcdefgh0123456.a'
-valid_ref 'refs/heads/abcdefgh01234567.a'
-
test_expect_success "check-ref-format --branch @{-1}" '
T=$(git write-tree) &&
sha1=$(echo A | git commit-tree $T) &&
diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh
index 06b18f8bc1..6847f75822 100755
--- a/t/t2013-checkout-submodule.sh
+++ b/t/t2013-checkout-submodule.sh
@@ -3,6 +3,7 @@
test_description='checkout can handle submodules'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
test_expect_success 'setup' '
mkdir submodule &&
@@ -62,4 +63,8 @@ test_expect_success '"checkout <submodule>" honors submodule.*.ignore from .git/
! test -s actual
'
+test_submodule_switch "git checkout"
+
+test_submodule_forced_switch "git checkout -f"
+
test_done
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 80e0a951ea..47b5682662 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -169,6 +169,29 @@ test_expect_success 'default to common base in @{upstream}s reflog if no upstrea
test_cmp expect actual
'
+test_expect_success 'cherry-picked commits and fork-point work together' '
+ git checkout default-base &&
+ echo Amended >A &&
+ git commit -a --no-edit --amend &&
+ test_commit B B &&
+ test_commit new_B B "New B" &&
+ test_commit C C &&
+ git checkout default &&
+ git reset --hard default-base@{4} &&
+ test_commit D D &&
+ git cherry-pick -2 default-base^ &&
+ test_commit final_B B "Final B" &&
+ git rebase &&
+ echo Amended >expect &&
+ test_cmp A expect &&
+ echo "Final B" >expect &&
+ test_cmp B expect &&
+ echo C >expect &&
+ test_cmp C expect &&
+ echo D >expect &&
+ test_cmp D expect
+'
+
test_expect_success 'rebase -q is quiet' '
git checkout -b quiet topic &&
git rebase -q master >output.out 2>&1 &&
diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh
new file mode 100755
index 0000000000..d5b896d445
--- /dev/null
+++ b/t/t3426-rebase-submodule.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+test_description='rebase can handle submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
+git_rebase () {
+ git status -su >expect &&
+ ls -1pR * >>expect &&
+ git checkout -b ours HEAD &&
+ echo x >>file1 &&
+ git add file1 &&
+ git commit -m add_x &&
+ git revert HEAD &&
+ git status -su >actual &&
+ ls -1pR * >>actual &&
+ test_cmp expect actual &&
+ git rebase "$1"
+}
+
+test_submodule_switch "git_rebase"
+
+git_rebase_interactive () {
+ git status -su >expect &&
+ ls -1pR * >>expect &&
+ git checkout -b ours HEAD &&
+ echo x >>file1 &&
+ git add file1 &&
+ git commit -m add_x &&
+ git revert HEAD &&
+ git status -su >actual &&
+ ls -1pR * >>actual &&
+ test_cmp expect actual &&
+ set_fake_editor &&
+ echo "fake-editor.sh" >.git/info/exclude &&
+ git rebase -i "$1"
+}
+
+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
+# The real reason "replace directory with submodule" fails is because a
+# directory "sub1" exists, but we reuse the suppression added for merge here
+test_submodule_switch "git_rebase_interactive"
+
+test_done
diff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh
new file mode 100755
index 0000000000..6863b7bb6f
--- /dev/null
+++ b/t/t3512-cherry-pick-submodule.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+test_description='cherry-pick can handle submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+
+KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1
+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
+KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1
+test_submodule_switch "git cherry-pick"
+
+test_done
diff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh
new file mode 100755
index 0000000000..a1c4e0216f
--- /dev/null
+++ b/t/t3513-revert-submodule.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+test_description='revert can handle submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+
+# Create a revert that moves from HEAD (including any test modifications to
+# the work tree) to $1 by first checking out $1 and reverting it. Reverting
+# the revert is the transition we test for. We tar the current work tree
+# first so we can restore the work tree test setup after doing the checkout
+# and revert. We test here that the restored work tree content is identical
+# to that at the beginning. The last revert is then tested by the framework.
+git_revert () {
+ git status -su >expect &&
+ ls -1pR * >>expect &&
+ tar czf "$TRASH_DIRECTORY/tmp.tgz" * &&
+ git checkout "$1" &&
+ git revert HEAD &&
+ rm -rf * &&
+ tar xzf "$TRASH_DIRECTORY/tmp.tgz" &&
+ git status -su >actual &&
+ ls -1pR * >>actual &&
+ test_cmp expect actual &&
+ git revert HEAD
+}
+
+KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1
+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
+test_submodule_switch "git_revert"
+
+test_done
diff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh
new file mode 100755
index 0000000000..d7219d6f8f
--- /dev/null
+++ b/t/t3906-stash-submodule.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+test_description='stash apply can handle submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+
+git_stash () {
+ git status -su >expect &&
+ ls -1pR * >>expect &&
+ git read-tree -u -m "$1" &&
+ git stash &&
+ git status -su >actual &&
+ ls -1pR * >>actual &&
+ test_cmp expect actual &&
+ git stash apply
+}
+
+KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1
+KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1
+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
+test_submodule_switch "git_stash"
+
+test_done
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 805b055c89..6ec6072118 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -324,4 +324,14 @@ test_expect_success 'diff --cached -- file on unborn branch' '
test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--cached_--_file0" result
'
+test_expect_success 'diff-tree --stdin with log formatting' '
+ cat >expect <<-\EOF &&
+ Side
+ Third
+ Second
+ EOF
+ git rev-list master | git diff-tree --stdin --format=%s -s >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index 463d63bde0..e4328964a7 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -26,8 +26,10 @@ add_file () {
echo "$name" >"$name" &&
git add "$name" &&
test_tick &&
- msg_added_iso88591=$(echo "Add $name ($added $name)" | iconv -f utf-8 -t $test_encoding) &&
- git -c "i18n.commitEncoding=$test_encoding" commit -m "$msg_added_iso88591"
+ # "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
)
diff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh
new file mode 100755
index 0000000000..a9bd40a6d0
--- /dev/null
+++ b/t/t4137-apply-submodule.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+test_description='git apply handling submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+
+apply_index () {
+ git diff --ignore-submodules=dirty "..$1" | git apply --index -
+}
+
+test_submodule_switch "apply_index"
+
+apply_3way () {
+ git diff --ignore-submodules=dirty "..$1" | git apply --3way -
+}
+
+test_submodule_switch "apply_3way"
+
+test_done
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index c84ec9ae61..349c531989 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -31,7 +31,7 @@ test_expect_success 'set up basic repos' '
git add foo &&
test_tick &&
git config i18n.commitEncoding $test_encoding &&
- git commit -m "$(commit_msg $test_encoding)" &&
+ commit_msg $test_encoding | git commit -F - &&
git add bar &&
test_tick &&
git commit -m "add bar" &&
diff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh
new file mode 100755
index 0000000000..8bde7dbb6d
--- /dev/null
+++ b/t/t4255-am-submodule.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+test_description='git am handling submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+
+am () {
+ git format-patch --stdout --ignore-submodules=dirty "..$1" | git am -
+}
+
+test_submodule_switch "am"
+
+am_3way () {
+ git format-patch --stdout --ignore-submodules=dirty "..$1" | git am --3way -
+}
+
+KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1
+test_submodule_switch "am_3way"
+
+test_done
diff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh
index 94553e1039..b46118846c 100755
--- a/t/t5539-fetch-http-shallow.sh
+++ b/t/t5539-fetch-http-shallow.sh
@@ -54,6 +54,7 @@ EOF
test_expect_success 'no shallow lines after receiving ACK ready' '
(
cd shallow &&
+ test_tick &&
for i in $(test_seq 15)
do
git checkout --orphan unrelated$i &&
diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh
new file mode 100755
index 0000000000..accfa5cc0c
--- /dev/null
+++ b/t/t5572-pull-submodule.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+test_description='pull can handle submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+
+reset_branch_to_HEAD () {
+ git branch -D "$1" &&
+ git checkout -b "$1" HEAD &&
+ git branch --set-upstream-to="origin/$1" "$1"
+}
+
+git_pull () {
+ reset_branch_to_HEAD "$1" &&
+ git pull
+}
+
+# pulls without conflicts
+test_submodule_switch "git_pull"
+
+git_pull_ff () {
+ reset_branch_to_HEAD "$1" &&
+ git pull --ff
+}
+
+test_submodule_switch "git_pull_ff"
+
+git_pull_ff_only () {
+ reset_branch_to_HEAD "$1" &&
+ git pull --ff-only
+}
+
+test_submodule_switch "git_pull_ff_only"
+
+git_pull_noff () {
+ reset_branch_to_HEAD "$1" &&
+ git pull --no-ff
+}
+
+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
+KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1
+test_submodule_switch "git_pull_noff"
+
+test_done
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index 88ed3191e8..a02a45afd2 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -35,13 +35,13 @@ test_expect_success 'setup' '
: >foo &&
git add foo &&
git config i18n.commitEncoding $test_encoding &&
- git commit -m "$added_iso88591" &&
+ echo "$added_iso88591" | git commit -F - &&
head1=$(git rev-parse --verify HEAD) &&
head1_short=$(git rev-parse --verify --short $head1) &&
tree1=$(git rev-parse --verify HEAD:) &&
tree1_short=$(git rev-parse --verify --short $tree1) &&
echo "$changed" > foo &&
- git commit -a -m "$changed_iso88591" &&
+ echo "$changed_iso88591" | git commit -a -F - &&
head2=$(git rev-parse --verify HEAD) &&
head2_short=$(git rev-parse --verify --short $head2) &&
tree2=$(git rev-parse --verify HEAD:) &&
diff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh
new file mode 100755
index 0000000000..c6b7aa6977
--- /dev/null
+++ b/t/t6041-bisect-submodule.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+test_description='bisect can handle submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+
+git_bisect () {
+ git status -su >expect &&
+ ls -1pR * >>expect &&
+ tar czf "$TRASH_DIRECTORY/tmp.tgz" * &&
+ GOOD=$(git rev-parse --verify HEAD) &&
+ git checkout "$1" &&
+ echo "foo" >bar &&
+ git add bar &&
+ git commit -m "bisect bad" &&
+ BAD=$(git rev-parse --verify HEAD) &&
+ git reset --hard HEAD^^ &&
+ git submodule update &&
+ git bisect start &&
+ git bisect good $GOOD &&
+ rm -rf * &&
+ tar xzf "$TRASH_DIRECTORY/tmp.tgz" &&
+ git status -su >actual &&
+ ls -1pR * >>actual &&
+ test_cmp expect actual &&
+ git bisect bad $BAD
+}
+
+test_submodule_switch "git_bisect"
+
+test_done
diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh
index 68b3cb26d9..4d5a25eedf 100755
--- a/t/t6050-replace.sh
+++ b/t/t6050-replace.sh
@@ -7,8 +7,9 @@ test_description='Tests replace refs functionality'
exec </dev/null
. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-gpg.sh"
-add_and_commit_file()
+add_and_commit_file ()
{
_file="$1"
_msg="$2"
@@ -18,6 +19,38 @@ add_and_commit_file()
git commit --quiet -m "$_file: $_msg"
}
+commit_buffer_contains_parents ()
+{
+ git cat-file commit "$1" >payload &&
+ sed -n -e '/^$/q' -e '/^parent /p' <payload >actual &&
+ shift &&
+ for _parent
+ do
+ echo "parent $_parent"
+ done >expected &&
+ test_cmp expected actual
+}
+
+commit_peeling_shows_parents ()
+{
+ _parent_number=1
+ _commit="$1"
+ shift &&
+ for _parent
+ do
+ _found=$(git rev-parse --verify $_commit^$_parent_number) || return 1
+ test "$_found" = "$_parent" || return 1
+ _parent_number=$(( $_parent_number + 1 ))
+ done &&
+ test_must_fail git rev-parse --verify $_commit^$_parent_number
+}
+
+commit_has_parents ()
+{
+ commit_buffer_contains_parents "$@" &&
+ commit_peeling_shows_parents "$@"
+}
+
HASH1=
HASH2=
HASH3=
@@ -27,36 +60,36 @@ HASH6=
HASH7=
test_expect_success 'set up buggy branch' '
- echo "line 1" >> hello &&
- echo "line 2" >> hello &&
- echo "line 3" >> hello &&
- echo "line 4" >> hello &&
+ echo "line 1" >>hello &&
+ echo "line 2" >>hello &&
+ echo "line 3" >>hello &&
+ echo "line 4" >>hello &&
add_and_commit_file hello "4 lines" &&
HASH1=$(git rev-parse --verify HEAD) &&
- echo "line BUG" >> hello &&
- echo "line 6" >> hello &&
- echo "line 7" >> hello &&
- echo "line 8" >> hello &&
+ echo "line BUG" >>hello &&
+ echo "line 6" >>hello &&
+ echo "line 7" >>hello &&
+ echo "line 8" >>hello &&
add_and_commit_file hello "4 more lines with a BUG" &&
HASH2=$(git rev-parse --verify HEAD) &&
- echo "line 9" >> hello &&
- echo "line 10" >> hello &&
+ echo "line 9" >>hello &&
+ echo "line 10" >>hello &&
add_and_commit_file hello "2 more lines" &&
HASH3=$(git rev-parse --verify HEAD) &&
- echo "line 11" >> hello &&
+ echo "line 11" >>hello &&
add_and_commit_file hello "1 more line" &&
HASH4=$(git rev-parse --verify HEAD) &&
- sed -e "s/BUG/5/" hello > hello.new &&
+ sed -e "s/BUG/5/" hello >hello.new &&
mv hello.new hello &&
add_and_commit_file hello "BUG fixed" &&
HASH5=$(git rev-parse --verify HEAD) &&
- echo "line 12" >> hello &&
- echo "line 13" >> hello &&
+ echo "line 12" >>hello &&
+ echo "line 13" >>hello &&
add_and_commit_file hello "2 more lines" &&
HASH6=$(git rev-parse --verify HEAD) &&
- echo "line 14" >> hello &&
- echo "line 15" >> hello &&
- echo "line 16" >> hello &&
+ echo "line 14" >>hello &&
+ echo "line 15" >>hello &&
+ echo "line 16" >>hello &&
add_and_commit_file hello "again 3 more lines" &&
HASH7=$(git rev-parse --verify HEAD)
'
@@ -95,7 +128,7 @@ test_expect_success 'tag replaced commit' '
'
test_expect_success '"git fsck" works' '
- git fsck master > fsck_master.out &&
+ git fsck master >fsck_master.out &&
grep "dangling commit $R" fsck_master.out &&
grep "dangling tag $(cat .git/refs/tags/mytag)" fsck_master.out &&
test -z "$(git fsck)"
@@ -217,14 +250,14 @@ test_expect_success 'fetch branch with replacement' '
(
cd clone_dir &&
git fetch origin refs/heads/tofetch:refs/heads/parallel3 &&
- git log --pretty=oneline parallel3 > output.txt &&
+ git log --pretty=oneline parallel3 >output.txt &&
! grep $PARA3 output.txt &&
- git show $PARA3 > para3.txt &&
+ git show $PARA3 >para3.txt &&
grep "A U Thor" para3.txt &&
git fetch origin "refs/replace/*:refs/replace/*" &&
- git log --pretty=oneline parallel3 > output.txt &&
+ git log --pretty=oneline parallel3 >output.txt &&
grep $PARA3 output.txt &&
- git show $PARA3 > para3.txt &&
+ git show $PARA3 >para3.txt &&
grep "O Thor" para3.txt
)
'
@@ -302,7 +335,7 @@ test_expect_success 'test --format medium' '
echo "$PARA3 -> $S" &&
echo "$MYTAG -> $HASH1"
} | sort >expected &&
- git replace -l --format medium | sort > actual &&
+ git replace -l --format medium | sort >actual &&
test_cmp expected actual
'
@@ -314,7 +347,7 @@ test_expect_success 'test --format long' '
echo "$PARA3 (commit) -> $S (commit)" &&
echo "$MYTAG (tag) -> $HASH1 (commit)"
} | sort >expected &&
- git replace --format=long | sort > actual &&
+ git replace --format=long | sort >actual &&
test_cmp expected actual
'
@@ -351,4 +384,60 @@ test_expect_success 'replace ref cleanup' '
test -z "$(git replace)"
'
+test_expect_success '--graft with and without already replaced object' '
+ test $(git log --oneline | wc -l) = 7 &&
+ git replace --graft $HASH5 &&
+ test $(git log --oneline | wc -l) = 3 &&
+ commit_has_parents $HASH5 &&
+ test_must_fail git replace --graft $HASH5 $HASH4 $HASH3 &&
+ git replace --force -g $HASH5 $HASH4 $HASH3 &&
+ commit_has_parents $HASH5 $HASH4 $HASH3 &&
+ git replace -d $HASH5
+'
+
+test_expect_success GPG 'set up a signed commit' '
+ echo "line 17" >>hello &&
+ echo "line 18" >>hello &&
+ git add hello &&
+ test_tick &&
+ git commit --quiet -S -m "hello: 2 more lines in a signed commit" &&
+ HASH8=$(git rev-parse --verify HEAD) &&
+ git verify-commit $HASH8
+'
+
+test_expect_success GPG '--graft with a signed commit' '
+ git cat-file commit $HASH8 >orig &&
+ git replace --graft $HASH8 &&
+ git cat-file commit $HASH8 >repl &&
+ commit_has_parents $HASH8 &&
+ test_must_fail git verify-commit $HASH8 &&
+ sed -n -e "/^tree /p" -e "/^author /p" -e "/^committer /p" orig >expected &&
+ echo >>expected &&
+ sed -e "/^$/q" repl >actual &&
+ test_cmp expected actual &&
+ git replace -d $HASH8
+'
+
+test_expect_success GPG 'set up a merge commit with a mergetag' '
+ git reset --hard HEAD &&
+ git checkout -b test_branch HEAD~2 &&
+ echo "line 1 from test branch" >>hello &&
+ echo "line 2 from test branch" >>hello &&
+ git add hello &&
+ test_tick &&
+ git commit -m "hello: 2 more lines from a test branch" &&
+ HASH9=$(git rev-parse --verify HEAD) &&
+ git tag -s -m "tag for testing with a mergetag" test_tag HEAD &&
+ git checkout master &&
+ git merge -s ours test_tag &&
+ HASH10=$(git rev-parse --verify HEAD) &&
+ git cat-file commit $HASH10 | grep "^mergetag object"
+'
+
+test_expect_success GPG '--graft on a commit with a mergetag' '
+ test_must_fail git replace --graft $HASH10 $HASH8^1 &&
+ git replace --graft $HASH10 $HASH8^1 $HASH9 &&
+ git replace -d $HASH10
+'
+
test_done
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index e4ab0f5b64..0366653088 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1385,41 +1385,77 @@ test_expect_success 'lexical sort' '
git tag foo1.6 &&
git tag foo1.10 &&
git tag -l --sort=refname "foo*" >actual &&
- cat >expect <<EOF &&
-foo1.10
-foo1.3
-foo1.6
-EOF
+ cat >expect <<-\EOF &&
+ foo1.10
+ foo1.3
+ foo1.6
+ EOF
test_cmp expect actual
'
test_expect_success 'version sort' '
git tag -l --sort=version:refname "foo*" >actual &&
- cat >expect <<EOF &&
-foo1.3
-foo1.6
-foo1.10
-EOF
+ cat >expect <<-\EOF &&
+ foo1.3
+ foo1.6
+ foo1.10
+ EOF
test_cmp expect actual
'
test_expect_success 'reverse version sort' '
git tag -l --sort=-version:refname "foo*" >actual &&
- cat >expect <<EOF &&
-foo1.10
-foo1.6
-foo1.3
-EOF
+ cat >expect <<-\EOF &&
+ foo1.10
+ foo1.6
+ foo1.3
+ EOF
test_cmp expect actual
'
test_expect_success 'reverse lexical sort' '
git tag -l --sort=-refname "foo*" >actual &&
- cat >expect <<EOF &&
-foo1.6
-foo1.3
-foo1.10
-EOF
+ cat >expect <<-\EOF &&
+ foo1.6
+ foo1.3
+ foo1.10
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'configured lexical sort' '
+ git config tag.sort "v:refname" &&
+ git tag -l "foo*" >actual &&
+ cat >expect <<-\EOF &&
+ foo1.3
+ foo1.6
+ foo1.10
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'option override configured sort' '
+ git tag -l --sort=-refname "foo*" >actual &&
+ cat >expect <<-\EOF &&
+ foo1.6
+ foo1.3
+ foo1.10
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'invalid sort parameter on command line' '
+ test_must_fail git tag -l --sort=notvalid "foo*" >actual
+'
+
+test_expect_success 'invalid sort parameter in configuratoin' '
+ git config tag.sort "v:notvalid" &&
+ git tag -l "foo*" >actual &&
+ cat >expect <<-\EOF &&
+ foo1.10
+ foo1.3
+ foo1.6
+ EOF
test_cmp expect actual
'
diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh
index ee703bed64..98bcfe21aa 100755
--- a/t/t7102-reset.sh
+++ b/t/t7102-reset.sh
@@ -44,7 +44,9 @@ test_expect_success 'creating initial files and commits' '
echo "1st line 2nd file" >secondfile &&
echo "2nd line 2nd file" >>secondfile &&
- git -c "i18n.commitEncoding=$test_encoding" commit -a -m "$(commit_msg $test_encoding)" &&
+ # "git commit -m" would break MinGW, as Windows refuse to pass
+ # $test_encoding encoded parameter to git.
+ commit_msg $test_encoding | git -c "i18n.commitEncoding=$test_encoding" commit -a -F - &&
head5=$(git rev-parse --verify HEAD)
'
# git log --pretty=oneline # to see those SHA1 involved
@@ -334,7 +336,9 @@ test_expect_success 'redoing the last two commits should succeed' '
echo "1st line 2nd file" >secondfile &&
echo "2nd line 2nd file" >>secondfile &&
- git -c "i18n.commitEncoding=$test_encoding" commit -a -m "$(commit_msg $test_encoding)" &&
+ # "git commit -m" would break MinGW, as Windows refuse to pass
+ # $test_encoding encoded parameter to git.
+ commit_msg $test_encoding | git -c "i18n.commitEncoding=$test_encoding" commit -a -F - &&
check_changes $head5
'
diff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh
new file mode 100755
index 0000000000..2eda6adeb1
--- /dev/null
+++ b/t/t7112-reset-submodule.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+test_description='reset can handle submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+
+test_submodule_switch "git reset --keep"
+
+test_submodule_switch "git reset --merge"
+
+test_submodule_forced_switch "git reset --hard"
+
+test_done
diff --git a/t/t7613-merge-submodule.sh b/t/t7613-merge-submodule.sh
new file mode 100755
index 0000000000..d1e9fcc781
--- /dev/null
+++ b/t/t7613-merge-submodule.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+test_description='merge can handle submodules'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-submodule-update.sh
+
+# merges without conflicts
+test_submodule_switch "git merge"
+
+test_submodule_switch "git merge --ff"
+
+test_submodule_switch "git merge --ff-only"
+
+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1
+KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1
+test_submodule_switch "git merge --no-ff"
+
+test_done
diff --git a/t/t7702-repack-cyclic-alternate.sh b/t/t7702-repack-cyclic-alternate.sh
new file mode 100755
index 0000000000..93b74867ac
--- /dev/null
+++ b/t/t7702-repack-cyclic-alternate.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Copyright (c) 2014 Ephrim Khong
+#
+
+test_description='repack involving cyclic alternate'
+. ./test-lib.sh
+
+test_expect_success setup '
+ GIT_OBJECT_DIRECTORY=.git//../.git/objects &&
+ export GIT_OBJECT_DIRECTORY &&
+ touch a &&
+ git add a &&
+ git commit -m 1 &&
+ git repack -adl &&
+ echo "$(pwd)"/.git/objects/../objects >.git/objects/info/alternates
+'
+
+test_expect_success 're-packing repository with itsself as alternate' '
+ git repack -adl &&
+ git fsck
+'
+
+test_done
diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh
index 1fc1f5f2af..95f4421f71 100755
--- a/t/t9814-git-p4-rename.sh
+++ b/t/t9814-git-p4-rename.sh
@@ -177,7 +177,10 @@ test_expect_success 'detect copies' '
level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
- test "$src" = file10 || test "$src" = file11 &&
+ case "$src" in
+ file10 | file11) : ;; # happy
+ *) false ;; # not
+ &&
git config git-p4.detectCopies $(($level + 2)) &&
git p4 submit &&
p4 filelog //depot/file12 &&
@@ -191,7 +194,10 @@ test_expect_success 'detect copies' '
level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
- test "$src" = file10 || test "$src" = file11 || test "$src" = file12 &&
+ case "$src" in
+ file10 | file11 | file12) : ;; # happy
+ *) false ;; # not
+ &&
git config git-p4.detectCopies $(($level - 2)) &&
git p4 submit &&
p4 filelog //depot/file13 &&
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 0377d3e296..dafd6ad21a 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -489,6 +489,17 @@ test_path_is_dir () {
fi
}
+# Check if the directory exists and is empty as expected, barf otherwise.
+test_dir_is_empty () {
+ test_path_is_dir "$1" &&
+ if test -n "$(ls -a1 "$1" | egrep -v '^\.\.?$')"
+ then
+ echo "Directory '$1' is not empty, it contains:"
+ ls -la "$1"
+ return 1
+ fi
+}
+
test_path_is_missing () {
if [ -e "$1" ]
then
diff --git a/t/test-lib.sh b/t/test-lib.sh
index a4795373a6..b1bc65bfb5 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -109,6 +109,10 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
export EDITOR
+# Tests using GIT_TRACE typically don't want <timestamp> <file>:<line> output
+GIT_TRACE_BARE=1
+export GIT_TRACE_BARE
+
if test -n "${TEST_GIT_INDEX_VERSION:+isset}"
then
GIT_INDEX_VERSION="$TEST_GIT_INDEX_VERSION"
diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp
index 9d51c92b74..0a6724fcc4 100644
--- a/t/valgrind/default.supp
+++ b/t/valgrind/default.supp
@@ -49,18 +49,3 @@
Memcheck:Addr4
fun:copy_ref
}
-{
- ignore-sse-check_refname_format-addr
- Memcheck:Addr8
- fun:check_refname_format
-}
-{
- ignore-sse-check_refname_format-cond
- Memcheck:Cond
- fun:check_refname_format
-}
-{
- ignore-sse-check_refname_format-value
- Memcheck:Value8
- fun:check_refname_format
-}