{"thread":{"id":"16683","subject":"[PATCH v2] submodule: Allow tracking of the newest revision of a branch in a submodule","startedAt":"2008-12-11T13:16:01Z","lastAt":"2008-12-11T19:26:47Z","messageCount":3,"participants":["Fabian Franz","Johannes Sixt","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"97596","messageId":"1229001361-9301-1-git-send-email-git@fabian-franz.de","threadId":"16683","inReplyTo":null,"subject":"[PATCH v2] submodule: Allow tracking of the newest revision of a branch in a submodule","fromName":"Fabian Franz","fromEmail":"git@fabian-franz.de","sentAt":"2008-12-11T13:16:01Z","receivedAt":"2008-12-11T13:16:01Z","isPatch":true,"sender":{"key":"git@fabian-franz.de","avatar":null},"body":"Submodules currently only allow tracking a specific revision\nand each update in a submodule leads to a new commit in the\nmaster repository. However some users may want to always track\nthe newest revision of a specific (named) tag or branch or HEAD.\nFor example the user might want to track a staging branch in all\nsubmodules.\n\nTo allow this the \"--track|-t <branch>\" parameter was added to\ngit-submodule.sh, which is added to .gitmodules config file as\nwell as \"track\" parameter. This creates a new local branch on\ncheckout, which is tracking the remote branch in case the local\nbranch does not yet exist.\n\nTechnically the gitlink code was changed to always compare\nsuccessful (so no changes) in case the sha1 is null. In that\ncase no new commit is created when there are changes in the\nsubmodule.\n\nThe submodule code is adding the file with 0000* on\n\"add\".\n\nSigned-off-by: Fabian Franz <git@fabian-franz.de>\n---\n\nOn Tue, Dec 9, 2008 at 01:57, Fabian Franz <git@xxxxxxxxxxxxxxx> wrote:\n>> Technically the gitlink code was changed to read .git/HEAD.gitlink\n>> if it exists instead of the normal HEAD. If you add 0000* as sha1\n>> sum to .git/HEAD.gitlink the submodule code will always fetch HEAD.\n\n>This feels like the porcelain \"fooling\" the plumbing. How about\n>something like this instead:\n>This should make the plumbing happy no matter which commit is actually\n>checked out in the submodule (not actually tested...). \n\nYeah, that works, thank you very much.\n\n>Then, cmd_update() can check if the requested sha1 is all '0' and\n>fetch+checkout latest HEAD (or some branch) without playing games with\n>.git/HEAD.gitlink.\n\nOkay. I do agree that this solution is much nicer.\n\n>Finally, cmd_add() needs to update the index in the\n>containing repository with the magic '0*' sha1 if '--track' is\n>specifed. This can be achieved by replacing 'git add $path' with 'echo\n>$mode $sha1\\t$path | git update-index --index-info'.\n\n>What do you think?\n\nI added that solution and it does work. However I see problems on remove (thought there is no submodule remove so far):\n\nNeither a new git add nor a git rm nor a git-update-index --remove do work afterwards.\n\nThis can just be done by doing the above command with some non-null sha1.\n\n>> @@ -327,10 +335,14 @@ cmd_update()\n>>                        say \"Maybe you want to use 'update --init'?\"\n>>                        continue\n>>                fi\n>> +               track=$(git config -f .gitmodules submodule.\"$name\".track)\n\n>I'm pretty certain that we don't want to use info from .gitmodules in\n>cmd_update(). Instead, cmd_init() probably should move the info from\n>.gitmodules into .git/config and cmd_update() should check the latter.\n\nOkay, I did this, however now I need a flag for init to be able to specify -f or a initalways command shortcut, so I can do in script:\n\ngit checkout staging # changes track = staging in .gitmodules\ngit submodule init -f\ngit submodule update # changes all branches to staging\n\nShould I add this in a different patch?\n\nTalking about script: Is there a possibility for a checkout hook?\n\nDoes something like that exist? Or do I need to add this myself, too?\n\nSo my workflow really is:\n\ngit checkout master # done long before\n[...]\ngit checkout staging\n# => in submodules/client/\n# Checked out submodules/client/ staging.\n# => in submodules/client/component1/\n# Checked out submodules/client/component/1 staging.\n\nSo I would like to have this recursively and I think a post checkout hook would be nice for that to achieve.\n\n>Btw: cmd_status() probably also needs some modifications to handle\n>this special case.\n\nI added the special case.\n\nHere is the new patch.\n\nWhat do you think?\n\nOr do we need a track and untrack command for the rm of a submodule to work properly?\n\nBest Wishes,\n\nFabian\n\n Documentation/git-submodule.txt |   10 +++++++++-\n git-submodule.sh                |   38 ++++++++++++++++++++++++++++++++++++--\n read-cache.c                    |    5 +++++\n 3 files changed, 50 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex babaa9b..9c29678 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules\n SYNOPSIS\n --------\n [verse]\n-'git submodule' [--quiet] add [-b branch] [--] <repository> <path>\n+'git submodule' [--quiet] add [-b branch] [-t|--track <branch>] [--] <repository> <path>\n 'git submodule' [--quiet] status [--cached] [--] [<path>...]\n 'git submodule' [--quiet] init [--] [<path>...]\n 'git submodule' [--quiet] update [--init] [--] [<path>...]\n@@ -118,6 +118,10 @@ update::\n If the submodule is not yet initialized, and you just want to use the\n setting as stored in .gitmodules, you can automatically initialize the\n submodule with the --init option.\n++\n+If you used --track or set the \"track\" option in .gitmodules this will\n+automatically pull the newest updates from remote instead of tracking a\n+specific revision.\n \n summary::\n \tShow commit summary between the given commit (defaults to HEAD) and\n@@ -159,6 +163,10 @@ OPTIONS\n --branch::\n \tBranch of repository to add as submodule.\n \n+-t::\n+--track::\n+\tBranch/Tag/HEAD of repository to track in a submodule.\n+\n --cached::\n \tThis option is only valid for status and summary commands.  These\n \tcommands typically use the commit found in the submodule HEAD, but\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 2f47e06..f25e744 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -5,7 +5,7 @@\n # Copyright (c) 2007 Lars Hjemli\n \n USAGE=\"[--quiet] [--cached] \\\n-[add <repo> [-b branch] <path>]|[status|init|update [-i|--init]|summary [-n|--summary-limit <n>] [<commit>]] \\\n+[add <repo> [-b branch] [--track|-t <branch>] <path>]|[status|init|update [-i|--init]|summary [-n|--summary-limit <n>] [<commit>]] \\\n [--] [<path>...]|[foreach <command>]|[sync [--] [<path>...]]\"\n OPTIONS_SPEC=\n . git-sh-setup\n@@ -16,6 +16,7 @@ command=\n branch=\n quiet=\n cached=\n+track=\n \n #\n # print stuff on stdout unless -q was specified\n@@ -130,6 +131,11 @@ cmd_add()\n \t\t-q|--quiet)\n \t\t\tquiet=1\n \t\t\t;;\n+\t\t-t|--track)\n+\t\t\tcase \"$2\" in '') usage ;; esac\n+\t\t\ttrack=$2\n+\t\t\tshift\n+\t\t\t;;\n \t\t--)\n \t\t\tshift\n \t\t\tbreak\n@@ -197,12 +203,14 @@ cmd_add()\n \t\t(unset GIT_DIR; cd \"$path\" && git checkout -f -q ${branch:+-b \"$branch\" \"origin/$branch\"}) ||\n \t\tdie \"Unable to checkout submodule '$path'\"\n \tfi\n+\t[ -n \"$track\" ] && echo \"160000 0000000000000000000000000000000000000000\\t$path\" | git update-index --index-info\n \n \tgit add \"$path\" ||\n \tdie \"Failed to add submodule '$path'\"\n \n \tgit config -f .gitmodules submodule.\"$path\".path \"$path\" &&\n \tgit config -f .gitmodules submodule.\"$path\".url \"$repo\" &&\n+\tgit config -f .gitmodules submodule.\"$path\".track \"$track\" &&\n \tgit add .gitmodules ||\n \tdie \"Failed to register submodule '$path'\"\n }\n@@ -277,6 +285,10 @@ cmd_init()\n \t\tgit config submodule.\"$name\".url \"$url\" ||\n \t\tdie \"Failed to register url for submodule path '$path'\"\n \n+\t\ttrack=$(git config -f .gitmodules submodule.\"$name\".track)\n+\t\tgit config submodule.\"$name\".track \"$track\" ||\n+\t\tdie \"Failed to register track for submodule path '$path'\"\n+\n \t\tsay \"Submodule '$name' ($url) registered for path '$path'\"\n \tdone\n }\n@@ -327,10 +339,12 @@ cmd_update()\n \t\t\tsay \"Maybe you want to use 'update --init'?\"\n \t\t\tcontinue\n \t\tfi\n+\t\ttrack=$(git config submodule.\"$name\".track)\n \n \t\tif ! test -d \"$path\"/.git -o -f \"$path\"/.git\n \t\tthen\n \t\t\tmodule_clone \"$path\" \"$url\" || exit\n+\n \t\t\tsubsha1=\n \t\telse\n \t\t\tsubsha1=$(unset GIT_DIR; cd \"$path\" &&\n@@ -345,11 +359,28 @@ cmd_update()\n \t\t\tthen\n \t\t\t\tforce=\"-f\"\n \t\t\tfi\n+\t\t\tpull=\n+\t\t\tif [ \"$sha1\" = \"0000000000000000000000000000000000000000\" ]\n+\t\t\tthen\n+\t\t\t\t[ -z \"$track\" ] && track=\"HEAD\"\n+\t\t\t\t# if the local branch does not yet exist, create it\n+\t\t\t\t( unset GIT_DIR; cd \"$path\"; git-show-ref --heads --tags -q \"$track\" || git branch --track \"$track\" \"origin/$track\" )\n+\t\t\t\tsha1=\"$track\"\n+\t\t\t\tpull=1\n+\t\t\tfi\n+\n \t\t\t(unset GIT_DIR; cd \"$path\" && git-fetch &&\n \t\t\t\tgit-checkout $force -q \"$sha1\") ||\n \t\t\tdie \"Unable to checkout '$sha1' in submodule path '$path'\"\n \n \t\t\tsay \"Submodule path '$path': checked out '$sha1'\"\n+\n+\t\t\tif [ \"$pull\" = \"1\" ]\n+\t\t\tthen\n+\t\t\t\t# Now pull new updates from origin\n+\t\t\t\t( unset GIT_DIR; cd \"$path\"; git-pull )\n+\t\t\tfi\n+\n \t\tfi\n \tdone\n }\n@@ -596,7 +627,10 @@ cmd_status()\n \t\tset_name_rev \"$path\" \"$sha1\"\n \t\tif git diff-files --quiet -- \"$path\"\n \t\tthen\n-\t\t\tsay \" $sha1 $path$revname\"\n+\t\t\ttrack=$(git config submodule.\"$name\".track)\n+\t\t\ttracking=\n+\t\t\t[ -n \"$track\" ] && tracking=\" (tracking $track)\"\n+\t\t\tsay \" $sha1 $path$revname$tracking\"\n \t\telse\n \t\t\tif test -z \"$cached\"\n \t\t\tthen\ndiff --git a/read-cache.c b/read-cache.c\nindex 8579663..0c14b68 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -137,6 +137,11 @@ static int ce_compare_gitlink(struct cache_entry *ce)\n \t */\n \tif (resolve_gitlink_ref(ce->name, \"HEAD\", sha1) < 0)\n \t\treturn 0;\n+\n+\t// To be able to track newest revision\n+\tif (is_null_sha1(ce->sha1))\n+\t\treturn 0;\n+\n \treturn hashcmp(sha1, ce->sha1);\n }\n \n-- \n1.6.1.rc2.1.g4859.dirty\n"},{"id":"97597","messageId":"494122B5.5060409@viscovery.net","threadId":"16683","inReplyTo":"1229001361-9301-1-git-send-email-git@fabian-franz.de","subject":"Re: [PATCH v2] submodule: Allow tracking of the newest revision of a branch in a submodule","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-12-11T14:24:53Z","receivedAt":"2008-12-11T14:24:53Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Fabian Franz schrieb:\n> Submodules currently only allow tracking a specific revision\n> and each update in a submodule leads to a new commit in the\n> master repository. However some users may want to always track\n> the newest revision of a specific (named) tag or branch or HEAD.\n> For example the user might want to track a staging branch in all\n> submodules.\n\nPersonally, I don't particularly like this feature (but then, nobody\nforces me to use it ;) In which situation do you need this?\n\nBy tieing a project commit to a particular submodule commit the committer\ngives the guarantee: \"I've tested this with this module version, and it\nworks; all is ok.\" With this new feature, this guarantee vanishes, because\nthe committer has no control over which version of the module will\nultimately be used; it could be newer or it could be older.\n\nI've reviewed the patch just from a shell code writer's point of view.\n\n> +\t[ -n \"$track\" ] && echo \"160000 0000000000000000000000000000000000000000\\t$path\" | git update-index --index-info\n\nWe tend to use \"test\" instead of \"[ ]\".\nYou cannot rely on that echo or the shell translates \"\\t\"; use printf.\n\n\ttest \"$track\" && printf '160000\n0000000000000000000000000000000000000000\\t%s\\n' \"$path\" | git update-index\n--index-info\n\n(The line-wrapping is from my MUA; sorry.)\n\n> @@ -327,10 +339,12 @@ cmd_update()\n>  \t\t\tsay \"Maybe you want to use 'update --init'?\"\n>  \t\t\tcontinue\n>  \t\tfi\n> +\t\ttrack=$(git config submodule.\"$name\".track)\n\nYou don't need $track *here*, do you?\n\n>  \t\tif ! test -d \"$path\"/.git -o -f \"$path\"/.git\n>  \t\tthen\n>  \t\t\tmodule_clone \"$path\" \"$url\" || exit\n> +\n>  \t\t\tsubsha1=\n\nAnd this extra blank line is an accident, isn't it?\n\n> +\t\t\t\t[ -z \"$track\" ] && track=\"HEAD\"\n\nInstead of this you can use a shell trick (but I don't know if it's portable):\n\t\t\t\t: \"${track:=HEAD}\"\n\nAnd I think you can even spare the quotes.\n\n> +\t\t\t\t# if the local branch does not yet exist, create it\n> +\t\t\t\t( unset GIT_DIR; cd \"$path\"; git-show-ref --heads --tags -q \"$track\" || git branch --track \"$track\" \"origin/$track\" )\n\nUgh! A *branch* named \"HEAD\"?? I think you should reconsider this decision.\n\n> +\t\t\tif [ \"$pull\" = \"1\" ]\n\n\t\t\tif test \"$pull\"\n\n> +\t\t\tthen\n> +\t\t\t\t# Now pull new updates from origin\n> +\t\t\t\t( unset GIT_DIR; cd \"$path\"; git-pull )\n\nWow! Creating new commits on the fly while doing a \"git submodule update\"!\nError check is missing here.\n\n> @@ -596,7 +627,10 @@ cmd_status()\n>  \t\tset_name_rev \"$path\" \"$sha1\"\n>  \t\tif git diff-files --quiet -- \"$path\"\n>  \t\tthen\n> -\t\t\tsay \" $sha1 $path$revname\"\n> +\t\t\ttrack=$(git config submodule.\"$name\".track)\n> +\t\t\ttracking=\n> +\t\t\t[ -n \"$track\" ] && tracking=\" (tracking $track)\"\n> +\t\t\tsay \" $sha1 $path$revname$tracking\"\n\nThe last three lines can be shortened to this:\n\n\tsay \" $sha1 $path$revname${track:+ (tracking \"$track\")}\"\n\n-- Hannes\n"},{"id":"97611","messageId":"7voczicy2w.fsf@gitster.siamese.dyndns.org","threadId":"16683","inReplyTo":"1229001361-9301-1-git-send-email-git@fabian-franz.de","subject":"Re: [PATCH v2] submodule: Allow tracking of the newest revision of a branch in a submodule","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-11T19:26:47Z","receivedAt":"2008-12-11T19:26:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Franz <git@fabian-franz.de> writes:\n\n> So my workflow really is:\n>\n> git checkout master # done long before\n> [...]\n> git checkout staging\n> # => in submodules/client/\n> # Checked out submodules/client/ staging.\n> # => in submodules/client/component1/\n> # Checked out submodules/client/component/1 staging.\n>\n> So I would like to have this recursively...\n\nDidn't we add foreach subcommand to the submodule command?\n"}]}