2010-07-08 22 views
83

Quiero controlar la versión de mi servidor web como se describe en Version control for my web server, al crear un git repo de mi /var/www directory. Tenía la esperanza de poder enviar contenido web de nuestro servidor de desarrollo a Github, llevarlo a nuestro servidor de producción y pasar el resto del día en la piscina.Conservación de permisos de archivos con Git

Aparentemente un inconveniente en mi plan es que Git no respetará los permisos de archivos (no lo he intentado, solo lo leo ahora). Creo que esto tiene sentido ya que es probable que diferentes cajas tengan diferentes usuarios/configuraciones de grupo. Pero si quería forzar la propagación de permisos, sabiendo que mis servidores están configurados de la misma manera, ¿tengo alguna opción? ¿O hay una manera más fácil de abordar lo que intento hacer?

+1

posible duplicado de [GIT - cómo recuperar el git permisos de archivos piensa que el archivo debe ser?] (Http://stackoverflow.com/questions/2517339/git-how-to-recover- the-file-permissions-git-thinks-the-file-should-be) – kennytm

+0

Sí, supongo que, aunque la solución que señalan, francamente no estoy seguro de qué hacer. Esperaba un enfoque más directo. – Yarin

+0

¿Qué pasa con la situación en la que el código fuente proviene del entorno Dev (por ejemplo, Windows - XAMPP, etc.) que no tiene información sobre la propiedad del archivo? Los archivos al final del proceso de git deben coincidir con la propiedad y los permisos para la ubicación de destino. ¿Puede git-cache-meta lidiar con esto? De acuerdo con Yarin ... seguramente este es un buen caso de uso general, que debería tener una solución bastante sencilla? – user3600150

Respuesta

37

El git-cache-meta mencionado en la pregunta "git - how to recover the file permissions git thinks the file should be?" de SO (y el git FAQ) es el enfoque más directo.

La idea es almacenar en un archivo .git_cache_meta los permisos de los archivos y directorios.
Es un archivo separado no versionado directamente en el repositorio de Git.

Es por ello que el uso de la misma están:

$ git bundle create mybundle.bdl master; git-cache-meta --store 
$ scp mybundle.bdl .git_cache_meta machine2: 
#then on machine2: 
$ git init; git pull mybundle.bdl master; git-cache-meta --apply 

Así que:

  • bundle your repo y guardar los permisos de archivo asociados.
  • copiar estos dos archivos en el servidor remoto
  • restaurar el repositorio allí, y se aplica el permiso
+1

VonC- Gracias por esto, lo intentaré, pero ¿es necesario el empaquetado? ¿No podría conservar mi flujo de trabajo (dev -> github -> producción) y simplemente registrar/verificar el metarchivo? – Yarin

+0

@Yarin: no, el paquete no es obligatorio. Es una buena manera de transferir repo cuando no hay otro protocolo de transferencia disponible. – VonC

+2

El uso de paquete aquí fue una gran distracción para mí. Me desconcertó por completo, en realidad. (No tengo dificultades para sacar el repo del servidor.) La respuesta de @ omid-ariyan a continuación con los enganches de pre/post commit fue mucho más comprensible. Más tarde me di cuenta de que esos scripts de gancho están haciendo exactamente el mismo trabajo que git-cache-meta. Ve a ver lo que quiero decir: https://gist.github.com/andris9/1978266. Están analizando y almacenando el retorno de 'git ls-files'. – pauljohn32

56

Git es el sistema de control de versiones, creada para el desarrollo de software, por lo que desde el conjunto de modos y permisos que almacena solo el bit ejecutable (para archivos comunes) y el bit de enlace simbólico. Si desea almacenar permisos completos, necesita una herramienta de terceros, como git-cache-meta (mentioned by VonC) o Metastore (utilizado por etckeeper). O puede usar IsiSetup, que IIRC usa git como back-end.

Ver la página Interfaces, frontends, and tools en Git Wiki.

+2

Gracias Jakub- ¿puedes explicarme por qué a Git le importa el fragmento ejecutable y solo eso? – Yarin

+5

@Yarin: ¿solo ejecutable? Cuando clonas un conjunto de archivos de un sistema a otro, la noción de "solo lectura" o "lectura-escritura" no es exactamente relevante (como dijiste en tu pregunta: diferentes usuarios/grupos). Pero la noción de "ejecutable" no depende de usuarios y grupos y puede reutilizarse desde el sistema al sistema (remoto). – VonC

+0

¡Ah, sí, eso tendría sentido! – Yarin

16

Esto es bastante tarde, pero podría ayudar a algunos otros. Hago lo que quiero hacer agregando dos ganchos git a mi repositorio.

.git/ganchos/comprobaciones previas a:

#!/bin/bash 
# 
# A hook script called by "git commit" with no arguments. The hook should 
# exit with non-zero status after issuing an appropriate message if it wants 
# to stop the commit. 

SELF_DIR=`git rev-parse --show-toplevel` 
DATABASE=$SELF_DIR/.permissions 

# Clear the permissions database file 
> $DATABASE 

echo -n "Backing-up file permissions..." 

IFS_OLD=$IFS; IFS=$'\n' 
for FILE in `git ls-files` 
do 
    # Save the permissions of all the files in the index 
    echo $FILE";"`stat -c "%a;%U;%G" $FILE` >> $DATABASE 
done 
IFS=$IFS_OLD 

# Add the permissions database file to the index 
git add $DATABASE 

echo "OK" 

.git/ganchos/post-pago y envío:

#!/bin/bash 

SELF_DIR=`git rev-parse --show-toplevel` 
DATABASE=$SELF_DIR/.permissions 

echo -n "Restoring file permissions..." 

IFS_OLD=$IFS; IFS=$'\n' 
while read -r LINE || [[ -n "$LINE" ]]; 
do 
    FILE=`echo $LINE | cut -d ";" -f 1` 
    PERMISSIONS=`echo $LINE | cut -d ";" -f 2` 
    USER=`echo $LINE | cut -d ";" -f 3` 
    GROUP=`echo $LINE | cut -d ";" -f 4` 

    # Set the file permissions 
    chmod $PERMISSIONS $FILE 

    # Set the file owner and groups 
    chown $USER:$GROUP $FILE 

done < $DATABASE 
IFS=$IFS_OLD 

echo "OK" 

exit 0 

El primer gancho se llama cuando se "compromete" y leerá la propiedad y los permisos para todos los archivos en el repositorio y los almacenará en un archivo en la raíz del repositorio llamado .permissions y luego agregará el archivo .permissions al commit.

Se llama al segundo enganche cuando "realiza el pago" y revisará la lista de archivos en el archivo .permissions y restaurará la propiedad y los permisos de esos archivos.

  • Es posible que tenga que realizar la confirmación y finalizar la compra con sudo.
  • Asegúrate de que los scripts de precompilación y post-checkout tengan permiso de ejecución.
+0

Omid ... ¡gracias! Encontré tu código para ser una solución perfecta para mí. – Ricalsin

+0

@Ricalsin ¡De nada! Me alegra haber ayudado :) –

