¿Cómo restaurar los permisos de archivos y directorios dentro de git si se han modificado?

278

Tengo un pago git. Todos los permisos de archivo son diferentes de lo que git cree que deberían ser, por lo tanto, todos se muestran como modificados.

Sin tocar el contenido de los archivos (solo quiero modificar los permisos), ¿cómo configuro todos los permisos de archivos a lo que git cree que deberían ser?

Dale Forester
fuente

Respuestas:

572

Git realiza un seguimiento del permiso de archivos y expone los cambios de permisos al crear parches usando git diff -p. Entonces todo lo que necesitamos es:

  1. crear un parche inverso
  2. incluir solo los cambios de permiso
  3. aplicar el parche a nuestra copia de trabajo

Como una línea:

git diff -p -R --no-ext-diff --no-color \
    | grep -E "^(diff|(old|new) mode)" --color=never  \
    | git apply

también puede agregarlo como un alias a su configuración de git ...

git config --global --add alias.permission-reset '!git diff -p -R --no-ext-diff --no-color | grep -E "^(diff|(old|new) mode)" --color=never | git apply'

... y puedes invocarlo a través de:

git permission-reset

Tenga en cuenta que si su shell es bash, asegúrese de usar en 'lugar de "comillas alrededor de !git, de lo contrario se sustituye con el últimogit comando que ejecutó.

Gracias a @Mixologic por señalar que simplemente usando -Ron git diff, el engorroso sedcomando ya no es necesario.

muhqu
fuente
3
Estoy en OS X, esto no funciona. He identificado que el problema está en la aplicación git. No aplica los cambios de permisos de archivo.
pepper_chico
15
Oh, funcionó, estaba tratando de aplicar desde un directorio diferente de la raíz del repositorio. git apply solo funciona allí.
pepper_chico
66
¿Hay alguna razón por la que no harías "git diff -p -R" en lugar de hacer el sed para revertirlo?
Mixologic
66
@RobQuist mis cambios locales no se eliminaron al usar el comando de muhqu
logion
17
Me estoy poniendofatal: unrecognized input
Tieme
120

Tratar git config core.fileMode false

Desde la git configpágina del manual:

core.fileMode

Si es falso, las diferencias de bits ejecutables entre el índice y la copia de trabajo se ignoran; útil en sistemas de archivos rotos como FAT. Ver git-update-index (1) .

El valor predeterminado es verdadero, excepto que git-clone (1) o git-init (1) probarán y establecerán core.fileMode false si es apropiado cuando se crea el repositorio.

Tim Henigan
fuente
Gracias, esto es lo que terminé haciendo. Muy utilizado para cvs que no siguen los permisos, por lo que esto funciona.
Dale Forester
3
@shovas: Me alegra que esto haya ayudado. Experimenté un problema similar al compartir repositorios entre Linux y Windows. Por cierto: si esto respondió a su pregunta, marque la respuesta como correcta.
Tim Henigan el
¿Es posible que git checkout origin/masterestablezca permisos de archivo comprometidos con el servidor para mi copia de trabajo local? Porque cada vez que compilo V8 para ArangoDB, los permisos del archivo cambian para que el acceso sea denegado a toda la carpeta de compilación (incluso con derechos elevados; Windows 7+). Necesito corregir todos los permisos de archivos locales antes de poder continuar con el proceso de compilación. ¿Puede core.filemode falsearreglar eso también? Sospecho que git establece permisos de Linux en mi máquina Windows. Los scripts de compilación podrían preservarlos y aplicar los mismos permisos a los archivos recién creados ...
CodeManX
Im pregunto si hay alguna desventaja de establecer filemodea false!
kevoroid
11

Git no almacena permisos de archivo que no sean scripts ejecutables. Considera usar algo como git-cache-meta para guardar la propiedad y los permisos del archivo.

Git solo puede almacenar dos tipos de modos: 755 (ejecutable) y 644 (no ejecutable). Si su archivo fuera 444 git lo almacenaría, tiene 644.

