{"thread":{"id":"36919","subject":"[PATCH 00/14] Add submodule test harness","startedAt":"2014-06-15T16:56:09Z","lastAt":"2014-07-14T21:18:36Z","messageCount":65,"participants":["Jens Lehmann","Eric Sunshine","Junio C Hamano","Torsten Bögershausen","Ramsay Jones","Johannes Sixt","Eric Wong","Erik Faye-Lund","Nico Williams","Karsten Blees"],"isPatch":true,"patchVersion":1,"patchTotal":14},"messages":[{"id":"244217","messageId":"539DD029.4030506@web.de","threadId":"36919","inReplyTo":null,"subject":"[PATCH 00/14] Add submodule test harness","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T16:56:09Z","receivedAt":"2014-06-15T16:56:09Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"This is the series I sought feedback for some time ago in gmane/$245048. It\ntook longer than I expected to finish this series because I had to diagnose\nthe test failures I saw with some of the ten commands I added since then.\nThey boiled down to four different inconsistencies in Git's handling of new\nor removed submodules. Sometimes no empty directory is created for a new\nsubmodule. stash and cherry-pick seem to use wrong submodule ignore settings\n(\"all\" instead of \"dirty\"), so they overlook submodule changes. And merge\nbehaves strange when a submodule is removed, as it tries to merge new tracked\nfiles with those remaining from the submodule. This series only documents\nthese issues (which most probably didn't cause any real world problems until\nnow because adding and removing submodules wasn't well supported anyway).\n\nThe first patch adds a simple helper function to the test lib which makes\nit easier to test for an empty submodule directory.\n\nThe second patch contains the heavy lifting, it adds the test framework for\nswitching submodules. Currently only transitions without merge conflicts are\ntested for, I intend to add others producing merge conflicts in a follow-up\nseries.\n\nThe other twelve patches use the framework to test all relevant work tree\nmanipulating commands. In addition to the two general problems documented\nin the second patch some patches add known failures for problems of some\ncommands/actions to be fixed in later patches.\n\nThe only work tree changing command I didn't cover here is checkout-index, as\nthat updates the work tree to the content of the index but doesn't remove any\nformerly tracked files, which means it doesn't do a full transition from one\ncommit to another. If I overlooked another command, please speak up so I can\ninclude it too.\n\nJens Lehmann (14):\n  test-lib: add test_dir_is_empty()\n  submodules: Add the lib-submodule-update.sh test library\n  checkout: call the new submodule update test framework\n  apply: add t4137 for submodule updates\n  read-tree: add t1013 for submodule updates\n  reset: add t7112 for submodule updates\n  bisect: add t6041 for submodule updates\n  merge: add t7613 for submodule updates\n  rebase: add t3426 for submodule updates\n  pull: add t5572 for submodule updates\n  cherry-pick: add t3512 for submodule updates\n  am: add t4255 for submodule updates\n  stash: add t3906 for submodule updates\n  revert: add t3513 for submodule updates\n\n t/lib-submodule-update.sh        | 670 +++++++++++++++++++++++++++++++++++++++\n t/t1013-read-tree-submodule.sh   |  12 +\n t/t2013-checkout-submodule.sh    |   5 +\n t/t3426-rebase-submodule.sh      |  46 +++\n t/t3512-cherry-pick-submodule.sh |  13 +\n t/t3513-revert-submodule.sh      |  32 ++\n t/t3906-stash-submodule.sh       |  24 ++\n t/t4137-apply-submodule.sh       |  20 ++\n t/t4255-am-submodule.sh          |  21 ++\n t/t5572-pull-submodule.sh        |  74 +++++\n t/t6041-bisect-submodule.sh      |  32 ++\n t/t7112-reset-submodule.sh       |  14 +\n t/t7613-merge-submodule.sh       |  19 ++\n t/test-lib-functions.sh          |  11 +\n 14 files changed, 993 insertions(+)\n create mode 100755 t/lib-submodule-update.sh\n create mode 100755 t/t1013-read-tree-submodule.sh\n create mode 100755 t/t3426-rebase-submodule.sh\n create mode 100755 t/t3512-cherry-pick-submodule.sh\n create mode 100755 t/t3513-revert-submodule.sh\n create mode 100755 t/t3906-stash-submodule.sh\n create mode 100755 t/t4137-apply-submodule.sh\n create mode 100755 t/t4255-am-submodule.sh\n create mode 100755 t/t5572-pull-submodule.sh\n create mode 100755 t/t6041-bisect-submodule.sh\n create mode 100755 t/t7112-reset-submodule.sh\n create mode 100755 t/t7613-merge-submodule.sh\n\n-- \n2.0.0.275.gc479268\n"},{"id":"244218","messageId":"539DD068.6020301@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 01/14] test-lib: add test_dir_is_empty()","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T16:57:12Z","receivedAt":"2014-06-15T16:57:12Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"For the upcoming submodule test framework we often need to assert that an\nempty directory exists in the work tree. Add the test_dir_is_empty()\nfunction which asserts that the given argument is an empty directory.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/test-lib-functions.sh | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 158e10a..546f0a6 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -489,6 +489,17 @@ test_path_is_dir () {\n \tfi\n }\n\n+# Check if the directory exists and is empty as expected, barf otherwise.\n+test_dir_is_empty () {\n+\ttest_path_is_dir \"$1\" &&\n+\tif test \"$(ls -a1 \"$1\" | egrep -v '^\\.\\.?$')\"\n+\tthen\n+\t\techo \"Directory '$1' is not empty, it contains:\"\n+\t\tls -la \"$1\"\n+\t\treturn 1\n+\tfi\n+}\n+\n test_path_is_missing () {\n \tif [ -e \"$1\" ]\n \tthen\n-- \n2.0.0.275.gc479268\n"},{"id":"244219","messageId":"539DD09A.7010200@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 02/14] submodules: Add the lib-submodule-update.sh test library","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T16:58:02Z","receivedAt":"2014-06-15T16:58:02Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Add this test library to simplify covering all combinations of submodule\nupdate scenarios without having to add those to a test of each work tree\nmanipulating command over and over again.\n\nThe functions test_submodule_switch() and test_submodule_forced_switch()\nare intended to be called from a test script with a single argument. This\nargument is either a work tree manipulating command (including any command\nline options) or a function (when more than a single git command is needed\nto switch work trees from the current HEAD to another commit). This\ncommand (or function) is passed a target branch as argument. The two new\nfunctions check that each submodule transition is handled as expected,\nwhich currently means that submodule work trees are not affected until\n\"git submodule update\" is called. The \"forced\" variant is for commands\nusing their '-f' or '--hard' option and expects them to overwrite local\nmodifications as a result. Each of these two functions contains 14\ntests_expect_* calls.\n\nCalling one of these test functions the first time creates a repository\nnamed \"submodule_update_repo\". At first it contains two files, then a\nsingle submodule is added in another commit followed by commits covering\nall relevant submodule modifications. This repository is newly cloned into\nthe \"submodule_update\" for each test_expect_* to avoid interference\nbetween different parts of the test functions (some to-be-tested commands\nalso manipulate refs along with the work tree, e.g. \"git reset\").\n\nFollow-up commits will then call these two test functions for all work\ntree manipulating commands (with a combination of all their options\nrelevant to what they do with the work tree) making sure they work as\nexpected. Later this test library will be extended to cover merges\nresulting in conflicts too. Also it is intended to be easily extendable\nfor the recursive update functionality, where even more combinations of\nsubmodule modifications have to be tested for.\n\nThis version documents two bugs in current Git with expected failures:\n\n*) When a submodule is replaced with a tracked file of the same name the\n   submodule work tree including any local modifications (and even the\n   whole history if it uses a .git directory instead of a gitfile!) is\n   silently removed.\n\n*) Forced work tree updates happily manipulate files in the directory of a\n   submodule that has just been removed in the superproject (but is of\n   course still present in the work tree due to the way submodules are\n   currently handled). This becomes dangerous when files in the submodule\n   directory are overwritten by files from the new superproject commit, as\n   any modifications to the submodule files will be lost) and is expected\n   to also destroy history in the - admittedly unlikely case - the new\n   commit adds a file named \".git\" to the submodule directory.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/lib-submodule-update.sh | 630 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 630 insertions(+)\n create mode 100755 t/lib-submodule-update.sh\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nnew file mode 100755\nindex 0000000..c6c842a\n--- /dev/null\n+++ b/t/lib-submodule-update.sh\n@@ -0,0 +1,630 @@\n+# Create a submodule layout used for all tests below.\n+#\n+# The following use cases are covered:\n+# - New submodule (no_submodule => add_sub1)\n+# - Removed submodule (add_sub1 => remove_sub1)\n+# - Updated submodule (add_sub1 => modify_sub1)\n+# - Submodule updated to invalid commit (add_sub1 => invalid_sub1)\n+# - Submodule updated from invalid commit (invalid_sub1 => valid_sub1)\n+# - Submodule replaced by tracked files in directory (add_sub1 =>\n+#   replace_sub1_with_directory)\n+# - Directory containing tracked files replaced by submodule\n+#   (replace_sub1_with_directory => replace_directory_with_sub1)\n+# - Submodule replaced by tracked file with the same name (add_sub1 =>\n+#   replace_sub1_with_file)\n+# - Tracked file replaced by submodule (replace_sub1_with_file =>\n+#   replace_file_with_sub1)\n+#\n+#                   --O-----O\n+#                  /  ^     replace_directory_with_sub1\n+#                 /   replace_sub1_with_directory\n+#                /----O\n+#               /     ^\n+#              /      modify_sub1\n+#      O------O-------O\n+#      ^      ^\\      ^\n+#      |      | \\     remove_sub1\n+#      |      |  -----O-----O\n+#      |      |   \\   ^     replace_file_with_sub1\n+#      |      |    \\  replace_sub1_with_file\n+#      |   add_sub1 --O-----O\n+# no_submodule        ^     valid_sub1\n+#                     invalid_sub1\n+#\n+create_lib_submodule_repo () {\n+\tgit init submodule_update_repo &&\n+\t(\n+\t\tcd submodule_update_repo &&\n+\t\techo \"expect\" >>.gitignore &&\n+\t\techo \"actual\" >>.gitignore &&\n+\t\techo \"x\" >file1 &&\n+\t\techo \"y\" >file2 &&\n+\t\tgit add .gitignore file1 file2 &&\n+\t\tgit commit -m \"Base\" &&\n+\t\tgit branch \"no_submodule\" &&\n+\n+\t\tgit checkout -b \"add_sub1\" &&\n+\t\tgit submodule add ./. sub1 &&\n+\t\tgit config -f .gitmodules submodule.sub1.ignore all &&\n+\t\tgit config submodule.sub1.ignore all &&\n+\t\tgit add .gitmodules &&\n+\t\tgit commit -m \"Add sub1\" &&\n+\t\tgit checkout -b remove_sub1 &&\n+\t\tgit revert HEAD &&\n+\n+\t\tgit checkout -b \"modify_sub1\" \"add_sub1\" &&\n+\t\tgit submodule update &&\n+\t\t(\n+\t\t\tcd sub1 &&\n+\t\t\tgit fetch &&\n+\t\t\tgit checkout -b \"modifications\" &&\n+\t\t\techo \"z\" >file2 &&\n+\t\t\techo \"x\" >file3 &&\n+\t\t\tgit add file2 file3 &&\n+\t\t\tgit commit -m \"modified file2 and added file3\" &&\n+\t\t\tgit push origin modifications\n+\t\t) &&\n+\t\tgit add sub1 &&\n+\t\tgit commit -m \"Modify sub1\" &&\n+\n+\t\tgit checkout -b \"replace_sub1_with_directory\" \"add_sub1\" &&\n+\t\tgit submodule update &&\n+\t\t(\n+\t\t\tcd sub1 &&\n+\t\t\tgit checkout modifications\n+\t\t) &&\n+\t\tgit rm --cached sub1 &&\n+\t\trm sub1/.git* &&\n+\t\tgit config -f .gitmodules --remove-section \"submodule.sub1\" &&\n+\t\tgit add .gitmodules sub1/* &&\n+\t\tgit commit -m \"Replace sub1 with directory\" &&\n+\t\tgit checkout -b replace_directory_with_sub1 &&\n+\t\tgit revert HEAD &&\n+\n+\t\tgit checkout -b \"replace_sub1_with_file\" \"add_sub1\" &&\n+\t\tgit rm sub1 &&\n+\t\techo \"content\" >sub1 &&\n+\t\tgit add sub1 &&\n+\t\tgit commit -m \"Replace sub1 with file\" &&\n+\t\tgit checkout -b replace_file_with_sub1 &&\n+\t\tgit revert HEAD &&\n+\n+\t\tgit checkout -b \"invalid_sub1\" \"add_sub1\" &&\n+\t\tgit update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 &&\n+\t\tgit commit -m \"Invalid sub1 commit\" &&\n+\t\tgit checkout -b valid_sub1 &&\n+\t\tgit revert HEAD &&\n+\t\tgit checkout master\n+\t)\n+}\n+\n+# Helper function to replace gitfile with .git directory\n+replace_gitfile_with_git_dir () {\n+\t(\n+\t\tcd \"$1\" &&\n+\t\tgit_dir=\"$(git rev-parse --git-dir)\" &&\n+\t\trm -f .git &&\n+\t\tcp -a \"$git_dir\" .git &&\n+\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t)\n+}\n+\n+# Test that the .git directory in the submodule is unchanged (except for the\n+# core.worktree setting)\n+test_git_directory_is_unchanged () {\n+\t(\n+\t\tcd \"$1\" &&\n+\t\tgit config core.worktree \"../../../$1\"\n+\t) &&\n+\tgit diff -r \".git/modules/$1\" \"$1/.git\" &&\n+\t(\n+\t\tcd \"$1\" &&\n+\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t)\n+}\n+\n+# Helper function to be executed at the start of every test below, it sets up\n+# the submodule repo if it doesn't exist and configures the most problematic\n+# settings for diff.ignoreSubmodules.\n+prolog () {\n+\t(test -d submodule_update_repo || create_lib_submodule_repo) &&\n+\ttest_config_global diff.ignoreSubmodules all &&\n+\ttest_config diff.ignoreSubmodules all\n+}\n+\n+# Helper function to bring work tree back into the state given by the\n+# commit. This includes trying to populate sub1 accordingly if it exists and\n+# should be updated to an existing commit.\n+reset_work_tree_to () {\n+\trm -rf submodule_update &&\n+\tgit clone submodule_update_repo submodule_update &&\n+\t(\n+\t\tcd submodule_update &&\n+\t\trm -rf sub1 &&\n+\t\tgit checkout -f \"$1\" &&\n+\t\tgit status -u -s >actual &&\n+\t\ttest_must_be_empty actual &&\n+\t\tsha1=$(git ls-tree HEAD \"sub1\" 2>/dev/null | grep 160000 | tr '\\t' ' ' | cut -d ' ' -f3) &&\n+\t\tif test -n \"$sha1\" &&\n+\t\t   test $(cd \"sub1\" && git rev-parse --verify \"$sha1^{commit}\")\n+\t\tthen\n+\t\t\tgit submodule update --init --recursive \"sub1\"\n+\t\tfi\n+\t)\n+}\n+\n+# Test that the superproject contains the content according to commit \"$1\"\n+# (the work tree must match the index for everything but submodules but the\n+# index must exactly match the given commit including any submodule SHA-1s).\n+test_superproject_content () {\n+\tgit diff-index --cached \"$1\" >actual &&\n+\ttest_must_be_empty actual &&\n+\tgit diff-files --ignore-submodules >actual &&\n+\ttest_must_be_empty actual\n+}\n+\n+# Test that the given submodule at path \"$1\" contains the content according\n+# to the submodule commit recorded in the superproject's commit \"$2\"\n+test_submodule_content () {\n+\tif test $# != 2\n+\tthen\n+\t\techo \"test_submodule_content needs two arguments\"\n+\t\treturn 1\n+\tfi &&\n+\tsubmodule=\"$1\" &&\n+\tcommit=\"$2\" &&\n+\ttest -d \"$submodule\"/ &&\n+\tif ! test -f \"$submodule\"/.git && ! test -d \"$submodule\"/.git\n+\tthen\n+\t\techo \"Submodule $submodule is not populated\"\n+\t\treturn 1\n+\tfi &&\n+\tsha1=$(git ls-tree \"$commit\" \"$submodule\" 2>/dev/null | tr '\\t' ' ' | cut -d ' ' -f3) &&\n+\tif test -z \"$sha1\"\n+\tthen\n+\t\techo \"Couldn't retrieve SHA-1 of $submodule for $commit\"\n+\t\treturn 1\n+\tfi &&\n+\t(\n+\t\tcd \"$submodule\" &&\n+\t\tgit status -u -s >actual &&\n+\t\ttest_must_be_empty actual &&\n+\t\tgit diff \"$sha1\" >actual &&\n+\t\ttest_must_be_empty actual\n+\t)\n+}\n+\n+# Test that the following transitions are correctly handled:\n+# - Updated submodule\n+# - New submodule\n+# - Removed submodule\n+# - Directory containing tracked files replaced by submodule\n+# - Submodule replaced by tracked files in directory\n+# - Submodule replaced by tracked file with the same name\n+# - tracked file replaced by submodule\n+#\n+# The default is that submodule contents aren't changed until \"git submodule\n+# update\" is run. And even then that command doesn't delete the work tree of\n+# a removed submodule.\n+#\n+# Removing a submodule containing a .git directory must fail even when forced\n+# to protect the history!\n+#\n+\n+# Test that submodule contents are currently not updated when switching\n+# between commits that change a submodule.\n+test_submodule_switch () {\n+\tcommand=\"$1\"\n+\t######################### Appearing submodule #########################\n+\t# Switching to a commit letting a submodule appear creates empty dir ...\n+\ttest_expect_success \"$command: added submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... and doesn't care if it already exists ...\n+\ttest_expect_success \"$command: added submodule leaves existing empty directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tmkdir sub1 &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... unless there is an untracked file in its place.\n+\ttest_expect_success \"$command: added submodule doesn't remove untracked unignored file with same name\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\techo -n >sub1 &&\n+\t\t\ttest_must_fail $command add_sub1 &&\n+\t\t\ttest_superproject_content origin/no_submodule &&\n+\t\t\ttest_must_be_empty sub1\n+\t\t)\n+\t'\n+\t# Replacing a tracked file with a submodule produces an empty\n+\t# directory ...\n+\ttest_expect_success \"$command: replace tracked file with submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_file &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\t$command replace_file_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n+\t\t)\n+\t'\n+\t# ... as does removing a directory with tracked files with a\n+\t# submodule.\n+\ttest_expect_success \"$command: replace directory with submodule\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_directory &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\t$command replace_directory_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n+\t\t)\n+\t'\n+\n+\t######################## Disappearing submodule #######################\n+\t# Removing a submodule doesn't remove its work tree ...\n+\ttest_expect_success \"$command: removed submodule leaves submodule directory and its contents in place\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_success \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1\n+\t\t)\n+\t'\n+\t# Replacing a submodule with files in a directory must fail as the\n+\t# submodule work tree isn't removed ...\n+\ttest_expect_success \"$command: replace submodule with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_success \"$command: replace submodule containing a .git directory with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1\n+\t\t)\n+\t'\n+\t# Replacing it with a file must fail as it could throw away any local\n+\t# work tree changes ...\n+\ttest_expect_failure \"$command: replace submodule with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... or even destroy unpushed parts of submodule history if that\n+\t# still uses a .git directory.\n+\ttest_expect_failure \"$command: replace submodule containing a .git directory with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1\n+\t\t)\n+\t'\n+\n+\t########################## Modified submodule #########################\n+\t# Updating a submodule sha1 doesn't update the submodule's work tree\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\t$command modify_sub1 &&\n+\t\t\ttest_superproject_content origin/modify_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\tgit submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1\n+\t\t)\n+\t'\n+\n+\t# Updating a submodule to an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will fail\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree to invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\t$command invalid_sub1 &&\n+\t\t\ttest_superproject_content origin/invalid_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_must_fail git submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule from an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will succeed\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree from invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to invalid_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\t$command valid_sub1 &&\n+\t\t\ttest_superproject_content origin/valid_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/valid_sub1\n+\t\t)\n+\t'\n+}\n+\n+# Test that submodule contents are currently not updated when switching\n+# between commits that change a submodule, but throwing away local changes in\n+# the superproject is allowed.\n+test_submodule_forced_switch () {\n+\tcommand=\"$1\"\n+\t######################### Appearing submodule #########################\n+\t# Switching to a commit letting a submodule appear creates empty dir ...\n+\ttest_expect_success \"$command: added submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... and doesn't care if it already exists ...\n+\ttest_expect_success \"$command: added submodule leaves existing empty directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\tmkdir sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... unless there is an untracked file in its place.\n+\ttest_expect_success \"$command: added submodule does remove untracked unignored file with same name when forced\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\techo -n >sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1\n+\t\t)\n+\t'\n+\t# Replacing a tracked file with a submodule produces an empty\n+\t# directory ...\n+\ttest_expect_success \"$command: replace tracked file with submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_file &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\t$command replace_file_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n+\t\t)\n+\t'\n+\t# ... as does removing a directory with tracked files with a\n+\t# submodule.\n+\ttest_expect_success \"$command: replace directory with submodule\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_directory &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\t$command replace_directory_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n+\t\t)\n+\t'\n+\n+\t######################## Disappearing submodule #######################\n+\t# Removing a submodule doesn't remove its work tree ...\n+\ttest_expect_success \"$command: removed submodule leaves submodule directory and its contents in place\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_success \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1\n+\t\t)\n+\t'\n+\t# Replacing a submodule with files in a directory must fail as the\n+\t# submodule work tree isn't removed ...\n+\ttest_expect_failure \"$command: replace submodule with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_failure \"$command: replace submodule containing a .git directory with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1\n+\t\t)\n+\t'\n+\t# Replacing it with a file must fail as it could throw away any local\n+\t# work tree changes ...\n+\ttest_expect_failure \"$command: replace submodule with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... or even destroy unpushed parts of submodule history if that\n+\t# still uses a .git directory.\n+\ttest_expect_failure \"$command: replace submodule containing a .git directory with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1\n+\t\t)\n+\t'\n+\n+\t########################## Modified submodule #########################\n+\t# Updating a submodule sha1 doesn't update the submodule's work tree\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\t$command modify_sub1 &&\n+\t\t\ttest_superproject_content origin/modify_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\tgit submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule to an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will fail\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree to invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\t$command invalid_sub1 &&\n+\t\t\ttest_superproject_content origin/invalid_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_must_fail git submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule from an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will succeed\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree from invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to invalid_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\t$command valid_sub1 &&\n+\t\t\ttest_superproject_content origin/valid_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/valid_sub1\n+\t\t)\n+\t'\n+}\n-- \n2.0.0.275.gc479268\n"},{"id":"244220","messageId":"539DD0C4.4000609@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 03/14] checkout: call the new submodule update test framework","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T16:58:44Z","receivedAt":"2014-06-15T16:58:44Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the checkout command updates the work tree as expected with\nand without the '-f' flag.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/t2013-checkout-submodule.sh | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex 06b18f8..6847f75 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -3,6 +3,7 @@\n test_description='checkout can handle submodules'\n\n . ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n\n test_expect_success 'setup' '\n \tmkdir submodule &&\n@@ -62,4 +63,8 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .git/\n \t! test -s actual\n '\n\n+test_submodule_switch \"git checkout\"\n+\n+test_submodule_forced_switch \"git checkout -f\"\n+\n test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244221","messageId":"539DD0E8.1020501@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 04/14] apply: add t4137 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T16:59:20Z","receivedAt":"2014-06-15T16:59:20Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the apply command updates the work tree as expected for the\n'--index' and the '--3way' options (for submodule changes which don't\nresult in conflicts).\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/t4137-apply-submodule.sh | 20 ++++++++++++++++++++\n 1 file changed, 20 insertions(+)\n create mode 100755 t/t4137-apply-submodule.sh\n\ndiff --git a/t/t4137-apply-submodule.sh b/t/t4137-apply-submodule.sh\nnew file mode 100755\nindex 0000000..a9bd40a\n--- /dev/null\n+++ b/t/t4137-apply-submodule.sh\n@@ -0,0 +1,20 @@\n+#!/bin/sh\n+\n+test_description='git apply handling submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+apply_index () {\n+\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --index -\n+}\n+\n+test_submodule_switch \"apply_index\"\n+\n+apply_3way () {\n+\tgit diff --ignore-submodules=dirty \"..$1\" | git apply --3way -\n+}\n+\n+test_submodule_switch \"apply_3way\"\n+\n+test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244222","messageId":"539DD107.2080303@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 05/14] read-tree: add t1013 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T16:59:51Z","receivedAt":"2014-06-15T16:59:51Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the read-tree command updates the work tree as expected for\nchanges which don't result in conflicts with the '-m' and '--reset' flag.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/t1013-read-tree-submodule.sh | 12 ++++++++++++\n 1 file changed, 12 insertions(+)\n create mode 100755 t/t1013-read-tree-submodule.sh\n\ndiff --git a/t/t1013-read-tree-submodule.sh b/t/t1013-read-tree-submodule.sh\nnew file mode 100755\nindex 0000000..20526ae\n--- /dev/null\n+++ b/t/t1013-read-tree-submodule.sh\n@@ -0,0 +1,12 @@\n+#!/bin/sh\n+\n+test_description='read-tree can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+test_submodule_switch \"git read-tree -u -m\"\n+\n+test_submodule_forced_switch \"git read-tree -u --reset\"\n+\n+test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244223","messageId":"539DD12C.7000009@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 06/14] reset: add t7112 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T17:00:28Z","receivedAt":"2014-06-15T17:00:28Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the reset command updates the work tree as expected for changes\nwith '--keep', '--merge' (for changes which don't result in conflicts) and\n'--hard'.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/t7112-reset-submodule.sh | 14 ++++++++++++++\n 1 file changed, 14 insertions(+)\n create mode 100755 t/t7112-reset-submodule.sh\n\ndiff --git a/t/t7112-reset-submodule.sh b/t/t7112-reset-submodule.sh\nnew file mode 100755\nindex 0000000..2eda6ad\n--- /dev/null\n+++ b/t/t7112-reset-submodule.sh\n@@ -0,0 +1,14 @@\n+#!/bin/sh\n+\n+test_description='reset can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+test_submodule_switch \"git reset --keep\"\n+\n+test_submodule_switch \"git reset --merge\"\n+\n+test_submodule_forced_switch \"git reset --hard\"\n+\n+test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244224","messageId":"539DD14C.4090609@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 07/14] bisect: add t6041 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T17:01:00Z","receivedAt":"2014-06-15T17:01:00Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the bisect command updates the work tree as expected. To make\nthat work with the new submodule test framework a git_bisect helper\nfunction is added. This adds a commit after the one given to be switched\nto and makes that one the bad commit. The starting point is then given to\nbisect as the good commit which makes bisect change the work tree to the\ncommit in between, which is the commit given.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/t6041-bisect-submodule.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n create mode 100755 t/t6041-bisect-submodule.sh\n\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nnew file mode 100755\nindex 0000000..4f37d24\n--- /dev/null\n+++ b/t/t6041-bisect-submodule.sh\n@@ -0,0 +1,32 @@\n+#!/bin/sh\n+\n+test_description='bisect can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+git_bisect () {\n+\tgit status -su >expected &&\n+\tls -1pR * >>expected &&\n+\ttar czf \"$TRASH_DIRECTORY/tmp.tgz\" * &&\n+\tGOOD=$(git rev-parse --verify HEAD) &&\n+\tgit checkout \"$1\" &&\n+\techo \"foo\" >bar &&\n+\tgit add bar &&\n+\tgit commit -m \"bisect bad\" &&\n+\tBAD=$(git rev-parse --verify HEAD) &&\n+\tgit reset --hard HEAD^^ &&\n+\tgit submodule update &&\n+\tgit bisect start &&\n+\tgit bisect good $GOOD &&\n+\trm -rf * &&\n+\ttar xzf \"$TRASH_DIRECTORY/tmp.tgz\" &&\n+\tgit status -su >actual &&\n+\tls -1pR * >>actual &&\n+\ttest_cmp expected actual &&\n+\tgit bisect bad $BAD\n+}\n+\n+test_submodule_switch \"git_bisect\"\n+\n+test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244225","messageId":"539DD175.5070005@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 08/14] merge: add t7613 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T17:01:41Z","receivedAt":"2014-06-15T17:01:41Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the merge command updates the work tree as expected (for\nsubmodule changes which don't result in conflicts) when used without\narguments or with the '--ff', '--ff-only' and '--no-ff' flag.\n\nImplement the KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR\nswitch to expect the known failure that --no-ff merges do not create the\nempty submodule directory.\n\nThe KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES\nswitch is also implemented to expect the known failure that --no-ff\nmerges attempt to merge the new files in the former submodule directory\nwith those of the removed submodule.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/lib-submodule-update.sh  | 24 +++++++++++++++++++++---\n t/t7613-merge-submodule.sh | 19 +++++++++++++++++++\n 2 files changed, 40 insertions(+), 3 deletions(-)\n create mode 100755 t/t7613-merge-submodule.sh\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex c6c842a..bc9415c 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -275,7 +275,16 @@ test_submodule_switch () {\n \t'\n \t# ... as does removing a directory with tracked files with a\n \t# submodule.\n-\ttest_expect_success \"$command: replace directory with submodule\" '\n+\tif test \"$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR\" = 1\n+\tthen\n+\t\t# Non fast-forward merges fail with \"Directory sub1 doesn't\n+\t\t# exist. sub1\" because the empty submodule directory is not\n+\t\t# created\n+\t\tRESULT=\"failure\"\n+\telse\n+\t\tRESULT=\"success\"\n+\tfi\n+\ttest_expect_$RESULT \"$command: replace directory with submodule\" '\n \t\tprolog &&\n \t\treset_work_tree_to replace_sub1_with_directory &&\n \t\t(\n@@ -318,7 +327,16 @@ test_submodule_switch () {\n \t'\n \t# Replacing a submodule with files in a directory must fail as the\n \t# submodule work tree isn't removed ...\n-\ttest_expect_success \"$command: replace submodule with a directory must fail\" '\n+\tif test \"$KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES\" = 1\n+\tthen\n+\t\t# Non fast-forward merges attempt to merge the former\n+\t\t# submodule files with the newly checked out ones in the\n+\t\t# directory of the same name while it shouldn't.\n+\t\tRESULT=\"failure\"\n+\telse\n+\t\tRESULT=\"success\"\n+\tfi\n+\ttest_expect_$RESULT \"$command: replace submodule with a directory must fail\" '\n \t\tprolog &&\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n@@ -330,7 +348,7 @@ test_submodule_switch () {\n \t\t)\n \t'\n \t# ... especially when it contains a .git directory.\n-\ttest_expect_success \"$command: replace submodule containing a .git directory with a directory must fail\" '\n+\ttest_expect_$RESULT \"$command: replace submodule containing a .git directory with a directory must fail\" '\n \t\tprolog &&\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\ndiff --git a/t/t7613-merge-submodule.sh b/t/t7613-merge-submodule.sh\nnew file mode 100755\nindex 0000000..d1e9fcc\n--- /dev/null\n+++ b/t/t7613-merge-submodule.sh\n@@ -0,0 +1,19 @@\n+#!/bin/sh\n+\n+test_description='merge can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+# merges without conflicts\n+test_submodule_switch \"git merge\"\n+\n+test_submodule_switch \"git merge --ff\"\n+\n+test_submodule_switch \"git merge --ff-only\"\n+\n+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n+KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n+test_submodule_switch \"git merge --no-ff\"\n+\n+test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244226","messageId":"539DD19B.6000504@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 09/14] rebase: add t3426 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T17:02:19Z","receivedAt":"2014-06-15T17:02:19Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the rebase command updates the work tree as expected for\nchanges which don't result in conflicts. To make that work add two\nhelper functions that add a commit only touching files and then\nrevert it. This allows to rebase the target commit over these two\nand to compare the result.\n\nSet KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR to\ndocument that \"replace directory with submodule\" fails for an\ninteractive rebase because a directory \"sub1\" already exists.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/t3426-rebase-submodule.sh | 46 +++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 46 insertions(+)\n create mode 100755 t/t3426-rebase-submodule.sh\n\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nnew file mode 100755\nindex 0000000..019ce52\n--- /dev/null\n+++ b/t/t3426-rebase-submodule.sh\n@@ -0,0 +1,46 @@\n+#!/bin/sh\n+\n+test_description='rebase can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+git_rebase () {\n+\tgit status -su >expected &&\n+\tls -1pR * >>expected &&\n+\tgit checkout -b ours HEAD &&\n+\techo x >>file1 &&\n+\tgit add file1 &&\n+\tgit commit -m add_x &&\n+\tgit revert HEAD &&\n+\tgit status -su >actual &&\n+\tls -1pR * >>actual &&\n+\ttest_cmp expected actual &&\n+\tgit rebase \"$1\"\n+}\n+\n+test_submodule_switch \"git_rebase\"\n+\n+git_rebase_interactive () {\n+\tgit status -su >expected &&\n+\tls -1pR * >>expected &&\n+\tgit checkout -b ours HEAD &&\n+\techo x >>file1 &&\n+\tgit add file1 &&\n+\tgit commit -m add_x &&\n+\tgit revert HEAD &&\n+\tgit status -su >actual &&\n+\tls -1pR * >>actual &&\n+\ttest_cmp expected actual &&\n+\tset_fake_editor &&\n+\techo \"fake-editor.sh\" >.git/info/exclude\n+\tgit rebase -i \"$1\"\n+}\n+\n+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n+# The real reason \"replace directory with submodule\" fails is because a\n+# directory \"sub1\" exists, but we reuse the suppression added for merge here\n+test_submodule_switch \"git_rebase_interactive\"\n+\n+test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244227","messageId":"539DD1B7.4060403@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 10/14] pull: add t5572 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T17:02:47Z","receivedAt":"2014-06-15T17:02:47Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the pull command updates the work tree as expected (for\nsubmodule changes which don't result in conflicts) when used without\narguments or with the '--ff', '--ff-only' and '--no-ff' flag each. Add\nhelper functions to reset the branch to be updated to to the current\nHEAD so that pull is doing the transition from HEAD to the given branch.\n\nSet KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES\nand KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR to\ndocument that pull has the same --no-ff known failures merge has.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/t5572-pull-submodule.sh | 45 +++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 45 insertions(+)\n create mode 100755 t/t5572-pull-submodule.sh\n\ndiff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh\nnew file mode 100755\nindex 0000000..accfa5c\n--- /dev/null\n+++ b/t/t5572-pull-submodule.sh\n@@ -0,0 +1,45 @@\n+#!/bin/sh\n+\n+test_description='pull can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+reset_branch_to_HEAD () {\n+\tgit branch -D \"$1\" &&\n+\tgit checkout -b \"$1\" HEAD &&\n+\tgit branch --set-upstream-to=\"origin/$1\" \"$1\"\n+}\n+\n+git_pull () {\n+\treset_branch_to_HEAD \"$1\" &&\n+\tgit pull\n+}\n+\n+# pulls without conflicts\n+test_submodule_switch \"git_pull\"\n+\n+git_pull_ff () {\n+\treset_branch_to_HEAD \"$1\" &&\n+\tgit pull --ff\n+}\n+\n+test_submodule_switch \"git_pull_ff\"\n+\n+git_pull_ff_only () {\n+\treset_branch_to_HEAD \"$1\" &&\n+\tgit pull --ff-only\n+}\n+\n+test_submodule_switch \"git_pull_ff_only\"\n+\n+git_pull_noff () {\n+\treset_branch_to_HEAD \"$1\" &&\n+\tgit pull --no-ff\n+}\n+\n+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n+KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n+test_submodule_switch \"git_pull_noff\"\n+\n+test_done\n-- \n2.0.0.275.gba02dd0\n"},{"id":"244228","messageId":"539DD1D6.6000509@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 11/14] cherry-pick: add t3512 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T17:03:18Z","receivedAt":"2014-06-15T17:03:18Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the cherry-pick command updates the work tree as expected (for\nsubmodule changes which don't result in conflicts).\n\nSet KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES\nand KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR to\ndocument that cherry-pick has the same --no-ff known failures merge has.\n\nImplement the KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT switch to expect\nthe known failure that while cherry picking just a SHA-1 update for an\nignored submodule the commit incorrectly fails with \"The previous\ncherry-pick is now empty, possibly due to conflict resolution.\".\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/lib-submodule-update.sh        | 15 ++++++++++++---\n t/t3512-cherry-pick-submodule.sh | 13 +++++++++++++\n 2 files changed, 25 insertions(+), 3 deletions(-)\n create mode 100755 t/t3512-cherry-pick-submodule.sh\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex bc9415c..95e041b 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -392,7 +392,16 @@ test_submodule_switch () {\n\n \t########################## Modified submodule #########################\n \t# Updating a submodule sha1 doesn't update the submodule's work tree\n-\ttest_expect_success \"$command: modified submodule does not update submodule work tree\" '\n+\tif test \"$KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT\" = 1\n+\tthen\n+\t\t# When cherry picking a SHA-1 update for an ignored submodule\n+\t\t# the commit incorrectly fails with \"The previous cherry-pick\n+\t\t# is now empty, possibly due to conflict resolution.\"\n+\t\tRESULT=\"failure\"\n+\telse\n+\t\tRESULT=\"success\"\n+\tfi\n+\ttest_expect_$RESULT \"$command: modified submodule does not update submodule work tree\" '\n \t\tprolog &&\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n@@ -408,7 +417,7 @@ test_submodule_switch () {\n\n \t# Updating a submodule to an invalid sha1 doesn't update the\n \t# submodule's work tree, subsequent update will fail\n-\ttest_expect_success \"$command: modified submodule does not update submodule work tree to invalid commit\" '\n+\ttest_expect_$RESULT \"$command: modified submodule does not update submodule work tree to invalid commit\" '\n \t\tprolog &&\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n@@ -423,7 +432,7 @@ test_submodule_switch () {\n \t'\n \t# Updating a submodule from an invalid sha1 doesn't update the\n \t# submodule's work tree, subsequent update will succeed\n-\ttest_expect_success \"$command: modified submodule does not update submodule work tree from invalid commit\" '\n+\ttest_expect_$RESULT \"$command: modified submodule does not update submodule work tree from invalid commit\" '\n \t\tprolog &&\n \t\treset_work_tree_to invalid_sub1 &&\n \t\t(\ndiff --git a/t/t3512-cherry-pick-submodule.sh b/t/t3512-cherry-pick-submodule.sh\nnew file mode 100755\nindex 0000000..6863b7b\n--- /dev/null\n+++ b/t/t3512-cherry-pick-submodule.sh\n@@ -0,0 +1,13 @@\n+#!/bin/sh\n+\n+test_description='cherry-pick can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n+KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n+test_submodule_switch \"git cherry-pick\"\n+\n+test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244229","messageId":"539DD1F9.7030005@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 12/14] am: add t4255 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T17:03:53Z","receivedAt":"2014-06-15T17:03:53Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the am command updates the work tree as expected (for submodule\nchanges which don't result in conflicts). To make that work add two\nhelper functions that use format-patch to create the input for am.\n\nAdd the KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES\nswitch to expect the known failure that --no-ff merges attempt to merge\nthe new files in the former submodule directory with those of the removed\nsubmodule.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/t4255-am-submodule.sh | 21 +++++++++++++++++++++\n 1 file changed, 21 insertions(+)\n create mode 100755 t/t4255-am-submodule.sh\n\ndiff --git a/t/t4255-am-submodule.sh b/t/t4255-am-submodule.sh\nnew file mode 100755\nindex 0000000..8bde7db\n--- /dev/null\n+++ b/t/t4255-am-submodule.sh\n@@ -0,0 +1,21 @@\n+#!/bin/sh\n+\n+test_description='git am handling submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+am () {\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am -\n+}\n+\n+test_submodule_switch \"am\"\n+\n+am_3way () {\n+\tgit format-patch --stdout --ignore-submodules=dirty \"..$1\" | git am --3way -\n+}\n+\n+KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1\n+test_submodule_switch \"am_3way\"\n+\n+test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244230","messageId":"539DD219.40108@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 13/14] stash: add t3906 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T17:04:25Z","receivedAt":"2014-06-15T17:04:25Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the stash apply command updates the work tree as expected for\nchanges which don't result in conflicts. To make that work add a helper\nfunction that uses read-tree to apply the changes of the target commit\nto the work tree, then stashes these changes and at last applies that\nstash.\n\nImplement the KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES switch\nand reuse two other already present switches to expect the known\nfailure that stash does ignore submodule changes.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/lib-submodule-update.sh  | 23 ++++++++++++++++++-----\n t/t3906-stash-submodule.sh | 24 ++++++++++++++++++++++++\n 2 files changed, 42 insertions(+), 5 deletions(-)\n create mode 100755 t/t3906-stash-submodule.sh\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 95e041b..9901b45 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -217,7 +217,14 @@ test_submodule_switch () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n-\ttest_expect_success \"$command: added submodule creates empty directory\" '\n+\tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n+\tthen\n+\t\t# Restoring stash fails to restore submodule index entry\n+\t\tRESULT=\"failure\"\n+\telse\n+\t\tRESULT=\"success\"\n+\tfi\n+\ttest_expect_$RESULT \"$command: added submodule creates empty directory\" '\n \t\tprolog &&\n \t\treset_work_tree_to no_submodule &&\n \t\t(\n@@ -231,7 +238,7 @@ test_submodule_switch () {\n \t\t)\n \t'\n \t# ... and doesn't care if it already exists ...\n-\ttest_expect_success \"$command: added submodule leaves existing empty directory alone\" '\n+\ttest_expect_$RESULT \"$command: added submodule leaves existing empty directory alone\" '\n \t\tprolog &&\n \t\treset_work_tree_to no_submodule &&\n \t\t(\n@@ -260,7 +267,7 @@ test_submodule_switch () {\n \t'\n \t# Replacing a tracked file with a submodule produces an empty\n \t# directory ...\n-\ttest_expect_success \"$command: replace tracked file with submodule creates empty directory\" '\n+\ttest_expect_$RESULT \"$command: replace tracked file with submodule creates empty directory\" '\n \t\tprolog &&\n \t\treset_work_tree_to replace_sub1_with_file &&\n \t\t(\n@@ -300,7 +307,13 @@ test_submodule_switch () {\n\n \t######################## Disappearing submodule #######################\n \t# Removing a submodule doesn't remove its work tree ...\n-\ttest_expect_success \"$command: removed submodule leaves submodule directory and its contents in place\" '\n+\tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n+\tthen\n+\t\tRESULT=\"failure\"\n+\telse\n+\t\tRESULT=\"success\"\n+\tfi\n+\ttest_expect_$RESULT \"$command: removed submodule leaves submodule directory and its contents in place\" '\n \t\tprolog &&\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n@@ -312,7 +325,7 @@ test_submodule_switch () {\n \t\t)\n \t'\n \t# ... especially when it contains a .git directory.\n-\ttest_expect_success \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n+\ttest_expect_$RESULT \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n \t\tprolog &&\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nnew file mode 100755\nindex 0000000..aaee424\n--- /dev/null\n+++ b/t/t3906-stash-submodule.sh\n@@ -0,0 +1,24 @@\n+#!/bin/sh\n+\n+test_description='stash apply can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+git_stash () {\n+\tgit status -su >expected &&\n+\tls -1pR * >>expected &&\n+\tgit read-tree -u -m \"$1\" &&\n+\tgit stash &&\n+\tgit status -su >actual &&\n+\tls -1pR * >>actual &&\n+\ttest_cmp expected actual &&\n+\tgit stash apply\n+}\n+\n+KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n+KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n+test_submodule_switch \"git_stash\"\n+\n+test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244231","messageId":"539DD23A.5000504@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"[PATCH 14/14] revert: add t3513 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-15T17:04:58Z","receivedAt":"2014-06-15T17:04:58Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the revert command updates the work tree as expected (for\nsubmodule changes which don't result in conflicts). Add a helper function\nto first revert the checked out target commit to make the last revert\nproduce the to-be-tested work tree.\n\nSet the KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT and\nKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR switches to\ndocument that revert has the similar failures.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n t/t3513-revert-submodule.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n create mode 100755 t/t3513-revert-submodule.sh\n\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nnew file mode 100755\nindex 0000000..57e2d75\n--- /dev/null\n+++ b/t/t3513-revert-submodule.sh\n@@ -0,0 +1,32 @@\n+#!/bin/sh\n+\n+test_description='revert can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+# Create a revert that moves from HEAD (including any test modifications to\n+# the work tree) to $1 by first checking out $1 and reverting it. Reverting\n+# the revert is the transition we test for. We tar the current work tree\n+# first so we can restore the work tree test setup after doing the checkout\n+# and revert.  We test here that the restored work tree content is identical\n+# to that at the beginning. The last revert is then tested by the framework.\n+git_revert () {\n+\tgit status -su >expected &&\n+\tls -1pR * >>expected &&\n+\ttar czf \"$TRASH_DIRECTORY/tmp.tgz\" * &&\n+\tgit checkout \"$1\" &&\n+\tgit revert HEAD &&\n+\trm -rf * &&\n+\ttar xzf \"$TRASH_DIRECTORY/tmp.tgz\" &&\n+\tgit status -su >actual &&\n+\tls -1pR * >>actual &&\n+\ttest_cmp expected actual &&\n+\tgit revert HEAD\n+}\n+\n+KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n+test_submodule_switch \"git_revert\"\n+\n+test_done\n-- \n2.0.0.275.gc479268\n"},{"id":"244244","messageId":"CAPig+cSU_8USZu3cr=aaOun07jE2BhgLt7yu9ix_AikUpK+pJQ@mail.gmail.com","threadId":"36919","inReplyTo":"539DD19B.6000504@web.de","subject":"Re: [PATCH 09/14] rebase: add t3426 for submodule updates","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2014-06-16T09:57:50Z","receivedAt":"2014-06-16T09:57:50Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Jun 15, 2014 at 1:02 PM, Jens Lehmann <Jens.Lehmann@web.de> wrote:\n> Test that the rebase command updates the work tree as expected for\n> changes which don't result in conflicts. To make that work add two\n> helper functions that add a commit only touching files and then\n> revert it. This allows to rebase the target commit over these two\n> and to compare the result.\n>\n> Set KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR to\n> document that \"replace directory with submodule\" fails for an\n> interactive rebase because a directory \"sub1\" already exists.\n>\n> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n> ---\n>  t/t3426-rebase-submodule.sh | 46 +++++++++++++++++++++++++++++++++++++++++++++\n>  1 file changed, 46 insertions(+)\n>  create mode 100755 t/t3426-rebase-submodule.sh\n>\n> diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\n> new file mode 100755\n> index 0000000..019ce52\n> --- /dev/null\n> +++ b/t/t3426-rebase-submodule.sh\n> @@ -0,0 +1,46 @@\n> +#!/bin/sh\n> +\n> +test_description='rebase can handle submodules'\n> +\n> +. ./test-lib.sh\n> +. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n> +. \"$TEST_DIRECTORY\"/lib-rebase.sh\n> +\n> +git_rebase () {\n> +       git status -su >expected &&\n> +       ls -1pR * >>expected &&\n> +       git checkout -b ours HEAD &&\n> +       echo x >>file1 &&\n> +       git add file1 &&\n> +       git commit -m add_x &&\n> +       git revert HEAD &&\n> +       git status -su >actual &&\n> +       ls -1pR * >>actual &&\n> +       test_cmp expected actual &&\n> +       git rebase \"$1\"\n> +}\n> +\n> +test_submodule_switch \"git_rebase\"\n> +\n> +git_rebase_interactive () {\n> +       git status -su >expected &&\n> +       ls -1pR * >>expected &&\n> +       git checkout -b ours HEAD &&\n> +       echo x >>file1 &&\n> +       git add file1 &&\n> +       git commit -m add_x &&\n> +       git revert HEAD &&\n> +       git status -su >actual &&\n> +       ls -1pR * >>actual &&\n> +       test_cmp expected actual &&\n> +       set_fake_editor &&\n> +       echo \"fake-editor.sh\" >.git/info/exclude\n\nBroken &&-chain.\n\n> +       git rebase -i \"$1\"\n> +}\n> +\n> +KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n> +# The real reason \"replace directory with submodule\" fails is because a\n> +# directory \"sub1\" exists, but we reuse the suppression added for merge here\n> +test_submodule_switch \"git_rebase_interactive\"\n> +\n> +test_done\n> --\n> 2.0.0.275.gc479268\n"},{"id":"244359","messageId":"xmqq7g4gpl1g.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"539DD068.6020301@web.de","subject":"Re: [PATCH 01/14] test-lib: add test_dir_is_empty()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-06-16T22:05:47Z","receivedAt":"2014-06-16T22:05:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> For the upcoming submodule test framework we often need to assert that an\n> empty directory exists in the work tree. Add the test_dir_is_empty()\n> function which asserts that the given argument is an empty directory.\n>\n> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n> ---\n>  t/test-lib-functions.sh | 11 +++++++++++\n>  1 file changed, 11 insertions(+)\n>\n> diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\n> index 158e10a..546f0a6 100644\n> --- a/t/test-lib-functions.sh\n> +++ b/t/test-lib-functions.sh\n> @@ -489,6 +489,17 @@ test_path_is_dir () {\n>  \tfi\n>  }\n>\n> +# Check if the directory exists and is empty as expected, barf otherwise.\n> +test_dir_is_empty () {\n> +\ttest_path_is_dir \"$1\" &&\n> +\tif test \"$(ls -a1 \"$1\" | egrep -v '^\\.\\.?$')\"\n\nIt is safer to say \"test -n\" when testing an emptyness of a string\nwhose contents you do not know or control (e.g. the string may begin\nwith \"-something\").\n\n> +\tthen\n> +\t\techo \"Directory '$1' is not empty, it contains:\"\n> +\t\tls -la \"$1\"\n> +\t\treturn 1\n> +\tfi\n> +}\n> +\n>  test_path_is_missing () {\n>  \tif [ -e \"$1\" ]\n>  \tthen\n"},{"id":"244361","messageId":"xmqqwqcgo4gc.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"539DD09A.7010200@web.de","subject":"Re: [PATCH 02/14] submodules: Add the lib-submodule-update.sh test library","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-06-16T22:49:23Z","receivedAt":"2014-06-16T22:49:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> Add this test library to simplify covering all combinations of submodule\n> update scenarios without having to add those to a test of each work tree\n> manipulating command over and over again.\n>\n> The functions test_submodule_switch() and test_submodule_forced_switch()\n> are intended to be called from a test script with a single argument. This\n> argument is either a work tree manipulating command (including any command\n> line options) or a function (when more than a single git command is needed\n> to switch work trees from the current HEAD to another commit). This\n> command (or function) is passed a target branch as argument. The two new\n> functions check that each submodule transition is handled as expected,\n> which currently means that submodule work trees are not affected until\n> \"git submodule update\" is called. The \"forced\" variant is for commands\n> using their '-f' or '--hard' option and expects them to overwrite local\n> modifications as a result. Each of these two functions contains 14\n> tests_expect_* calls.\n>\n> Calling one of these test functions the first time creates a repository\n> named \"submodule_update_repo\". At first it contains two files, then a\n> single submodule is added in another commit followed by commits covering\n> all relevant submodule modifications. This repository is newly cloned into\n> the \"submodule_update\" for each test_expect_* to avoid interference\n> between different parts of the test functions (some to-be-tested commands\n> also manipulate refs along with the work tree, e.g. \"git reset\").\n>\n> Follow-up commits will then call these two test functions for all work\n> tree manipulating commands (with a combination of all their options\n> relevant to what they do with the work tree) making sure they work as\n> expected. Later this test library will be extended to cover merges\n> resulting in conflicts too. Also it is intended to be easily extendable\n> for the recursive update functionality, where even more combinations of\n> submodule modifications have to be tested for.\n>\n> This version documents two bugs in current Git with expected failures:\n>\n> *) When a submodule is replaced with a tracked file of the same name the\n>    submodule work tree including any local modifications (and even the\n>    whole history if it uses a .git directory instead of a gitfile!) is\n>    silently removed.\n>\n> *) Forced work tree updates happily manipulate files in the directory of a\n>    submodule that has just been removed in the superproject (but is of\n>    course still present in the work tree due to the way submodules are\n>    currently handled). This becomes dangerous when files in the submodule\n>    directory are overwritten by files from the new superproject commit, as\n>    any modifications to the submodule files will be lost) and is expected\n>    to also destroy history in the - admittedly unlikely case - the new\n>    commit adds a file named \".git\" to the submodule directory.\n>\n> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n> ---\n>  t/lib-submodule-update.sh | 630 ++++++++++++++++++++++++++++++++++++++++++++++\n>  1 file changed, 630 insertions(+)\n>  create mode 100755 t/lib-submodule-update.sh\n>\n> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n> new file mode 100755\n> index 0000000..c6c842a\n> --- /dev/null\n> +++ b/t/lib-submodule-update.sh\n> @@ -0,0 +1,630 @@\n> +# Create a submodule layout used for all tests below.\n> +#\n> +# The following use cases are covered:\n> +# - New submodule (no_submodule => add_sub1)\n> +# - Removed submodule (add_sub1 => remove_sub1)\n> +# - Updated submodule (add_sub1 => modify_sub1)\n> +# - Submodule updated to invalid commit (add_sub1 => invalid_sub1)\n> +# - Submodule updated from invalid commit (invalid_sub1 => valid_sub1)\n> +# - Submodule replaced by tracked files in directory (add_sub1 =>\n> +#   replace_sub1_with_directory)\n> +# - Directory containing tracked files replaced by submodule\n> +#   (replace_sub1_with_directory => replace_directory_with_sub1)\n> +# - Submodule replaced by tracked file with the same name (add_sub1 =>\n> +#   replace_sub1_with_file)\n> +# - Tracked file replaced by submodule (replace_sub1_with_file =>\n> +#   replace_file_with_sub1)\n> +#\n> +#                   --O-----O\n> +#                  /  ^     replace_directory_with_sub1\n> +#                 /   replace_sub1_with_directory\n> +#                /----O\n> +#               /     ^\n> +#              /      modify_sub1\n> +#      O------O-------O\n> +#      ^      ^\\      ^\n> +#      |      | \\     remove_sub1\n> +#      |      |  -----O-----O\n> +#      |      |   \\   ^     replace_file_with_sub1\n> +#      |      |    \\  replace_sub1_with_file\n> +#      |   add_sub1 --O-----O\n> +# no_submodule        ^     valid_sub1\n> +#                     invalid_sub1\n> +#\n> +create_lib_submodule_repo () {\n> +\tgit init submodule_update_repo &&\n> +\t(\n> +\t\tcd submodule_update_repo &&\n> +\t\techo \"expect\" >>.gitignore &&\n> +\t\techo \"actual\" >>.gitignore &&\n> +\t\techo \"x\" >file1 &&\n> +\t\techo \"y\" >file2 &&\n> +\t\tgit add .gitignore file1 file2 &&\n> +\t\tgit commit -m \"Base\" &&\n> +\t\tgit branch \"no_submodule\" &&\n> +\n> +\t\tgit checkout -b \"add_sub1\" &&\n> +\t\tgit submodule add ./. sub1 &&\n\nThis is not technically wrong per-se, but having the project's\nhistory itself as its own submodule *is* something nobody sane would\ndo in the real life.  Do we really have to do it this unusual way?\n\n> +\t\tgit config -f .gitmodules submodule.sub1.ignore all &&\n> +\t\tgit config submodule.sub1.ignore all &&\n> +\t\tgit add .gitmodules &&\n> +\t\tgit commit -m \"Add sub1\" &&\n> +\t\tgit checkout -b remove_sub1 &&\n> +\t\tgit revert HEAD &&\n> +\n> +\t\tgit checkout -b \"modify_sub1\" \"add_sub1\" &&\n> +\t\tgit submodule update &&\n> +\t\t(\n> +\t\t\tcd sub1 &&\n> +\t\t\tgit fetch &&\n> +\t\t\tgit checkout -b \"modifications\" &&\n> +\t\t\techo \"z\" >file2 &&\n> +\t\t\techo \"x\" >file3 &&\n> +\t\t\tgit add file2 file3 &&\n> +\t\t\tgit commit -m \"modified file2 and added file3\" &&\n> +\t\t\tgit push origin modifications\n> +\t\t) &&\n> +\t\tgit add sub1 &&\n> +\t\tgit commit -m \"Modify sub1\" &&\n> +\n> +\t\tgit checkout -b \"replace_sub1_with_directory\" \"add_sub1\" &&\n> +\t\tgit submodule update &&\n> +\t\t(\n> +\t\t\tcd sub1 &&\n> +\t\t\tgit checkout modifications\n> +\t\t) &&\n> +\t\tgit rm --cached sub1 &&\n> +\t\trm sub1/.git* &&\n> +\t\tgit config -f .gitmodules --remove-section \"submodule.sub1\" &&\n> +\t\tgit add .gitmodules sub1/* &&\n> +\t\tgit commit -m \"Replace sub1 with directory\" &&\n> +\t\tgit checkout -b replace_directory_with_sub1 &&\n> +\t\tgit revert HEAD &&\n> +\n> +\t\tgit checkout -b \"replace_sub1_with_file\" \"add_sub1\" &&\n> +\t\tgit rm sub1 &&\n> +\t\techo \"content\" >sub1 &&\n> +\t\tgit add sub1 &&\n> +\t\tgit commit -m \"Replace sub1 with file\" &&\n> +\t\tgit checkout -b replace_file_with_sub1 &&\n> +\t\tgit revert HEAD &&\n> +\n> +\t\tgit checkout -b \"invalid_sub1\" \"add_sub1\" &&\n> +\t\tgit update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 &&\n> +\t\tgit commit -m \"Invalid sub1 commit\" &&\n> +\t\tgit checkout -b valid_sub1 &&\n> +\t\tgit revert HEAD &&\n> +\t\tgit checkout master\n> +\t)\n> +}\n> +\n> +# Helper function to replace gitfile with .git directory\n> +replace_gitfile_with_git_dir () {\n> +\t(\n> +\t\tcd \"$1\" &&\n> +\t\tgit_dir=\"$(git rev-parse --git-dir)\" &&\n> +\t\trm -f .git &&\n> +\t\tcp -a \"$git_dir\" .git &&\n\nWe avoid \"cp -a\" for portability, don't we?\n\n> +\t\tGIT_WORK_TREE=. git config --unset core.worktree\n\nHmph.  What does GIT_WORK_TREE=. alone without GIT_DIR=<somewhere>\ndo?  It's not like it is a workaround for \"git config\" that complains\nwhen you do not have a working tree, right?  Puzzled...\n\n> +\t)\n> +}\n> +\n> +# Test that the .git directory in the submodule is unchanged (except for the\n> +# core.worktree setting)\n> +test_git_directory_is_unchanged () {\n> +\t(\n> +\t\tcd \"$1\" &&\n> +\t\tgit config core.worktree \"../../../$1\"\n> +\t) &&\n> +\tgit diff -r \".git/modules/$1\" \"$1/.git\" &&\n\nI'd prefer to see \"--no-index\" spelled out, if that is what is going\non.\n\n> +\t(\n> +\t\tcd \"$1\" &&\n> +\t\tGIT_WORK_TREE=. git config --unset core.worktree\n> +\t)\n> +}\n> +\n> +# Helper function to be executed at the start of every test below, it sets up\n> +# the submodule repo if it doesn't exist and configures the most problematic\n> +# settings for diff.ignoreSubmodules.\n> +prolog () {\n> +\t(test -d submodule_update_repo || create_lib_submodule_repo) &&\n> +\ttest_config_global diff.ignoreSubmodules all &&\n> +\ttest_config diff.ignoreSubmodules all\n> +}\n> +\n> +# Helper function to bring work tree back into the state given by the\n> +# commit. This includes trying to populate sub1 accordingly if it exists and\n> +# should be updated to an existing commit.\n> +reset_work_tree_to () {\n> +\trm -rf submodule_update &&\n> +\tgit clone submodule_update_repo submodule_update &&\n> +\t(\n> +\t\tcd submodule_update &&\n> +\t\trm -rf sub1 &&\n> +\t\tgit checkout -f \"$1\" &&\n> +\t\tgit status -u -s >actual &&\n> +\t\ttest_must_be_empty actual &&\n> +\t\tsha1=$(git ls-tree HEAD \"sub1\" 2>/dev/null | grep 160000 | tr '\\t' ' ' | cut -d ' ' -f3) &&\n\nWhy discard the standard error stream?\n\ngrep|tr|cut looks somewhat stupid.  Can't we do that with a single\nsed?\n\n\tsha1=$(git ls-tree HEAD sub1 | sed -ne \"s/^160000 commit \\($_x40\\)     .*/\\1/p\")\n\nor better yet, perhaps\n\n\tsha1=$(git rev-parse HEAD:sub1)\n\n\n> +# Test that the given submodule at path \"$1\" contains the content according\n> +# to the submodule commit recorded in the superproject's commit \"$2\"\n> +test_submodule_content () {\n> +\tif test $# != 2\n> +\tthen\n> +\t\techo \"test_submodule_content needs two arguments\"\n> +\t\treturn 1\n> +\tfi &&\n> +\tsubmodule=\"$1\" &&\n> +\tcommit=\"$2\" &&\n> +\ttest -d \"$submodule\"/ &&\n> +\tif ! test -f \"$submodule\"/.git && ! test -d \"$submodule\"/.git\n\nI wonder if we can get away with a single \"test -e\" (we do not\nexpect us to be creating device nodes or fifos there, do we?).\n\n> +\tthen\n> +\t\techo \"Submodule $submodule is not populated\"\n> +\t\treturn 1\n> +\tfi &&\n> +\tsha1=$(git ls-tree \"$commit\" \"$submodule\" 2>/dev/null | tr '\\t' ' ' | cut -d ' ' -f3) &&\n\nLikewise.\n"},{"id":"244454","messageId":"53A0710B.2060202@web.de","threadId":"36919","inReplyTo":"xmqq7g4gpl1g.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 01/14] test-lib: add test_dir_is_empty()","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-17T16:47:07Z","receivedAt":"2014-06-17T16:47:07Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 17.06.2014 00:05, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> For the upcoming submodule test framework we often need to assert that an\n>> empty directory exists in the work tree. Add the test_dir_is_empty()\n>> function which asserts that the given argument is an empty directory.\n>>\n>> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n>> ---\n>>  t/test-lib-functions.sh | 11 +++++++++++\n>>  1 file changed, 11 insertions(+)\n>>\n>> diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\n>> index 158e10a..546f0a6 100644\n>> --- a/t/test-lib-functions.sh\n>> +++ b/t/test-lib-functions.sh\n>> @@ -489,6 +489,17 @@ test_path_is_dir () {\n>>  \tfi\n>>  }\n>>\n>> +# Check if the directory exists and is empty as expected, barf otherwise.\n>> +test_dir_is_empty () {\n>> +\ttest_path_is_dir \"$1\" &&\n>> +\tif test \"$(ls -a1 \"$1\" | egrep -v '^\\.\\.?$')\"\n> \n> It is safer to say \"test -n\" when testing an emptyness of a string\n> whose contents you do not know or control (e.g. the string may begin\n> with \"-something\").\n\nYup, will do so in v2.\n\n>> +\tthen\n>> +\t\techo \"Directory '$1' is not empty, it contains:\"\n>> +\t\tls -la \"$1\"\n>> +\t\treturn 1\n>> +\tfi\n>> +}\n>> +\n>>  test_path_is_missing () {\n>>  \tif [ -e \"$1\" ]\n>>  \tthen\n> \n"},{"id":"244459","messageId":"53A07BCE.5010100@web.de","threadId":"36919","inReplyTo":"xmqqwqcgo4gc.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 02/14] submodules: Add the lib-submodule-update.sh test library","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-17T17:33:02Z","receivedAt":"2014-06-17T17:33:02Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 17.06.2014 00:49, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> Add this test library to simplify covering all combinations of submodule\n>> update scenarios without having to add those to a test of each work tree\n>> manipulating command over and over again.\n>>\n>> The functions test_submodule_switch() and test_submodule_forced_switch()\n>> are intended to be called from a test script with a single argument. This\n>> argument is either a work tree manipulating command (including any command\n>> line options) or a function (when more than a single git command is needed\n>> to switch work trees from the current HEAD to another commit). This\n>> command (or function) is passed a target branch as argument. The two new\n>> functions check that each submodule transition is handled as expected,\n>> which currently means that submodule work trees are not affected until\n>> \"git submodule update\" is called. The \"forced\" variant is for commands\n>> using their '-f' or '--hard' option and expects them to overwrite local\n>> modifications as a result. Each of these two functions contains 14\n>> tests_expect_* calls.\n>>\n>> Calling one of these test functions the first time creates a repository\n>> named \"submodule_update_repo\". At first it contains two files, then a\n>> single submodule is added in another commit followed by commits covering\n>> all relevant submodule modifications. This repository is newly cloned into\n>> the \"submodule_update\" for each test_expect_* to avoid interference\n>> between different parts of the test functions (some to-be-tested commands\n>> also manipulate refs along with the work tree, e.g. \"git reset\").\n>>\n>> Follow-up commits will then call these two test functions for all work\n>> tree manipulating commands (with a combination of all their options\n>> relevant to what they do with the work tree) making sure they work as\n>> expected. Later this test library will be extended to cover merges\n>> resulting in conflicts too. Also it is intended to be easily extendable\n>> for the recursive update functionality, where even more combinations of\n>> submodule modifications have to be tested for.\n>>\n>> This version documents two bugs in current Git with expected failures:\n>>\n>> *) When a submodule is replaced with a tracked file of the same name the\n>>    submodule work tree including any local modifications (and even the\n>>    whole history if it uses a .git directory instead of a gitfile!) is\n>>    silently removed.\n>>\n>> *) Forced work tree updates happily manipulate files in the directory of a\n>>    submodule that has just been removed in the superproject (but is of\n>>    course still present in the work tree due to the way submodules are\n>>    currently handled). This becomes dangerous when files in the submodule\n>>    directory are overwritten by files from the new superproject commit, as\n>>    any modifications to the submodule files will be lost) and is expected\n>>    to also destroy history in the - admittedly unlikely case - the new\n>>    commit adds a file named \".git\" to the submodule directory.\n>>\n>> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n>> ---\n>>  t/lib-submodule-update.sh | 630 ++++++++++++++++++++++++++++++++++++++++++++++\n>>  1 file changed, 630 insertions(+)\n>>  create mode 100755 t/lib-submodule-update.sh\n>>\n>> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n>> new file mode 100755\n>> index 0000000..c6c842a\n>> --- /dev/null\n>> +++ b/t/lib-submodule-update.sh\n>> @@ -0,0 +1,630 @@\n>> +# Create a submodule layout used for all tests below.\n>> +#\n>> +# The following use cases are covered:\n>> +# - New submodule (no_submodule => add_sub1)\n>> +# - Removed submodule (add_sub1 => remove_sub1)\n>> +# - Updated submodule (add_sub1 => modify_sub1)\n>> +# - Submodule updated to invalid commit (add_sub1 => invalid_sub1)\n>> +# - Submodule updated from invalid commit (invalid_sub1 => valid_sub1)\n>> +# - Submodule replaced by tracked files in directory (add_sub1 =>\n>> +#   replace_sub1_with_directory)\n>> +# - Directory containing tracked files replaced by submodule\n>> +#   (replace_sub1_with_directory => replace_directory_with_sub1)\n>> +# - Submodule replaced by tracked file with the same name (add_sub1 =>\n>> +#   replace_sub1_with_file)\n>> +# - Tracked file replaced by submodule (replace_sub1_with_file =>\n>> +#   replace_file_with_sub1)\n>> +#\n>> +#                   --O-----O\n>> +#                  /  ^     replace_directory_with_sub1\n>> +#                 /   replace_sub1_with_directory\n>> +#                /----O\n>> +#               /     ^\n>> +#              /      modify_sub1\n>> +#      O------O-------O\n>> +#      ^      ^\\      ^\n>> +#      |      | \\     remove_sub1\n>> +#      |      |  -----O-----O\n>> +#      |      |   \\   ^     replace_file_with_sub1\n>> +#      |      |    \\  replace_sub1_with_file\n>> +#      |   add_sub1 --O-----O\n>> +# no_submodule        ^     valid_sub1\n>> +#                     invalid_sub1\n>> +#\n>> +create_lib_submodule_repo () {\n>> +\tgit init submodule_update_repo &&\n>> +\t(\n>> +\t\tcd submodule_update_repo &&\n>> +\t\techo \"expect\" >>.gitignore &&\n>> +\t\techo \"actual\" >>.gitignore &&\n>> +\t\techo \"x\" >file1 &&\n>> +\t\techo \"y\" >file2 &&\n>> +\t\tgit add .gitignore file1 file2 &&\n>> +\t\tgit commit -m \"Base\" &&\n>> +\t\tgit branch \"no_submodule\" &&\n>> +\n>> +\t\tgit checkout -b \"add_sub1\" &&\n>> +\t\tgit submodule add ./. sub1 &&\n> \n> This is not technically wrong per-se, but having the project's\n> history itself as its own submodule *is* something nobody sane would\n> do in the real life.  Do we really have to do it this unusual way?\n\nI agree that this isn't a sane setup for real world usage, but I did\nthat because it makes things easier when adding tests for recursive\nsubmodule update later, as we can then use the same test setup just\none submodule level deeper.\n\n>> +\t\tgit config -f .gitmodules submodule.sub1.ignore all &&\n>> +\t\tgit config submodule.sub1.ignore all &&\n>> +\t\tgit add .gitmodules &&\n>> +\t\tgit commit -m \"Add sub1\" &&\n>> +\t\tgit checkout -b remove_sub1 &&\n>> +\t\tgit revert HEAD &&\n>> +\n>> +\t\tgit checkout -b \"modify_sub1\" \"add_sub1\" &&\n>> +\t\tgit submodule update &&\n>> +\t\t(\n>> +\t\t\tcd sub1 &&\n>> +\t\t\tgit fetch &&\n>> +\t\t\tgit checkout -b \"modifications\" &&\n>> +\t\t\techo \"z\" >file2 &&\n>> +\t\t\techo \"x\" >file3 &&\n>> +\t\t\tgit add file2 file3 &&\n>> +\t\t\tgit commit -m \"modified file2 and added file3\" &&\n>> +\t\t\tgit push origin modifications\n>> +\t\t) &&\n>> +\t\tgit add sub1 &&\n>> +\t\tgit commit -m \"Modify sub1\" &&\n>> +\n>> +\t\tgit checkout -b \"replace_sub1_with_directory\" \"add_sub1\" &&\n>> +\t\tgit submodule update &&\n>> +\t\t(\n>> +\t\t\tcd sub1 &&\n>> +\t\t\tgit checkout modifications\n>> +\t\t) &&\n>> +\t\tgit rm --cached sub1 &&\n>> +\t\trm sub1/.git* &&\n>> +\t\tgit config -f .gitmodules --remove-section \"submodule.sub1\" &&\n>> +\t\tgit add .gitmodules sub1/* &&\n>> +\t\tgit commit -m \"Replace sub1 with directory\" &&\n>> +\t\tgit checkout -b replace_directory_with_sub1 &&\n>> +\t\tgit revert HEAD &&\n>> +\n>> +\t\tgit checkout -b \"replace_sub1_with_file\" \"add_sub1\" &&\n>> +\t\tgit rm sub1 &&\n>> +\t\techo \"content\" >sub1 &&\n>> +\t\tgit add sub1 &&\n>> +\t\tgit commit -m \"Replace sub1 with file\" &&\n>> +\t\tgit checkout -b replace_file_with_sub1 &&\n>> +\t\tgit revert HEAD &&\n>> +\n>> +\t\tgit checkout -b \"invalid_sub1\" \"add_sub1\" &&\n>> +\t\tgit update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 &&\n>> +\t\tgit commit -m \"Invalid sub1 commit\" &&\n>> +\t\tgit checkout -b valid_sub1 &&\n>> +\t\tgit revert HEAD &&\n>> +\t\tgit checkout master\n>> +\t)\n>> +}\n>> +\n>> +# Helper function to replace gitfile with .git directory\n>> +replace_gitfile_with_git_dir () {\n>> +\t(\n>> +\t\tcd \"$1\" &&\n>> +\t\tgit_dir=\"$(git rev-parse --git-dir)\" &&\n>> +\t\trm -f .git &&\n>> +\t\tcp -a \"$git_dir\" .git &&\n> \n> We avoid \"cp -a\" for portability, don't we?\n\nYup, will change to \"cp -R\".\n\n>> +\t\tGIT_WORK_TREE=. git config --unset core.worktree\n> \n> Hmph.  What does GIT_WORK_TREE=. alone without GIT_DIR=<somewhere>\n> do?  It's not like it is a workaround for \"git config\" that complains\n> when you do not have a working tree, right?  Puzzled...\n\nIt is, it overrides the core.worktree config that would stop us\nfrom unsetting the core.worktree config with this error message:\n\n  fatal: Could not chdir to '../../../sub1': No such file or directory\n\n(We use the same pattern in git-submodule.sh and some other tests)\n\n>> +\t)\n>> +}\n>> +\n>> +# Test that the .git directory in the submodule is unchanged (except for the\n>> +# core.worktree setting)\n>> +test_git_directory_is_unchanged () {\n>> +\t(\n>> +\t\tcd \"$1\" &&\n>> +\t\tgit config core.worktree \"../../../$1\"\n>> +\t) &&\n>> +\tgit diff -r \".git/modules/$1\" \"$1/.git\" &&\n> \n> I'd prefer to see \"--no-index\" spelled out, if that is what is going\n> on.\n\nThanks for catching, this should read \"diff -r\" (to compare the two\ndirectories like the comment above states). Correcting this brings\nup two test failures (in which the index file changed), will\ninvestigate ...\n\n>> +\t(\n>> +\t\tcd \"$1\" &&\n>> +\t\tGIT_WORK_TREE=. git config --unset core.worktree\n>> +\t)\n>> +}\n>> +\n>> +# Helper function to be executed at the start of every test below, it sets up\n>> +# the submodule repo if it doesn't exist and configures the most problematic\n>> +# settings for diff.ignoreSubmodules.\n>> +prolog () {\n>> +\t(test -d submodule_update_repo || create_lib_submodule_repo) &&\n>> +\ttest_config_global diff.ignoreSubmodules all &&\n>> +\ttest_config diff.ignoreSubmodules all\n>> +}\n>> +\n>> +# Helper function to bring work tree back into the state given by the\n>> +# commit. This includes trying to populate sub1 accordingly if it exists and\n>> +# should be updated to an existing commit.\n>> +reset_work_tree_to () {\n>> +\trm -rf submodule_update &&\n>> +\tgit clone submodule_update_repo submodule_update &&\n>> +\t(\n>> +\t\tcd submodule_update &&\n>> +\t\trm -rf sub1 &&\n>> +\t\tgit checkout -f \"$1\" &&\n>> +\t\tgit status -u -s >actual &&\n>> +\t\ttest_must_be_empty actual &&\n>> +\t\tsha1=$(git ls-tree HEAD \"sub1\" 2>/dev/null | grep 160000 | tr '\\t' ' ' | cut -d ' ' -f3) &&\n> \n> Why discard the standard error stream?\n\nBecause we sometimes reset to commits where \"sub1\" isn't present:\n\n  fatal: Path 'sub1' does not exist in 'HEAD'\n\n> grep|tr|cut looks somewhat stupid.  Can't we do that with a single\n> sed?\n> \n> \tsha1=$(git ls-tree HEAD sub1 | sed -ne \"s/^160000 commit \\($_x40\\)     .*/\\1/p\")\n> \n> or better yet, perhaps\n> \n> \tsha1=$(git rev-parse HEAD:sub1)\n\nCool, that's much better. Due to the sometimes missing \"sub1\" I\nneeded to modify it to drop the error and not fail:\n\n  sha1=$(git rev-parse HEAD:sub1 2>/dev/null || true) &&\n\n>> +# Test that the given submodule at path \"$1\" contains the content according\n>> +# to the submodule commit recorded in the superproject's commit \"$2\"\n>> +test_submodule_content () {\n>> +\tif test $# != 2\n>> +\tthen\n>> +\t\techo \"test_submodule_content needs two arguments\"\n>> +\t\treturn 1\n>> +\tfi &&\n>> +\tsubmodule=\"$1\" &&\n>> +\tcommit=\"$2\" &&\n>> +\ttest -d \"$submodule\"/ &&\n>> +\tif ! test -f \"$submodule\"/.git && ! test -d \"$submodule\"/.git\n> \n> I wonder if we can get away with a single \"test -e\" (we do not\n> expect us to be creating device nodes or fifos there, do we?).\n\nBut a symbolic link maybe? I wouldn't object loosening this\ntest, but I thought it best to spell out the only two\ncurrently expected cases.\n\n>> +\tthen\n>> +\t\techo \"Submodule $submodule is not populated\"\n>> +\t\treturn 1\n>> +\tfi &&\n>> +\tsha1=$(git ls-tree \"$commit\" \"$submodule\" 2>/dev/null | tr '\\t' ' ' | cut -d ' ' -f3) &&\n> \n> Likewise.\n\nYup, I changed this to:\n\n  sha1=$(git rev-parse \"$commit:$submodule\")\n\nbecause \"$submodule\" should always exist when we end up here.\n"},{"id":"244461","messageId":"53A07DC6.3080406@web.de","threadId":"36919","inReplyTo":"CAPig+cSU_8USZu3cr=aaOun07jE2BhgLt7yu9ix_AikUpK+pJQ@mail.gmail.com","subject":"Re: [PATCH 09/14] rebase: add t3426 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-17T17:41:26Z","receivedAt":"2014-06-17T17:41:26Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 16.06.2014 11:57, schrieb Eric Sunshine:\n> On Sun, Jun 15, 2014 at 1:02 PM, Jens Lehmann <Jens.Lehmann@web.de> wrote:\n>> Test that the rebase command updates the work tree as expected for\n>> changes which don't result in conflicts. To make that work add two\n>> helper functions that add a commit only touching files and then\n>> revert it. This allows to rebase the target commit over these two\n>> and to compare the result.\n>>\n>> Set KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR to\n>> document that \"replace directory with submodule\" fails for an\n>> interactive rebase because a directory \"sub1\" already exists.\n>>\n>> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n>> ---\n>>  t/t3426-rebase-submodule.sh | 46 +++++++++++++++++++++++++++++++++++++++++++++\n>>  1 file changed, 46 insertions(+)\n>>  create mode 100755 t/t3426-rebase-submodule.sh\n>>\n>> diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\n>> new file mode 100755\n>> index 0000000..019ce52\n>> --- /dev/null\n>> +++ b/t/t3426-rebase-submodule.sh\n>> @@ -0,0 +1,46 @@\n>> +#!/bin/sh\n>> +\n>> +test_description='rebase can handle submodules'\n>> +\n>> +. ./test-lib.sh\n>> +. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n>> +. \"$TEST_DIRECTORY\"/lib-rebase.sh\n>> +\n>> +git_rebase () {\n>> +       git status -su >expected &&\n>> +       ls -1pR * >>expected &&\n>> +       git checkout -b ours HEAD &&\n>> +       echo x >>file1 &&\n>> +       git add file1 &&\n>> +       git commit -m add_x &&\n>> +       git revert HEAD &&\n>> +       git status -su >actual &&\n>> +       ls -1pR * >>actual &&\n>> +       test_cmp expected actual &&\n>> +       git rebase \"$1\"\n>> +}\n>> +\n>> +test_submodule_switch \"git_rebase\"\n>> +\n>> +git_rebase_interactive () {\n>> +       git status -su >expected &&\n>> +       ls -1pR * >>expected &&\n>> +       git checkout -b ours HEAD &&\n>> +       echo x >>file1 &&\n>> +       git add file1 &&\n>> +       git commit -m add_x &&\n>> +       git revert HEAD &&\n>> +       git status -su >actual &&\n>> +       ls -1pR * >>actual &&\n>> +       test_cmp expected actual &&\n>> +       set_fake_editor &&\n>> +       echo \"fake-editor.sh\" >.git/info/exclude\n> \n> Broken &&-chain.\n\nThanks for spotting!\n\n>> +       git rebase -i \"$1\"\n>> +}\n>> +\n>> +KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n>> +# The real reason \"replace directory with submodule\" fails is because a\n>> +# directory \"sub1\" exists, but we reuse the suppression added for merge here\n>> +test_submodule_switch \"git_rebase_interactive\"\n>> +\n>> +test_done\n>> --\n>> 2.0.0.275.gc479268\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n> \n"},{"id":"244466","messageId":"xmqqwqcfl6jh.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53A07BCE.5010100@web.de","subject":"Re: [PATCH 02/14] submodules: Add the lib-submodule-update.sh test library","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-06-17T18:44:50Z","receivedAt":"2014-06-17T18:44:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> Am 17.06.2014 00:49, schrieb Junio C Hamano:\n>> Jens Lehmann <Jens.Lehmann@web.de> writes:\n>>> +\t\tgit checkout -b \"add_sub1\" &&\n>>> +\t\tgit submodule add ./. sub1 &&\n>> \n>> This is not technically wrong per-se, but having the project's\n>> history itself as its own submodule *is* something nobody sane would\n>> do in the real life.  Do we really have to do it this unusual way?\n>\n> I agree that this isn't a sane setup for real world usage, but I did\n> that because it makes things easier when adding tests for recursive\n> submodule update later, as we can then use the same test setup just\n> one submodule level deeper.\n\nHmmm... ok....\n\n>>> +\t\tGIT_WORK_TREE=. git config --unset core.worktree\n>> \n>> Hmph.  What does GIT_WORK_TREE=. alone without GIT_DIR=<somewhere>\n>> do?  It's not like it is a workaround for \"git config\" that complains\n>> when you do not have a working tree, right?  Puzzled...\n>\n> It is, it overrides the core.worktree config that would stop us\n> from unsetting the core.worktree config with this error message:\n>\n>   fatal: Could not chdir to '../../../sub1': No such file or directory\n>\n> (We use the same pattern in git-submodule.sh and some other tests)\n\nIs this a work-around for a bug in \"git config\"?  Or is this an\nexpected failure and it is unusual and not realistic outside of test\nsetup to want to unset core.worktree?  I am inclined to think it is\nthe latter, but I dunno.\n\n>>> +\t\tsha1=$(git ls-tree HEAD \"sub1\" 2>/dev/null | grep 160000 | tr '\\t' ' ' | cut -d ' ' -f3) &&\n>> \n>> Why discard the standard error stream?\n>\n> Because we sometimes reset to commits where \"sub1\" isn't present:\n>\n>   fatal: Path 'sub1' does not exist in 'HEAD'\n\nHuh?  We shouldn't.\n\n\t$ git ls-tree HEAD no-such; echo $?\n        0\n\nIt discards errors that may happen in other situations, too---is\nthat something we do not have to worry about?\n\n> Cool, that's much better. Due to the sometimes missing \"sub1\" I\n> needed to modify it to drop the error and not fail:\n>\n>   sha1=$(git rev-parse HEAD:sub1 2>/dev/null || true) &&\n\nThe \"HEAD:sub1\" notation does require that the path exists in the\nspecified tree-ish.  Even if we tried to express the above in a more\ncarefully written form:\n\n\t# We may or may not have sub1 in HEAD\n        if \"sub1 exists in HEAD\"\n        then\n        \tsha1=$(git rev-parse HEAD:sub1)\n\telse\n\t\tsha1= # empty\n\tfi\n\nwe would end up using \"git rev-parse HEAD:sub1\" to implement \"sub1\nexists in HEAD\" part, so your updated alternative would be the best\nwe could do, I would think.\n\n>>> +# Test that the given submodule at path \"$1\" contains the content according\n>>> +# to the submodule commit recorded in the superproject's commit \"$2\"\n>>> +test_submodule_content () {\n>>> +\tif test $# != 2\n>>> +\tthen\n>>> +\t\techo \"test_submodule_content needs two arguments\"\n>>> +\t\treturn 1\n>>> +\tfi &&\n>>> +\tsubmodule=\"$1\" &&\n>>> +\tcommit=\"$2\" &&\n>>> +\ttest -d \"$submodule\"/ &&\n>>> +\tif ! test -f \"$submodule\"/.git && ! test -d \"$submodule\"/.git\n>> \n>> I wonder if we can get away with a single \"test -e\" (we do not\n>> expect us to be creating device nodes or fifos there, do we?).\n>\n> But a symbolic link maybe?\n\nSymlinks should pose no problems, I would say, without loosening\nanything.\n\n\t$ test -f RelNotes; echo $?; test -e RelNotes; echo $?\n        0\n        0\n        $ ln -s t tests; test -d tests; echo $?; test -e tests; echo $?\n        0\n        $ ln -s no-such x; test -f x; echo $?; test -e x; echo $?\n        1\n        1\n\n\nThanks.\n"},{"id":"244481","messageId":"53A0A93A.9050305@web.de","threadId":"36919","inReplyTo":"xmqqwqcfl6jh.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 02/14] submodules: Add the lib-submodule-update.sh test library","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-17T20:46:50Z","receivedAt":"2014-06-17T20:46:50Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 17.06.2014 20:44, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> Am 17.06.2014 00:49, schrieb Junio C Hamano:\n>>> Jens Lehmann <Jens.Lehmann@web.de> writes:\n>>>> +\t\tGIT_WORK_TREE=. git config --unset core.worktree\n>>>\n>>> Hmph.  What does GIT_WORK_TREE=. alone without GIT_DIR=<somewhere>\n>>> do?  It's not like it is a workaround for \"git config\" that complains\n>>> when you do not have a working tree, right?  Puzzled...\n>>\n>> It is, it overrides the core.worktree config that would stop us\n>> from unsetting the core.worktree config with this error message:\n>>\n>>   fatal: Could not chdir to '../../../sub1': No such file or directory\n>>\n>> (We use the same pattern in git-submodule.sh and some other tests)\n> \n> Is this a work-around for a bug in \"git config\"?  Or is this an\n> expected failure and it is unusual and not realistic outside of test\n> setup to want to unset core.worktree?  I am inclined to think it is\n> the latter, but I dunno.\n\nI didn't think deeply about that, but when I first encountered\nthis behavior it felt a bit strange that config does a chdir into\nthe work tree. I somehow expected it only to access the config\nfile in GIT_DIR and not the work tree, but I didn't care enough\nto investigate further after I found this solution.\n\n>>>> +\t\tsha1=$(git ls-tree HEAD \"sub1\" 2>/dev/null | grep 160000 | tr '\\t' ' ' | cut -d ' ' -f3) &&\n>>>\n>>> Why discard the standard error stream?\n>>\n>> Because we sometimes reset to commits where \"sub1\" isn't present:\n>>\n>>   fatal: Path 'sub1' does not exist in 'HEAD'\n> \n> Huh?  We shouldn't.\n> \n> \t$ git ls-tree HEAD no-such; echo $?\n>         0\n\nYou are correct, it looks like I used rev-parse instead of\nls-files when producing that error.\n\n> It discards errors that may happen in other situations, too---is\n> that something we do not have to worry about?\n\nI'll look deeper into that tomorrow. After all in some tests\n\"sub1\" will be a file and not a submodule, and then we should\nnot try to populate it ...\n\n>>>> +# Test that the given submodule at path \"$1\" contains the content according\n>>>> +# to the submodule commit recorded in the superproject's commit \"$2\"\n>>>> +test_submodule_content () {\n>>>> +\tif test $# != 2\n>>>> +\tthen\n>>>> +\t\techo \"test_submodule_content needs two arguments\"\n>>>> +\t\treturn 1\n>>>> +\tfi &&\n>>>> +\tsubmodule=\"$1\" &&\n>>>> +\tcommit=\"$2\" &&\n>>>> +\ttest -d \"$submodule\"/ &&\n>>>> +\tif ! test -f \"$submodule\"/.git && ! test -d \"$submodule\"/.git\n>>>\n>>> I wonder if we can get away with a single \"test -e\" (we do not\n>>> expect us to be creating device nodes or fifos there, do we?).\n>>\n>> But a symbolic link maybe?\n> \n> Symlinks should pose no problems, ...\n\nOh, I forgot to add a smiley there, I haven't been serious about\nthat statement. I don't care too deeply about it but feel a bit\nmore confident with the two explicit tests. Do you want me to\nchange them to a single \"test -e\"?\n"},{"id":"244482","messageId":"xmqqlhsvl00x.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53A0A93A.9050305@web.de","subject":"Re: [PATCH 02/14] submodules: Add the lib-submodule-update.sh test library","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-06-17T21:05:34Z","receivedAt":"2014-06-17T21:05:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> Oh, I forgot to add a smiley there, I haven't been serious about\n> that statement. I don't care too deeply about it but feel a bit\n> more confident with the two explicit tests. Do you want me to\n> change them to a single \"test -e\"?\n\nI have no strong preference.\n"},{"id":"244704","messageId":"53A34427.6010704@web.de","threadId":"36919","inReplyTo":"539DD068.6020301@web.de","subject":"[PATCH v2 01/14] test-lib: add test_dir_is_empty()","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-19T20:12:23Z","receivedAt":"2014-06-19T20:12:23Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"For the upcoming submodule test framework we often need to assert that an\nempty directory exists in the work tree. Add the test_dir_is_empty()\nfunction which asserts that the given argument is an empty directory.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\n\nChanges to v1:\n\n*) Added \"-n\" to test expression (you have this as \"SQUASH???\" commit in pu)\n\n\n t/test-lib-functions.sh | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex c617c82..acd9a55 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -489,6 +489,17 @@ test_path_is_dir () {\n \tfi\n }\n\n+# Check if the directory exists and is empty as expected, barf otherwise.\n+test_dir_is_empty () {\n+\ttest_path_is_dir \"$1\" &&\n+\tif test -n \"$(ls -a1 \"$1\" | egrep -v '^\\.\\.?$')\"\n+\tthen\n+\t\techo \"Directory '$1' is not empty, it contains:\"\n+\t\tls -la \"$1\"\n+\t\treturn 1\n+\tfi\n+}\n+\n test_path_is_missing () {\n \tif [ -e \"$1\" ]\n \tthen\n-- \n2.0.0.406.gf4dce28\n"},{"id":"244705","messageId":"53A3443D.9020000@web.de","threadId":"36919","inReplyTo":"539DD09A.7010200@web.de","subject":"[PATCH v2 02/14] submodules: Add the lib-submodule-update.sh test library","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-19T20:12:45Z","receivedAt":"2014-06-19T20:12:45Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Add this test library to simplify covering all combinations of submodule\nupdate scenarios without having to add those to a test of each work tree\nmanipulating command over and over again.\n\nThe functions test_submodule_switch() and test_submodule_forced_switch()\nare intended to be called from a test script with a single argument. This\nargument is either a work tree manipulating command (including any command\nline options) or a function (when more than a single git command is needed\nto switch work trees from the current HEAD to another commit). This\ncommand (or function) is passed a target branch as argument. The two new\nfunctions check that each submodule transition is handled as expected,\nwhich currently means that submodule work trees are not affected until\n\"git submodule update\" is called. The \"forced\" variant is for commands\nusing their '-f' or '--hard' option and expects them to overwrite local\nmodifications as a result. Each of these two functions contains 14\ntests_expect_* calls.\n\nCalling one of these test functions the first time creates a repository\nnamed \"submodule_update_repo\". At first it contains two files, then a\nsingle submodule is added in another commit followed by commits covering\nall relevant submodule modifications. This repository is newly cloned into\nthe \"submodule_update\" for each test_expect_* to avoid interference\nbetween different parts of the test functions (some to-be-tested commands\nalso manipulate refs along with the work tree, e.g. \"git reset\").\n\nFollow-up commits will then call these two test functions for all work\ntree manipulating commands (with a combination of all their options\nrelevant to what they do with the work tree) making sure they work as\nexpected. Later this test library will be extended to cover merges\nresulting in conflicts too. Also it is intended to be easily extendable\nfor the recursive update functionality, where even more combinations of\nsubmodule modifications have to be tested for.\n\nThis version documents two bugs in current Git with expected failures:\n\n*) When a submodule is replaced with a tracked file of the same name the\n   submodule work tree including any local modifications (and even the\n   whole history if it uses a .git directory instead of a gitfile!) is\n   silently removed.\n\n*) Forced work tree updates happily manipulate files in the directory of a\n   submodule that has just been removed in the superproject (but is of\n   course still present in the work tree due to the way submodules are\n   currently handled). This becomes dangerous when files in the submodule\n   directory are overwritten by files from the new superproject commit, as\n   any modifications to the submodule files will be lost) and is expected\n   to also destroy history in the - admittedly unlikely case - the new\n   commit adds a file named \".git\" to the submodule directory.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\n\nChanges to v1:\n\n*) avoid non-portable \"cp -a\"\n\n*) use \"diff -r\" without \"git \" when comparing directory trees\n\n*) simplify retrieving the SHA-1 of sub1\n\n*) call test_git_directory_is_unchanged before test_submodule_content (this\n   was the reason for two test failures after removing the \"git \" before\n   \"diff\" as test_submodule_content would sometimes modify the index)\n\n\n t/lib-submodule-update.sh | 632 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 632 insertions(+)\n create mode 100755 t/lib-submodule-update.sh\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nnew file mode 100755\nindex 0000000..03217b2\n--- /dev/null\n+++ b/t/lib-submodule-update.sh\n@@ -0,0 +1,632 @@\n+# Create a submodule layout used for all tests below.\n+#\n+# The following use cases are covered:\n+# - New submodule (no_submodule => add_sub1)\n+# - Removed submodule (add_sub1 => remove_sub1)\n+# - Updated submodule (add_sub1 => modify_sub1)\n+# - Submodule updated to invalid commit (add_sub1 => invalid_sub1)\n+# - Submodule updated from invalid commit (invalid_sub1 => valid_sub1)\n+# - Submodule replaced by tracked files in directory (add_sub1 =>\n+#   replace_sub1_with_directory)\n+# - Directory containing tracked files replaced by submodule\n+#   (replace_sub1_with_directory => replace_directory_with_sub1)\n+# - Submodule replaced by tracked file with the same name (add_sub1 =>\n+#   replace_sub1_with_file)\n+# - Tracked file replaced by submodule (replace_sub1_with_file =>\n+#   replace_file_with_sub1)\n+#\n+#                   --O-----O\n+#                  /  ^     replace_directory_with_sub1\n+#                 /   replace_sub1_with_directory\n+#                /----O\n+#               /     ^\n+#              /      modify_sub1\n+#      O------O-------O\n+#      ^      ^\\      ^\n+#      |      | \\     remove_sub1\n+#      |      |  -----O-----O\n+#      |      |   \\   ^     replace_file_with_sub1\n+#      |      |    \\  replace_sub1_with_file\n+#      |   add_sub1 --O-----O\n+# no_submodule        ^     valid_sub1\n+#                     invalid_sub1\n+#\n+create_lib_submodule_repo () {\n+\tgit init submodule_update_repo &&\n+\t(\n+\t\tcd submodule_update_repo &&\n+\t\techo \"expect\" >>.gitignore &&\n+\t\techo \"actual\" >>.gitignore &&\n+\t\techo \"x\" >file1 &&\n+\t\techo \"y\" >file2 &&\n+\t\tgit add .gitignore file1 file2 &&\n+\t\tgit commit -m \"Base\" &&\n+\t\tgit branch \"no_submodule\" &&\n+\n+\t\tgit checkout -b \"add_sub1\" &&\n+\t\tgit submodule add ./. sub1 &&\n+\t\tgit config -f .gitmodules submodule.sub1.ignore all &&\n+\t\tgit config submodule.sub1.ignore all &&\n+\t\tgit add .gitmodules &&\n+\t\tgit commit -m \"Add sub1\" &&\n+\t\tgit checkout -b remove_sub1 &&\n+\t\tgit revert HEAD &&\n+\n+\t\tgit checkout -b \"modify_sub1\" \"add_sub1\" &&\n+\t\tgit submodule update &&\n+\t\t(\n+\t\t\tcd sub1 &&\n+\t\t\tgit fetch &&\n+\t\t\tgit checkout -b \"modifications\" &&\n+\t\t\techo \"z\" >file2 &&\n+\t\t\techo \"x\" >file3 &&\n+\t\t\tgit add file2 file3 &&\n+\t\t\tgit commit -m \"modified file2 and added file3\" &&\n+\t\t\tgit push origin modifications\n+\t\t) &&\n+\t\tgit add sub1 &&\n+\t\tgit commit -m \"Modify sub1\" &&\n+\n+\t\tgit checkout -b \"replace_sub1_with_directory\" \"add_sub1\" &&\n+\t\tgit submodule update &&\n+\t\t(\n+\t\t\tcd sub1 &&\n+\t\t\tgit checkout modifications\n+\t\t) &&\n+\t\tgit rm --cached sub1 &&\n+\t\trm sub1/.git* &&\n+\t\tgit config -f .gitmodules --remove-section \"submodule.sub1\" &&\n+\t\tgit add .gitmodules sub1/* &&\n+\t\tgit commit -m \"Replace sub1 with directory\" &&\n+\t\tgit checkout -b replace_directory_with_sub1 &&\n+\t\tgit revert HEAD &&\n+\n+\t\tgit checkout -b \"replace_sub1_with_file\" \"add_sub1\" &&\n+\t\tgit rm sub1 &&\n+\t\techo \"content\" >sub1 &&\n+\t\tgit add sub1 &&\n+\t\tgit commit -m \"Replace sub1 with file\" &&\n+\t\tgit checkout -b replace_file_with_sub1 &&\n+\t\tgit revert HEAD &&\n+\n+\t\tgit checkout -b \"invalid_sub1\" \"add_sub1\" &&\n+\t\tgit update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 &&\n+\t\tgit commit -m \"Invalid sub1 commit\" &&\n+\t\tgit checkout -b valid_sub1 &&\n+\t\tgit revert HEAD &&\n+\t\tgit checkout master\n+\t)\n+}\n+\n+# Helper function to replace gitfile with .git directory\n+replace_gitfile_with_git_dir () {\n+\t(\n+\t\tcd \"$1\" &&\n+\t\tgit_dir=\"$(git rev-parse --git-dir)\" &&\n+\t\trm -f .git &&\n+\t\tcp -R \"$git_dir\" .git &&\n+\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t)\n+}\n+\n+# Test that the .git directory in the submodule is unchanged (except for the\n+# core.worktree setting, which we temporarily restore). Call this function\n+# before test_submodule_content as the latter might write the index file\n+# leading to false positive index differences.\n+test_git_directory_is_unchanged () {\n+\t(\n+\t\tcd \"$1\" &&\n+\t\tgit config core.worktree \"../../../$1\"\n+\t) &&\n+\tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n+\t(\n+\t\tcd \"$1\" &&\n+\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t)\n+}\n+\n+# Helper function to be executed at the start of every test below, it sets up\n+# the submodule repo if it doesn't exist and configures the most problematic\n+# settings for diff.ignoreSubmodules.\n+prolog () {\n+\t(test -d submodule_update_repo || create_lib_submodule_repo) &&\n+\ttest_config_global diff.ignoreSubmodules all &&\n+\ttest_config diff.ignoreSubmodules all\n+}\n+\n+# Helper function to bring work tree back into the state given by the\n+# commit. This includes trying to populate sub1 accordingly if it exists and\n+# should be updated to an existing commit.\n+reset_work_tree_to () {\n+\trm -rf submodule_update &&\n+\tgit clone submodule_update_repo submodule_update &&\n+\t(\n+\t\tcd submodule_update &&\n+\t\trm -rf sub1 &&\n+\t\tgit checkout -f \"$1\" &&\n+\t\tgit status -u -s >actual &&\n+\t\ttest_must_be_empty actual &&\n+\t\tsha1=$(git rev-parse HEAD:sub1 || true) &&\n+\t\tif test -n \"$sha1\" &&\n+\t\t   test $(cd \"sub1\" && git rev-parse --verify \"$sha1^{commit}\")\n+\t\tthen\n+\t\t\tgit submodule update --init --recursive \"sub1\"\n+\t\tfi\n+\t)\n+}\n+\n+# Test that the superproject contains the content according to commit \"$1\"\n+# (the work tree must match the index for everything but submodules but the\n+# index must exactly match the given commit including any submodule SHA-1s).\n+test_superproject_content () {\n+\tgit diff-index --cached \"$1\" >actual &&\n+\ttest_must_be_empty actual &&\n+\tgit diff-files --ignore-submodules >actual &&\n+\ttest_must_be_empty actual\n+}\n+\n+# Test that the given submodule at path \"$1\" contains the content according\n+# to the submodule commit recorded in the superproject's commit \"$2\"\n+test_submodule_content () {\n+\tif test $# != 2\n+\tthen\n+\t\techo \"test_submodule_content needs two arguments\"\n+\t\treturn 1\n+\tfi &&\n+\tsubmodule=\"$1\" &&\n+\tcommit=\"$2\" &&\n+\ttest -d \"$submodule\"/ &&\n+\tif ! test -f \"$submodule\"/.git && ! test -d \"$submodule\"/.git\n+\tthen\n+\t\techo \"Submodule $submodule is not populated\"\n+\t\treturn 1\n+\tfi &&\n+\tsha1=$(git rev-parse \"$commit:$submodule\") &&\n+\tif test -z \"$sha1\"\n+\tthen\n+\t\techo \"Couldn't retrieve SHA-1 of $submodule for $commit\"\n+\t\treturn 1\n+\tfi &&\n+\t(\n+\t\tcd \"$submodule\" &&\n+\t\tgit status -u -s >actual &&\n+\t\ttest_must_be_empty actual &&\n+\t\tgit diff \"$sha1\" >actual &&\n+\t\ttest_must_be_empty actual\n+\t)\n+}\n+\n+# Test that the following transitions are correctly handled:\n+# - Updated submodule\n+# - New submodule\n+# - Removed submodule\n+# - Directory containing tracked files replaced by submodule\n+# - Submodule replaced by tracked files in directory\n+# - Submodule replaced by tracked file with the same name\n+# - tracked file replaced by submodule\n+#\n+# The default is that submodule contents aren't changed until \"git submodule\n+# update\" is run. And even then that command doesn't delete the work tree of\n+# a removed submodule.\n+#\n+# Removing a submodule containing a .git directory must fail even when forced\n+# to protect the history!\n+#\n+\n+# Test that submodule contents are currently not updated when switching\n+# between commits that change a submodule.\n+test_submodule_switch () {\n+\tcommand=\"$1\"\n+\t######################### Appearing submodule #########################\n+\t# Switching to a commit letting a submodule appear creates empty dir ...\n+\ttest_expect_success \"$command: added submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... and doesn't care if it already exists ...\n+\ttest_expect_success \"$command: added submodule leaves existing empty directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tmkdir sub1 &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... unless there is an untracked file in its place.\n+\ttest_expect_success \"$command: added submodule doesn't remove untracked unignored file with same name\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\techo -n >sub1 &&\n+\t\t\ttest_must_fail $command add_sub1 &&\n+\t\t\ttest_superproject_content origin/no_submodule &&\n+\t\t\ttest_must_be_empty sub1\n+\t\t)\n+\t'\n+\t# Replacing a tracked file with a submodule produces an empty\n+\t# directory ...\n+\ttest_expect_success \"$command: replace tracked file with submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_file &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\t$command replace_file_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n+\t\t)\n+\t'\n+\t# ... as does removing a directory with tracked files with a\n+\t# submodule.\n+\ttest_expect_success \"$command: replace directory with submodule\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_directory &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\t$command replace_directory_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n+\t\t)\n+\t'\n+\n+\t######################## Disappearing submodule #######################\n+\t# Removing a submodule doesn't remove its work tree ...\n+\ttest_expect_success \"$command: removed submodule leaves submodule directory and its contents in place\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_success \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Replacing a submodule with files in a directory must fail as the\n+\t# submodule work tree isn't removed ...\n+\ttest_expect_success \"$command: replace submodule with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_success \"$command: replace submodule containing a .git directory with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Replacing it with a file must fail as it could throw away any local\n+\t# work tree changes ...\n+\ttest_expect_failure \"$command: replace submodule with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... or even destroy unpushed parts of submodule history if that\n+\t# still uses a .git directory.\n+\ttest_expect_failure \"$command: replace submodule containing a .git directory with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\n+\t########################## Modified submodule #########################\n+\t# Updating a submodule sha1 doesn't update the submodule's work tree\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\t$command modify_sub1 &&\n+\t\t\ttest_superproject_content origin/modify_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\tgit submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1\n+\t\t)\n+\t'\n+\n+\t# Updating a submodule to an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will fail\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree to invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\t$command invalid_sub1 &&\n+\t\t\ttest_superproject_content origin/invalid_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_must_fail git submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule from an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will succeed\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree from invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to invalid_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\t$command valid_sub1 &&\n+\t\t\ttest_superproject_content origin/valid_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/valid_sub1\n+\t\t)\n+\t'\n+}\n+\n+# Test that submodule contents are currently not updated when switching\n+# between commits that change a submodule, but throwing away local changes in\n+# the superproject is allowed.\n+test_submodule_forced_switch () {\n+\tcommand=\"$1\"\n+\t######################### Appearing submodule #########################\n+\t# Switching to a commit letting a submodule appear creates empty dir ...\n+\ttest_expect_success \"$command: added submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... and doesn't care if it already exists ...\n+\ttest_expect_success \"$command: added submodule leaves existing empty directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\tmkdir sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... unless there is an untracked file in its place.\n+\ttest_expect_success \"$command: added submodule does remove untracked unignored file with same name when forced\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\techo -n >sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1\n+\t\t)\n+\t'\n+\t# Replacing a tracked file with a submodule produces an empty\n+\t# directory ...\n+\ttest_expect_success \"$command: replace tracked file with submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_file &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\t$command replace_file_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n+\t\t)\n+\t'\n+\t# ... as does removing a directory with tracked files with a\n+\t# submodule.\n+\ttest_expect_success \"$command: replace directory with submodule\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_directory &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\t$command replace_directory_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n+\t\t)\n+\t'\n+\n+\t######################## Disappearing submodule #######################\n+\t# Removing a submodule doesn't remove its work tree ...\n+\ttest_expect_success \"$command: removed submodule leaves submodule directory and its contents in place\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_success \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Replacing a submodule with files in a directory must fail as the\n+\t# submodule work tree isn't removed ...\n+\ttest_expect_failure \"$command: replace submodule with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_failure \"$command: replace submodule containing a .git directory with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Replacing it with a file must fail as it could throw away any local\n+\t# work tree changes ...\n+\ttest_expect_failure \"$command: replace submodule with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... or even destroy unpushed parts of submodule history if that\n+\t# still uses a .git directory.\n+\ttest_expect_failure \"$command: replace submodule containing a .git directory with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\n+\t########################## Modified submodule #########################\n+\t# Updating a submodule sha1 doesn't update the submodule's work tree\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\t$command modify_sub1 &&\n+\t\t\ttest_superproject_content origin/modify_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\tgit submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule to an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will fail\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree to invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\t$command invalid_sub1 &&\n+\t\t\ttest_superproject_content origin/invalid_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_must_fail git submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule from an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will succeed\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree from invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to invalid_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\t$command valid_sub1 &&\n+\t\t\ttest_superproject_content origin/valid_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/valid_sub1\n+\t\t)\n+\t'\n+}\n-- \n2.0.0.406.gf4dce28\n"},{"id":"244706","messageId":"53A34440.604@web.de","threadId":"36919","inReplyTo":"539DD14C.4090609@web.de","subject":"[PATCH v2 07/14] bisect: add t6041 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-19T20:12:48Z","receivedAt":"2014-06-19T20:12:48Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the bisect command updates the work tree as expected. To make\nthat work with the new submodule test framework a git_bisect helper\nfunction is added. This adds a commit after the one given to be switched\nto and makes that one the bad commit. The starting point is then given to\nbisect as the good commit which makes bisect change the work tree to the\ncommit in between, which is the commit given.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\n\nChanges to v1:\n\n*) use \"expect\" instead of \"expected\"\n\n\n t/t6041-bisect-submodule.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n create mode 100755 t/t6041-bisect-submodule.sh\n\ndiff --git a/t/t6041-bisect-submodule.sh b/t/t6041-bisect-submodule.sh\nnew file mode 100755\nindex 0000000..c6b7aa6\n--- /dev/null\n+++ b/t/t6041-bisect-submodule.sh\n@@ -0,0 +1,32 @@\n+#!/bin/sh\n+\n+test_description='bisect can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+git_bisect () {\n+\tgit status -su >expect &&\n+\tls -1pR * >>expect &&\n+\ttar czf \"$TRASH_DIRECTORY/tmp.tgz\" * &&\n+\tGOOD=$(git rev-parse --verify HEAD) &&\n+\tgit checkout \"$1\" &&\n+\techo \"foo\" >bar &&\n+\tgit add bar &&\n+\tgit commit -m \"bisect bad\" &&\n+\tBAD=$(git rev-parse --verify HEAD) &&\n+\tgit reset --hard HEAD^^ &&\n+\tgit submodule update &&\n+\tgit bisect start &&\n+\tgit bisect good $GOOD &&\n+\trm -rf * &&\n+\ttar xzf \"$TRASH_DIRECTORY/tmp.tgz\" &&\n+\tgit status -su >actual &&\n+\tls -1pR * >>actual &&\n+\ttest_cmp expect actual &&\n+\tgit bisect bad $BAD\n+}\n+\n+test_submodule_switch \"git_bisect\"\n+\n+test_done\n-- \n2.0.0.406.gf4dce28\n"},{"id":"244708","messageId":"53A34443.3070301@web.de","threadId":"36919","inReplyTo":"539DD19B.6000504@web.de","subject":"[PATCH v2 09/14] rebase: add t3426 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-19T20:12:51Z","receivedAt":"2014-06-19T20:12:51Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the rebase command updates the work tree as expected for\nchanges which don't result in conflicts. To make that work add two\nhelper functions that add a commit only touching files and then\nrevert it. This allows to rebase the target commit over these two\nand to compare the result.\n\nSet KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR to\ndocument that \"replace directory with submodule\" fails for an\ninteractive rebase because a directory \"sub1\" already exists.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\n\nChanges to v1:\n\n*) fix broken &&-chain (you have this as \"SQUASH???\" commit in pu)\n\n*) use \"expect\" instead of \"expected\"\n\n\n t/t3426-rebase-submodule.sh | 46 +++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 46 insertions(+)\n create mode 100755 t/t3426-rebase-submodule.sh\n\ndiff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh\nnew file mode 100755\nindex 0000000..d5b896d\n--- /dev/null\n+++ b/t/t3426-rebase-submodule.sh\n@@ -0,0 +1,46 @@\n+#!/bin/sh\n+\n+test_description='rebase can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+git_rebase () {\n+\tgit status -su >expect &&\n+\tls -1pR * >>expect &&\n+\tgit checkout -b ours HEAD &&\n+\techo x >>file1 &&\n+\tgit add file1 &&\n+\tgit commit -m add_x &&\n+\tgit revert HEAD &&\n+\tgit status -su >actual &&\n+\tls -1pR * >>actual &&\n+\ttest_cmp expect actual &&\n+\tgit rebase \"$1\"\n+}\n+\n+test_submodule_switch \"git_rebase\"\n+\n+git_rebase_interactive () {\n+\tgit status -su >expect &&\n+\tls -1pR * >>expect &&\n+\tgit checkout -b ours HEAD &&\n+\techo x >>file1 &&\n+\tgit add file1 &&\n+\tgit commit -m add_x &&\n+\tgit revert HEAD &&\n+\tgit status -su >actual &&\n+\tls -1pR * >>actual &&\n+\ttest_cmp expect actual &&\n+\tset_fake_editor &&\n+\techo \"fake-editor.sh\" >.git/info/exclude &&\n+\tgit rebase -i \"$1\"\n+}\n+\n+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n+# The real reason \"replace directory with submodule\" fails is because a\n+# directory \"sub1\" exists, but we reuse the suppression added for merge here\n+test_submodule_switch \"git_rebase_interactive\"\n+\n+test_done\n-- \n2.0.0.406.gf4dce28\n"},{"id":"244707","messageId":"53A34446.5080009@web.de","threadId":"36919","inReplyTo":"539DD219.40108@web.de","subject":"[PATCH v2 13/14] stash: add t3906 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-19T20:12:54Z","receivedAt":"2014-06-19T20:12:54Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the stash apply command updates the work tree as expected for\nchanges which don't result in conflicts. To make that work add a helper\nfunction that uses read-tree to apply the changes of the target commit\nto the work tree, then stashes these changes and at last applies that\nstash.\n\nImplement the KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES switch\nand reuse two other already present switches to expect the known\nfailure that stash does ignore submodule changes.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\n\nChanges to v1:\n\n*) use \"expect\" instead of \"expected\"\n\n\n t/lib-submodule-update.sh  | 23 ++++++++++++++++++-----\n t/t3906-stash-submodule.sh | 24 ++++++++++++++++++++++++\n 2 files changed, 42 insertions(+), 5 deletions(-)\n create mode 100755 t/t3906-stash-submodule.sh\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex a38cf52..2a504b2 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -219,7 +219,14 @@ test_submodule_switch () {\n \tcommand=\"$1\"\n \t######################### Appearing submodule #########################\n \t# Switching to a commit letting a submodule appear creates empty dir ...\n-\ttest_expect_success \"$command: added submodule creates empty directory\" '\n+\tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n+\tthen\n+\t\t# Restoring stash fails to restore submodule index entry\n+\t\tRESULT=\"failure\"\n+\telse\n+\t\tRESULT=\"success\"\n+\tfi\n+\ttest_expect_$RESULT \"$command: added submodule creates empty directory\" '\n \t\tprolog &&\n \t\treset_work_tree_to no_submodule &&\n \t\t(\n@@ -233,7 +240,7 @@ test_submodule_switch () {\n \t\t)\n \t'\n \t# ... and doesn't care if it already exists ...\n-\ttest_expect_success \"$command: added submodule leaves existing empty directory alone\" '\n+\ttest_expect_$RESULT \"$command: added submodule leaves existing empty directory alone\" '\n \t\tprolog &&\n \t\treset_work_tree_to no_submodule &&\n \t\t(\n@@ -262,7 +269,7 @@ test_submodule_switch () {\n \t'\n \t# Replacing a tracked file with a submodule produces an empty\n \t# directory ...\n-\ttest_expect_success \"$command: replace tracked file with submodule creates empty directory\" '\n+\ttest_expect_$RESULT \"$command: replace tracked file with submodule creates empty directory\" '\n \t\tprolog &&\n \t\treset_work_tree_to replace_sub1_with_file &&\n \t\t(\n@@ -302,7 +309,13 @@ test_submodule_switch () {\n\n \t######################## Disappearing submodule #######################\n \t# Removing a submodule doesn't remove its work tree ...\n-\ttest_expect_success \"$command: removed submodule leaves submodule directory and its contents in place\" '\n+\tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n+\tthen\n+\t\tRESULT=\"failure\"\n+\telse\n+\t\tRESULT=\"success\"\n+\tfi\n+\ttest_expect_$RESULT \"$command: removed submodule leaves submodule directory and its contents in place\" '\n \t\tprolog &&\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\n@@ -314,7 +327,7 @@ test_submodule_switch () {\n \t\t)\n \t'\n \t# ... especially when it contains a .git directory.\n-\ttest_expect_success \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n+\ttest_expect_$RESULT \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n \t\tprolog &&\n \t\treset_work_tree_to add_sub1 &&\n \t\t(\ndiff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh\nnew file mode 100755\nindex 0000000..d7219d6\n--- /dev/null\n+++ b/t/t3906-stash-submodule.sh\n@@ -0,0 +1,24 @@\n+#!/bin/sh\n+\n+test_description='stash apply can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+git_stash () {\n+\tgit status -su >expect &&\n+\tls -1pR * >>expect &&\n+\tgit read-tree -u -m \"$1\" &&\n+\tgit stash &&\n+\tgit status -su >actual &&\n+\tls -1pR * >>actual &&\n+\ttest_cmp expect actual &&\n+\tgit stash apply\n+}\n+\n+KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES=1\n+KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n+test_submodule_switch \"git_stash\"\n+\n+test_done\n-- \n2.0.0.406.gf4dce28\n"},{"id":"244709","messageId":"53A34448.4070002@web.de","threadId":"36919","inReplyTo":"539DD23A.5000504@web.de","subject":"[PATCH v2 14/14] revert: add t3513 for submodule updates","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-06-19T20:12:56Z","receivedAt":"2014-06-19T20:12:56Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Test that the revert command updates the work tree as expected (for\nsubmodule changes which don't result in conflicts). Add a helper function\nto first revert the checked out target commit to make the last revert\nproduce the to-be-tested work tree.\n\nSet the KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT and\nKNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR switches to\ndocument that revert has the similar failures.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\n\nChanges to v1:\n\n*) use \"expect\" instead of \"expected\"\n\n\n t/t3513-revert-submodule.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n create mode 100755 t/t3513-revert-submodule.sh\n\ndiff --git a/t/t3513-revert-submodule.sh b/t/t3513-revert-submodule.sh\nnew file mode 100755\nindex 0000000..a1c4e02\n--- /dev/null\n+++ b/t/t3513-revert-submodule.sh\n@@ -0,0 +1,32 @@\n+#!/bin/sh\n+\n+test_description='revert can handle submodules'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-submodule-update.sh\n+\n+# Create a revert that moves from HEAD (including any test modifications to\n+# the work tree) to $1 by first checking out $1 and reverting it. Reverting\n+# the revert is the transition we test for. We tar the current work tree\n+# first so we can restore the work tree test setup after doing the checkout\n+# and revert.  We test here that the restored work tree content is identical\n+# to that at the beginning. The last revert is then tested by the framework.\n+git_revert () {\n+\tgit status -su >expect &&\n+\tls -1pR * >>expect &&\n+\ttar czf \"$TRASH_DIRECTORY/tmp.tgz\" * &&\n+\tgit checkout \"$1\" &&\n+\tgit revert HEAD &&\n+\trm -rf * &&\n+\ttar xzf \"$TRASH_DIRECTORY/tmp.tgz\" &&\n+\tgit status -su >actual &&\n+\tls -1pR * >>actual &&\n+\ttest_cmp expect actual &&\n+\tgit revert HEAD\n+}\n+\n+KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1\n+KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1\n+test_submodule_switch \"git_revert\"\n+\n+test_done\n-- \n2.0.0.406.gf4dce28\n"},{"id":"244986","messageId":"xmqqk3847k4r.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53A3443D.9020000@web.de","subject":"Re: [PATCH v2 02/14] submodules: Add the lib-submodule-update.sh test library","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-06-20T17:31:08Z","receivedAt":"2014-06-20T17:31:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> +\t\trm -rf sub1 &&\n> +\t\tgit checkout -f \"$1\" &&\n> +\t\tgit status -u -s >actual &&\n> +\t\ttest_must_be_empty actual &&\n> +\t\tsha1=$(git rev-parse HEAD:sub1 || true) &&\n\n\t$ xx=; xx=$(git rev-parse HEAD:no-such-path || true) ; echo $? ; echo \"<$xx>\"\n        fatal: Path 'no-such-path' does not exist in 'HEAD'\n        0\n        <HEAD:no-such-path>\n\nPerhaps you want --verify (or --revs-only) there, i.e.\n\n\tsha1=$(git rev-parse --verify HEAD:sub1 || :) &&\n\nor\n\n\tsha1=$(git rev-parse --revs-only HEAD:sub1) &&\n\n> +\t\tif test -n \"$sha1\" &&\n> ...\n> +\tsha1=$(git rev-parse \"$commit:$submodule\") &&\n\nAnd here too.\n\n> +\tif test -z \"$sha1\"\n"},{"id":"245258","messageId":"53B326FE.3010304@web.de","threadId":"36919","inReplyTo":"xmqqk3847k4r.fsf@gitster.dls.corp.google.com","subject":"[PATCH v3 02/14] submodules: Add the lib-submodule-update.sh test library","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-07-01T21:24:14Z","receivedAt":"2014-07-01T21:24:14Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Add this test library to simplify covering all combinations of submodule\nupdate scenarios without having to add those to a test of each work tree\nmanipulating command over and over again.\n\nThe functions test_submodule_switch() and test_submodule_forced_switch()\nare intended to be called from a test script with a single argument. This\nargument is either a work tree manipulating command (including any command\nline options) or a function (when more than a single git command is needed\nto switch work trees from the current HEAD to another commit). This\ncommand (or function) is passed a target branch as argument. The two new\nfunctions check that each submodule transition is handled as expected,\nwhich currently means that submodule work trees are not affected until\n\"git submodule update\" is called. The \"forced\" variant is for commands\nusing their '-f' or '--hard' option and expects them to overwrite local\nmodifications as a result. Each of these two functions contains 14\ntests_expect_* calls.\n\nCalling one of these test functions the first time creates a repository\nnamed \"submodule_update_repo\". At first it contains two files, then a\nsingle submodule is added in another commit followed by commits covering\nall relevant submodule modifications. This repository is newly cloned into\nthe \"submodule_update\" for each test_expect_* to avoid interference\nbetween different parts of the test functions (some to-be-tested commands\nalso manipulate refs along with the work tree, e.g. \"git reset\").\n\nFollow-up commits will then call these two test functions for all work\ntree manipulating commands (with a combination of all their options\nrelevant to what they do with the work tree) making sure they work as\nexpected. Later this test library will be extended to cover merges\nresulting in conflicts too. Also it is intended to be easily extendable\nfor the recursive update functionality, where even more combinations of\nsubmodule modifications have to be tested for.\n\nThis version documents two bugs in current Git with expected failures:\n\n*) When a submodule is replaced with a tracked file of the same name the\n   submodule work tree including any local modifications (and even the\n   whole history if it uses a .git directory instead of a gitfile!) is\n   silently removed.\n\n*) Forced work tree updates happily manipulate files in the directory of a\n   submodule that has just been removed in the superproject (but is of\n   course still present in the work tree due to the way submodules are\n   currently handled). This becomes dangerous when files in the submodule\n   directory are overwritten by files from the new superproject commit, as\n   any modifications to the submodule files will be lost) and is expected\n   to also destroy history in the - admittedly unlikely case - the new\n   commit adds a file named \".git\" to the submodule directory.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\n\nAm 20.06.2014 19:31, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> +\t\trm -rf sub1 &&\n>> +\t\tgit checkout -f \"$1\" &&\n>> +\t\tgit status -u -s >actual &&\n>> +\t\ttest_must_be_empty actual &&\n>> +\t\tsha1=$(git rev-parse HEAD:sub1 || true) &&\n> \n> \t$ xx=; xx=$(git rev-parse HEAD:no-such-path || true) ; echo $? ; echo \"<$xx>\"\n>         fatal: Path 'no-such-path' does not exist in 'HEAD'\n>         0\n>         <HEAD:no-such-path>\n> \n> Perhaps you want --verify (or --revs-only) there, i.e.\n> \n> \tsha1=$(git rev-parse --verify HEAD:sub1 || :) &&\n> \n> or\n> \n> \tsha1=$(git rev-parse --revs-only HEAD:sub1) &&\n> \n>> +\t\tif test -n \"$sha1\" &&\n>> ...\n>> +\tsha1=$(git rev-parse \"$commit:$submodule\") &&\n> \n> And here too.\n\nThanks, I squashed your \"SQUASH???\" commit (currently in pu) into this version.\n\n\n t/lib-submodule-update.sh | 632 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 632 insertions(+)\n create mode 100755 t/lib-submodule-update.sh\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nnew file mode 100755\nindex 0000000..ceeaaeb\n--- /dev/null\n+++ b/t/lib-submodule-update.sh\n@@ -0,0 +1,632 @@\n+# Create a submodule layout used for all tests below.\n+#\n+# The following use cases are covered:\n+# - New submodule (no_submodule => add_sub1)\n+# - Removed submodule (add_sub1 => remove_sub1)\n+# - Updated submodule (add_sub1 => modify_sub1)\n+# - Submodule updated to invalid commit (add_sub1 => invalid_sub1)\n+# - Submodule updated from invalid commit (invalid_sub1 => valid_sub1)\n+# - Submodule replaced by tracked files in directory (add_sub1 =>\n+#   replace_sub1_with_directory)\n+# - Directory containing tracked files replaced by submodule\n+#   (replace_sub1_with_directory => replace_directory_with_sub1)\n+# - Submodule replaced by tracked file with the same name (add_sub1 =>\n+#   replace_sub1_with_file)\n+# - Tracked file replaced by submodule (replace_sub1_with_file =>\n+#   replace_file_with_sub1)\n+#\n+#                   --O-----O\n+#                  /  ^     replace_directory_with_sub1\n+#                 /   replace_sub1_with_directory\n+#                /----O\n+#               /     ^\n+#              /      modify_sub1\n+#      O------O-------O\n+#      ^      ^\\      ^\n+#      |      | \\     remove_sub1\n+#      |      |  -----O-----O\n+#      |      |   \\   ^     replace_file_with_sub1\n+#      |      |    \\  replace_sub1_with_file\n+#      |   add_sub1 --O-----O\n+# no_submodule        ^     valid_sub1\n+#                     invalid_sub1\n+#\n+create_lib_submodule_repo () {\n+\tgit init submodule_update_repo &&\n+\t(\n+\t\tcd submodule_update_repo &&\n+\t\techo \"expect\" >>.gitignore &&\n+\t\techo \"actual\" >>.gitignore &&\n+\t\techo \"x\" >file1 &&\n+\t\techo \"y\" >file2 &&\n+\t\tgit add .gitignore file1 file2 &&\n+\t\tgit commit -m \"Base\" &&\n+\t\tgit branch \"no_submodule\" &&\n+\n+\t\tgit checkout -b \"add_sub1\" &&\n+\t\tgit submodule add ./. sub1 &&\n+\t\tgit config -f .gitmodules submodule.sub1.ignore all &&\n+\t\tgit config submodule.sub1.ignore all &&\n+\t\tgit add .gitmodules &&\n+\t\tgit commit -m \"Add sub1\" &&\n+\t\tgit checkout -b remove_sub1 &&\n+\t\tgit revert HEAD &&\n+\n+\t\tgit checkout -b \"modify_sub1\" \"add_sub1\" &&\n+\t\tgit submodule update &&\n+\t\t(\n+\t\t\tcd sub1 &&\n+\t\t\tgit fetch &&\n+\t\t\tgit checkout -b \"modifications\" &&\n+\t\t\techo \"z\" >file2 &&\n+\t\t\techo \"x\" >file3 &&\n+\t\t\tgit add file2 file3 &&\n+\t\t\tgit commit -m \"modified file2 and added file3\" &&\n+\t\t\tgit push origin modifications\n+\t\t) &&\n+\t\tgit add sub1 &&\n+\t\tgit commit -m \"Modify sub1\" &&\n+\n+\t\tgit checkout -b \"replace_sub1_with_directory\" \"add_sub1\" &&\n+\t\tgit submodule update &&\n+\t\t(\n+\t\t\tcd sub1 &&\n+\t\t\tgit checkout modifications\n+\t\t) &&\n+\t\tgit rm --cached sub1 &&\n+\t\trm sub1/.git* &&\n+\t\tgit config -f .gitmodules --remove-section \"submodule.sub1\" &&\n+\t\tgit add .gitmodules sub1/* &&\n+\t\tgit commit -m \"Replace sub1 with directory\" &&\n+\t\tgit checkout -b replace_directory_with_sub1 &&\n+\t\tgit revert HEAD &&\n+\n+\t\tgit checkout -b \"replace_sub1_with_file\" \"add_sub1\" &&\n+\t\tgit rm sub1 &&\n+\t\techo \"content\" >sub1 &&\n+\t\tgit add sub1 &&\n+\t\tgit commit -m \"Replace sub1 with file\" &&\n+\t\tgit checkout -b replace_file_with_sub1 &&\n+\t\tgit revert HEAD &&\n+\n+\t\tgit checkout -b \"invalid_sub1\" \"add_sub1\" &&\n+\t\tgit update-index --cacheinfo 160000 0123456789012345678901234567890123456789 sub1 &&\n+\t\tgit commit -m \"Invalid sub1 commit\" &&\n+\t\tgit checkout -b valid_sub1 &&\n+\t\tgit revert HEAD &&\n+\t\tgit checkout master\n+\t)\n+}\n+\n+# Helper function to replace gitfile with .git directory\n+replace_gitfile_with_git_dir () {\n+\t(\n+\t\tcd \"$1\" &&\n+\t\tgit_dir=\"$(git rev-parse --git-dir)\" &&\n+\t\trm -f .git &&\n+\t\tcp -R \"$git_dir\" .git &&\n+\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t)\n+}\n+\n+# Test that the .git directory in the submodule is unchanged (except for the\n+# core.worktree setting, which we temporarily restore). Call this function\n+# before test_submodule_content as the latter might write the index file\n+# leading to false positive index differences.\n+test_git_directory_is_unchanged () {\n+\t(\n+\t\tcd \"$1\" &&\n+\t\tgit config core.worktree \"../../../$1\"\n+\t) &&\n+\tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n+\t(\n+\t\tcd \"$1\" &&\n+\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t)\n+}\n+\n+# Helper function to be executed at the start of every test below, it sets up\n+# the submodule repo if it doesn't exist and configures the most problematic\n+# settings for diff.ignoreSubmodules.\n+prolog () {\n+\t(test -d submodule_update_repo || create_lib_submodule_repo) &&\n+\ttest_config_global diff.ignoreSubmodules all &&\n+\ttest_config diff.ignoreSubmodules all\n+}\n+\n+# Helper function to bring work tree back into the state given by the\n+# commit. This includes trying to populate sub1 accordingly if it exists and\n+# should be updated to an existing commit.\n+reset_work_tree_to () {\n+\trm -rf submodule_update &&\n+\tgit clone submodule_update_repo submodule_update &&\n+\t(\n+\t\tcd submodule_update &&\n+\t\trm -rf sub1 &&\n+\t\tgit checkout -f \"$1\" &&\n+\t\tgit status -u -s >actual &&\n+\t\ttest_must_be_empty actual &&\n+\t\tsha1=$(git rev-parse --revs-only HEAD:sub1) &&\n+\t\tif test -n \"$sha1\" &&\n+\t\t   test $(cd \"sub1\" && git rev-parse --verify \"$sha1^{commit}\")\n+\t\tthen\n+\t\t\tgit submodule update --init --recursive \"sub1\"\n+\t\tfi\n+\t)\n+}\n+\n+# Test that the superproject contains the content according to commit \"$1\"\n+# (the work tree must match the index for everything but submodules but the\n+# index must exactly match the given commit including any submodule SHA-1s).\n+test_superproject_content () {\n+\tgit diff-index --cached \"$1\" >actual &&\n+\ttest_must_be_empty actual &&\n+\tgit diff-files --ignore-submodules >actual &&\n+\ttest_must_be_empty actual\n+}\n+\n+# Test that the given submodule at path \"$1\" contains the content according\n+# to the submodule commit recorded in the superproject's commit \"$2\"\n+test_submodule_content () {\n+\tif test $# != 2\n+\tthen\n+\t\techo \"test_submodule_content needs two arguments\"\n+\t\treturn 1\n+\tfi &&\n+\tsubmodule=\"$1\" &&\n+\tcommit=\"$2\" &&\n+\ttest -d \"$submodule\"/ &&\n+\tif ! test -f \"$submodule\"/.git && ! test -d \"$submodule\"/.git\n+\tthen\n+\t\techo \"Submodule $submodule is not populated\"\n+\t\treturn 1\n+\tfi &&\n+\tsha1=$(git rev-parse --verify \"$commit:$submodule\") &&\n+\tif test -z \"$sha1\"\n+\tthen\n+\t\techo \"Couldn't retrieve SHA-1 of $submodule for $commit\"\n+\t\treturn 1\n+\tfi &&\n+\t(\n+\t\tcd \"$submodule\" &&\n+\t\tgit status -u -s >actual &&\n+\t\ttest_must_be_empty actual &&\n+\t\tgit diff \"$sha1\" >actual &&\n+\t\ttest_must_be_empty actual\n+\t)\n+}\n+\n+# Test that the following transitions are correctly handled:\n+# - Updated submodule\n+# - New submodule\n+# - Removed submodule\n+# - Directory containing tracked files replaced by submodule\n+# - Submodule replaced by tracked files in directory\n+# - Submodule replaced by tracked file with the same name\n+# - tracked file replaced by submodule\n+#\n+# The default is that submodule contents aren't changed until \"git submodule\n+# update\" is run. And even then that command doesn't delete the work tree of\n+# a removed submodule.\n+#\n+# Removing a submodule containing a .git directory must fail even when forced\n+# to protect the history!\n+#\n+\n+# Test that submodule contents are currently not updated when switching\n+# between commits that change a submodule.\n+test_submodule_switch () {\n+\tcommand=\"$1\"\n+\t######################### Appearing submodule #########################\n+\t# Switching to a commit letting a submodule appear creates empty dir ...\n+\ttest_expect_success \"$command: added submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... and doesn't care if it already exists ...\n+\ttest_expect_success \"$command: added submodule leaves existing empty directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tmkdir sub1 &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... unless there is an untracked file in its place.\n+\ttest_expect_success \"$command: added submodule doesn't remove untracked unignored file with same name\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\techo -n >sub1 &&\n+\t\t\ttest_must_fail $command add_sub1 &&\n+\t\t\ttest_superproject_content origin/no_submodule &&\n+\t\t\ttest_must_be_empty sub1\n+\t\t)\n+\t'\n+\t# Replacing a tracked file with a submodule produces an empty\n+\t# directory ...\n+\ttest_expect_success \"$command: replace tracked file with submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_file &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\t$command replace_file_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n+\t\t)\n+\t'\n+\t# ... as does removing a directory with tracked files with a\n+\t# submodule.\n+\ttest_expect_success \"$command: replace directory with submodule\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_directory &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\t$command replace_directory_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n+\t\t)\n+\t'\n+\n+\t######################## Disappearing submodule #######################\n+\t# Removing a submodule doesn't remove its work tree ...\n+\ttest_expect_success \"$command: removed submodule leaves submodule directory and its contents in place\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_success \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Replacing a submodule with files in a directory must fail as the\n+\t# submodule work tree isn't removed ...\n+\ttest_expect_success \"$command: replace submodule with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_success \"$command: replace submodule containing a .git directory with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Replacing it with a file must fail as it could throw away any local\n+\t# work tree changes ...\n+\ttest_expect_failure \"$command: replace submodule with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... or even destroy unpushed parts of submodule history if that\n+\t# still uses a .git directory.\n+\ttest_expect_failure \"$command: replace submodule containing a .git directory with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\n+\t########################## Modified submodule #########################\n+\t# Updating a submodule sha1 doesn't update the submodule's work tree\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\t$command modify_sub1 &&\n+\t\t\ttest_superproject_content origin/modify_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\tgit submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1\n+\t\t)\n+\t'\n+\n+\t# Updating a submodule to an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will fail\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree to invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\t$command invalid_sub1 &&\n+\t\t\ttest_superproject_content origin/invalid_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_must_fail git submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule from an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will succeed\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree from invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to invalid_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\t$command valid_sub1 &&\n+\t\t\ttest_superproject_content origin/valid_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/valid_sub1\n+\t\t)\n+\t'\n+}\n+\n+# Test that submodule contents are currently not updated when switching\n+# between commits that change a submodule, but throwing away local changes in\n+# the superproject is allowed.\n+test_submodule_forced_switch () {\n+\tcommand=\"$1\"\n+\t######################### Appearing submodule #########################\n+\t# Switching to a commit letting a submodule appear creates empty dir ...\n+\ttest_expect_success \"$command: added submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... and doesn't care if it already exists ...\n+\ttest_expect_success \"$command: added submodule leaves existing empty directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\tmkdir sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... unless there is an untracked file in its place.\n+\ttest_expect_success \"$command: added submodule does remove untracked unignored file with same name when forced\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to no_submodule &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n+\t\t\techo -n >sub1 &&\n+\t\t\t$command add_sub1 &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_dir_is_empty sub1\n+\t\t)\n+\t'\n+\t# Replacing a tracked file with a submodule produces an empty\n+\t# directory ...\n+\ttest_expect_success \"$command: replace tracked file with submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_file &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\t$command replace_file_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n+\t\t)\n+\t'\n+\t# ... as does removing a directory with tracked files with a\n+\t# submodule.\n+\ttest_expect_success \"$command: replace directory with submodule\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_directory &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_directory_with_sub1 origin/replace_directory_with_sub1 &&\n+\t\t\t$command replace_directory_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_directory_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_directory_with_sub1\n+\t\t)\n+\t'\n+\n+\t######################## Disappearing submodule #######################\n+\t# Removing a submodule doesn't remove its work tree ...\n+\ttest_expect_success \"$command: removed submodule leaves submodule directory and its contents in place\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_success \"$command: removed submodule leaves submodule containing a .git directory alone\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t remove_sub1 origin/remove_sub1 &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\t$command remove_sub1 &&\n+\t\t\ttest_superproject_content origin/remove_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Replacing a submodule with files in a directory must fail as the\n+\t# submodule work tree isn't removed ...\n+\ttest_expect_failure \"$command: replace submodule with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... especially when it contains a .git directory.\n+\ttest_expect_failure \"$command: replace submodule containing a .git directory with a directory must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_directory origin/replace_sub1_with_directory &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_directory &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Replacing it with a file must fail as it could throw away any local\n+\t# work tree changes ...\n+\ttest_expect_failure \"$command: replace submodule with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# ... or even destroy unpushed parts of submodule history if that\n+\t# still uses a .git directory.\n+\ttest_expect_failure \"$command: replace submodule containing a .git directory with a file must fail\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_sub1_with_file origin/replace_sub1_with_file &&\n+\t\t\treplace_gitfile_with_git_dir sub1 &&\n+\t\t\ttest_must_fail $command replace_sub1_with_file &&\n+\t\t\ttest_superproject_content origin/add_sub1 &&\n+\t\t\ttest_git_directory_is_unchanged sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\n+\t########################## Modified submodule #########################\n+\t# Updating a submodule sha1 doesn't update the submodule's work tree\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t modify_sub1 origin/modify_sub1 &&\n+\t\t\t$command modify_sub1 &&\n+\t\t\ttest_superproject_content origin/modify_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\tgit submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/modify_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule to an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will fail\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree to invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to add_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t invalid_sub1 origin/invalid_sub1 &&\n+\t\t\t$command invalid_sub1 &&\n+\t\t\ttest_superproject_content origin/invalid_sub1 &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1 &&\n+\t\t\ttest_must_fail git submodule update &&\n+\t\t\ttest_submodule_content sub1 origin/add_sub1\n+\t\t)\n+\t'\n+\t# Updating a submodule from an invalid sha1 doesn't update the\n+\t# submodule's work tree, subsequent update will succeed\n+\ttest_expect_success \"$command: modified submodule does not update submodule work tree from invalid commit\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to invalid_sub1 &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t valid_sub1 origin/valid_sub1 &&\n+\t\t\t$command valid_sub1 &&\n+\t\t\ttest_superproject_content origin/valid_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/valid_sub1\n+\t\t)\n+\t'\n+}\n-- \n2.0.1.458.gf680257\n"},{"id":"245299","messageId":"53B41D42.2090805@web.de","threadId":"36919","inReplyTo":"539DD029.4030506@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2014-07-02T14:54:58Z","receivedAt":"2014-07-02T14:54:58Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"(Not sure if this is the right thread)\n(I haven't checked if this is fixed in your latest version)\n\nOn what I have on pu 7a0da7902cbbc9a876b90c9, Tue Jul 1 14:51:53 2014 -0700\n\nMany submodule tests are broken.\nOne problem is here:\n\nlib-submodule-update.sh:264: possible problem: echo -n is not portable (please use printf):                     echo -n >sub1 &&\nlib-submodule-update.sh:507: possible problem: echo -n is not portable (please use printf):                     echo -n >sub1 &&\n\nYou can remove the \"empty\" \"echo -n\" to create an empty file:\n>sub1 &&\n"},{"id":"245347","messageId":"53B46425.3030000@web.de","threadId":"36919","inReplyTo":"53B41D42.2090805@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-07-02T19:57:25Z","receivedAt":"2014-07-02T19:57:25Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 02.07.2014 16:54, schrieb Torsten Bögershausen:\n> (Not sure if this is the right thread)\n> (I haven't checked if this is fixed in your latest version)\n\nYes, this is the right thread and no, it isn't fixed yet.\n\n> On what I have on pu 7a0da7902cbbc9a876b90c9, Tue Jul 1 14:51:53 2014 -0700\n> \n> Many submodule tests are broken.\n> One problem is here:\n> \n> lib-submodule-update.sh:264: possible problem: echo -n is not portable (please use printf):                     echo -n >sub1 &&\n> lib-submodule-update.sh:507: possible problem: echo -n is not portable (please use printf):                     echo -n >sub1 &&\n> \n> You can remove the \"empty\" \"echo -n\" to create an empty file:\n>> sub1 &&\n\nThanks for spotting and diagnosing this. Running \"make lint\" in the\ntest directory only feeds the tests to check-non-portable-shell.pl,\nbut not the *lib*.sh helper scripts, which made me miss this one.\n\nThe following diff should fix it for you. Am I understanding you\ncorrectly that you are experiencing other failures too? I see no\nother incompatibilities when running ./check-non-portable-shell.pl\non all the shell scripts in the repo.\n\n-----8<----\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 24c9fd7..3584755 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -304,7 +304,7 @@ test_submodule_switch () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n-\t\t\techo -n >sub1 &&\n+\t\t\t>sub1 &&\n \t\t\ttest_must_fail $command add_sub1 &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n \t\t\ttest_must_be_empty sub1\n@@ -547,7 +547,7 @@ test_submodule_forced_switch () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n-\t\t\techo -n >sub1 &&\n+\t\t\t>sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1\n-- \n2.0.1.458.gf680257.dirty\n"},{"id":"245367","messageId":"53B4F0AA.10809@web.de","threadId":"36919","inReplyTo":"53B46425.3030000@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2014-07-03T05:56:58Z","receivedAt":"2014-07-03T05:56:58Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 07/02/2014 09:57 PM, Jens Lehmann wrote:\n> Am 02.07.2014 16:54, schrieb Torsten Bögershausen:\n>> (Not sure if this is the right thread)\n>> (I haven't checked if this is fixed in your latest version)\n> Yes, this is the right thread and no, it isn't fixed yet.\n>\n>> On what I have on pu 7a0da7902cbbc9a876b90c9, Tue Jul 1 14:51:53 2014 -0700\n>>\n>> Many submodule tests are broken.\n>> One problem is here:\n>>\n>> lib-submodule-update.sh:264: possible problem: echo -n is not portable (please use printf):                     echo -n >sub1 &&\n>> lib-submodule-update.sh:507: possible problem: echo -n is not portable (please use printf):                     echo -n >sub1 &&\n>>\n>> You can remove the \"empty\" \"echo -n\" to create an empty file:\n>>> sub1 &&\n> Thanks for spotting and diagnosing this. Running \"make lint\" in the\n> test directory only feeds the tests to check-non-portable-shell.pl,\n> but not the *lib*.sh helper scripts, which made me miss this one.\n>\n> The following diff should fix it for you. Am I understanding you\n> correctly that you are experiencing other failures too? I see no\n> other incompatibilities when running ./check-non-portable-shell.pl\n> on all the shell scripts in the repo.\nThe longer story is that I run the test suite once a week or so.\nMost often under Mac OS, sometimes cygwin or Linux.\nWhenever there is a breakage under Mac OS which I can not\ndebug within some minutes, I run it under Linux to see if there\nis the same breakage.\n\nThe ./check-non-portable-shell.pl can sometimes give an indication\nwhy some test fail.\nYou can run it from command line:\n  ./check-non-portable-shell.pl *.sh\nand it will find the \"echo -n\" which I reported.\nOn the longer run it could probably check all *.sh files,\nnot only the ones under t/\nI do not have the time to test the snipped patch below, but I can check pu\nwhen the next round of your patch is in and give you some more info.\n"},{"id":"245391","messageId":"53B5C7AC.4040701@web.de","threadId":"36919","inReplyTo":"53B4F0AA.10809@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-07-03T21:14:20Z","receivedAt":"2014-07-03T21:14:20Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 03.07.2014 07:56, schrieb Torsten Bögershausen:\n> On 07/02/2014 09:57 PM, Jens Lehmann wrote:\n>> Am 02.07.2014 16:54, schrieb Torsten Bögershausen:\n>>> (Not sure if this is the right thread)\n>>> (I haven't checked if this is fixed in your latest version)\n>> Yes, this is the right thread and no, it isn't fixed yet.\n>>\n>>> On what I have on pu 7a0da7902cbbc9a876b90c9, Tue Jul 1 14:51:53 2014 -0700\n>>>\n>>> Many submodule tests are broken.\n>>> One problem is here:\n>>>\n>>> lib-submodule-update.sh:264: possible problem: echo -n is not portable (please use printf):                     echo -n >sub1 &&\n>>> lib-submodule-update.sh:507: possible problem: echo -n is not portable (please use printf):                     echo -n >sub1 &&\n>>>\n>>> You can remove the \"empty\" \"echo -n\" to create an empty file:\n>>>> sub1 &&\n>> Thanks for spotting and diagnosing this. Running \"make lint\" in the\n>> test directory only feeds the tests to check-non-portable-shell.pl,\n>> but not the *lib*.sh helper scripts, which made me miss this one.\n>>\n>> The following diff should fix it for you. Am I understanding you\n>> correctly that you are experiencing other failures too? I see no\n>> other incompatibilities when running ./check-non-portable-shell.pl\n>> on all the shell scripts in the repo.\n> The longer story is that I run the test suite once a week or so.\n> Most often under Mac OS, sometimes cygwin or Linux.\n> Whenever there is a breakage under Mac OS which I can not\n> debug within some minutes, I run it under Linux to see if there\n> is the same breakage.\n\nThanks, that really helps a lot and is more than I could ask for.\n\n> The ./check-non-portable-shell.pl can sometimes give an indication\n> why some test fail.\n> You can run it from command line:\n>  ./check-non-portable-shell.pl *.sh\n> and it will find the \"echo -n\" which I reported.\n> On the longer run it could probably check all *.sh files,\n> not only the ones under t/\n\nThat is exactly what I thought when I tried to find out why I missed\nthis. Will cook up a patch to at least check the test helpers too.\n\n> I do not have the time to test the snipped patch below, but I can check pu\n> when the next round of your patch is in and give you some more info.\n\nThat'd be great!\n\nJunio, do you want me to resend 02/14 without the non-portable \"echo -n\"\nor could you just squash the following diff in?\n\n-----8<----\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 24c9fd7..3584755 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -304,7 +304,7 @@ test_submodule_switch () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n-\t\t\techo -n >sub1 &&\n+\t\t\t>sub1 &&\n \t\t\ttest_must_fail $command add_sub1 &&\n \t\t\ttest_superproject_content origin/no_submodule &&\n \t\t\ttest_must_be_empty sub1\n@@ -547,7 +547,7 @@ test_submodule_forced_switch () {\n \t\t(\n \t\t\tcd submodule_update &&\n \t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n-\t\t\techo -n >sub1 &&\n+\t\t\t>sub1 &&\n \t\t\t$command add_sub1 &&\n \t\t\ttest_superproject_content origin/add_sub1 &&\n \t\t\ttest_dir_is_empty sub1\n-- 2.0.1.458.gf680257.dirty\n"},{"id":"245476","messageId":"xmqqsimddrq3.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53B5C7AC.4040701@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-07T17:05:40Z","receivedAt":"2014-07-07T17:05:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> Junio, do you want me to resend 02/14 without the non-portable \"echo -n\"\n> or could you just squash the following diff in?\n\nAmended locally here already; thanks, both.\n\n>\n> -----8<----\n> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n> index 24c9fd7..3584755 100755\n> --- a/t/lib-submodule-update.sh\n> +++ b/t/lib-submodule-update.sh\n> @@ -304,7 +304,7 @@ test_submodule_switch () {\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n>  \t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> -\t\t\techo -n >sub1 &&\n> +\t\t\t>sub1 &&\n>  \t\t\ttest_must_fail $command add_sub1 &&\n>  \t\t\ttest_superproject_content origin/no_submodule &&\n>  \t\t\ttest_must_be_empty sub1\n> @@ -547,7 +547,7 @@ test_submodule_forced_switch () {\n>  \t\t(\n>  \t\t\tcd submodule_update &&\n>  \t\t\tgit branch -t add_sub1 origin/add_sub1 &&\n> -\t\t\techo -n >sub1 &&\n> +\t\t\t>sub1 &&\n>  \t\t\t$command add_sub1 &&\n>  \t\t\ttest_superproject_content origin/add_sub1 &&\n>  \t\t\ttest_dir_is_empty sub1\n> -- 2.0.1.458.gf680257.dirty\n"},{"id":"245490","messageId":"53BAF7AF.4020901@web.de","threadId":"36919","inReplyTo":"xmqqsimddrq3.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2014-07-07T19:40:31Z","receivedAt":"2014-07-07T19:40:31Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 2014-07-07 19.05, Junio C Hamano wrote:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> Junio, do you want me to resend 02/14 without the non-portable \"echo -n\"\n>> or could you just squash the following diff in?\n> \n> Amended locally here already; thanks, both.\n\nThere seems to be some other trouble under Mac OS, not yet fully tracked down,\n(may be related to the \"diff -r\")\n\nAnd Msysgit complains \nerror: fchmod on c:/xxxt/trash directory.t7613-merge-submodule/submodule_update_repo/.git/modules/sub1/config.lock failed: Function not implemented\n"},{"id":"245547","messageId":"53BC47BD.1000705@web.de","threadId":"36919","inReplyTo":"53BAF7AF.4020901@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-07-08T19:34:21Z","receivedAt":"2014-07-08T19:34:21Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 07.07.2014 21:40, schrieb Torsten Bögershausen:\n> On 2014-07-07 19.05, Junio C Hamano wrote:\n>> Jens Lehmann <Jens.Lehmann@web.de> writes:\n>>\n>>> Junio, do you want me to resend 02/14 without the non-portable \"echo -n\"\n>>> or could you just squash the following diff in?\n>>\n>> Amended locally here already; thanks, both.\n> \n> There seems to be some other trouble under Mac OS, not yet fully tracked down,\n> (may be related to the \"diff -r\")\n\nTorsten sees failures of this kind under Mac OS:\n\ndiff -r .git/modules/sub1/config sub1/.git/config\n6d5\n<     worktree = ../../../sub1\n8a8\n>     worktree = ../../../sub1\n\nSo the config contains the same content, but the worktree setting moved\nto a different line. This seems to be the result of setting core.worktree\nin the test_git_directory_is_unchanged function just before the \"diff -r\",\nbut only under Mac OS.\n\n> And Msysgit complains \n> error: fchmod on c:/xxxt/trash directory.t7613-merge-submodule/submodule_update_repo/.git/modules/sub1/config.lock failed: Function not implemented\n\nI'm not sure what this is about, seems to happen during the \"cp -R\" of\nthe repo under .git/modules into the submodule.\n\nI'm currently investigating both issues (the next steps probably being\nto install msysgit and to do some Git hacking on a Mac in the family).\n"},{"id":"245549","messageId":"53BC53C3.1010304@ramsay1.demon.co.uk","threadId":"36919","inReplyTo":"53BC47BD.1000705@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsay1.demon.co.uk","sentAt":"2014-07-08T20:25:39Z","receivedAt":"2014-07-08T20:25:39Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"On 08/07/14 20:34, Jens Lehmann wrote:\n> Am 07.07.2014 21:40, schrieb Torsten Bögershausen:\n>> On 2014-07-07 19.05, Junio C Hamano wrote:\n>>> Jens Lehmann <Jens.Lehmann@web.de> writes:\n>>>\n>>>> Junio, do you want me to resend 02/14 without the non-portable \"echo -n\"\n>>>> or could you just squash the following diff in?\n>>>\n>>> Amended locally here already; thanks, both.\n>>\n>> There seems to be some other trouble under Mac OS, not yet fully tracked down,\n>> (may be related to the \"diff -r\")\n> \n> Torsten sees failures of this kind under Mac OS:\n> \n> diff -r .git/modules/sub1/config sub1/.git/config\n> 6d5\n> <     worktree = ../../../sub1\n> 8a8\n>>     worktree = ../../../sub1\n> \n> So the config contains the same content, but the worktree setting moved\n> to a different line. This seems to be the result of setting core.worktree\n> in the test_git_directory_is_unchanged function just before the \"diff -r\",\n> but only under Mac OS.\n> \n>> And Msysgit complains \n>> error: fchmod on c:/xxxt/trash directory.t7613-merge-submodule/submodule_update_repo/.git/modules/sub1/config.lock failed: Function not implemented\n> \n> I'm not sure what this is about, seems to happen during the \"cp -R\" of\n> the repo under .git/modules into the submodule.\n\nI haven't looked into this at all, but from the above message, and\nnoting that fchmod() is not implemented in mingw (see compat/mingw.h\nline 91), and the following:\n\n    $ git grep -n fchmod\n    compat/mingw.h:91:static inline int fchmod(int fildes, mode_t mode)\n    config.c:1639:          if (fchmod(fd, st.st_mode & 07777) < 0) {\n    config.c:1640:                  error(\"fchmod on %s failed: %s\",\n    config.c:1818:  if (fchmod(out_fd, st.st_mode & 07777) < 0) {\n    config.c:1819:          ret = error(\"fchmod on %s failed: %s\",\n    $ \n\n[I happen to be on the pu branch at the moment, so YMMV!]\n\nBoth calls to fchmod() above are on config lock files, one\nin git_config_set_multivar_in_file() and the other in\ngit_config_rename_section_in_file().\n\nATB,\nRamsay Jones\n"},{"id":"245555","messageId":"53BC5CBC.7030005@ramsay1.demon.co.uk","threadId":"36919","inReplyTo":"53BC53C3.1010304@ramsay1.demon.co.uk","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsay1.demon.co.uk","sentAt":"2014-07-08T21:03:56Z","receivedAt":"2014-07-08T21:03:56Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"On 08/07/14 21:25, Ramsay Jones wrote:\n> On 08/07/14 20:34, Jens Lehmann wrote:\n>> Am 07.07.2014 21:40, schrieb Torsten Bögershausen:\n>>> On 2014-07-07 19.05, Junio C Hamano wrote:\n>>>> Jens Lehmann <Jens.Lehmann@web.de> writes:\n>>>>\n>>>>> Junio, do you want me to resend 02/14 without the non-portable \"echo -n\"\n>>>>> or could you just squash the following diff in?\n>>>>\n>>>> Amended locally here already; thanks, both.\n>>>\n>>> There seems to be some other trouble under Mac OS, not yet fully tracked down,\n>>> (may be related to the \"diff -r\")\n>>\n>> Torsten sees failures of this kind under Mac OS:\n>>\n>> diff -r .git/modules/sub1/config sub1/.git/config\n>> 6d5\n>> <     worktree = ../../../sub1\n>> 8a8\n>>>     worktree = ../../../sub1\n>>\n>> So the config contains the same content, but the worktree setting moved\n>> to a different line. This seems to be the result of setting core.worktree\n>> in the test_git_directory_is_unchanged function just before the \"diff -r\",\n>> but only under Mac OS.\n>>\n>>> And Msysgit complains \n>>> error: fchmod on c:/xxxt/trash directory.t7613-merge-submodule/submodule_update_repo/.git/modules/sub1/config.lock failed: Function not implemented\n>>\n>> I'm not sure what this is about, seems to happen during the \"cp -R\" of\n>> the repo under .git/modules into the submodule.\n> \n> I haven't looked into this at all, but from the above message, and\n> noting that fchmod() is not implemented in mingw (see compat/mingw.h\n> line 91), and the following:\n> \n>     $ git grep -n fchmod\n>     compat/mingw.h:91:static inline int fchmod(int fildes, mode_t mode)\n>     config.c:1639:          if (fchmod(fd, st.st_mode & 07777) < 0) {\n>     config.c:1640:                  error(\"fchmod on %s failed: %s\",\n>     config.c:1818:  if (fchmod(out_fd, st.st_mode & 07777) < 0) {\n>     config.c:1819:          ret = error(\"fchmod on %s failed: %s\",\n>     $ \n> \n> [I happen to be on the pu branch at the moment, so YMMV!]\n> \n> Both calls to fchmod() above are on config lock files, one\n> in git_config_set_multivar_in_file() and the other in\n> git_config_rename_section_in_file().\n> \n\nSee commit daa22c6f8 (\"config: preserve config file permissions\non edits\", 06-05-2014).\n\nATB,\nRamsay Jones\n"},{"id":"245573","messageId":"53BCDDE2.1080301@web.de","threadId":"36919","inReplyTo":"53BC47BD.1000705@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2014-07-09T06:14:58Z","receivedAt":"2014-07-09T06:14:58Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"\n>> There seems to be some other trouble under Mac OS, not yet fully tracked down,\n>> (may be related to the \"diff -r\")\n> Torsten sees failures of this kind under Mac OS:\n>\n> diff -r .git/modules/sub1/config sub1/.git/config\n> 6d5\n> <     worktree = ../../../sub1\n> 8a8\n>>      worktree = ../../../sub1\n> So the config contains the same content, but the worktree setting moved\n> to a different line. This seems to be the result of setting core.worktree\n> in the test_git_directory_is_unchanged function just before the \"diff -r\",\n> but only under Mac OS.\n>\nSo I was suspecting diff -r beinng non-portable, but that doesn't seem \nto be the problem here.\n(But I wouldn't be surprised if there where problems with diff -r on \nsome Unix systems)\nAnyway, checking all the files in the working tree seems to be a good \nthing to do,\nbut that does not necessarily work for .git/config.\nA \"brute force\" approach could be to simply run the config file(s) \nthrough sort and compare them:\n\nsort <.git/modules/sub1/config >expect &&\nsort <sub1/.git/config >actual &&\ntest_cmp expect actual &&\nrm expect actual &&\ncp git/modules/sub1/config sub1/.git/config\n\n\n[end of scriptlet]\nAnd here the \"dumps\" of the 2 config files:\n.......\nBranch remove_sub1 set up to track remote branch remove_sub1 from origin.\nwarning: unable to rmdir sub1: Directory not empty\nUpdating 68c8810..81b9f6a\nFast-forward\n  .gitmodules | 4 ----\n  1 file changed, 4 deletions(-)\n  delete mode 100644 .gitmodules\n---------------------\n[core]\n         repositoryformatversion = 0\n         filemode = true\n         bare = false\n         logallrefupdates = true\n         worktree = ../../../sub1\n         ignorecase = true\n         precomposeunicode = true\n[remote \"origin\"]\n         url = /Users/tb/projects/git/tb.140704_JensLehman/t/trash \ndirectory.t7613-merge-submodule/submodule_update_repo/.\n         fetch = +refs/heads/*:refs/remotes/origin/*\n[branch \"master\"]\n         remote = origin\n         merge = refs/heads/master\n----------------\n[core]\n         repositoryformatversion = 0\n         filemode = true\n         bare = false\n         logallrefupdates = true\n         ignorecase = true\n         precomposeunicode = true\n         worktree = ../../../sub1\n[remote \"origin\"]\n         url = /Users/tb/projects/git/tb.140704_JensLehman/t/trash \ndirectory.t7613-merge-submodule/submodule_update_repo/.\n         fetch = +refs/heads/*:refs/remotes/origin/*\n[branch \"master\"]\n         remote = origin\n         merge = refs/heads/master\n=====================\ndiff -r .git/modules/sub1/config sub1/.git/config\n6d5\n<       worktree = ../../../sub1\n8a8\n >       worktree = ../../../sub1\nnot ok 7 - git merge: removed submodule leaves submodule containing a \n.git directory alone\n"},{"id":"245575","messageId":"53BCE3A7.8070600@web.de","threadId":"36919","inReplyTo":"53BC53C3.1010304@ramsay1.demon.co.uk","subject":"No fchmod() under msygit - Was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2014-07-09T06:39:35Z","receivedAt":"2014-07-09T06:39:35Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 07/08/2014 10:25 PM, Ramsay Jones wrote:\n> On 08/07/14 20:34, Jens Lehmann wrote:\n>> Am 07.07.2014 21:40, schrieb Torsten Bögershausen:\n>>> On 2014-07-07 19.05, Junio C Hamano wrote:\n>>>> Jens Lehmann <Jens.Lehmann@web.de> writes:\n>>>>\n>>>>> Junio, do you want me to resend 02/14 without the non-portable \"echo -n\"\n>>>>> or could you just squash the following diff in?\n>>>> Amended locally here already; thanks, both.\n>>> There seems to be some other trouble under Mac OS, not yet fully tracked down,\n>>> (may be related to the \"diff -r\")\n>> Torsten sees failures of this kind under Mac OS:\n>>\n>> diff -r .git/modules/sub1/config sub1/.git/config\n>> 6d5\n>> <     worktree = ../../../sub1\n>> 8a8\n>>>      worktree = ../../../sub1\n>> So the config contains the same content, but the worktree setting moved\n>> to a different line. This seems to be the result of setting core.worktree\n>> in the test_git_directory_is_unchanged function just before the \"diff -r\",\n>> but only under Mac OS.\n>>\n>>> And Msysgit complains\n>>> error: fchmod on c:/xxxt/trash directory.t7613-merge-submodule/submodule_update_repo/.git/modules/sub1/config.lock failed: Function not implemented\n>> I'm not sure what this is about, seems to happen during the \"cp -R\" of\n>> the repo under .git/modules into the submodule.\n> I haven't looked into this at all, but from the above message, and\n> noting that fchmod() is not implemented in mingw (see compat/mingw.h\n> line 91), and the following:\n>\n>      $ git grep -n fchmodcommit daa22c6f8da466bd7a438f1bc27375fd737ffcf3\n> Author: Eric Wong <normalperson@yhbt.net>\n> Date:   Tue May 6 00:17:14 2014 +0000\n>\n>      config: preserve config file permissions on edits\n>      \n>\n>      compat/mingw.h:91:static inline int fchmod(int fildes, mode_t mode)\n>      config.c:1639:          if (fchmod(fd, st.st_mode & 07777) < 0) {\n>      config.c:1640:                  error(\"fchmod on %s failed: %s\",\n>      config.c:1818:  if (fchmod(out_fd, st.st_mode & 07777) < 0) {\n>      config.c:1819:          ret = error(\"fchmod on %s failed: %s\",\n>      $\n>\n> [I happen to be on the pu branch at the moment, so YMMV!]\n>\n> Both calls to fchmod() above are on config lock files, one\n> in git_config_set_multivar_in_file() and the other in\n> git_config_rename_section_in_file().\n>\n>\n\ncommit daa22c6f8da466bd7a438f1bc27375fd737ffcf3\nAuthor: Eric Wong <normalperson@yhbt.net>\nDate:   Tue May 6 00:17:14 2014 +0000\n\n     config: preserve config file permissions on edits\n\n(And why is it  \"& 07777\" and not  \"& 0777\")\nCan we avoid the fchmod()  all together ?\n"},{"id":"245635","messageId":"xmqqion67e4p.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53BCDDE2.1080301@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-09T15:20:22Z","receivedAt":"2014-07-09T15:20:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n> A \"brute force\" approach could be to simply run the config file(s)\n> through sort and compare them:\n>\n> sort <.git/modules/sub1/config >expect &&\n> sort <sub1/.git/config >actual &&\n> test_cmp expect actual &&\n\nOr \"git config --list\" from these files, perhaps?\n"},{"id":"245640","messageId":"53BD7A36.2030300@kdbg.org","threadId":"36919","inReplyTo":"53BC47BD.1000705@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2014-07-09T17:21:58Z","receivedAt":"2014-07-09T17:21:58Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 08.07.2014 21:34, schrieb Jens Lehmann:\n>> And Msysgit complains \n>> error: fchmod on c:/xxxt/trash directory.t7613-merge-submodule/submodule_update_repo/.git/modules/sub1/config.lock failed: Function not implemented\n> \n> I'm not sure what this is about, seems to happen during the \"cp -R\" of\n> the repo under .git/modules into the submodule.\n\nNo. It happens because fchmod() is not implemented in our Windows port.\n\nPlease see my band-aid patch at\nhttp://thread.gmane.org/gmane.comp.version-control.git/248154/focus=20266\nThe sub-thread ended inconclusive.\n\n-- Hannes\n"},{"id":"245643","messageId":"53BD87B3.8050901@web.de","threadId":"36919","inReplyTo":"53BCDDE2.1080301@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-07-09T18:19:31Z","receivedAt":"2014-07-09T18:19:31Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 09.07.2014 08:14, schrieb Torsten Bögershausen:\n> \n>>> There seems to be some other trouble under Mac OS, not yet fully tracked down,\n>>> (may be related to the \"diff -r\")\n>> Torsten sees failures of this kind under Mac OS:\n>>\n>> diff -r .git/modules/sub1/config sub1/.git/config\n>> 6d5\n>> <     worktree = ../../../sub1\n>> 8a8\n>>>      worktree = ../../../sub1\n>> So the config contains the same content, but the worktree setting moved\n>> to a different line. This seems to be the result of setting core.worktree\n>> in the test_git_directory_is_unchanged function just before the \"diff -r\",\n>> but only under Mac OS.\n>>\n> So I was suspecting diff -r beinng non-portable, but that doesn't seem to be the problem here.\n> (But I wouldn't be surprised if there where problems with diff -r on some Unix systems)\n> Anyway, checking all the files in the working tree seems to be a good thing to do,\n> but that does not necessarily work for .git/config.\n\nI agree, but this case is special. The test asserts that nobody\nadded, modified or removed *anything* inside the .git directory.\nThe reason for problem we are seeing here is that I have to\nremove the core.worktree setting when moving the git directory\nfrom .git/modules into the submodule work tree. So the test adds\nit again to be able to diff it, and this happens in a different\nline only on Mac OS as comparing the two core sections shows:\n\n> ---------------------\n> [core]\n>         repositoryformatversion = 0\n>         filemode = true\n>         bare = false\n>         logallrefupdates = true\n>         worktree = ../../../sub1\n>         ignorecase = true\n>         precomposeunicode = true\n> [remote \"origin\"]\n\nvs.\n\n> ----------------\n> [core]\n>         repositoryformatversion = 0\n>         filemode = true\n>         bare = false\n>         logallrefupdates = true\n>         ignorecase = true\n>         precomposeunicode = true\n>         worktree = ../../../sub1\n> [remote \"origin\"]\n\nAnd now it's clear what happens here: On Mac OS the ignorecase\nand precomposeunicode settings are added behind the worktree\nline, then re-adding worktree later for the comparison adds it\nafter these two.\n\nCould you please test the following? It should avoid this kind\nof problem by removing the core.worktree setting temporarily\nfrom the original config in .git/modules instead of adding it\ntemporarily to .git/config:\n-----------------------8<-----------------------\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 3584755..98c86e3 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -143,18 +143,18 @@ replace_gitfile_with_git_dir () {\n }\n\n # Test that the .git directory in the submodule is unchanged (except for the\n-# core.worktree setting, which we temporarily restore). Call this function\n+# core.worktree setting, which we temporarily remove). Call this function\n # before test_submodule_content as the latter might write the index file\n # leading to false positive index differences.\n test_git_directory_is_unchanged () {\n \t(\n-\t\tcd \"$1\" &&\n-\t\tgit config core.worktree \"../../../$1\"\n+\t\tcd \".git/modules/$1\" &&\n+\t\tgit config --unset core.worktree\n \t) &&\n \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n \t(\n-\t\tcd \"$1\" &&\n-\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t\tcd \".git/modules/$1\" &&\n+\t\tgit config core.worktree \"../../../$1\"\n \t)\n }\n"},{"id":"245644","messageId":"xmqqr41u9w27.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53BD7A36.2030300@kdbg.org","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-09T19:22:24Z","receivedAt":"2014-07-09T19:22:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Am 08.07.2014 21:34, schrieb Jens Lehmann:\n>>> And Msysgit complains \n>>> error: fchmod on c:/xxxt/trash directory.t7613-merge-submodule/submodule_update_repo/.git/modules/sub1/config.lock failed: Function not implemented\n>> \n>> I'm not sure what this is about, seems to happen during the \"cp -R\" of\n>> the repo under .git/modules into the submodule.\n>\n> No. It happens because fchmod() is not implemented in our Windows port.\n>\n> Please see my band-aid patch at\n> http://thread.gmane.org/gmane.comp.version-control.git/248154/focus=20266\n> The sub-thread ended inconclusive.\n\nWe need to start somewhere, and a no-op fchmod() in your patch may\nbe as a good place to start as anything.  At least we would then\nkeep the old behaviour without introducing any new failure.\n\nAn alternative might be to use chmod() after we are done writing to\nthe config.lock in order to avoid the use of fchmod() altogether,\nwhich I think can replace the existing two callsites of fchmod().\nThat approach might be a more expedient, but may turn out to be\nundesirable in the longer term.\n\nI also wonder if this \"carry forward the original permission bits\nwhen updating an existing file by first writing the updated contents\ninto a lockfile and then renaming it after we are done\" pattern\nought to be done in the lockfile API at commit_lock_file() time (Duy\nand Michael Cc'ed for their input, as they have recently touched\nlockfile API implementation in their series somewhat), not at the\nlevel of the user of the lockfile API like Eric's patch daa22c6f\n(config: preserve config file permissions on edits, 2014-05-06) did\nonly for the config file.\n"},{"id":"245645","messageId":"xmqqmwci9vn1.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53BD87B3.8050901@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-09T19:31:29Z","receivedAt":"2014-07-09T19:31:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> I agree, but this case is special. The test asserts that nobody\n> added, modified or removed *anything* inside the .git directory.\n> The reason for problem we are seeing here is that I have to\n> remove the core.worktree setting when moving the git directory\n> from .git/modules into the submodule work tree.\n\nHmph.  Comparing the files with core.worktree removed sounds like a\nworkaround that knows too much about the implementation detail of\nwhat is being tested.  I am just wondering if core.worktree will\nstay forever be the only thing that is special, or there may come\nother things (perhaps as a fallout of integrating things like Duy's\nmultiple-worktree stuff).\n\nBut perhaps we cannot do better than this.\n\n> Could you please test the following? It should avoid this kind\n> of problem by removing the core.worktree setting temporarily\n> from the original config in .git/modules instead of adding it\n> temporarily to .git/config:\n> -----------------------8<-----------------------\n> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n> index 3584755..98c86e3 100755\n> --- a/t/lib-submodule-update.sh\n> +++ b/t/lib-submodule-update.sh\n> @@ -143,18 +143,18 @@ replace_gitfile_with_git_dir () {\n>  }\n>\n>  # Test that the .git directory in the submodule is unchanged (except for the\n> -# core.worktree setting, which we temporarily restore). Call this function\n> +# core.worktree setting, which we temporarily remove). Call this function\n>  # before test_submodule_content as the latter might write the index file\n>  # leading to false positive index differences.\n>  test_git_directory_is_unchanged () {\n>  \t(\n> -\t\tcd \"$1\" &&\n> -\t\tgit config core.worktree \"../../../$1\"\n> +\t\tcd \".git/modules/$1\" &&\n> +\t\tgit config --unset core.worktree\n>  \t) &&\n>  \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n>  \t(\n> -\t\tcd \"$1\" &&\n> -\t\tGIT_WORK_TREE=. git config --unset core.worktree\n> +\t\tcd \".git/modules/$1\" &&\n> +\t\tgit config core.worktree \"../../../$1\"\n>  \t)\n>  }\n"},{"id":"245650","messageId":"20140709195619.GA17454@dcvr.yhbt.net","threadId":"36919","inReplyTo":"xmqqr41u9w27.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2014-07-09T19:56:19Z","receivedAt":"2014-07-09T19:56:19Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> Johannes Sixt <j6t@kdbg.org> writes:\n> > Am 08.07.2014 21:34, schrieb Jens Lehmann:\n> >>> And Msysgit complains \n> >>> error: fchmod on c:/xxxt/trash directory.t7613-merge-submodule/submodule_update_repo/.git/modules/sub1/config.lock failed: Function not implemented\n> >> \n> >> I'm not sure what this is about, seems to happen during the \"cp -R\" of\n> >> the repo under .git/modules into the submodule.\n> >\n> > No. It happens because fchmod() is not implemented in our Windows port.\n> >\n> > Please see my band-aid patch at\n> > http://thread.gmane.org/gmane.comp.version-control.git/248154/focus=20266\n> > The sub-thread ended inconclusive.\n> \n> We need to start somewhere, and a no-op fchmod() in your patch may\n> be as a good place to start as anything.  At least we would then\n> keep the old behaviour without introducing any new failure.\n\nRight, this likely makes the most sense for single-user systems or\nsystesm without a *nix-like permission system.\n\n> An alternative might be to use chmod() after we are done writing to\n> the config.lock in order to avoid the use of fchmod() altogether,\n> which I think can replace the existing two callsites of fchmod().\n> That approach might be a more expedient, but may turn out to be\n> undesirable in the longer term.\n\nIn that case, we would need to open with mode=0600 to avoid a window\nwhere the file may be world-readable with any data in it.\n"},{"id":"245651","messageId":"20140709200046.GB17454@dcvr.yhbt.net","threadId":"36919","inReplyTo":"53BCE3A7.8070600@web.de","subject":"Re: No fchmod() under msygit - Was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2014-07-09T20:00:46Z","receivedAt":"2014-07-09T20:00:46Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Torsten Bögershausen <tboegi@web.de> wrote:\n> (And why is it  \"& 07777\" and not  \"& 0777\")\n\nThis is to preserve the uncommon sticky/sgid/suid bits.  Probably not\nneeded, but better to keep as much intact as possible.\n\n> Can we avoid the fchmod()  all together ?\n\nFor single-user systems, sure.\n\nFor multi-user systems with git-imap-send users and passwords in\n$GIT_CONFIG, I suggest not.\n"},{"id":"245664","messageId":"xmqqion69ovj.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"20140709195619.GA17454@dcvr.yhbt.net","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-09T21:57:36Z","receivedAt":"2014-07-09T21:57:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <normalperson@yhbt.net> writes:\n\n> Junio C Hamano <gitster@pobox.com> wrote:\n>> Johannes Sixt <j6t@kdbg.org> writes:\n>> > Am 08.07.2014 21:34, schrieb Jens Lehmann:\n>> >>> And Msysgit complains \n>> >>> error: fchmod on c:/xxxt/trash directory.t7613-merge-submodule/submodule_update_repo/.git/modules/sub1/config.lock failed: Function not implemented\n>> >> \n>> >> I'm not sure what this is about, seems to happen during the \"cp -R\" of\n>> >> the repo under .git/modules into the submodule.\n>> >\n>> > No. It happens because fchmod() is not implemented in our Windows port.\n>> >\n>> > Please see my band-aid patch at\n>> > http://thread.gmane.org/gmane.comp.version-control.git/248154/focus=20266\n>> > The sub-thread ended inconclusive.\n>> \n>> We need to start somewhere, and a no-op fchmod() in your patch may\n>> be as a good place to start as anything.  At least we would then\n>> keep the old behaviour without introducing any new failure.\n>\n> Right, this likely makes the most sense for single-user systems or\n> systesm without a *nix-like permission system.\n>\n>> An alternative might be to use chmod() after we are done writing to\n>> the config.lock in order to avoid the use of fchmod() altogether,\n>> which I think can replace the existing two callsites of fchmod().\n>> That approach might be a more expedient, but may turn out to be\n>> undesirable in the longer term.\n>\n> In that case, we would need to open with mode=0600 to avoid a window\n> where the file may be world-readable with any data in it.\n\nYes, of course.\n\nTo elaborate what I was alluding to at the end of the message you\nare responding to a bit more, if we were to move this \"grab perms\nfrom existing file (if there is any) and propagate to the new one\"\ninto the lockfile API, \n\n - in hold_lock_file_for_update(), we would record the permission of\n   the original file, if any, to a new field in \"struct lock_file\";\n - open with 0600 or tighter in lock_file(), and\n\n - either before closing the file use fchmod() or after closing and\n   moving the file use chmod() to propagate the permission.\n\nIf the original did not exist, we would pass 0666 to open as before\nin lock_file() and do not bother chmod/fchmod at the end.\n\nOr something like that, perhaps.\n"},{"id":"245680","messageId":"53BE3127.8020805@web.de","threadId":"36919","inReplyTo":"xmqqion69ovj.fsf@gitster.dls.corp.google.com","subject":"No fchmd. was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2014-07-10T06:22:31Z","receivedAt":"2014-07-10T06:22:31Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 07/09/2014 11:57 PM, Junio C Hamano wrote:\n> Eric Wong <normalperson@yhbt.net> writes:\n>\n>> Junio C Hamano <gitster@pobox.com> wrote:\n>>> Johannes Sixt <j6t@kdbg.org> writes:\n>>>> Am 08.07.2014 21:34, schrieb Jens Lehmann:\n>>>>>> And Msysgit complains\n>>>>>> error: fchmod on c:/xxxt/trash directory.t7613-merge-submodule/submodule_update_repo/.git/modules/sub1/config.lock failed: Function not implemented\n>>>>> I'm not sure what this is about, seems to happen during the \"cp -R\" of\n>>>>> the repo under .git/modules into the submodule.\n>>>> No. It happens because fchmod() is not implemented in our Windows port.\n>>>>\n>>>> Please see my band-aid patch at\n>>>> http://thread.gmane.org/gmane.comp.version-control.git/248154/focus=20266\n>>>> The sub-thread ended inconclusive.\n>>> We need to start somewhere, and a no-op fchmod() in your patch may\n>>> be as a good place to start as anything.  At least we would then\n>>> keep the old behaviour without introducing any new failure.\n>> Right, this likely makes the most sense for single-user systems or\n>> systesm without a *nix-like permission system.\n>>\n>>> An alternative might be to use chmod() after we are done writing to\n>>> the config.lock in order to avoid the use of fchmod() altogether,\n>>> which I think can replace the existing two callsites of fchmod().\n>>> That approach might be a more expedient, but may turn out to be\n>>> undesirable in the longer term.\n>> In that case, we would need to open with mode=0600 to avoid a window\n>> where the file may be world-readable with any data in it.\n> Yes, of course.\n>\n> To elaborate what I was alluding to at the end of the message you\n> are responding to a bit more, if we were to move this \"grab perms\n> from existing file (if there is any) and propagate to the new one\"\n> into the lockfile API,\n>\n>   - in hold_lock_file_for_update(), we would record the permission of\n>     the original file, if any, to a new field in \"struct lock_file\";\n>   - open with 0600 or tighter in lock_file(), and\n>\n>   - either before closing the file use fchmod() or after closing and\n>     moving the file use chmod() to propagate the permission.\n>\n> If the original did not exist, we would pass 0666 to open as before\n> in lock_file() and do not bother chmod/fchmod at the end.\n>\n> Or something like that, perhaps.\n\nIsn't the whole problem starting here:\nin config.c:\n\n     fd = hold_lock_file_for_update(lock, config_filename, 0);\nIn lockfile.c:\n   /* This should return a meaningful errno on failure */\n   int hold_lock_file_for_update(struct lock_file *lk, const char *path, \nint flags)\n   {\n       int fd = lock_file(lk, path, flags);\nwhich leads to\n   static int lock_file(struct lock_file *lk, const char *path, int flags)\n     []\n     lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);\n\nThere is no way to tell which permissions the new lockfile should have.\nThat is somewhat unlucky.\n\nOn the other hand, shouldn't we call\nadjust_shared_perm(const char *path) from path.c on the config file?\n\nAnd to all files which are fiddled through the lock_file API?\nIn other words, the lockfile could be created with the restrictive \npermissions\n600, and once the lockfile had been closed and renamed into the final name\nwe apply adjust_shared_perm() on it ?\n\nOr probably directly after close() ?\n\nI think there are 2 different things missing here:\n\n- Be able to specify permissions to hold_lock_file_for_update(),\n    especially restrictive ones, like 600 and not 666.\n\n- Adjust the permissions for \"shared files\" in a shared repo.\n   This is probably needed for a shared repo, when the user itself\n    has a umask which is too restrictive and adjust_shared_perm()\n    must be run to widen the permissions.\n\nDo I miss something ?\n"},{"id":"245705","messageId":"xmqq61j5805g.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53BE3127.8020805@web.de","subject":"Re: No fchmd. was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-10T19:49:15Z","receivedAt":"2014-07-10T19:49:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n> Isn't the whole problem starting here:\n> in config.c:\n>\n>     fd = hold_lock_file_for_update(lock, config_filename, 0);\n> In lockfile.c:\n>   /* This should return a meaningful errno on failure */\n>   int hold_lock_file_for_update(struct lock_file *lk, const char\n> *path, int flags)\n>   {\n>       int fd = lock_file(lk, path, flags);\n> which leads to\n>   static int lock_file(struct lock_file *lk, const char *path, int flags)\n>     []\n>     lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);\n>\n> There is no way to tell which permissions the new lockfile should have.\n\nWe follow whategver user's umask says with this code.\n\n> That is somewhat unlucky.\n>\n> On the other hand, shouldn't we call\n> adjust_shared_perm(const char *path) from path.c on the config file?\n\nGood question, but I am not sure.  For $GIT_DIR/config, I tend to\nagree we should, but \"git config --global foo bar\" would not be a\nshared file anyway, and my understanding of Eric's original\nmotivation is to keep $HOME/.gitconfig to be tighter than the user's\numask normally would indicate.\n\n> And to all files which are fiddled through the lock_file API?\n> In other words, the lockfile could be created with the restrictive\n> permissions\n> 600, and once the lockfile had been closed and renamed into the final name\n> we apply adjust_shared_perm() on it ?\n\nFor all files that adjust-shared-perm should apply, yes, but I do\nnot think it is relevant to the codepath in question.\n\n> I think there are 2 different things missing here:\n>\n> - Be able to specify permissions to hold_lock_file_for_update(),\n>    especially restrictive ones, like 600 and not 666.\n\nYes (in the sense that \"yes we can add an extra parameter\") and no\n(in the sense that \"where would we get the value to pass to the\nextra parameter from?  would it be worth to add configurations\nvariables for different kinds of files?\").\n\nIf we limit the case to \"Inherit permissions from the file we are\nreplacing by taking a lock on it\", which is the topic of discussion\nin this thread, we do not have to worry about how to configure the\nvalue (we do not have to) and adding a new parameter to tell the\nmode to hold-lock-file-for-update is unneeded (the function will\nhave a pathname of the original and can learn the current permission\nbits itself).\n\n> - Adjust the permissions for \"shared files\" in a shared repo.\n>   This is probably needed for a shared repo, when the user itself\n>    has a umask which is too restrictive and adjust_shared_perm()\n>    must be run to widen the permissions.\n\nDon't we already do that for $GIT_DIR/config?  In any case that will\nnot help $HOME/.gitconfig and other files that are not shared.\n"},{"id":"245721","messageId":"xmqqsim96ine.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"xmqqmwci9vn1.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-10T20:52:37Z","receivedAt":"2014-07-10T20:52:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n>\n>> I agree, but this case is special. The test asserts that nobody\n>> added, modified or removed *anything* inside the .git directory.\n>> The reason for problem we are seeing here is that I have to\n>> remove the core.worktree setting when moving the git directory\n>> from .git/modules into the submodule work tree.\n>\n> Hmph.  Comparing the files with core.worktree removed sounds like a\n> workaround that knows too much about the implementation detail of\n> what is being tested.  I am just wondering if core.worktree will\n> stay forever be the only thing that is special, or there may come\n> other things (perhaps as a fallout of integrating things like Duy's\n> multiple-worktree stuff).\n>\n> But perhaps we cannot do better than this.\n\nOne thing we should be able to do (and must do) better is to\nvalidate that core.worktree in the relocated config file actually\npoints at the right place.  Unsetting before comparing may let us\ncompare the relocated one in .git/modules/$1/config with the one\nthat is embedded in the working tree (hence no .git/config), but the\nway your \"how about this?\" patch does, we wouldn't catch a possible\nbreakage to the relocation code to point core.worktree to a bogus\nlocation, I'm afraid.\n\nPerhaps squashing this to 7e8e5af9 instead?\n\n t/lib-submodule-update.sh | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex e441b98..fc1da84 100755\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -110,18 +110,23 @@ replace_gitfile_with_git_dir () {\n }\n \n # Test that the .git directory in the submodule is unchanged (except for the\n-# core.worktree setting, which we temporarily restore). Call this function\n-# before test_submodule_content as the latter might write the index file\n-# leading to false positive index differences.\n+# core.worktree setting, which appears only in $GIT_DIR/modules/$1/config).\n+# Call this function before test_submodule_content as the latter might\n+# write the index file leading to false positive index differences.\n test_git_directory_is_unchanged () {\n \t(\n-\t\tcd \"$1\" &&\n-\t\tgit config core.worktree \"../../../$1\"\n+\t\tcd \".git/modules/$1\" &&\n+\t\t# does core.worktree point at the right place?\n+\t\ttest \"$(git config core.worktree)\" = \"../../../$1\" &&\n+\t\t# remove it temporarily before comparing, as\n+\t\t# \"$1/.git/config\" lacks it...\n+\t\tgit config --unset core.worktree\n \t) &&\n \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n \t(\n-\t\tcd \"$1\" &&\n-\t\tGIT_WORK_TREE=. git config --unset core.worktree\n+\t\t# ... and then restore.\n+\t\tcd \".git/modules/$1\" &&\n+\t\tgit config core.worktree \"../../../$1\"\n \t)\n }\n \n"},{"id":"245723","messageId":"53BEFDA8.7020409@web.de","threadId":"36919","inReplyTo":"xmqq61j5805g.fsf@gitster.dls.corp.google.com","subject":"Re: No fchmd. was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Torsten Bögershausen","fromEmail":"tboegi@web.de","sentAt":"2014-07-10T20:55:04Z","receivedAt":"2014-07-10T20:55:04Z","isPatch":true,"sender":{"key":"tboegi@web.de","avatar":"https://avatars.githubusercontent.com/u/7138363?v=4"},"body":"On 2014-07-10 21.49, Junio C Hamano wrote:\n[]\n> If we limit the case to \"Inherit permissions from the file we are\n> replacing by taking a lock on it\", which is the topic of discussion\n> in this thread, we do not have to worry about how to configure the\n> value (we do not have to) and adding a new parameter to tell the\n> mode to hold-lock-file-for-update is unneeded (the function will\n> have a pathname of the original and can learn the current permission\n> bits itself).\nSo something like this:\n(I will probably not have the time to make a proper patch :-(\n\n\ndiff --git a/lockfile.c b/lockfile.c\nindex 4899270..134d5c8 100644\n--- a/lockfile.c\n+++ b/lockfile.c\n@@ -156,6 +156,11 @@ static void resolve_symlink(struct strbuf *path)\n /* Make sure errno contains a meaningful value on error */\n static int lock_file(struct lock_file *lk, const char *path, int flags)\n {\n+       int perms = 0666;\n+       struct stat st;\n+       if (!lstat(path, &st))\n+               perms = st.st_mode & 0777;\n+\n        if (!lock_file_list) {\n                /* One-time initialization */\n                sigchain_push_common(remove_lock_file_on_signal);\n@@ -179,7 +184,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)\n        if (!(flags & LOCK_NODEREF))\n                resolve_symlink(&lk->filename);\n        strbuf_addstr(&lk->filename, LOCK_SUFFIX);\n-       lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);\n+       lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, perms);\n        if (lk->fd < 0) {\n                strbuf_reset(&lk->filename);\n                return -1;\n"},{"id":"245724","messageId":"xmqqoaww7uvs.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53BEFDA8.7020409@web.de","subject":"Re: No fchmd. was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-10T21:43:03Z","receivedAt":"2014-07-10T21:43:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Torsten Bögershausen <tboegi@web.de> writes:\n\n> On 2014-07-10 21.49, Junio C Hamano wrote:\n> []\n>> If we limit the case to \"Inherit permissions from the file we are\n>> replacing by taking a lock on it\", which is the topic of discussion\n>> in this thread, we do not have to worry about how to configure the\n>> value (we do not have to) and adding a new parameter to tell the\n>> mode to hold-lock-file-for-update is unneeded (the function will\n>> have a pathname of the original and can learn the current permission\n>> bits itself).\n> So something like this:\n\nYeah, I think something along those lines may be sufficient and we\ndo not have to do anything when closing/committing, at least POSIX\nsystems.  I do not know if other filesystems we may care about let\nyou open with 0400 and still write into it, though.\n\n> (I will probably not have the time to make a proper patch :-(\n\nThat's OK.  I see many names on Cc: who are all capable of helping\nus ;-)\n\n>\n> diff --git a/lockfile.c b/lockfile.c\n> index 4899270..134d5c8 100644\n> --- a/lockfile.c\n> +++ b/lockfile.c\n> @@ -156,6 +156,11 @@ static void resolve_symlink(struct strbuf *path)\n>  /* Make sure errno contains a meaningful value on error */\n>  static int lock_file(struct lock_file *lk, const char *path, int flags)\n>  {\n> +       int perms = 0666;\n> +       struct stat st;\n> +       if (!lstat(path, &st))\n> +               perms = st.st_mode & 0777;\n> +\n>         if (!lock_file_list) {\n>                 /* One-time initialization */\n>                 sigchain_push_common(remove_lock_file_on_signal);\n> @@ -179,7 +184,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)\n>         if (!(flags & LOCK_NODEREF))\n>                 resolve_symlink(&lk->filename);\n>         strbuf_addstr(&lk->filename, LOCK_SUFFIX);\n> -       lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);\n> +       lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, perms);\n>         if (lk->fd < 0) {\n>                 strbuf_reset(&lk->filename);\n>                 return -1;\n"},{"id":"245899","messageId":"53C17D16.80106@web.de","threadId":"36919","inReplyTo":"xmqqsim96ine.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-07-12T18:23:18Z","receivedAt":"2014-07-12T18:23:18Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 10.07.2014 22:52, schrieb Junio C Hamano:\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n>> Jens Lehmann <Jens.Lehmann@web.de> writes:\n>>\n>>> I agree, but this case is special. The test asserts that nobody\n>>> added, modified or removed *anything* inside the .git directory.\n>>> The reason for problem we are seeing here is that I have to\n>>> remove the core.worktree setting when moving the git directory\n>>> from .git/modules into the submodule work tree.\n>>\n>> Hmph.  Comparing the files with core.worktree removed sounds like a\n>> workaround that knows too much about the implementation detail of\n>> what is being tested.  I am just wondering if core.worktree will\n>> stay forever be the only thing that is special, or there may come\n>> other things (perhaps as a fallout of integrating things like Duy's\n>> multiple-worktree stuff).\n>>\n>> But perhaps we cannot do better than this.\n> \n> One thing we should be able to do (and must do) better is to\n> validate that core.worktree in the relocated config file actually\n> points at the right place.  Unsetting before comparing may let us\n> compare the relocated one in .git/modules/$1/config with the one\n> that is embedded in the working tree (hence no .git/config), but the\n> way your \"how about this?\" patch does, we wouldn't catch a possible\n> breakage to the relocation code to point core.worktree to a bogus\n> location, I'm afraid.\n\nIndeed.\n\n> Perhaps squashing this to 7e8e5af9 instead?\n\nYes please, this is much better than my first attempt.\n\n>  t/lib-submodule-update.sh | 19 ++++++++++++-------\n>  1 file changed, 12 insertions(+), 7 deletions(-)\n> \n> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n> index e441b98..fc1da84 100755\n> --- a/t/lib-submodule-update.sh\n> +++ b/t/lib-submodule-update.sh\n> @@ -110,18 +110,23 @@ replace_gitfile_with_git_dir () {\n>  }\n>  \n>  # Test that the .git directory in the submodule is unchanged (except for the\n> -# core.worktree setting, which we temporarily restore). Call this function\n> -# before test_submodule_content as the latter might write the index file\n> -# leading to false positive index differences.\n> +# core.worktree setting, which appears only in $GIT_DIR/modules/$1/config).\n> +# Call this function before test_submodule_content as the latter might\n> +# write the index file leading to false positive index differences.\n>  test_git_directory_is_unchanged () {\n>  \t(\n> -\t\tcd \"$1\" &&\n> -\t\tgit config core.worktree \"../../../$1\"\n> +\t\tcd \".git/modules/$1\" &&\n> +\t\t# does core.worktree point at the right place?\n> +\t\ttest \"$(git config core.worktree)\" = \"../../../$1\" &&\n> +\t\t# remove it temporarily before comparing, as\n> +\t\t# \"$1/.git/config\" lacks it...\n> +\t\tgit config --unset core.worktree\n>  \t) &&\n>  \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n>  \t(\n> -\t\tcd \"$1\" &&\n> -\t\tGIT_WORK_TREE=. git config --unset core.worktree\n> +\t\t# ... and then restore.\n> +\t\tcd \".git/modules/$1\" &&\n> +\t\tgit config core.worktree \"../../../$1\"\n>  \t)\n>  }\n>  \n> \n"},{"id":"245963","messageId":"xmqq4myk21o8.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53C17D16.80106@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-14T01:01:59Z","receivedAt":"2014-07-14T01:01:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n>> Perhaps squashing this to 7e8e5af9 instead?\n>\n> Yes please, this is much better than my first attempt.\n\nOne thing that I found troubling is the ../../../ \"three levels up\"\nis hardcoded.  Would it be always true for any value of \"$1\"?  If\nthe submodule is bound to the superproject at sub/dir/, not at dir/,\nfor example, would it have to change?\n\nI am not saying that we must support artibrary cases, but if there\nis such a limitation in the implementation, people who will use the\nhelper in their new tests want it at least documented, I think.\n\n>>  t/lib-submodule-update.sh | 19 ++++++++++++-------\n>>  1 file changed, 12 insertions(+), 7 deletions(-)\n>> \n>> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n>> index e441b98..fc1da84 100755\n>> --- a/t/lib-submodule-update.sh\n>> +++ b/t/lib-submodule-update.sh\n>> @@ -110,18 +110,23 @@ replace_gitfile_with_git_dir () {\n>>  }\n>>  \n>>  # Test that the .git directory in the submodule is unchanged (except for the\n>> -# core.worktree setting, which we temporarily restore). Call this function\n>> -# before test_submodule_content as the latter might write the index file\n>> -# leading to false positive index differences.\n>> +# core.worktree setting, which appears only in $GIT_DIR/modules/$1/config).\n>> +# Call this function before test_submodule_content as the latter might\n>> +# write the index file leading to false positive index differences.\n>>  test_git_directory_is_unchanged () {\n>>  \t(\n>> -\t\tcd \"$1\" &&\n>> -\t\tgit config core.worktree \"../../../$1\"\n>> +\t\tcd \".git/modules/$1\" &&\n>> +\t\t# does core.worktree point at the right place?\n>> +\t\ttest \"$(git config core.worktree)\" = \"../../../$1\" &&\n>> +\t\t# remove it temporarily before comparing, as\n>> +\t\t# \"$1/.git/config\" lacks it...\n>> +\t\tgit config --unset core.worktree\n>>  \t) &&\n>>  \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n>>  \t(\n>> -\t\tcd \"$1\" &&\n>> -\t\tGIT_WORK_TREE=. git config --unset core.worktree\n>> +\t\t# ... and then restore.\n>> +\t\tcd \".git/modules/$1\" &&\n>> +\t\tgit config core.worktree \"../../../$1\"\n>>  \t)\n>>  }\n>>  \n>> \n"},{"id":"245985","messageId":"CABPQNSY5x_JOsxyKn7xZ9nc5TJ0yHdNvam0htyX01U58bvV7vg@mail.gmail.com","threadId":"36919","inReplyTo":"20140709200046.GB17454@dcvr.yhbt.net","subject":"Re: No fchmod() under msygit - Was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@gmail.com","sentAt":"2014-07-14T11:31:35Z","receivedAt":"2014-07-14T11:31:35Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Wed, Jul 9, 2014 at 10:00 PM, Eric Wong <normalperson@yhbt.net> wrote:\n> Torsten Bögershausen <tboegi@web.de> wrote:\n>> (And why is it  \"& 07777\" and not  \"& 0777\")\n>\n> This is to preserve the uncommon sticky/sgid/suid bits.  Probably not\n> needed, but better to keep as much intact as possible.\n>\n>> Can we avoid the fchmod()  all together ?\n>\n> For single-user systems, sure.\n>\n> For multi-user systems with git-imap-send users and passwords in\n> $GIT_CONFIG, I suggest not.\n\nYou're saying this as if Windows is a single-user system. It's not,\nbut it uses ACLs rather than POSIX permissions to manage file-system\npermissions. So far we've opted to ignore ACLs in Git for Windows,\nthough.\n"},{"id":"245987","messageId":"CAK3OfOjoqOsL5GnJAC251gqRoQo_4qwKMicLSod=7ZA69SL68w@mail.gmail.com","threadId":"36919","inReplyTo":"CABPQNSY5x_JOsxyKn7xZ9nc5TJ0yHdNvam0htyX01U58bvV7vg@mail.gmail.com","subject":"Re: No fchmod() under msygit - Was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Nico Williams","fromEmail":"nico@cryptonector.com","sentAt":"2014-07-14T13:55:29Z","receivedAt":"2014-07-14T13:55:29Z","isPatch":true,"sender":{"key":"nico@cryptonector.com","avatar":null},"body":"On Mon, Jul 14, 2014 at 6:31 AM, Erik Faye-Lund <kusmabite@gmail.com> wrote:\n> On Wed, Jul 9, 2014 at 10:00 PM, Eric Wong <normalperson@yhbt.net> wrote:\n>> Torsten Bögershausen <tboegi@web.de> wrote:\n>>\n>\n> You're saying this as if Windows is a single-user system. It's not,\n> but it uses ACLs rather than POSIX permissions to manage file-system\n> permissions. So far we've opted to ignore ACLs in Git for Windows,\n> though.\n\nThe clever thing to do (that some versions of ZFS do nowadays) is to\nuse the new mask to \"edit\" the ACL as follows:\n\n - leave any DENY ACEs as-is; for all others continue\n\n - remove (reset) from any ACEs for Everyone (and/or Authenticated\nUsers) any bits corresponding to zero'ed bits in the new mask's other\nbits\n\n - remove from any other ACEs that are not for the owner (@OWNER in\nNFSv4 speak) any bits corresponding to zero'ed bits in the new mask's\ngroup bits\n\n - remove from the owner's ACEs any bits corresponding to zero'ed bits\nin the new mask's owner bits, but with some exceptions, in particular\nthe owner must retain the right to edit the ACL\n\n - add (set) to the Everyone (and/or Authenticated Users) ACEs a set\nof bits corresponding to the set bits in the new mask's other bits\n\n - add (set) either only to the ACE for the file's group\n(alternatively, to all non-owner, non-Everyone/Authenticated Users\nACEs) a set of bits corresponding to the set bits in the new mask's\ngroup bits\n\n...\n\nI.e., use the chmod mask to decrease/increase access without changing\nthe \"shape\" of the ACL.\n\nDetermining a file's mode_t from an ACL is similar, though it must\ntake DENY entries into account: make a set of users/groups referred to\nby any ACEs in the ACL, divide them into owner, other (Everyone and/or\nAuthenticated Users), and group (all others), find the maximal access\ngranted.\n\nStill, git might like to know what ACLs to apply to files at checkout\ntime.  That would be a vast new feature, I think, and probably not\nworth it, particularly since that would require dealing with the\ndifferent types of ACLs: NTFS/NFSv4/ZFS on the one hand, POSIX Draft\non the other, plus AFS and who knows what else -- ETOOMUCH IMO.\n\nNico\n--\n"},{"id":"245988","messageId":"CAK3OfOie62GORn9f7CUXj-TKQiHb++ZYz5Xm0fVL6rYOArm5eg@mail.gmail.com","threadId":"36919","inReplyTo":"CAK3OfOjoqOsL5GnJAC251gqRoQo_4qwKMicLSod=7ZA69SL68w@mail.gmail.com","subject":"Re: No fchmod() under msygit - Was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Nico Williams","fromEmail":"nico@cryptonector.com","sentAt":"2014-07-14T14:02:52Z","receivedAt":"2014-07-14T14:02:52Z","isPatch":true,"sender":{"key":"nico@cryptonector.com","avatar":null},"body":"> Still, git might like to know what ACLs to apply to files at checkout\n> time.  That would be a vast new feature, I think, and probably not\n> worth it, particularly since that would require dealing with the\n> different types of ACLs: NTFS/NFSv4/ZFS on the one hand, POSIX Draft\n> on the other, plus AFS and who knows what else -- ETOOMUCH IMO.\n\nTo complete that thought...\n\nInheritable ACLs + chmod should suffice.  The user should setup\ninheritable ACLs for the directory where a repo is to be cloned, then\non checkout git should just apply mode changes in such a way as to\nleave ACL \"shapes\" unchanged, only adding or removing bits from\nnon-DENY ACEs according to the saved file modes.\n\nInheritable ACEs should be left as-is, since git doesn't track\ndirectory permissions (right?), or if it did, then those should be\nedited just like normal ACEs.\n\nNico\n--\n"},{"id":"246001","messageId":"53C41FED.5080101@web.de","threadId":"36919","inReplyTo":"xmqq4myk21o8.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2014-07-14T18:22:37Z","receivedAt":"2014-07-14T18:22:37Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 14.07.2014 03:01, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>>> Perhaps squashing this to 7e8e5af9 instead?\n>>\n>> Yes please, this is much better than my first attempt.\n> \n> One thing that I found troubling is the ../../../ \"three levels up\"\n> is hardcoded.  Would it be always true for any value of \"$1\"?  If\n> the submodule is bound to the superproject at sub/dir/, not at dir/,\n> for example, would it have to change?\n\nYes. And the code currently also doesn't handle submodules whose\nname and path differ.\n\n> I am not saying that we must support artibrary cases, but if there\n> is such a limitation in the implementation, people who will use the\n> helper in their new tests want it at least documented, I think.\n\nAh, I didn't think about other tests reusing that and only wrote\nthis as a local helper. But you're right, it would make sense to\nreuse this function instead of coding that again (even though I'd\nprefer to extract the generic helpers to t/lib-submodule.sh for\nthat purpose).\n\nSo what about adding \"Currently only submodules living in the\nroot directory of the superproject with the default name (same\nas the path) are supported.\" to the comment above the function?\n\n>>>  t/lib-submodule-update.sh | 19 ++++++++++++-------\n>>>  1 file changed, 12 insertions(+), 7 deletions(-)\n>>>\n>>> diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\n>>> index e441b98..fc1da84 100755\n>>> --- a/t/lib-submodule-update.sh\n>>> +++ b/t/lib-submodule-update.sh\n>>> @@ -110,18 +110,23 @@ replace_gitfile_with_git_dir () {\n>>>  }\n>>>  \n>>>  # Test that the .git directory in the submodule is unchanged (except for the\n>>> -# core.worktree setting, which we temporarily restore). Call this function\n>>> -# before test_submodule_content as the latter might write the index file\n>>> -# leading to false positive index differences.\n>>> +# core.worktree setting, which appears only in $GIT_DIR/modules/$1/config).\n>>> +# Call this function before test_submodule_content as the latter might\n>>> +# write the index file leading to false positive index differences.\n>>>  test_git_directory_is_unchanged () {\n>>>  \t(\n>>> -\t\tcd \"$1\" &&\n>>> -\t\tgit config core.worktree \"../../../$1\"\n>>> +\t\tcd \".git/modules/$1\" &&\n>>> +\t\t# does core.worktree point at the right place?\n>>> +\t\ttest \"$(git config core.worktree)\" = \"../../../$1\" &&\n>>> +\t\t# remove it temporarily before comparing, as\n>>> +\t\t# \"$1/.git/config\" lacks it...\n>>> +\t\tgit config --unset core.worktree\n>>>  \t) &&\n>>>  \tdiff -r \".git/modules/$1\" \"$1/.git\" &&\n>>>  \t(\n>>> -\t\tcd \"$1\" &&\n>>> -\t\tGIT_WORK_TREE=. git config --unset core.worktree\n>>> +\t\t# ... and then restore.\n>>> +\t\tcd \".git/modules/$1\" &&\n>>> +\t\tgit config core.worktree \"../../../$1\"\n>>>  \t)\n>>>  }\n>>>  \n>>>\n> \n"},{"id":"246005","messageId":"53C42FE0.10904@gmail.com","threadId":"36919","inReplyTo":"20140709200046.GB17454@dcvr.yhbt.net","subject":"Re: No fchmod() under msygit - Was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Karsten Blees","fromEmail":"karsten.blees@gmail.com","sentAt":"2014-07-14T19:30:40Z","receivedAt":"2014-07-14T19:30:40Z","isPatch":true,"sender":{"key":"karsten.blees@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1111200?v=4"},"body":"Am 09.07.2014 22:00, schrieb Eric Wong:\n> Torsten Bögershausen <tboegi@web.de> wrote:\n>> (And why is it  \"& 07777\" and not  \"& 0777\")\n> \n> This is to preserve the uncommon sticky/sgid/suid bits.  Probably not\n> needed, but better to keep as much intact as possible.\n> \n>> Can we avoid the fchmod()  all together ?\n> \n> For single-user systems, sure.\n> \n> For multi-user systems with git-imap-send users and passwords in\n> $GIT_CONFIG, I suggest not.\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n> \n\nThe Windows fchmod() problem is easily solved by using chmod() instead of\nfchmod(). The file name is known in both cases (and even used in the error\nmessage).\n\nHowever, IMO there are more fundamental problems with your patch (not\nrelated to Windows):\n\n1.) Permissions of files in .git are controlled by the core.sharedRepository\nsetting, and your patch seems to break that (i.e. if someone accidentally\nhas made .git/config world readable, git-config no longer fixes that, even\nif core.sharedRepository=0600).\n\n2.) Sensitive data such as passwords doesn't belong in config files in the\nfirst place, that's what git-credentials is good for.\n"},{"id":"246031","messageId":"xmqqha2jy704.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53C42FE0.10904@gmail.com","subject":"Re: No fchmod() under msygit - Was: Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-14T21:18:03Z","receivedAt":"2014-07-14T21:18:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Karsten Blees <karsten.blees@gmail.com> writes:\n\n> 1.) Permissions of files in .git are controlled by the core.sharedRepository\n> setting, and your patch seems to break that (i.e. if someone accidentally\n> has made .git/config world readable, git-config no longer fixes that, even\n> if core.sharedRepository=0600).\n\nFor any repository, when you further run \"git config\" to update it,\n.git/config always exists with the permission bits initialized when\n\"git init\" was run there.  And Eric's change is to propagate that\nsame bits to a new file, so there wouldn't be any difference, no?\n\nAnd $HOME/.gitconfig should not be governed by \"sharedRepository\",\nand that was the primary focus of Eric's change, I would think.\n"},{"id":"246032","messageId":"xmqqd2d7y6z7.fsf@gitster.dls.corp.google.com","threadId":"36919","inReplyTo":"53C41FED.5080101@web.de","subject":"Re: [PATCH 00/14] Add submodule test harness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-14T21:18:36Z","receivedAt":"2014-07-14T21:18:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> So what about adding \"Currently only submodules living in the\n> root directory of the superproject with the default name (same\n> as the path) are supported.\" to the comment above the function?\n\nOK, done, and merged to 'next'.\n\nThanks.\n"}]}