{"thread":{"id":"10577","subject":"[PATCH] post-update hook: update working copy","startedAt":"2007-11-02T00:45:04Z","lastAt":"2007-11-02T17:28:20Z","messageCount":6,"participants":["Sam Vilain","Junio C Hamano","Andreas Ericsson","Steven Grimm"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"57908","messageId":"1193964304-10847-1-git-send-email-sam.vilain@catalyst.net.nz","threadId":"10577","inReplyTo":null,"subject":"[PATCH] post-update hook: update working copy","fromName":"Sam Vilain","fromEmail":"sam.vilain@catalyst.net.nz","sentAt":"2007-11-02T00:45:04Z","receivedAt":"2007-11-02T00:45:04Z","isPatch":true,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Now that git-stash is available, it is not so unsafe to push to a\nnon-bare repository, but care needs to be taken to preserve any dirty\nworking copy or index state.  This hook script does that, using\ngit-stash.\n\nSigned-off-by: Sam Vilain <sam.vilain@catalyst.net.nz>\n---\n templates/hooks--post-update |   76 ++++++++++++++++++++++++++++++++++++++++--\n 1 files changed, 73 insertions(+), 3 deletions(-)\n mode change 100644 => 100755 templates/hooks--post-update\n\ndiff --git a/templates/hooks--post-update b/templates/hooks--post-update\nold mode 100644\nnew mode 100755\nindex bcba893..352a432\n--- a/templates/hooks--post-update\n+++ b/templates/hooks--post-update\n@@ -1,8 +1,78 @@\n #!/bin/sh\n #\n-# An example hook script to prepare a packed repository for use over\n-# dumb transports.\n+# This hook does two things:\n+#\n+#  1. update the \"info\" files that allow the list of references to be\n+#     queries over dumb transports such as http\n+#\n+#  2. if this repository looks like it is a non-bare repository, and\n+#     the checked-out branch is pushed to, then update the working copy.\n+#     This makes \"push\" function somewhat similarly to darcs and bzr.\n #\n # To enable this hook, make this file executable by \"chmod +x post-update\".\n \n-exec git-update-server-info\n+git-update-server-info\n+\n+is_bare=$(git-config --get --bool core.bare)\n+\n+if [ -z \"$is_bare\" ]\n+then\n+\t# for compatibility's sake, guess\n+\tgit_dir_full=$(cd $GIT_DIR; pwd)\n+\tcase $git_dir_full in */.git) is_bare=false;; *) is_bare=true;; esac\n+fi\n+\n+update_wc() {\n+\tref=$1\n+\techo \"Push to checked out branch $ref\" >&2\n+\tif (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null)\n+\tthen\n+\t\twc_dirty=0\n+\telse\n+\t\techo \"W:unstaged changes found in working copy\" >&2\n+\t\twc_dirty=1\n+\t\tdesc=\"working copy\"\n+\tfi\n+\tif git diff-index HEAD@{1} >/dev/null\n+\tthen\n+\t\tindex_dirty=0\n+\telse\n+\t\techo \"W:uncommitted, staged changes found\" >&2\n+\t\tindex_dirty=1\n+\t\tif [ -n \"$desc\" ]\n+\t\tthen\n+\t\t\tdesc=\"$desc and index\"\n+\t\telse\n+\t\t\tdesc=\"index\"\n+\t\tfi\n+\tfi\n+\tif [ \"$wc_dirty\" -ne 0 -o \"$index_dirty\" -ne 0 ]\n+\tthen\n+\t\tnew=$(git rev-parse HEAD)\n+\t\tgit-update-ref --no-deref HEAD HEAD@{1}\n+\t\techo \"W:stashing dirty $desc - see git-stash(1)\" >&2\n+\t\t(cd $GIT_WORK_TREE\n+\t\tgit stash save \"dirty $desc before update to $new\")\n+\t\tgit-symbolic-ref HEAD \"$ref\"\n+\tfi\n+\n+\t# eye candy - show the WC updates :)\n+\techo \"Updating working copy\" >&2\n+\t(cd $GIT_WORK_TREE\n+\tgit-diff-index -R --name-status HEAD >&2\n+\tgit-reset --hard HEAD)\n+}\n+\n+if [ \"$is_bare\" = \"false\" ]\n+then\n+\tactive_branch=`git-symbolic-ref HEAD`\n+\texport GIT_DIR=$(cd $GIT_DIR; pwd)\n+\tGIT_WORK_TREE=${GIT_WORK_TREE-..}\n+\tfor ref\n+\tdo\n+\t\tif [ \"$ref\" = \"$active_branch\" ]\n+\t\tthen\n+\t\t\tupdate_wc $ref\n+\t\tfi\n+\tdone\n+fi\n-- \n1.5.3.2.3.g2f2dcc-dirty\n"},{"id":"57910","messageId":"7vd4ut7948.fsf@gitster.siamese.dyndns.org","threadId":"10577","inReplyTo":"1193964304-10847-1-git-send-email-sam.vilain@catalyst.net.nz","subject":"Re: [PATCH] post-update hook: update working copy","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-11-02T01:02:15Z","receivedAt":"2007-11-02T01:02:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sam Vilain <sam.vilain@catalyst.net.nz> writes:\n\n> Now that git-stash is available, it is not so unsafe to push to a\n> non-bare repository, but care needs to be taken to preserve any dirty\n> working copy or index state.  This hook script does that, using\n> git-stash.\n\nHonestly, I am reluctant to do things that _encourages_ pushing\ninto a live tree.\n\n - Who guarantees that the reflog is enabled for the HEAD?\n\n - Who guarantees that a human user is not actively editing the\n   work tree files without saving?  You would not see \"dirty\n   state\", the editor would notice \"the file was modified since\n   you started editing it\" and tell so to the user, but the user\n   cannot recover from the situation without knowing to do the\n   three-way merge between HEAD@{1}, HEAD and the index _anyway_.\n\n> +update_wc() {\n> +\tref=$1\n> +\techo \"Push to checked out branch $ref\" >&2\n> +\tif (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null)\n> +\tthen\n> +\t\twc_dirty=0\n> +\telse\n> +\t\techo \"W:unstaged changes found in working copy\" >&2\n> +\t\twc_dirty=1\n> +\t\tdesc=\"working copy\"\n> +\tfi\n> +\tif git diff-index HEAD@{1} >/dev/null\n\nAre you missing \"--cached\" here?\n\n> +\tif [ \"$wc_dirty\" -ne 0 -o \"$index_dirty\" -ne 0 ]\n> +\tthen\n> +\t\tnew=$(git rev-parse HEAD)\n> +\t\tgit-update-ref --no-deref HEAD HEAD@{1}\n> +\t\techo \"W:stashing dirty $desc - see git-stash(1)\" >&2\n> +\t\t(cd $GIT_WORK_TREE\n> +\t\tgit stash save \"dirty $desc before update to $new\")\n> +\t\tgit-symbolic-ref HEAD \"$ref\"\n\nThis part feels somewhat dangerous.  What happens if we are\ninterrupted in the middle of these commands?\n\n> +\tfi\n> +\n> +\t# eye candy - show the WC updates :)\n> +\techo \"Updating working copy\" >&2\n> +\t(cd $GIT_WORK_TREE\n> +\tgit-diff-index -R --name-status HEAD >&2\n> +\tgit-reset --hard HEAD)\n> +}\n\nAnd I would have expected you would unstash the dirty state here.\nAre there any reason not to?\n"},{"id":"57916","messageId":"472A9B26.2020608@vilain.net","threadId":"10577","inReplyTo":"7vd4ut7948.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] post-update hook: update working copy","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2007-11-02T03:36:06Z","receivedAt":"2007-11-02T03:36:06Z","isPatch":true,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Junio C Hamano wrote:\n>> Now that git-stash is available, it is not so unsafe to push to a\n>> non-bare repository, but care needs to be taken to preserve any dirty\n>> working copy or index state.  This hook script does that, using\n>> git-stash.\n> \n> Honestly, I am reluctant to do things that _encourages_ pushing\n> into a live tree.\n\nI think a lot of people want this, and explaining why it doesn't work to\npeople is especially tiresome given that I know it can work, and the\ncaveats get smaller and smaller each time.  I still think that the\noperation can be made safe enough for general use.\n\n>  - Who guarantees that the reflog is enabled for the HEAD?\n\nOk, so I guess if that's the case then the old behaviour is OK.\nHowever, this would not be required if implemented in receive-pack, as\nthe only thing I'm using it for is to get the revision that the current\nindex is based on.\n\nThe other option, which was writing two hooks, both of which need to be\nenabled, seemed far too ugly!\n\n>  - Who guarantees that a human user is not actively editing the\n>    work tree files without saving?  You would not see \"dirty\n>    state\", the editor would notice \"the file was modified since\n>    you started editing it\" and tell so to the user, but the user\n>    cannot recover from the situation without knowing to do the\n>    three-way merge between HEAD@{1}, HEAD and the index _anyway_.\n\nThere seems to be a lot of focus on this.  However I don't think it is a\nshowstopper; in this instance that the person who has their life ruined\nby the incoming push can blame the person who did it, blame themselves\nfor giving that stupid user access to their working directory, and then\naccept that the tool is doing the best that it can.\n\n>> +\tif git diff-index HEAD@{1} >/dev/null\n> \n> Are you missing \"--cached\" here?\n\nAh, yes, good catch.\n\n>> +\tif [ \"$wc_dirty\" -ne 0 -o \"$index_dirty\" -ne 0 ]\n>> +\tthen\n>> +\t\tnew=$(git rev-parse HEAD)\n>> +\t\tgit-update-ref --no-deref HEAD HEAD@{1}\n>> +\t\techo \"W:stashing dirty $desc - see git-stash(1)\" >&2\n>> +\t\t(cd $GIT_WORK_TREE\n>> +\t\tgit stash save \"dirty $desc before update to $new\")\n>> +\t\tgit-symbolic-ref HEAD \"$ref\"\n> \n> This part feels somewhat dangerous.  What happens if we are\n> interrupted in the middle of these commands?\n\nHeh.  What seems to happen is that the local command is aborted and the\nremote one continues.  Nonetheless I'll add a trap statement, but again\nif implemented in receive-pack it could probably be more resilient.\n\n>> +\tfi\n>> +\n>> +\t# eye candy - show the WC updates :)\n>> +\techo \"Updating working copy\" >&2\n>> +\t(cd $GIT_WORK_TREE\n>> +\tgit-diff-index -R --name-status HEAD >&2\n>> +\tgit-reset --hard HEAD)\n>> +}\n> \n> And I would have expected you would unstash the dirty state here.\n> Are there any reason not to?\n\nIf git-stash could support stashing conflicted merges, I don't think so.\n\nHowever, if the user is a git-shell user, then they won't be able to\nresolve the conflict and they won't be able to re-push as the stash will\nfail (a condition not visited by the above).\n\nSam.\n\nchanges as you suggested are below;\n\ndiff --git a/templates/hooks--post-update b/templates/hooks--post-update\nindex 352a432..b15c711 100755\n--- a/templates/hooks--post-update\n+++ b/templates/hooks--post-update\n@@ -25,6 +25,11 @@ fi\n update_wc() {\n \tref=$1\n \techo \"Push to checked out branch $ref\" >&2\n+\tif [ ! -f $GIT_DIR/logs/HEAD ]\n+\tthen\n+\t\techo \"E:push to non-bare repository requires a HEAD reflog\" >&2\n+\t\texit 1\n+\tfi\n \tif (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null)\n \tthen\n \t\twc_dirty=0\n@@ -33,7 +38,7 @@ update_wc() {\n \t\twc_dirty=1\n \t\tdesc=\"working copy\"\n \tfi\n-\tif git diff-index HEAD@{1} >/dev/null\n+\tif git diff-index --cached HEAD@{1} >/dev/null\n \tthen\n \t\tindex_dirty=0\n \telse\n@@ -49,11 +54,13 @@ update_wc() {\n \tif [ \"$wc_dirty\" -ne 0 -o \"$index_dirty\" -ne 0 ]\n \tthen\n \t\tnew=$(git rev-parse HEAD)\n-\t\tgit-update-ref --no-deref HEAD HEAD@{1}\n \t\techo \"W:stashing dirty $desc - see git-stash(1)\" >&2\n-\t\t(cd $GIT_WORK_TREE\n-\t\tgit stash save \"dirty $desc before update to $new\")\n+\t\t( trap 'echo trapped $$; git symbolic-ref HEAD \"'\"$ref\"'\"' 2 3 13 15 ERR EXIT\n+\t\tgit-update-ref --no-deref HEAD HEAD@{1}\n+\t\tcd $GIT_WORK_TREE\n+\t\tgit stash save \"dirty $desc before update to $new\";\n \t\tgit-symbolic-ref HEAD \"$ref\"\n+\t\t)\n \tfi\n \n \t# eye candy - show the WC updates :)\n"},{"id":"57939","messageId":"7vd4ut58wl.fsf@gitster.siamese.dyndns.org","threadId":"10577","inReplyTo":"472A9B26.2020608@vilain.net","subject":"Re: [PATCH] post-update hook: update working copy","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-11-02T08:49:46Z","receivedAt":"2007-11-02T08:49:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sam Vilain <sam@vilain.net> writes:\n\n> changes as you suggested are below;\n\nI squashed these and looked the result over, but I see it is\ncontradicting with itself.  You do not want to \"publish\" a live\ngit repository so running git-update-server-info in a repository\nthat is served by this script feels very wrong.\n\nHow about having this in contrib/hooks/post-update-worktre?\n\nBy the way, there are quite a few careless places that use shell\nvariables without quoting.\n"},{"id":"57963","messageId":"472AFD39.6000006@op5.se","threadId":"10577","inReplyTo":"7vd4ut7948.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] post-update hook: update working copy","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-11-02T10:34:33Z","receivedAt":"2007-11-02T10:34:33Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Sam Vilain <sam.vilain@catalyst.net.nz> writes:\n> \n>> Now that git-stash is available, it is not so unsafe to push to a\n>> non-bare repository, but care needs to be taken to preserve any dirty\n>> working copy or index state.  This hook script does that, using\n>> git-stash.\n> \n> Honestly, I am reluctant to do things that _encourages_ pushing\n> into a live tree.\n> \n\n\"Live\" and \"living\" are perhaps two different things here. I for one have\nsomething similar, but only for repositories residing on certain servers,\nwhere there really must be zero local changes to the working tree.\n\n>  - Who guarantees that the reflog is enabled for the HEAD?\n> \n\nI disable reflogs on that server. There's (hardly ever) any human interaction\nwith the scripts in that repo, so I really, really don't care about reflogs.\n\n>  - Who guarantees that a human user is not actively editing the\n>    work tree files without saving?\n\nThere are times when one simply doesn't care.\n\nI realize that for my situation, a much simpler script can (and is) used, so\nI agree with your concerns. The idea that every git repo has a human hacking\non it isn't true though, so doing things like this are sometimes useful,\ntimesaving and a real help.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"58010","messageId":"472B5E34.60709@midwinter.com","threadId":"10577","inReplyTo":"472AFD39.6000006@op5.se","subject":"Re: [PATCH] post-update hook: update working copy","fromName":"Steven Grimm","fromEmail":"koreth@midwinter.com","sentAt":"2007-11-02T17:28:20Z","receivedAt":"2007-11-02T17:28:20Z","isPatch":true,"sender":{"key":"koreth@midwinter.com","avatar":"https://gravatar.com/avatar/71b4d2e8b62f168bdc9e9205341159e3567003b4f9e2127c617c5fa0a1f5bad2?d=mp&s=160"},"body":"Andreas Ericsson wrote:\n>>  - Who guarantees that a human user is not actively editing the\n>>    work tree files without saving?\n> There are times when one simply doesn't care.\n>\n> I realize that for my situation, a much simpler script can (and is) \n> used, so\n> I agree with your concerns. The idea that every git repo has a human \n> hacking\n> on it isn't true though, so doing things like this are sometimes useful,\n> timesaving and a real help.\n\nYeah, that's absolutely true. My use cases would be twofold. First, a \npublic reference tree on a shared development server where people can \nlook over my corner of the code base without having to check the whole \nthing out for themselves.\n\nSecond, a Web server with a bunch of static text/image files and PHP \nscripts. If I can deploy by just pushing to a \"current release\" branch, \nthat saves me from having to first push then ssh to the machine and do \n\"git reset --hard\".\n\nNeither one of those things is impossible to do with vanilla git. They \njust require extra busywork steps at the moment if you don't use an \n\"update the working copy on push\" hook.\n\n-Steve\n"}]}