kroger
fuente
14
Lo siento, pero esto es incorrecto. Git, de hecho, rastrea los permisos.
Se
44
Es más o menos exacto, vea git.wiki.kernel.org/index.php/ContentLimitations . Los permisos exactos que se configuran parecen basarse en el servidor y posiblemente en el cliente umask, así como una configuración, consulte stackoverflow.com/a/12735291/125150 .
Motti Strom
12
@ No, no lo hace. No puedo creer que tu comentario haya recibido tantos votos positivos.
EIS
@ Will, esto es más o menos correcto. Según los documentos ...a mode of 100644, which means it’s a normal file. Other options are 100755, which means it’s an executable file; and 120000, which specifies a symbolic link. The mode is taken from normal UNIX modes but is much less flexible — these three modes are the only ones that are valid for files (blobs) in Git (although other modes are used for directories and submodules).
esmail
9
git diff -p \
| grep -E '^(diff|old mode|new mode)' \
| sed -e 's/^old/NEW/;s/^new/old/;s/^NEW/new/' \
| git apply

funcionará en la mayoría de los casos, pero si tiene instaladas herramientas externas de diferencia como meld, debe agregar --no-ext-diff

git diff --no-ext-diff -p \
    | grep -E '^(diff|old mode|new mode)' \
    | sed -e 's/^old/NEW/;s/^new/old/;s/^NEW/new/' \
    | git apply

era necesario en mi situación

zainengineer
fuente
0

Uso git de cygwin en Windows, la git applysolución no me funciona. Aquí está mi solución, ejecutar chmoden cada archivo para restablecer sus permisos.

#!/bin/bash
IFS=$'\n'
for c in `git diff -p |sed -n '/diff --git/{N;s/diff --git//g;s/\n/ /g;s# a/.* b/##g;s/old mode //g;s/\(.*\) 100\(.*\)/chmod \2 \1/g;p}'`
do
        eval $c
done
unset IFS

alijandro
fuente
-1

git diff -pusado en la respuesta de muhqu puede no mostrar todas las discrepancias.

  • vi esto en Cygwin para archivos que no poseía
  • los cambios de modo se ignoran por completo si core.filemodees false(que es el valor predeterminado para MSysGit)

Este código lee los metadatos directamente en su lugar:

(set -o errexit pipefail nounset;
git ls-tree HEAD -z | while read -r -d $'\0' mask type blob path
do
    if [ "$type" != "blob" ]; then continue; fi;
    case "$mask" in
    #do not touch other bits
    100644) chmod a-x "$path";;
    100755) chmod a+x "$path";;
    *) echo "invalid: $mask $type $blob\t$path" >&2; false;;
    esac
done)

Una sola línea de grado no de producción (reemplaza las máscaras por completo):

git ls-tree HEAD | perl -ne '/^10(0\d{3}) blob \S+\t(.+)$/ && { system "chmod",$1,$2 || die }'

(El crédito para "$ '\ 0'" va a http://transnum.blogspot.ru/2008/11/bashs-read-built-in-supports-0-as.html )

ivan_pozdeev
fuente
-2

Lo más fácil es cambiar de nuevo los permisos. Como señaló @kroger, git solo rastrea bits ejecutables. Por lo tanto, probablemente solo necesite ejecutarlo chmod -x filenamepara solucionarlo (o +xsi eso es lo que se necesita.

Pat Notz
fuente
Aquí hay un ejemplo de git show: diff --git a / OpenWatch / src / org / ale / openwatch / fb / FBUtils.java b / OpenWatch / src / org / ale / openwatch / fb / FBUtils.java index cd6fa6a..e5b0935 100644 That poco en negrita están los permisos de archivo.
Conrado
Esto también me pareció más fácil. Desafortunadamente, encontré el mismo problema que Conrado: no pude cambiar el permiso de 100644a 100755. No creo que merezca un voto negativo; Git debería ser rechazado. Está tan roto de muchas maneras en tantos niveles diferentes ...
jww
-2

La etckeeperherramienta puede manejar permisos y con:

etckeeper init -d /mydir

Puede usarlo para otros directorios que no sean /etc.

Instale utilizando su administrador de paquetes u obtenga fuentes del enlace anterior.

MoreIT
fuente
44
¿Para qué establece los permisos? Si no lee los metadatos de Git o invoca a Git, no hace lo que solicitó el OP.
ivan_pozdeev