+1

'$ SELF_DIR /../../' no es necesariamente la raíz del repositorio ... pero 'git rev-parse --show-toplevel' es. (No estoy seguro de por qué no usaría 'pwd' para el directorio actual, pero eso es discutible de todos modos.) – PJSCopeland

1

En pre-commit/post-checkout una opción sería utilizar (Ubuntu) utilidad que "compara una jerarquía de archivos contra una especificación "mtree"(FreeBSD), o "fmtree", crea una especificación para una jerarquía de archivos, o modifica una especificación ".

El conjunto predeterminado son flags, gid, link, mode, nlink, size, time, type y uid. Esto se puede adaptar al propósito específico con el modificador -k.

2

En caso de que esté entrando en esto en este momento, he pasado por esto hoy y puedo resumir dónde está esto. Si aún no lo has intentado, algunos detalles aquí pueden ayudarte.

Creo que el enfoque de @Omid Ariyan es la mejor manera. Agregue los scripts de precompilación y postpago. NO olvide nombrarlos exactamente como lo hace Omid y NO olvide hacerlos ejecutables. Si olvida alguno de estos, no tienen ningún efecto y ejecuta "git commit" una y otra vez preguntándose por qué no sucede nada :) Además, si corta y pega fuera del navegador web, tenga cuidado de que las comillas y los tics no sean correctos. alterado

