{"thread":{"id":"8661","subject":"post-update script to update wc - suggestions welcome","startedAt":"2007-06-20T06:21:44Z","lastAt":"2007-06-20T22:28:33Z","messageCount":6,"participants":["Sam Vilain","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"45412","messageId":"E1I0tZY-0001Uz-00@www.watts.utsl.gen.nz","threadId":"8661","inReplyTo":null,"subject":"post-update script to update wc - suggestions welcome","fromName":"Sam Vilain","fromEmail":"samv@utsl.gen.nz","sentAt":"2007-06-20T06:21:44Z","receivedAt":"2007-06-20T06:21:44Z","isPatch":false,"sender":{"key":"samv@utsl.gen.nz","avatar":null},"body":"#!/bin/sh\n#\n# An example hook script to prepare a packed repository for use over\n# dumb transports.\n#\n# To enable this hook, make this file executable by \"chmod +x post-update\".\n\ngit-update-server-info\n\nref=$1\nactive=`git-symbolic-ref HEAD`\nif [ \"$ref\" = \"$active\" ]\nthen\n  echo \"Pushing to checked out branch - updating working copy\" >&2\n  export GIT_DIR=`cd $GIT_DIR; pwd`\n  cd ..\n  success=\n  if git-diff-files\n  then\n    git-diff-index -z -R --name-status HEAD | perl -n0 -le \\\n\t'if ($z^=1) {\n\t\t$status=$_;\n\t }\n\t else {\n        \t$filename=$_;\n\t\tprintf STDERR \"$status\\t$filename\\n\";\n\t\tif($status eq \"D\"){\n\t\t\tunlink($filename)\n\t\t\t\tor die(\"unlink($filename) failed; $!\")\n\t\t}\n         }' &&\n    git-reset --hard HEAD && success=1\n  fi\n  if [ -z \"$success\" ]\n  then\n    (\n    echo \"Non-bare repository checkout is not clean - not updating it\"\n    echo \"However I AM going to update the index.  Any in-progress commit\"\n    echo \"happening in that checkout will be thrown away, but on the bright\"\n    echo \"side this is probably the least confusing thing for us to do and\"\n    echo \"at least we're not throwing any files somebody has changed away\"\n    git-reset --mixed HEAD\n    echo \n    echo \"This is the new status of the upstream working copy:\"\n    git-status\n    ) >&2\n  fi\nfi\n"},{"id":"45414","messageId":"4678D13A.7090904@vilain.net","threadId":"8661","inReplyTo":"E1I0tZY-0001Uz-00@www.watts.utsl.gen.nz","subject":"Re: post-update script to update wc - suggestions welcome","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2007-06-20T07:03:22Z","receivedAt":"2007-06-20T07:03:22Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Sam Vilain wrote:\n> #!/bin/sh\n> #\n> # An example hook script to prepare a packed repository for use over\n> # dumb transports.\n> #\n> # To enable this hook, make this file executable by \"chmod +x post-update\".\n> \n> git-update-server-info\n> \n> ref=$1\n\nIn particular, if anyone can think of a clever and reliable way to\ndetect whether the repository is bare or not (perhaps the presence of\n$GIT_DIR/index ?), then this could conceivably become the default\nexample hook script, by making the below bit conditional on whether this\nlooks like a non-bare repository.\n\nSam.\n\n> active=`git-symbolic-ref HEAD`\n> if [ \"$ref\" = \"$active\" ]\n> then\n>   echo \"Pushing to checked out branch - updating working copy\" >&2\n>   export GIT_DIR=`cd $GIT_DIR; pwd`\n>   cd ..\n>   success=\n>   if git-diff-files\n>   then\n>     git-diff-index -z -R --name-status HEAD | perl -n0 -le \\\n> \t'if ($z^=1) {\n> \t\t$status=$_;\n> \t }\n> \t else {\n>         \t$filename=$_;\n> \t\tprintf STDERR \"$status\\t$filename\\n\";\n> \t\tif($status eq \"D\"){\n> \t\t\tunlink($filename)\n> \t\t\t\tor die(\"unlink($filename) failed; $!\")\n> \t\t}\n>          }' &&\n>     git-reset --hard HEAD && success=1\n>   fi\n>   if [ -z \"$success\" ]\n>   then\n>     (\n>     echo \"Non-bare repository checkout is not clean - not updating it\"\n>     echo \"However I AM going to update the index.  Any in-progress commit\"\n>     echo \"happening in that checkout will be thrown away, but on the bright\"\n>     echo \"side this is probably the least confusing thing for us to do and\"\n>     echo \"at least we're not throwing any files somebody has changed away\"\n>     git-reset --mixed HEAD\n>     echo \n>     echo \"This is the new status of the upstream working copy:\"\n>     git-status\n>     ) >&2\n>   fi\n> fi\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"},{"id":"45422","messageId":"7vr6o7uhwz.fsf@assigned-by-dhcp.pobox.com","threadId":"8661","inReplyTo":"E1I0tZY-0001Uz-00@www.watts.utsl.gen.nz","subject":"Re: post-update script to update wc - suggestions welcome","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-20T08:52:28Z","receivedAt":"2007-06-20T08:52:28Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sam Vilain <samv@utsl.gen.nz> writes:\n\n> #!/bin/sh\n> #\n> # An example hook script to prepare a packed repository for use over\n> # dumb transports.\n> #\n> # To enable this hook, make this file executable by \"chmod +x post-update\".\n>\n> git-update-server-info\n>\n> ref=$1\n> active=`git-symbolic-ref HEAD`\n> if [ \"$ref\" = \"$active\" ]\n\npost-update hook takes list of refs that have been updated, so\nthe above check is bogus, I think.\n\nBetter do something like:\n\n\tcase \" $* \" in\n        *\" $active \"*)\n        \t: current branch was updated...\n\t\t;;\n\t*)\n        \t: do not have to worry about this one\n                exit 0\n                ;;\n\tesac\n\t# ... rest of the code here ...\n\nAlso you would want to see if the thing is bare.  \n\nUnfortunately, git-sh-setup's is_bare_repository does a wrong\nthing because receive-pack already runs GIT_DIR set to '.' after\nchdir to it.  Matthias's long set of patches currently parked in\n'pu' is supposed to clarify the semantics of bare/non-bare, so\nit may help though (it has \"rev-parse --is-bare-repository).\n\nI think 80% of the time (because other 20% of bare repositories\nare initialized, following an often repeated incorrect procedure\nof making a worktree-full repository and moving its .git/ to\nanother place, $name.git --- that is wrong for at least three\nreasons), if $GIT_DIR/index exists, you can treat it as a\nnon-bare repository.\n\nSo in short, I would follow the above quoted one with:\n\n\ttest -f \"$GIT_DIR/index\" || exit 0\n\nto ignore bare repositories.\n\nMatthias, do you know if your patchset correctly handle this\ncase?  That is:\n\n\t$ git push site:my.git set of refs\n\nwill:\n\n        (1) spawn git-receive-pack with my.git as its\n            argument;\n\n        (2) git-receive-pack finds the repository and chdir()'s\n            to the directory that has refs/ and HEAD in it\n            (i.e. if my.git is bare, the directory itself, if\n            my.git has my.git/.git and possibly a checkout in\n            my.git/{Makefile,README,...}, then it chdir()'s to\n            my.git/.git);\n\n\t(3) then it sets GIT_DIR=. and exports it.\n\nand from that environment, post-update hook is called.\n\nI think Matthias's patch series may need to (conditionally) set\nGIT_WORK_TREE environment when it finds the repository and see\nif there is an associated work tree at its natural place (that\nis, if $something/.git is found in (2) and $something/.git/index\nexists, then worktree should be rooted at $something/, unless\ncore.worktree is set) .\n\n> then\n>   echo \"Pushing to checked out branch - updating working copy\" >&2\n>   export GIT_DIR=`cd $GIT_DIR; pwd`\n\n... and Matthias's patch series probably needs to update this\npart of your patch as well.\n\n>   cd ..\n>   success=\n>   if git-diff-files\n>   then\n\nI would suggest running update-index --refresh before running\ndiff-files.  The user may have cache-dirty file and only that.\n\n>     git-diff-index -z -R --name-status HEAD | perl -n0 -le \\\n> \t'if ($z^=1) {\n> \t\t$status=$_;\n> \t }\n> \t else {\n>         \t$filename=$_;\n> \t\tprintf STDERR \"$status\\t$filename\\n\";\n> \t\tif($status eq \"D\"){\n> \t\t\tunlink($filename)\n> \t\t\t\tor die(\"unlink($filename) failed; $!\")\n> \t\t}\n>          }' &&\n\nWith \"--name-only --diff-filter=D\" you would not have to do most\nof the above ;-)  Use --diff-filter=A without -R, perhaps, to\nmake it even shorter.\n\n>     git-reset --hard HEAD && success=1\n>   fi\n\nWouldn't \"reset --hard HEAD\" pretty much unconditionally nuke\nyour local changes, including added files to the index?  For\nexample, if I do this:\n\n\t$ >foo && git add foo && git reset --hard HEAD\n\nit would remove the newly added 'foo' from both the index and\nthe working tree.  So I am not quite sure what you are trying to\nachieve with \"diff-index | perl\" magic.\n\n>   if [ -z \"$success\" ]\n>   then\n>     (\n>     echo \"Non-bare repository checkout is not clean - not updating it\"\n>     echo \"However I AM going to update the index.  Any in-progress commit\"\n>     echo \"happening in that checkout will be thrown away, but on the bright\"\n>     echo \"side this is probably the least confusing thing for us to do and\"\n>     echo \"at least we're not throwing any files somebody has changed away\"\n>     git-reset --mixed HEAD\n>     echo \n>     echo \"This is the new status of the upstream working copy:\"\n>     git-status\n>     ) >&2\n>   fi\n> fi\n\nI'll cook up an alternative patch perhaps tomorrow.\n"},{"id":"45436","messageId":"46798AB6.6060403@vilain.net","threadId":"8661","inReplyTo":"7vr6o7uhwz.fsf@assigned-by-dhcp.pobox.com","subject":"Re: post-update script to update wc - suggestions welcome","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2007-06-20T20:14:46Z","receivedAt":"2007-06-20T20:14:46Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Also you would want to see if the thing is bare.\n>\n> Unfortunately, git-sh-setup's is_bare_repository does a wrong\n> thing because receive-pack already runs GIT_DIR set to '.' after\n> chdir to it.  Matthias's long set of patches currently parked in\n> 'pu' is supposed to clarify the semantics of bare/non-bare, so\n> it may help though (it has \"rev-parse --is-bare-repository).\n>\n> I think 80% of the time (because other 20% of bare repositories\n> are initialized, following an often repeated incorrect procedure\n> of making a worktree-full repository and moving its .git/ to\n> another place, $name.git --- that is wrong for at least three\n> reasons), if $GIT_DIR/index exists, you can treat it as a\n> non-bare repository.\n>   \n\nGreat, well in lieu of that, Matthias suggests a reasonable extra\nheuristic of whether or not the pathname ends in \"/.git\" (or \"\\.git\").\nWhich falls into the \"why didn't I think of that\" category ;-).\n\nNo doubt with those patches the hook can be simplified, especially if it\nsets GIT_WORK_TREE.\n\n>>   cd ..\n>>   success=\n>>   if git-diff-files\n>>   then\n>>     \n>\n> I would suggest running update-index --refresh before running\n> diff-files.  The user may have cache-dirty file and only that.\n>   \n\nAh yes, is that what git-status does that checks the filestamps in the\nindex and updates them... Handy to know.\n\n>>     git-diff-index -z -R --name-status HEAD | perl -n0 -le \\\n>> \t'if ($z^=1) {\n>> \t\t$status=$_;\n>> \t }\n>> \t else {\n>>         \t$filename=$_;\n>> \t\tprintf STDERR \"$status\\t$filename\\n\";\n>> \t\tif($status eq \"D\"){\n>> \t\t\tunlink($filename)\n>> \t\t\t\tor die(\"unlink($filename) failed; $!\")\n>> \t\t}\n>>          }' &&\n>>     \n>\n> With \"--name-only --diff-filter=D\" you would not have to do most\n> of the above ;-)  Use --diff-filter=A without -R, perhaps, to\n> make it even shorter.\n>   \n\nYou're right, it was right there!\n\nI think it's a good thing to echo back to the user the output of the\n--name-status command, so they can see the changes that were made.\n\n>>     git-reset --hard HEAD && success=1\n>>   fi\n>>     \n>\n> Wouldn't \"reset --hard HEAD\" pretty much unconditionally nuke\n> your local changes, including added files to the index?  For\n> example, if I do this:\n>\n> \t$ >foo && git add foo && git reset --hard HEAD\n>\n> it would remove the newly added 'foo' from both the index and\n> the working tree.  So I am not quite sure what you are trying to\n> achieve with \"diff-index | perl\" magic.\n>   \n\nRight, but we've already checked using diff-files that there weren't any\nlocal changes. So all we're saying is \"remove all files which won't be\nwritten by git reset --hard, then checkout new versions of files\".\n\nActually there is a slight deficiency in the above script - empty\ndirectories will not be removed, so replacing a directory with a file\nwill be broken.\n\n> I'll cook up an alternative patch perhaps tomorrow.\n>   \n\nCool! I'm sure bzr and darcs users will thank you :-)\n\nSam.\n"},{"id":"45444","messageId":"7vtzt2s5jl.fsf@assigned-by-dhcp.pobox.com","threadId":"8661","inReplyTo":"46798AB6.6060403@vilain.net","subject":"Re: post-update script to update wc - suggestions welcome","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-20T21:02:38Z","receivedAt":"2007-06-20T21:02:38Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sam Vilain <sam@vilain.net> writes:\n\n>>>   cd ..\n>>>   success=\n>>>   if git-diff-files\n>>>   then\n>>>     \n>> ...\n>>\n>>>     git-reset --hard HEAD && success=1\n>>>   fi\n>>>     \n>>\n>> Wouldn't \"reset --hard HEAD\" pretty much unconditionally nuke\n>> your local changes, including added files to the index?  For\n>> example, if I do this:\n>>\n>> \t$ >foo && git add foo && git reset --hard HEAD\n>>\n>> it would remove the newly added 'foo' from both the index and\n>> the working tree.  So I am not quite sure what you are trying to\n>> achieve with \"diff-index | perl\" magic.\n>\n> Right, but we've already checked using diff-files that there weren't any\n> local changes. So all we're saying is \"remove all files which won't be\n> written by git reset --hard, then checkout new versions of files\".\n\nI am afraid I am not following your logic.\n\nI missed that \"if git-diff-files\"; it is not checking (you would\nhave to ask for --exit-code or something --- traditionally we\nnever used git-diff-xxxx exit code to indicate if there is any\nchanges).\n\nSuppose we update that \"if\" to see if diff-files says \"no change\nin the working tree wrt the index\".  But then, I think what you\nhave at the end, \"git reset --hard HEAD\", where the HEAD is an\narbitrary commit that does not necessarily have to do anything\nwith what the index is based on, would remove what is known to\nthe index but not in HEAD.  Which was my point about the\n\"diff-index piped to perl\".  I do not think that one is\nnecessary.\n\nActually, more importantly, why is it justified to remove a file\nthat is unchanged since the index, if the updated HEAD does not\nhave it?  That is losing information, isn't it?\n\nOr are you assuming that this is used only for a worktree where\nthere is NO actual development happens, but just kept up to date\nto whatever commit comes at HEAD?\n"},{"id":"45448","messageId":"4679AA11.5050407@vilain.net","threadId":"8661","inReplyTo":"7vtzt2s5jl.fsf@assigned-by-dhcp.pobox.com","subject":"Re: post-update script to update wc - suggestions welcome","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2007-06-20T22:28:33Z","receivedAt":"2007-06-20T22:28:33Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> I am afraid I am not following your logic.\n> \n> I missed that \"if git-diff-files\"; it is not checking (you would\n> have to ask for --exit-code or something --- traditionally we\n> never used git-diff-xxxx exit code to indicate if there is any\n> changes).\n\nOh, I expected a diff command to return an error code if differences\nwere found, like diff does.\n\n> Suppose we update that \"if\" to see if diff-files says \"no change\n> in the working tree wrt the index\".  But then, I think what you\n> have at the end, \"git reset --hard HEAD\", where the HEAD is an\n> arbitrary commit that does not necessarily have to do anything\n> with what the index is based on, would remove what is known to\n> the index but not in HEAD.\n\nGood point.  Yes a semi-staged commit would lose information.  So we\nalso need to check that the index matches the previous value of what the\ncurrent branch points to.\n\nHow about this.  We call write-tree and get a tree ID.  If we can find\nthat tree in any of the commits reachable by the reflog or the history\nof the current branch then we can be happy that no local changes have\nbeen staged.  That will imply that if you want a non-bare repository to\nupdate automatically and use push -f, you need reflog.\n\n>  Which was my point about the\n> \"diff-index piped to perl\".  I do not think that one is\n> necessary.\n\nSure, I only did that because I didn't think reset --hard would remove\nfiles which were previously in the index but not in the version being\nreset to.\n\n> Actually, more importantly, why is it justified to remove a file\n> that is unchanged since the index, if the updated HEAD does not\n> have it?  That is losing information, isn't it?\n\nWell, not if you can confirm that the index matches some previous\nversion of the branch.\n\n> Or are you assuming that this is used only for a worktree where\n> there is NO actual development happens, but just kept up to date\n> to whatever commit comes at HEAD?\n\nI was aiming for something safe that people can just chmod +x to get\nsymmetric push/pull semantics.\n\nSam.\n"}]}