{"thread":{"id":"21224","subject":"Changing branches in supermodule does not affect submodule?","startedAt":"2009-10-13T10:29:08Z","lastAt":"2009-10-14T20:12:57Z","messageCount":6,"participants":["Peter Krefting","Jens Lehmann","Junio C Hamano","Heiko Voigt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"124838","messageId":"alpine.DEB.2.00.0910131115160.14223@ds9.cixit.se","threadId":"21224","inReplyTo":null,"subject":"Changing branches in supermodule does not affect submodule?","fromName":"Peter Krefting","fromEmail":"peter@softwolves.pp.se","sentAt":"2009-10-13T10:29:08Z","receivedAt":"2009-10-13T10:29:08Z","isPatch":false,"sender":{"key":"peter@softwolves.pp.se","avatar":"https://avatars.githubusercontent.com/u/990764?v=4"},"body":"Hi!\n\nIf I have a repository with submodules that is in a clean state, and switch \nbranches in the super repository, the submodules are left in the state they \nwere in before I switched branches (with 1.6.4, at least). Is this the \nexpected behaviour?\n\n--->8--8<---\n#!/bin/bash\n# Create supermodule.\nmkdir super-$$\ncd super-$$\ngit init\n\n# Create submodule with commit.\nmkdir sub\ncd sub\ngit init\necho C > c.txt\necho D > d.txt\ngit add c.txt d.txt\ngit commit -m Created.\ncd ..\n\n# Create commit and branch in supermodule.\necho A > a.txt\necho B > b.txt\ngit add a.txt b.txt sub\ngit commit -m Created.\ngit tag branchpoint\ngit checkout -b branch1\n\n# Create branch1 in submodule and commit.\ncd sub\ngit checkout -b branch1\necho E > c.txt\necho F > d.txt\ngit add c.txt d.txt\ngit commit -m Branched.\ncd ..\n\n# Commit to a branch in the supermodule.\ngit add sub\ngit commit -m Sub-update.\n\n# Status should now be clean.\ngit status\n\n# Create a new branch in supermodule, from the original commit.\ngit checkout -b branch2 branchpoint\n\n# I now expect the submodule to be up-to-date and the state clean.\ngit status\n--->8--8<---\n\n-- \n\\\\// Peter - http://www.softwolves.pp.se/\n"},{"id":"124845","messageId":"4AD47C65.5080904@web.de","threadId":"21224","inReplyTo":"alpine.DEB.2.00.0910131115160.14223@ds9.cixit.se","subject":"Re: Changing branches in supermodule does not affect submodule?","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2009-10-13T13:11:01Z","receivedAt":"2009-10-13T13:11:01Z","isPatch":false,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Peter Krefting schrieb:\n> If I have a repository with submodules that is in a clean state, and\n> switch branches in the super repository, the submodules are left in the\n> state they were in before I switched branches (with 1.6.4, at least). Is\n> this the expected behaviour?\n\nYup, submodules have to be updated separatly.\n\nWhen they are cloned from a remote with \"git submodule add\" followed by\na \"git submodule init\", just calling \"git submodule update\" every time\nyou want the submodule to be updated according to the state committed\nin the superproject will do the trick (but keep in mind that all\nreferenced commits have to be accessible in the local clone of your\nsubmodule, so you might have to do a fetch there once in a while).\n\n\nJens\n"},{"id":"124942","messageId":"alpine.DEB.2.00.0910140728420.16100@ds9.cixit.se","threadId":"21224","inReplyTo":"4AD47C65.5080904@web.de","subject":"Re: Changing branches in supermodule does not affect submodule?","fromName":"Peter Krefting","fromEmail":"peter@softwolves.pp.se","sentAt":"2009-10-14T06:31:04Z","receivedAt":"2009-10-14T06:31:04Z","isPatch":false,"sender":{"key":"peter@softwolves.pp.se","avatar":"https://avatars.githubusercontent.com/u/990764?v=4"},"body":"Jens Lehmann:\n\n> just calling \"git submodule update\" every time you want the submodule to \n> be updated according to the state committed in the superproject will do \n> the trick (but keep in mind that all referenced commits have to be \n> accessible in the local clone of your submodule, so you might have to do a \n> fetch there once in a while).\n\nIs it possible to automate this from a hook or something else? Basically, I \nwould like it to update all the submodules to the state recorded in the \ncommit I move to, if they were in a clean state before I moved. I do not \nwant it to change states if I do something like\n\n   cd submodule\n   # do some changes\n   git commit\n   cd ..\n   git checkout -b newbranch\n\nbecause there I want the commit I made to the submodule to be recorded on \nthe new branch I created. But then it was in a dirty state before I created \nthe branch anyway, so that shouldn't be a problem.\n\n-- \n\\\\// Peter - http://www.softwolves.pp.se/\n"},{"id":"124983","messageId":"4AD5F0B1.4000507@web.de","threadId":"21224","inReplyTo":"alpine.DEB.2.00.0910140728420.16100@ds9.cixit.se","subject":"Re: Changing branches in supermodule does not affect submodule?","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2009-10-14T15:39:29Z","receivedAt":"2009-10-14T15:39:29Z","isPatch":false,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Peter Krefting schrieb:\n> Jens Lehmann:\n> \n>> just calling \"git submodule update\" every time you want the submodule\n>> to be updated according to the state committed in the superproject\n>> will do the trick (but keep in mind that all referenced commits have\n>> to be accessible in the local clone of your submodule, so you might\n>> have to do a fetch there once in a while).\n\nBTW: unless you use the -N or --no-fetch option, git submodule update\nwill do the fetch for you.\n\n\n> Is it possible to automate this from a hook or something else?\n\nYep, you can use the post-checkout hook for that, just put a \"git\nsubmodule update\" in it.\n\n*But*: If you do a checkout in the superproject while the submodule\nhas new commits not contained in any branch (remember submodules\noften have a detached head) you'll silently lose these commits!\nThen only the reflog can help you ...\n"},{"id":"125013","messageId":"7vtyy1bv65.fsf@alter.siamese.dyndns.org","threadId":"21224","inReplyTo":"alpine.DEB.2.00.0910140728420.16100@ds9.cixit.se","subject":"Re: Changing branches in supermodule does not affect submodule?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-10-14T20:02:58Z","receivedAt":"2009-10-14T20:02:58Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Peter Krefting <peter@softwolves.pp.se> writes:\n\n> Basically, I would like it to update all the submodules to the state\n> recorded in the commit I move to, if they were in a clean state before\n> I moved. I do not want it to change states if I do something like\n>\n>   cd submodule\n>   # do some changes\n>   git commit\n>   cd ..\n>   git checkout -b newbranch\n>\n> because there I want the commit I made to the submodule to be recorded\n> on the new branch I created. But then it was in a dirty state before I\n> created the branch anyway, so that shouldn't be a problem.\n\nMy understanding is that the primary reason \"git checkout $another_branch\"\ndoes not touch submodules (other than updating the commit object name\nbound in the index in the superproject) is because we did not know what\npeople would want to happen when submodule support was introduced.\n\nNow people have used submodules for a while, we can update this.  I think\nmodelling the behaviour after how normal blobs are updated upon branch\nswitching would make sense.\n\nSo let's step back a bit and review what happens to a normal blob upon\nbranch switching.  There are three cases for a path while switching\nbranches from A to B:\n\n #1 The path is the same between A and B.  In this case, whatever you have\n    for path in the index and in the work tree stay the same.  Your local\n    modification is carried across branch switching.\n\n    This is already what we do with submodules.  In cases #2 and #3 below,\n    path is different between A and B.\n\n #2 You do not have any change to the path in either the index nor in the\n    work tree.  The path is updated to B's version in the index and also\n    what you have in the work tree matches it.\n\n    Note that if B lacks the path, it is _removed_ from both the index and\n    the work tree.\n\n #3 You have a change to the path in the index or in the work tree.  The\n    branch switch is refused if the index does not match what is in B.\n\n    I think this also is already what we do with submodules.\n\nWith a reasonable definition of \"have a change in the work tree\" for a\nsubmodule path, we can define a reasonable behaviour for updating the\nsubmodules when a different branch is checked out in the superproject.\n\nFor a regular blob, having a change in the work tree is that the object\nrecorded in HEAD (in the superproject) is different from what you have in\nthe work tree.  What should the definition be for a submodule?\n\nThe HEAD (in the submodule), the index (in the submodule) and the work\ntree (in the submodule) form the \"state\" of what you have in the path, and\nthat corresponds to the \"work tree state\".  So I think we can say that\nthere is no change in the work tree for a submodule at path P if all of\nthe following holds:\n\n    - the HEAD in the submodule matches the commit recorded for the path P\n      in the HEAD in the superproject;\n\n    - the index in the submodule matches the HEAD in the submodule; and\n\n    - the work tree in the submodule matches the index in the submodule.\n\nWith this definition, you should be able to patch \"git checkout\" to\nrecurse into the submodule directory for case #2.\n\nAs to the implementation, I'd suggest:\n\n - the check between the submodule HEAD and what the superproject records\n   in the HEAD (the first condition above) be done inside the main process\n   (because we already have a working check for #3 to refuse branch\n   switching, I think it would be easier to implement this check by\n   comparison between the submodule HEAD and the superproject index).\n\n - the check between the index and the HEAD in the submodule and the check\n   between the index and the work tree in the submodule (the second and\n   the third conditions above) be done in a subprocess that runs something\n   like \"git status\" via the run_command() interface; and\n\n - the actual recursive checkout to happen in a subprocess that runs\n   another instance of \"git checkout\" via the run_command() interface.\n\nThere is one caveat.  The potential removal of the work tree path in #2\nmay not be desirable for a submodule path, even if you do not have any\nchange to it (i.e. both the index and the work tree in the submodule match\nthe HEAD in the submodule), as you may have untracked files you would\nrather want to keep in the submodule work tree.\n"},{"id":"125015","messageId":"20091014201257.GA5788@book.hvoigt.net","threadId":"21224","inReplyTo":"4AD5F0B1.4000507@web.de","subject":"[RFC PATCH] implement sample post-checkout hook to checkout new/unchanged submodules","fromName":"Heiko Voigt","fromEmail":"hvoigt@hvoigt.net","sentAt":"2009-10-14T20:12:57Z","receivedAt":"2009-10-14T20:12:57Z","isPatch":true,"sender":{"key":"hvoigt@hvoigt.net","avatar":"https://avatars.githubusercontent.com/u/184958?v=4"},"body":"Currently gits default behaviour is not to recursively update submodules\nwhen they are unchanged in the working copy. This hook implements this\nby comparing whether the current HEAD in the submodule is the same as\nrecorded in the commit we are coming from. It then initializes or\nupdates the submodule as necessary.\n\nSigned-off-by: Heiko Voigt <hvoigt@hvoigt.net>\n---\n\nOn Wed, Oct 14, 2009 at 05:39:29PM +0200, Jens Lehmann wrote:\n> Peter Krefting schrieb:\n> > Jens Lehmann:\n> > \n> >> just calling \"git submodule update\" every time you want the submodule\n> >> to be updated according to the state committed in the superproject\n> >> will do the trick (but keep in mind that all referenced commits have\n> >> to be accessible in the local clone of your submodule, so you might\n> >> have to do a fetch there once in a while).\n> \n> BTW: unless you use the -N or --no-fetch option, git submodule update\n> will do the fetch for you.\n> \n> \n> > Is it possible to automate this from a hook or something else?\n> \n> Yep, you can use the post-checkout hook for that, just put a \"git\n> submodule update\" in it.\n\nIncidentially I have just been working on such a hook. Here is a patch\nthat implements it as a sample hook.\n\nI tested most cases, but I have not worked with it productively so it\nmight have strange results in some cases. One I already found is that\npost-checkout is not called after a merge so you need to add a\nsubmodule update there as well.\n\ncheers Heiko\n\n\n templates/hooks--post-checkout.sample |   50 +++++++++++++++++++++++++++++++++\n 1 files changed, 50 insertions(+), 0 deletions(-)\n create mode 100644 templates/hooks--post-checkout.sample\n\ndiff --git a/templates/hooks--post-checkout.sample b/templates/hooks--post-checkout.sample\nnew file mode 100644\nindex 0000000..9ffffa0\n--- /dev/null\n+++ b/templates/hooks--post-checkout.sample\n@@ -0,0 +1,50 @@\n+#!/bin/sh\n+\n+# if this is a file checkout we do nothing\n+flag=$3\n+if [ ! $flag ]\n+then\n+\texit 0\n+fi\n+\n+# if this is the initial checkout also intialize submodules\n+if [ $1 == \"0000000000000000000000000000000000000000\" ]; then\n+\tgit submodule init\n+\tgit submodule update\n+\t# after initial checkout we are done now\n+\texit 0\n+fi\n+\n+# update all submodules that where not modified beforehand\n+# or did not exist\n+prev_sha1=$1\n+new_sha1=$2\n+\n+git ls-tree $new_sha1 | grep ^160000 |cut -f2 |\n+while read submodule\n+do\n+\tprev_submodule_sha1=$(git ls-tree $prev_sha1 |\n+\t\tgrep \"\t$submodule$\" | cut -f1 | cut -d' ' -f3)\n+\tcurr_submodule_sha1=$(cd \"$submodule\"; git rev-parse HEAD \\\n+\t\t2>/dev/null)\n+\n+\tif [ -z \"$prev_submodule_sha1\" ]\n+\tthen\n+\t\tgit submodule init \"$submodule\"\n+\t\tgit submodule update \"$submodule\"\n+\t\tcontinue\n+\tfi\n+\n+\tif [ \"$prev_submodule_sha1\" = \"$curr_submodule_sha1\" ]\n+\tthen\n+\t\tif [ -z \"$(git config submodule.\"$submodule\".url)\" ]\n+\t\tthen\n+\t\t\tgit submodule init \"$submodule\"\n+\t\tfi\n+\n+\t\tif [ \"$(git diff $prev_sha1 $new_sha1 -- \"$submodule\")\" ]\n+\t\tthen\n+\t\t\tgit submodule update \"$submodule\"\n+\t\tfi\n+\tfi\n+done\n-- \n1.6.5.rc1.12.gc72fe\n"}]}