Si ejecuta el script de precompilación una vez (ejecutando una confirmación de git), se crearán las licencias del archivo. Puede agregarlo al repositorio y creo que es innecesario agregarlo una y otra vez al final del script precompromiso. Pero no duele, creo (esperanza).

Hay algunos pequeños problemas sobre el nombre del directorio y la existencia de espacios en los nombres de los archivos en los scripts de Omid. Los espacios eran un problema aquí y tuve algunos problemas con el arreglo IFS. Para el registro, esta pre-commit guión ha funcionado correctamente para mí:

#!/bin/bash 

SELF_DIR=`git rev-parse --show-toplevel` 
DATABASE=$SELF_DIR/.permissions 

# Clear the permissions database file 
> $DATABASE 

echo -n "Backing-up file permissions..." 

IFSold=$IFS 
IFS=$'\n' 
for FILE in `git ls-files` 
do 
    # Save the permissions of all the files in the index 
    echo $FILE";"`stat -c "%a;%U;%G" $FILE` >> $DATABASE 
done 
IFS=${IFSold} 
# Add the permissions database file to the index 
git add $DATABASE 

echo "OK" 

Ahora, lo que vamos a salir de esta?

El archivo .permissions está en el nivel superior del git repo. Cuenta con una línea por cada archivo, aquí está la parte superior de mi ejemplo:

$ cat .permissions 
.gitignore;660;pauljohn;pauljohn 
05.WhatToReport/05.WhatToReport.doc;664;pauljohn;pauljohn 
05.WhatToReport/05.WhatToReport.pdf;664;pauljohn;pauljohn 

Como se puede ver, tenemos

filepath;perms;owner;group 

En los comentarios sobre este enfoque, uno de los carteles se queja de que se solo funciona con el mismo nombre de usuario, y eso es técnicamente cierto, pero es muy fácil solucionarlo. Tenga en cuenta el script de post-pago y envío tiene 2 piezas de acción,

# Set the file permissions 
chmod $PERMISSIONS $FILE 
# Set the file owner and groups 
chown $USER:$GROUP $FILE 

Así que sólo estoy manteniendo la primera, eso es todo lo que necesito. Mi nombre de usuario en el servidor web es realmente diferente, pero lo más importante es que no puede ejecutar chown a menos que sea root. Puede ejecutar "chgrp", sin embargo. Es bastante claro cómo poner eso en uso.

En la primera respuesta en esta publicación, la que es más ampliamente aceptada, la sugerencia es usar git-cache-meta, una secuencia de comandos que está haciendo el mismo trabajo que los scripts pre y post aquí están haciendo (salida de análisis desde git ls-files). Estos guiones son más fáciles de entender, el código git-cache-meta es bastante más elaborado. Es posible mantener git-cache-meta en la ruta y escribir scripts de pre-commit y post-checkout que lo usarían.

Los espacios en los nombres de los archivos son un problema con los dos scripts de Omid. En el script de post-pago y envío, usted sabe que tiene los espacios en los nombres de archivo si ve errores como éste

$ git checkout -- upload.sh 
Restoring file permissions...chmod: cannot access '04.StartingValuesInLISREL/Open': No such file or directory 
chmod: cannot access 'Notebook.onetoc2': No such file or directory 
chown: cannot access '04.StartingValuesInLISREL/Open': No such file or directory 
chown: cannot access 'Notebook.onetoc2': No such file or directory 

