lib-submodule-update.sh [plain text]
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
)
}
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_git_directory_is_unchanged () {
(
cd ".git/modules/$1" &&
test "$(git config core.worktree)" = "../../../$1" &&
git config --unset core.worktree
) &&
diff -r ".git/modules/$1" "$1/.git" &&
(
cd ".git/modules/$1" &&
git config core.worktree "../../../$1"
)
}
prolog () {
(test -d submodule_update_repo || create_lib_submodule_repo) &&
test_config_global diff.ignoreSubmodules all &&
test_config diff.ignoreSubmodules all
}
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_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_submodule_content () {
if test $ 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_submodule_switch () {
command="$1"
if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
then
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
)
'
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
)
'
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
)
'
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
)
'
if test "$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR" = 1
then
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
)
'
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
)
'
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
)
'
if test "$KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES" = 1
then
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
)
'
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
)
'
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
)
'
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
)
'
if test "$KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT" = 1
then
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
)
'
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
)
'
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_submodule_forced_switch () {
command="$1"
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
)
'
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
)
'
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
)
'
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
)
'
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
)
'
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
)
'
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
)
'
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
)
'
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
)
'
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
)
'
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
)
'
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
)
'
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
)
'
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
)
'
}