diff options
Diffstat (limited to 't')
28 files changed, 1841 insertions, 111 deletions
diff --git a/t/Makefile b/t/Makefile index 8fd1a72357..43b15e36ae 100644 --- a/t/Makefile +++ b/t/Makefile @@ -13,7 +13,7 @@ TAR ?= $(TAR) RM ?= rm -f PROVE ?= prove DEFAULT_TEST_TARGET ?= test -TEST_LINT ?= test-lint-duplicates test-lint-executable +TEST_LINT ?= test-lint ifdef TEST_OUTPUT_DIRECTORY TEST_RESULTS_DIRECTORY = $(TEST_OUTPUT_DIRECTORY)/test-results @@ -29,6 +29,7 @@ TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY)) T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) TSVN = $(sort $(wildcard t91[0-9][0-9]-*.sh)) TGITWEB = $(sort $(wildcard t95[0-9][0-9]-*.sh)) +THELPERS = $(sort $(filter-out $(T),$(wildcard *.sh))) all: $(DEFAULT_TEST_TARGET) @@ -65,7 +66,7 @@ test-lint-executable: echo >&2 "non-executable tests:" $$bad; exit 1; } test-lint-shell-syntax: - @'$(PERL_PATH_SQ)' check-non-portable-shell.pl $(T) + @'$(PERL_PATH_SQ)' check-non-portable-shell.pl $(T) $(THELPERS) aggregate-results-and-cleanup: $(T) $(MAKE) aggregate-results 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/t0025-crlf-auto.sh b/t/t0025-crlf-auto.sh index 28102de1a0..c164b4662a 100755 --- a/t/t0025-crlf-auto.sh +++ b/t/t0025-crlf-auto.sh @@ -12,144 +12,144 @@ test_expect_success setup ' git config core.autocrlf false && - for w in Hello world how are you; do echo $w; done >one && - for w in I am very very fine thank you; do echo ${w}Q; done | q_to_cr >two && - for w in Oh here is a QNUL byte how alarming; do echo ${w}; done | q_to_nul >three && + for w in Hello world how are you; do echo $w; done >LFonly && + for w in I am very very fine thank you; do echo ${w}Q; done | q_to_cr >CRLFonly && + for w in Oh here is a QNUL byte how alarming; do echo ${w}; done | q_to_nul >LFwithNUL && git add . && git commit -m initial && - one=$(git rev-parse HEAD:one) && - two=$(git rev-parse HEAD:two) && - three=$(git rev-parse HEAD:three) && + LFonly=$(git rev-parse HEAD:LFonly) && + CRLFonly=$(git rev-parse HEAD:CRLFonly) && + LFwithNUL=$(git rev-parse HEAD:LFwithNUL) && echo happy. ' test_expect_success 'default settings cause no changes' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git read-tree --reset -u HEAD && - ! has_cr one && - has_cr two && - onediff=$(git diff one) && - twodiff=$(git diff two) && - threediff=$(git diff three) && - test -z "$onediff" && test -z "$twodiff" && test -z "$threediff" + ! has_cr LFonly && + has_cr CRLFonly && + LFonlydiff=$(git diff LFonly) && + CRLFonlydiff=$(git diff CRLFonly) && + LFwithNULdiff=$(git diff LFwithNUL) && + test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff" ' test_expect_success 'crlf=true causes a CRLF file to be normalized' ' # Backwards compatibility check - rm -f .gitattributes tmp one two three && - echo "two crlf" > .gitattributes && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && + echo "CRLFonly crlf" > .gitattributes && git read-tree --reset -u HEAD && # Note, "normalized" means that git will normalize it if added - has_cr two && - twodiff=$(git diff two) && - test -n "$twodiff" + has_cr CRLFonly && + CRLFonlydiff=$(git diff CRLFonly) && + test -n "$CRLFonlydiff" ' test_expect_success 'text=true causes a CRLF file to be normalized' ' - rm -f .gitattributes tmp one two three && - echo "two text" > .gitattributes && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && + echo "CRLFonly text" > .gitattributes && git read-tree --reset -u HEAD && # Note, "normalized" means that git will normalize it if added - has_cr two && - twodiff=$(git diff two) && - test -n "$twodiff" + has_cr CRLFonly && + CRLFonlydiff=$(git diff CRLFonly) && + test -n "$CRLFonlydiff" ' test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=false' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf false && - echo "one eol=crlf" > .gitattributes && + echo "LFonly eol=crlf" > .gitattributes && git read-tree --reset -u HEAD && - has_cr one && - onediff=$(git diff one) && - test -z "$onediff" + has_cr LFonly && + LFonlydiff=$(git diff LFonly) && + test -z "$LFonlydiff" ' test_expect_success 'eol=crlf gives a normalized file CRLFs with autocrlf=input' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf input && - echo "one eol=crlf" > .gitattributes && + echo "LFonly eol=crlf" > .gitattributes && git read-tree --reset -u HEAD && - has_cr one && - onediff=$(git diff one) && - test -z "$onediff" + has_cr LFonly && + LFonlydiff=$(git diff LFonly) && + test -z "$LFonlydiff" ' test_expect_success 'eol=lf gives a normalized file LFs with autocrlf=true' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf true && - echo "one eol=lf" > .gitattributes && + echo "LFonly eol=lf" > .gitattributes && git read-tree --reset -u HEAD && - ! has_cr one && - onediff=$(git diff one) && - test -z "$onediff" + ! has_cr LFonly && + LFonlydiff=$(git diff LFonly) && + test -z "$LFonlydiff" ' test_expect_success 'autocrlf=true does not normalize CRLF files' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf true && git read-tree --reset -u HEAD && - has_cr one && - has_cr two && - onediff=$(git diff one) && - twodiff=$(git diff two) && - threediff=$(git diff three) && - test -z "$onediff" && test -z "$twodiff" && test -z "$threediff" + has_cr LFonly && + has_cr CRLFonly && + LFonlydiff=$(git diff LFonly) && + CRLFonlydiff=$(git diff CRLFonly) && + LFwithNULdiff=$(git diff LFwithNUL) && + test -z "$LFonlydiff" -a -z "$CRLFonlydiff" -a -z "$LFwithNULdiff" ' test_expect_success 'text=auto, autocrlf=true _does_ normalize CRLF files' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf true && echo "* text=auto" > .gitattributes && git read-tree --reset -u HEAD && - has_cr one && - has_cr two && - onediff=$(git diff one) && - twodiff=$(git diff two) && - threediff=$(git diff three) && - test -z "$onediff" && test -n "$twodiff" && test -z "$threediff" + has_cr LFonly && + has_cr CRLFonly && + LFonlydiff=$(git diff LFonly) && + CRLFonlydiff=$(git diff CRLFonly) && + LFwithNULdiff=$(git diff LFwithNUL) && + test -z "$LFonlydiff" -a -n "$CRLFonlydiff" -a -z "$LFwithNULdiff" ' test_expect_success 'text=auto, autocrlf=true does not normalize binary files' ' - rm -f .gitattributes tmp one two three && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && git config core.autocrlf true && echo "* text=auto" > .gitattributes && git read-tree --reset -u HEAD && - ! has_cr three && - threediff=$(git diff three) && - test -z "$threediff" + ! has_cr LFwithNUL && + LFwithNULdiff=$(git diff LFwithNUL) && + test -z "$LFwithNULdiff" ' test_expect_success 'eol=crlf _does_ normalize binary files' ' - rm -f .gitattributes tmp one two three && - echo "three eol=crlf" > .gitattributes && + rm -f .gitattributes tmp LFonly CRLFonly LFwithNUL && + echo "LFwithNUL eol=crlf" > .gitattributes && git read-tree --reset -u HEAD && - has_cr three && - threediff=$(git diff three) && - test -z "$threediff" + has_cr LFwithNUL && + LFwithNULdiff=$(git diff LFwithNUL) && + test -z "$LFwithNULdiff" ' test_done diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh new file mode 100755 index 0000000000..72dd3e8bb4 --- /dev/null +++ b/t/t0027-auto-crlf.sh @@ -0,0 +1,265 @@ +#!/bin/sh + +test_description='CRLF conversion all combinations' + +. ./test-lib.sh + +if ! test_have_prereq EXPENSIVE +then + skip_all="EXPENSIVE not set" + test_done +fi + + +compare_files() +{ + od -c <"$1" >"$1".expect && + od -c <"$2" >"$2".actual && + test_cmp "$1".expect "$2".actual && + rm "$1".expect "$2".actual +} + +compare_ws_file() +{ + pfx=$1 + exp=$2.expect + act=$pfx.actual.$3 + od -c <"$2" >"$exp" && + od -c <"$3" >"$act" && + test_cmp $exp $act && + rm $exp $act +} + +create_gitattributes() +{ + txtbin=$1 + case "$txtbin" in + auto) + echo "*.txt text=auto" >.gitattributes + ;; + text) + echo "*.txt text" >.gitattributes + ;; + -text) + echo "*.txt -text" >.gitattributes + ;; + *) + echo >.gitattributes + ;; + esac +} + +create_file_in_repo() +{ + crlf=$1 + txtbin=$2 + create_gitattributes "$txtbin" && + for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul + do + pfx=crlf_${crlf}_attr_${txtbin}_$f.txt && + cp $f $pfx && git -c core.autocrlf=$crlf add $pfx + done && + git commit -m "core.autocrlf $crlf" +} + +check_files_in_repo() +{ + crlf=$1 + txtbin=$2 + lfname=$3 + crlfname=$4 + lfmixcrlf=$5 + lfmixcr=$6 + crlfnul=$7 + pfx=crlf_${crlf}_attr_${txtbin}_ && + compare_files $lfname ${pfx}LF.txt && + compare_files $crlfname ${pfx}CRLF.txt && + compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt && + compare_files $lfmixcr ${pfx}LF_mix_CR.txt && + compare_files $crlfnul ${pfx}CRLF_nul.txt +} + + +check_files_in_ws() +{ + eol=$1 + crlf=$2 + txtbin=$3 + lfname=$4 + crlfname=$5 + lfmixcrlf=$6 + lfmixcr=$7 + crlfnul=$8 + create_gitattributes $txtbin && + git config core.autocrlf $crlf && + pfx=eol_${eol}_crlf_${crlf}_attr_${txtbin}_ && + src=crlf_false_attr__ && + for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul + do + rm $src$f.txt && + if test -z "$eol"; then + git checkout $src$f.txt + else + git -c core.eol=$eol checkout $src$f.txt + fi + done + + + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=LF" " + compare_ws_file $pfx $lfname ${src}LF.txt + " + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=CRLF" " + compare_ws_file $pfx $crlfname ${src}CRLF.txt + " + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=CRLF_mix_LF" " + compare_ws_file $pfx $lfmixcrlf ${src}CRLF_mix_LF.txt + " + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=LF_mix_CR" " + compare_ws_file $pfx $lfmixcr ${src}LF_mix_CR.txt + " + test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=CRLF_nul" " + compare_ws_file $pfx $crlfnul ${src}CRLF_nul.txt + " +} + +####### +( + type od >/dev/null && + printf "line1Q\r\nline2\r\nline3" | q_to_nul >CRLF_nul && + cat >expect <<-EOF && + 0000000 l i n e 1 \0 \r \n l i n e 2 \r \n l + 0000020 i n e 3 + 0000024 +EOF + od -c CRLF_nul | sed -e "s/[ ][ ]*/ /g" -e "s/ *$//" >actual + test_cmp expect actual && + rm expect actual +) || { + skip_all="od not found or od -c not usable" + exit 0 + test_done +} + +test_expect_success 'setup master' ' + echo >.gitattributes && + git checkout -b master && + git add .gitattributes && + git commit -m "add .gitattributes" "" && + printf "line1\nline2\nline3" >LF && + printf "line1\r\nline2\r\nline3" >CRLF && + printf "line1\r\nline2\nline3" >CRLF_mix_LF && + printf "line1\nline2\rline3" >LF_mix_CR && + printf "line1\r\nline2\rline3" >CRLF_mix_CR && + printf "line1Q\nline2\nline3" | q_to_nul >LF_nul +' +# CRLF_nul had been created above + +test_expect_success 'create files' ' + create_file_in_repo false "" && + create_file_in_repo true "" && + create_file_in_repo input "" && + + create_file_in_repo false "auto" && + create_file_in_repo true "auto" && + create_file_in_repo input "auto" && + + create_file_in_repo false "text" && + create_file_in_repo true "text" && + create_file_in_repo input "text" && + + create_file_in_repo false "-text" && + create_file_in_repo true "-text" && + create_file_in_repo input "-text" && + rm -f *.txt && + git reset --hard +' + +test_expect_success 'commit empty gitattribues' ' + check_files_in_repo false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul && + check_files_in_repo true "" LF LF LF LF_mix_CR CRLF_nul && + check_files_in_repo input "" LF LF LF LF_mix_CR CRLF_nul +' + +test_expect_success 'commit text=auto' ' + check_files_in_repo false "auto" LF LF LF LF_mix_CR CRLF_nul && + check_files_in_repo true "auto" LF LF LF LF_mix_CR CRLF_nul && + check_files_in_repo input "auto" LF LF LF LF_mix_CR CRLF_nul +' + +test_expect_success 'commit text' ' + check_files_in_repo false "text" LF LF LF LF_mix_CR LF_nul && + check_files_in_repo true "text" LF LF LF LF_mix_CR LF_nul && + check_files_in_repo input "text" LF LF LF LF_mix_CR LF_nul +' + +test_expect_success 'commit -text' ' + check_files_in_repo false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul && + check_files_in_repo true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul && + check_files_in_repo input "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +' + +################################################################################ +# Check how files in the repo are changed when they are checked out +# How to read the table below: +# - check_files_in_ws will check multiple files, see below +# - parameter $1 : core.eol lf | crlf +# - parameter $2 : core.autocrlf false | true | input +# - parameter $3 : text in .gitattributs "" (empty) | auto | text | -text +# - parameter $4 : reference for a file with only LF in the repo +# - parameter $5 : reference for a file with only CRLF in the repo +# - parameter $6 : reference for a file with mixed LF and CRLF in the repo +# - parameter $7 : reference for a file with LF and CR in the repo (does somebody uses this ?) +# - parameter $8 : reference for a file with CRLF and a NUL (should be handled as binary when auto) + +check_files_in_ws lf false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws lf true "" CRLF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws lf input "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + +check_files_in_ws lf false "auto" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws lf true "auto" CRLF CRLF CRLF LF_mix_CR CRLF_nul +check_files_in_ws lf input "auto" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + +check_files_in_ws lf false "text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws lf true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +check_files_in_ws lf input "text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + +check_files_in_ws lf false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws lf true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws lf input "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + +########### +#core.autocrlf=input is forbidden with core.eol=crlf +check_files_in_ws crlf false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws crlf true "" CRLF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + +check_files_in_ws crlf false "auto" CRLF CRLF CRLF LF_mix_CR CRLF_nul +check_files_in_ws crlf true "auto" CRLF CRLF CRLF LF_mix_CR CRLF_nul + +check_files_in_ws crlf false "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +check_files_in_ws crlf true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul + +check_files_in_ws crlf false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws crlf true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + +if test_have_prereq MINGW +then +check_files_in_ws "" false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws "" true "" CRLF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws "" false "auto" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws "" true "auto" CRLF CRLF CRLF LF_mix_CR CRLF_nul +check_files_in_ws "" false "text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws "" true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +check_files_in_ws "" false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws "" true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul + +check_files_in_ws native false "" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws native true "" CRLF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws native false "auto" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws native true "auto" CRLF CRLF CRLF LF_mix_CR CRLF_nul +check_files_in_ws native false "text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws native true "text" CRLF CRLF CRLF CRLF_mix_CR CRLF_nul +check_files_in_ws native false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +check_files_in_ws native true "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul +fi + +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/t1700-split-index.sh b/t/t1700-split-index.sh new file mode 100755 index 0000000000..94fb473e7c --- /dev/null +++ b/t/t1700-split-index.sh @@ -0,0 +1,194 @@ +#!/bin/sh + +test_description='split index mode tests' + +. ./test-lib.sh + +# We need total control of index splitting here +sane_unset GIT_TEST_SPLIT_INDEX + +test_expect_success 'enable split index' ' + git update-index --split-index && + test-dump-split-index .git/index >actual && + cat >expect <<EOF && +own 8299b0bcd1ac364e5f1d7768efb62fa2da79a339 +base 39d890139ee5356c7ef572216cebcd27aa41f9df +replacements: +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'add one file' ' + : >one && + git update-index --add one && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +base 39d890139ee5356c7ef572216cebcd27aa41f9df +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +replacements: +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'disable split index' ' + git update-index --no-split-index && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + BASE=`test-dump-split-index .git/index | grep "^own" | sed "s/own/base/"` && + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +not a split index +EOF + test_cmp expect actual +' + +test_expect_success 'enable split index again, "one" now belongs to base index"' ' + git update-index --split-index && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +$BASE +replacements: +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'modify original file, base index untouched' ' + echo modified >one && + git update-index one && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + q_to_tab >expect <<EOF && +$BASE +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0Q +replacements: 0 +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'add another file, which stays index' ' + : >two && + git update-index --add two && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0 one +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + q_to_tab >expect <<EOF && +$BASE +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0Q +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +replacements: 0 +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'remove file not in base index' ' + git update-index --force-remove two && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + q_to_tab >expect <<EOF && +$BASE +100644 2e0996000b7e9019eabcad29391bf0f5c7702f0b 0Q +replacements: 0 +deletions: +EOF + test_cmp expect actual +' + +test_expect_success 'remove file in base index' ' + git update-index --force-remove one && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +$BASE +replacements: +deletions: 0 +EOF + test_cmp expect actual +' + +test_expect_success 'add original file back' ' + : >one && + git update-index --add one && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +EOF + test_cmp ls-files.expect ls-files.actual && + + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +$BASE +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +replacements: +deletions: 0 +EOF + test_cmp expect actual +' + +test_expect_success 'add new file' ' + : >two && + git update-index --add two && + git ls-files --stage >actual && + cat >expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +EOF + test_cmp expect actual +' + +test_expect_success 'unify index, two files remain' ' + git update-index --no-split-index && + git ls-files --stage >ls-files.actual && + cat >ls-files.expect <<EOF && +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 one +100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 two +EOF + test_cmp ls-files.expect ls-files.actual + + test-dump-split-index .git/index | sed "/^own/d" >actual && + cat >expect <<EOF && +not a split index +EOF + test_cmp expect actual +' + +test_done 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/t2104-update-index-skip-worktree.sh b/t/t2104-update-index-skip-worktree.sh index 29c1fb10ca..cc830da58d 100755 --- a/t/t2104-update-index-skip-worktree.sh +++ b/t/t2104-update-index-skip-worktree.sh @@ -7,6 +7,8 @@ test_description='skip-worktree bit test' . ./test-lib.sh +sane_unset GIT_TEST_SPLIT_INDEX + test_set_index_version 3 cat >expect.full <<EOF 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/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/t4202-log.sh b/t/t4202-log.sh index cb03d28769..99ab7ca21f 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -3,6 +3,7 @@ test_description='git log' . ./test-lib.sh +. "$TEST_DIRECTORY/lib-gpg.sh" test_expect_success setup ' @@ -841,4 +842,34 @@ test_expect_success 'dotdot is a parent directory' ' test_cmp expect actual ' +test_expect_success GPG 'log --graph --show-signature' ' + test_when_finished "git reset --hard && git checkout master" && + git checkout -b signed master && + echo foo >foo && + git add foo && + git commit -S -m signed_commit && + git log --graph --show-signature -n1 signed >actual && + grep "^| gpg: Signature made" actual && + grep "^| gpg: Good signature" actual +' + +test_expect_success GPG 'log --graph --show-signature for merged tag' ' + test_when_finished "git reset --hard && git checkout master" && + git checkout -b plain master && + echo aaa >bar && + git add bar && + git commit -m bar_commit && + git checkout -b tagged master && + echo bbb >baz && + git add baz && + git commit -m baz_commit && + git tag -s -m signed_tag_msg signed_tag && + git checkout plain && + git merge --no-ff -m msg signed_tag && + git log --graph --show-signature -n1 plain >actual && + grep "^|\\\ merged tag" actual && + grep "^| | gpg: Signature made" actual && + grep "^| | gpg: Good signature" actual +' + test_done 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/t6023-merge-file.sh b/t/t6023-merge-file.sh index 432f086c06..3758961765 100755 --- a/t/t6023-merge-file.sh +++ b/t/t6023-merge-file.sh @@ -77,12 +77,29 @@ test_expect_success "merge without conflict (--quiet)" \ "git merge-file --quiet test.txt orig.txt new2.txt" cp new1.txt test2.txt -test_expect_success "merge without conflict (missing LF at EOF)" \ - "git merge-file test2.txt orig.txt new2.txt" +test_expect_failure "merge without conflict (missing LF at EOF)" \ + "git merge-file test2.txt orig.txt new4.txt" -test_expect_success "merge result added missing LF" \ +test_expect_failure "merge result added missing LF" \ "test_cmp test.txt test2.txt" +cp new4.txt test3.txt +test_expect_success "merge without conflict (missing LF at EOF, away from change in the other file)" \ + "git merge-file --quiet test3.txt new2.txt new3.txt" + +cat > expect.txt << EOF +DOMINUS regit me, +et nihil mihi deerit. +In loco pascuae ibi me collocavit, +super aquam refectionis educavit me; +animam meam convertit, +deduxit me super semitas jusitiae, +EOF +printf "propter nomen suum." >> expect.txt + +test_expect_success "merge does not add LF away of change" \ + "test_cmp test3.txt expect.txt" + cp test.txt backup.txt test_expect_success "merge with conflicts" \ "test_must_fail git merge-file test.txt orig.txt new3.txt" @@ -107,6 +124,55 @@ EOF test_expect_success "expected conflict markers" "test_cmp test.txt expect.txt" cp backup.txt test.txt + +cat > expect.txt << EOF +Dominus regit me, et nihil mihi deerit. +In loco pascuae ibi me collocavit, +super aquam refectionis educavit me; +animam meam convertit, +deduxit me super semitas jusitiae, +propter nomen suum. +Nam et si ambulavero in medio umbrae mortis, +non timebo mala, quoniam tu mecum es: +virga tua et baculus tuus ipsa me consolata sunt. +EOF +test_expect_success "merge conflicting with --ours" \ + "git merge-file --ours test.txt orig.txt new3.txt && test_cmp test.txt expect.txt" +cp backup.txt test.txt + +cat > expect.txt << EOF +DOMINUS regit me, +et nihil mihi deerit. +In loco pascuae ibi me collocavit, +super aquam refectionis educavit me; +animam meam convertit, +deduxit me super semitas jusitiae, +propter nomen suum. +Nam et si ambulavero in medio umbrae mortis, +non timebo mala, quoniam tu mecum es: +virga tua et baculus tuus ipsa me consolata sunt. +EOF +test_expect_success "merge conflicting with --theirs" \ + "git merge-file --theirs test.txt orig.txt new3.txt && test_cmp test.txt expect.txt" +cp backup.txt test.txt + +cat > expect.txt << EOF +Dominus regit me, et nihil mihi deerit. +DOMINUS regit me, +et nihil mihi deerit. +In loco pascuae ibi me collocavit, +super aquam refectionis educavit me; +animam meam convertit, +deduxit me super semitas jusitiae, +propter nomen suum. +Nam et si ambulavero in medio umbrae mortis, +non timebo mala, quoniam tu mecum es: +virga tua et baculus tuus ipsa me consolata sunt. +EOF +test_expect_success "merge conflicting with --union" \ + "git merge-file --union test.txt orig.txt new3.txt && test_cmp test.txt expect.txt" +cp backup.txt test.txt + test_expect_success "merge with conflicts, using -L" \ "test_must_fail git merge-file -L 1 -L 2 test.txt orig.txt new3.txt" @@ -260,4 +326,23 @@ test_expect_success 'marker size' ' test_cmp expect actual ' +printf "line1\nline2\nline3" >nolf-orig.txt +printf "line1\nline2\nline3x" >nolf-diff1.txt +printf "line1\nline2\nline3y" >nolf-diff2.txt + +test_expect_success 'conflict at EOF without LF resolved by --ours' \ + 'git merge-file -p --ours nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt && + printf "line1\nline2\nline3x" >expect.txt && + test_cmp expect.txt output.txt' + +test_expect_success 'conflict at EOF without LF resolved by --theirs' \ + 'git merge-file -p --theirs nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt && + printf "line1\nline2\nline3y" >expect.txt && + test_cmp expect.txt output.txt' + +test_expect_success 'conflict at EOF without LF resolved by --union' \ + 'git merge-file -p --union nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >output.txt && + printf "line1\nline2\nline3x\nline3y" >expect.txt && + test_cmp expect.txt output.txt' + test_done 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/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 9496736a89..66643e4bd7 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -308,6 +308,17 @@ test_expect_success 'Prune empty commits' ' test_cmp expect actual ' +test_expect_success 'prune empty collapsed merges' ' + test_config merge.ff false && + git rev-list HEAD >expect && + test_commit to_remove_2 && + git reset --hard HEAD^ && + test_merge non-ff to_remove_2 && + git filter-branch -f --index-filter "git update-index --remove to_remove_2.t" --prune-empty HEAD && + git rev-list HEAD >actual && + test_cmp expect actual +' + test_expect_success '--remap-to-ancestor with filename filters' ' git checkout master && git reset --hard A && 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/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/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" |