{"thread":{"id":"26732","subject":"git-reset HEAD --permissions-only","startedAt":"2011-03-14T20:29:51Z","lastAt":"2011-03-17T06:01:29Z","messageCount":4,"participants":["Neal Kreitzinger","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"163344","messageId":"illts0$c6q$1@dough.gmane.org","threadId":"26732","inReplyTo":null,"subject":"git-reset HEAD --permissions-only","fromName":"Neal Kreitzinger","fromEmail":"neal@rsss.com","sentAt":"2011-03-14T20:29:51Z","receivedAt":"2011-03-14T20:29:51Z","isPatch":false,"sender":{"key":"neal@rsss.com","avatar":null},"body":"Is there a way to only reset the file permissions of the working-tree to \nmatch HEAD file permissions without resetting the content of the files?\n\nHEAD file permissions = the permissions of the objects in the object store.\n\nI'm using the vendor branch method of the git-rm manpage (git ls-files -z | \nxargs -0 rm -f && tar xzf vendor-version.tar.gz && git add -A) and I want to \ndiscard the vendor's file permissions changes to existing files and reset \nthem back to what they are in HEAD.\n\n\"existing files\" = ALL files that already existed in the HEAD and are not \n\"deleted\" or \"new\" in the working-tree relative to the HEAD.\nHEAD = before \"rm\"\nWorking-Tree = after the untar.\n\nv/r,\nNeal \n"},{"id":"163362","messageId":"20110315013223.GB31865@sigill.intra.peff.net","threadId":"26732","inReplyTo":"illts0$c6q$1@dough.gmane.org","subject":"Re: git-reset HEAD --permissions-only","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-03-15T01:32:23Z","receivedAt":"2011-03-15T01:32:23Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Mar 14, 2011 at 03:29:51PM -0500, Neal Kreitzinger wrote:\n\n> Is there a way to only reset the file permissions of the working-tree\n> to match HEAD file permissions without resetting the content of the\n> files?\n\nNot directly, but you could munge a patch to do so and apply it in\nreverse. For example:\n\n  git diff \"$@\" |\n  perl -ne '\n    if (/^diff/) { $diff = $_ }\n    elsif (/^old mode/) { print $diff, $_ }\n    elsif (/^new mode/) { print $_ }\n  ' |\n  git apply -R\n\nWhich seems a little more complicated than it needs to be, but we don't\n(AFAIK) have a way to say \"show me only the mode changes from this\ndiff in an applicable form\". The closest would be \"git diff --summary\",\nbut you cannot directly apply it (and I would hesitate to recommend\nparsing it).\n\nYou could also use \"git checkout -p\", which is designed for exactly this\nsort of picking-apart of a patch, but it has no way to specify \"say yes\nto all of the mode changes, no to everything else\"; you have to manually\napprove each hunk. Which doesn't work if you have a lot of these files.\n\nI guess for mode changes, you don't care if you chmod something that is\nalready fine. So yet another way to do it would be:\n\n  git ls-files -sz |\n  perl -0ne '\n    /100(\\d+).*?\\t(.*)/ or next;\n    -e $2 or next;\n    chmod(oct($1), $2)\n      or die \"chmod failed: $!\";\n  '\n\nHope that helps,\n-Peff\n"},{"id":"163413","messageId":"4D800D0B.2000307@gmail.com","threadId":"26732","inReplyTo":"20110315013223.GB31865@sigill.intra.peff.net","subject":"Re: git-reset HEAD --permissions-only","fromName":"Neal Kreitzinger","fromEmail":"nkreitzinger@gmail.com","sentAt":"2011-03-16T01:06:19Z","receivedAt":"2011-03-16T01:06:19Z","isPatch":false,"sender":{"key":"nkreitzinger@gmail.com","avatar":null},"body":"On 3/14/2011 8:32 PM, Jeff King wrote:\n> On Mon, Mar 14, 2011 at 03:29:51PM -0500, Neal Kreitzinger wrote:\n>\n>> Is there a way to only reset the file permissions of the\n>> working-tree to match HEAD file permissions without resetting the\n>> content of the files?\n>\n> Not directly, but you could munge a patch to do so and apply it in\n> reverse. For example:\n>\n> git diff \"$@\" | perl -ne ' if (/^diff/) { $diff = $_ } elsif (/^old\n> mode/) { print $diff, $_ } elsif (/^new mode/) { print $_ } ' | git\n> apply -R\n>\n> Which seems a little more complicated than it needs to be, but we\n> don't (AFAIK) have a way to say \"show me only the mode changes from\n> this diff in an applicable form\". The closest would be \"git diff\n> --summary\", but you cannot directly apply it (and I would hesitate to\n> recommend parsing it).\n>\n> You could also use \"git checkout -p\", which is designed for exactly\n> this sort of picking-apart of a patch, but it has no way to specify\n> \"say yes to all of the mode changes, no to everything else\"; you have\n> to manually approve each hunk. Which doesn't work if you have a lot\n> of these files.\n>\n> I guess for mode changes, you don't care if you chmod something that\n> is already fine. So yet another way to do it would be:\n>\n> git ls-files -sz | perl -0ne ' /100(\\d+).*?\\t(.*)/ or next; -e $2 or\n> next; chmod(oct($1), $2) or die \"chmod failed: $!\"; '\n>\nYou are right about git checkout -p because there are alot of code\nchanges to alot of files.  I haven't used git patches and I don't know \nperl.  However, your reasoning about the last example seems the most \nstraight-forward so I used it.  I symptomatically validated my re-keying \nof the syntax as follows since TTBOMK I couldn't copy+paste your example \ndue to whitespace:\n\ngit ls-files -sz | perl -0ne '/100(\\d+).*?\\t(.*)/\n  or next; -e $2 or next; chmod(oct($1), $2) or die \"chmod failed: $!\";'\n\n(0) repo contains bad modes in working tree only.\n(1) make a copy of the repo (cp -rp repo repoX)\n(2) add and commit (via superuser and git-commit --no-verify) the \"bad\" \nmodes.\n(3) make another copy of the repo (repoY)\n(4) run your perl script on repoY working-tree\n(5) git diff | grep \"old mode\" (shows no occurences)\n(6) commit \"good\" modes.\n(7) make repox \"bad\" modes branch a remote of repoy and fetched the bad \nmodes commit (git remote add -t bad-mode-branch repo-X /opt/me/repoX).\n(8) diffed the bad modes commit vs the good modes commit and saw that \nonly the modes differed.\n\nThanks!\n\nv/r,\nneal\n"},{"id":"163528","messageId":"20110317060129.GC11931@sigill.intra.peff.net","threadId":"26732","inReplyTo":"4D800D0B.2000307@gmail.com","subject":"Re: git-reset HEAD --permissions-only","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2011-03-17T06:01:29Z","receivedAt":"2011-03-17T06:01:29Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Mar 15, 2011 at 08:06:19PM -0500, Neal Kreitzinger wrote:\n\n> You are right about git checkout -p because there are alot of code\n> changes to alot of files.  I haven't used git patches and I don't\n> know perl.  However, your reasoning about the last example seems the\n> most straight-forward so I used it.  I symptomatically validated my\n> re-keying of the syntax as follows since TTBOMK I couldn't copy+paste\n> your example due to whitespace:\n> \n> git ls-files -sz | perl -0ne '/100(\\d+).*?\\t(.*)/\n>  or next; -e $2 or next; chmod(oct($1), $2) or die \"chmod failed: $!\";'\n\nThe whitespace in what I sent was fine, though it's possible your MUA\nmangled it.\n\nIt sounds like the solution worked for you, so cool. But I did have one\nmore thought to mention: since you are working with a vendor branch, you\nshould be able to have a \"pristine\" vendor branch complete with their\nwrong permissions, and then build your permissions fixes on top of that.\nAnd then when you merge the pristine branch up to your branch, git will\nautomatically resolve the permissions in favor of yours (because its\nbuilt on top).\n\nSo something like:\n\n  # import initial vendor branch\n  git init\n  # untar or whatever happens to get the files\n  tar xzf /path/to/vendor-1.0.tar.gz\n  git add .\n  git commit -m 'import vendor 1.0'\n\n  # now move it to vendor branch and make our munged-vendor branch\n  git branch vendor\n  git checkout -b vendor-fixed vendor\n\n  # now tweak permissions\n  .. chmod or however you did it originally ...\n  git add -u\n  git commit -m 'fix broken vendor permissions'\n\n  # and then built your real work on top of vendor-fixed\n  git branch -f master vendor-fixed\n  git checkout master\n\n  # weeks pass; vendor releases 1.1\n  git checkout vendor\n  # untar or whatever we do to get the files\n  tar xzf /path/to/vendor-1.1.tar.gz\n  git add -A\n  git commit -m 'import vendor 1.1'\n\n  # now we merge it in, but our permissions fixes will be retained\n  git checkout vendor-fixed\n  git merge vendor\n  # however we may still have to deal with new files\n  ... chmod or whatever on new files ...\n  git add -u\n  git commit -m 'fix more broken vendor permissions'\n\n...and repeat for each new version the vendor releases.\n\nThat gives you three branches: vendor with the pristine vendor source,\nvendor-fixed with any baseline fixes (permissions changes in this case),\nand then your real work goes on master (or on topic branches that get\nmerged to master).\n\nYou could also omit the vendor-fixed branch and just put your fixes on\nthe master branch. Doing it with the third branch, though, means you\nwill have a less noisy diff doing \"git diff master vendor-fixed\", since\nit will not include all the permissions mucking.\n\n-Peff\n"}]}