Estoy comprobando en las soluciones para ello. Esto es algo que parece funcionar, pero sólo lo he probado en un caso

#!/bin/bash 

SELF_DIR=`git rev-parse --show-toplevel` 
DATABASE=$SELF_DIR/.permissions 

echo -n "Restoring file permissions..." 
IFSold=${IFS} 
IFS=$ 
while read -r LINE || [[ -n "$LINE" ]]; 
do 
    FILE=`echo $LINE | cut -d ";" -f 1` 
    PERMISSIONS=`echo $LINE | cut -d ";" -f 2` 
    USER=`echo $LINE | cut -d ";" -f 3` 
    GROUP=`echo $LINE | cut -d ";" -f 4` 

    # Set the file permissions 
    chmod $PERMISSIONS $FILE 
    # Set the file owner and groups 
    chown $USER:$GROUP $FILE 
done < $DATABASE 
IFS=${IFSold} 
echo "OK" 

exit 0 

Dado que la información de permisos es una línea a la vez, me puse IFS a $, por lo que sólo los saltos de línea son vistos como cosas nuevas.

He leído que es MUY IMPORTANTE volver a establecer la variable de entorno IFS como estaba. Puede ver por qué una sesión de shell puede salir mal si deja $ como el único separador.

1

Me estoy ejecutando en FreeBSD 11.1, el concepto de virtualización de la cárcel freebsd hace que el sistema operativo sea óptimo. La versión actual de Git que estoy usando es 2.15.1, también prefiero ejecutar todo en scripts de shell. Con esto en mente he modificado las sugerencias anteriores como sigue:

git push: .git/ganchos/pre-commit

#! /bin/sh - 
# 
# A hook script called by "git commit" with no arguments. The hook should 
# exit with non-zero status after issuing an appropriate message if it wants 
# to stop the commit. 

SELF_DIR=$(git rev-parse --show-toplevel) 
DATABASE=$SELF_DIR/.permissions 

# Clear the permissions database file 
> $DATABASE 

printf "Backing-up file permissions...\n"; 

IFS_OLD=$IFS; 
IFS=$'\n' 
for FILE in `git ls-files` 
do 
    # Save the permissions of all the files in the index 
    printf "%s;%s\n" $FILE $(stat -f "%Lp;%u;%g" $FILE) >> $DATABASE; 
done 
IFS=$IFS_OLD 

# Add the permissions database file to the index 
git add $DATABASE; 

printf "OK\n"; 

git pull: .git/ganchos/post-merge

#! /bin/sh - 

SELF_DIR=$(git rev-parse --show-toplevel) 
DATABASE=$SELF_DIR/.permissions 

printf "Restoring file permissions...\n"; 

IFS_OLD=$IFS; 
IFS=$'\n' 
while read -r LINE || [ -n "$LINE" ]; 
do 
    FILE=$(printf "%s" $LINE | cut -d ";" -f 1) 
    PERMISSIONS=$(printf "%s" $LINE | cut -d ";" -f 2) 
    USER=$(printf "%s" $LINE | cut -d ";" -f 3) 
    GROUP=$(printf "%s" $LINE | cut -d ";" -f 4) 

    # Set the file permissions 
    chmod $PERMISSIONS $FILE 

    # Set the file owner and groups 
    chown $USER:$GROUP $FILE 

done < $DATABASE 
IFS=$IFS_OLD 

pritnf "OK\n"; 

exit 0 

Si por alguna razón necesita volver a crear la secuencia de comandos del archivo de salida .permissions debe tener el siguiente formato:

.gitignore;644;0;0 

Para un archivo .gitignore con 644 permisos otorgados a la raíz: rueda

Observe que tuve que hacer algunos cambios en las opciones de estadísticas.

Disfrute,

Cuestiones relacionadas