Is there a way to only reset the file permissions of the working-tree to
match HEAD file permissions without resetting the content of the files?
HEAD file permissions = the permissions of the objects in the object store.
I'm using the vendor branch method of the git-rm manpage (git ls-files -z |
xargs -0 rm -f && tar xzf vendor-version.tar.gz && git add -A) and I want to
discard the vendor's file permissions changes to existing files and reset
them back to what they are in HEAD.
"existing files" = ALL files that already existed in the HEAD and are not
"deleted" or "new" in the working-tree relative to the HEAD.
HEAD = before "rm"
Working-Tree = after the untar.
v/r,
Neal
From: Jeff King <hidden> Date: 2016-06-15 22:50:46
On Mon, Mar 14, 2011 at 03:29:51PM -0500, Neal Kreitzinger wrote:
Is there a way to only reset the file permissions of the working-tree
to match HEAD file permissions without resetting the content of the
files?
Not directly, but you could munge a patch to do so and apply it in
reverse. For example:
git diff "$@" |
perl -ne '
if (/^diff/) { $diff = $_ }
elsif (/^old mode/) { print $diff, $_ }
elsif (/^new mode/) { print $_ }
' |
git apply -R
Which seems a little more complicated than it needs to be, but we don't
(AFAIK) have a way to say "show me only the mode changes from this
diff in an applicable form". The closest would be "git diff --summary",
but you cannot directly apply it (and I would hesitate to recommend
parsing it).
You could also use "git checkout -p", which is designed for exactly this
sort of picking-apart of a patch, but it has no way to specify "say yes
to all of the mode changes, no to everything else"; you have to manually
approve each hunk. Which doesn't work if you have a lot of these files.
I guess for mode changes, you don't care if you chmod something that is
already fine. So yet another way to do it would be:
git ls-files -sz |
perl -0ne '
/100(\d+).*?\t(.*)/ or next;
-e $2 or next;
chmod(oct($1), $2)
or die "chmod failed: $!";
'
Hope that helps,
-Peff
On Mon, Mar 14, 2011 at 03:29:51PM -0500, Neal Kreitzinger wrote:
quoted
Is there a way to only reset the file permissions of the
working-tree to match HEAD file permissions without resetting the
content of the files?
Not directly, but you could munge a patch to do so and apply it in
reverse. For example:
git diff "$@" | perl -ne ' if (/^diff/) { $diff = $_ } elsif (/^old
mode/) { print $diff, $_ } elsif (/^new mode/) { print $_ } ' | git
apply -R
Which seems a little more complicated than it needs to be, but we
don't (AFAIK) have a way to say "show me only the mode changes from
this diff in an applicable form". The closest would be "git diff
--summary", but you cannot directly apply it (and I would hesitate to
recommend parsing it).
You could also use "git checkout -p", which is designed for exactly
this sort of picking-apart of a patch, but it has no way to specify
"say yes to all of the mode changes, no to everything else"; you have
to manually approve each hunk. Which doesn't work if you have a lot
of these files.
I guess for mode changes, you don't care if you chmod something that
is already fine. So yet another way to do it would be:
git ls-files -sz | perl -0ne ' /100(\d+).*?\t(.*)/ or next; -e $2 or
next; chmod(oct($1), $2) or die "chmod failed: $!"; '
You are right about git checkout -p because there are alot of code
changes to alot of files. I haven't used git patches and I don't know
perl. However, your reasoning about the last example seems the most
straight-forward so I used it. I symptomatically validated my re-keying
of the syntax as follows since TTBOMK I couldn't copy+paste your example
due to whitespace:
git ls-files -sz | perl -0ne '/100(\d+).*?\t(.*)/
or next; -e $2 or next; chmod(oct($1), $2) or die "chmod failed: $!";'
(0) repo contains bad modes in working tree only.
(1) make a copy of the repo (cp -rp repo repoX)
(2) add and commit (via superuser and git-commit --no-verify) the "bad"
modes.
(3) make another copy of the repo (repoY)
(4) run your perl script on repoY working-tree
(5) git diff | grep "old mode" (shows no occurences)
(6) commit "good" modes.
(7) make repox "bad" modes branch a remote of repoy and fetched the bad
modes commit (git remote add -t bad-mode-branch repo-X /opt/me/repoX).
(8) diffed the bad modes commit vs the good modes commit and saw that
only the modes differed.
Thanks!
v/r,
neal
From: Jeff King <hidden> Date: 2016-06-15 22:50:47
On Tue, Mar 15, 2011 at 08:06:19PM -0500, Neal Kreitzinger wrote:
You are right about git checkout -p because there are alot of code
changes to alot of files. I haven't used git patches and I don't
know perl. However, your reasoning about the last example seems the
most straight-forward so I used it. I symptomatically validated my
re-keying of the syntax as follows since TTBOMK I couldn't copy+paste
your example due to whitespace:
git ls-files -sz | perl -0ne '/100(\d+).*?\t(.*)/
or next; -e $2 or next; chmod(oct($1), $2) or die "chmod failed: $!";'
The whitespace in what I sent was fine, though it's possible your MUA
mangled it.
It sounds like the solution worked for you, so cool. But I did have one
more thought to mention: since you are working with a vendor branch, you
should be able to have a "pristine" vendor branch complete with their
wrong permissions, and then build your permissions fixes on top of that.
And then when you merge the pristine branch up to your branch, git will
automatically resolve the permissions in favor of yours (because its
built on top).
So something like:
# import initial vendor branch
git init
# untar or whatever happens to get the files
tar xzf /path/to/vendor-1.0.tar.gz
git add .
git commit -m 'import vendor 1.0'
# now move it to vendor branch and make our munged-vendor branch
git branch vendor
git checkout -b vendor-fixed vendor
# now tweak permissions
.. chmod or however you did it originally ...
git add -u
git commit -m 'fix broken vendor permissions'
# and then built your real work on top of vendor-fixed
git branch -f master vendor-fixed
git checkout master
# weeks pass; vendor releases 1.1
git checkout vendor
# untar or whatever we do to get the files
tar xzf /path/to/vendor-1.1.tar.gz
git add -A
git commit -m 'import vendor 1.1'
# now we merge it in, but our permissions fixes will be retained
git checkout vendor-fixed
git merge vendor
# however we may still have to deal with new files
... chmod or whatever on new files ...
git add -u
git commit -m 'fix more broken vendor permissions'
...and repeat for each new version the vendor releases.
That gives you three branches: vendor with the pristine vendor source,
vendor-fixed with any baseline fixes (permissions changes in this case),
and then your real work goes on master (or on topic branches that get
merged to master).
You could also omit the vendor-fixed branch and just put your fixes on
the master branch. Doing it with the third branch, though, means you
will have a less noisy diff doing "git diff master vendor-fixed", since
it will not include all the permissions mucking.
-Peff