web-dev-qa-db-fra.com

Conserver les autorisations de fichiers avec Git

Je souhaite contrôler les versions de mon serveur Web, comme décrit dans la section Contrôle des versions de mon serveur Web , en créant un dépôt Git à partir de mon /var/www directory. J'espérais pouvoir ensuite transmettre le contenu Web de notre serveur de développement à github, le transférer sur notre serveur de production et passer le reste de la journée à la piscine.

Apparemment, dans mon plan, mon plan est que Git ne respectera pas les autorisations de fichiers (je ne l’ai pas encore essayé, je ne l’ai lu que maintenant). Je suppose que cela a du sens car différentes boîtes sont susceptibles d’avoir des configurations d’utilisateur/groupe différentes. Mais si je voulais forcer la propagation des autorisations, sachant que mes serveurs sont configurés de la même manière, ai-je des options? Ou y a-t-il un moyen plus facile d'aborder ce que j'essaie de faire?

97
Yarin

Le git-cache-meta mentionné dans SO question " git - comment récupérer les autorisations de fichiers git pense que le fichier devrait être? " (et le git FAQ ) est l'approche la plus ferme.

L'idée est de stocker dans un .git_cache_meta file les permissions des fichiers et des répertoires.
Il s’agit d’un fichier distinct qui n’est pas directement versionné dans le dépôt Git.

C'est pourquoi son utilisation est:

$ 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

Alors vous:

  • regroupez votre repo et enregistrez les autorisations de fichier associées.
  • copier ces deux fichiers sur le serveur distant
  • restaurez le repo et appliquez la permission
43
VonC

Git est un système de contrôle de version, créé pour le développement de logiciels. Ainsi, pour l'ensemble des modes et des autorisations, il ne stocke que les bits exécutables (pour les fichiers ordinaires) et les liens symboliques. Si vous souhaitez stocker des autorisations complètes, vous avez besoin d'un outil tiers, tel que git-cache-meta ( mentionné par VonC ), ou Metastore (utilisé par etckeeper ). Ou vous pouvez utiliser IsiSetup , que l'IIRC utilise git comme backend.

Voir Interfaces, interfaces et outils page sur Git Wiki.

60
Jakub Narębski

C'est assez tard mais cela pourrait aider d'autres. Je fais ce que vous voulez en ajoutant deux hooks git à mon dépôt.

. git/hooks/pre-commit:

#!/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 permissions..."

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

for DIRECTORY in `git ls-files --full-name | xargs -n 1 dirname | uniq`
do
   # Save the permissions of all the directories in the index
   echo $DIRECTORY";"`stat -c "%a;%U;%G" $DIRECTORY` >> $DATABASE
done
IFS=$IFS_OLD

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

echo "OK"

. git/hooks/post-checkout:

#!/bin/bash

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

echo -n "Restoring permissions..."

IFS_OLD=$IFS; IFS=$'\n'
while read -r LINE || [[ -n "$LINE" ]];
do
   ITEM=`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/directory permissions
   chmod $PERMISSIONS $ITEM

   # Set the file/directory owner and groups
   chown $USER:$GROUP $ITEM

done < $DATABASE
IFS=$IFS_OLD

echo "OK"

exit 0

Le premier raccordement est appelé lorsque vous "commettez". Il lit les droits de propriété et les autorisations de tous les fichiers du référentiel et les stocke dans un fichier situé à la racine du référentiel, appelé .permissions, puis ajoute le fichier .permissions à la validation.

Le deuxième crochet est appelé lorsque vous "passez à la caisse". Il parcourt la liste des fichiers du fichier .permissions et restaure la propriété et les autorisations de ces fichiers.

  • Vous devrez peut-être effectuer les commits et les commandes avec Sudo.
  • Assurez-vous que les scripts de pré-validation et de post-extraction ont une autorisation d'exécution.
21
Omid Ariyan

Au cas où vous aborderiez ceci en ce moment, je viens de le lire aujourd'hui et je peux résumer où cela se trouve. Si vous ne l'avez pas encore essayé, quelques détails ici pourraient vous aider.

Je pense que l'approche d'Omid Ariyan est la meilleure solution. Ajoutez les scripts de pré-validation et de post-extraction. NE PAS oublier de les nommer exactement comme Omid et NE PAS oublier de les rendre exécutables. Si vous oubliez l'un ou l'autre, ils n'ont aucun effet et vous exécutez "git commit" sans cesse en vous demandant pourquoi rien ne se produit :) De plus, si vous coupez et collez du navigateur Web, veillez à ce que les guillemets et les graduations ne soient pas cochés. modifié.

Si vous exécutez le script de pré-validation une fois (en exécutant une validation git), le fichier .permissions sera créé. Vous pouvez l'ajouter au référentiel et je pense qu'il n'est pas nécessaire de l'ajouter encore et encore à la fin du script de pré-validation. Mais ça ne fait pas mal, je pense (espère).

Il y a quelques petits problèmes concernant le nom de répertoire et l'existence d'espaces dans les noms de fichiers dans les scripts d'Omid. Les espaces étaient un problème ici et j'ai eu quelques problèmes avec le correctif IFS. Pour mémoire, ce script de pré-validation a fonctionné correctement pour moi:

#!/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"

Maintenant, qu'est-ce qu'on en tire?

Le fichier .permissions se trouve au niveau supérieur du référentiel git. Il a une ligne par fichier, voici le haut de mon exemple:

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

Comme vous pouvez le voir, nous avons

filepath;perms;owner;group

Dans les commentaires sur cette approche, l'une des affiches se plaint de ne pouvoir fonctionner qu'avec le même nom d'utilisateur, ce qui est techniquement vrai, mais il est très facile de le corriger. Notez que le script post-paiement comporte 2 actions,

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

Je ne garde donc que le premier, c'est tout ce dont j'ai besoin. Mon nom d'utilisateur sur le serveur Web est en effet différent, mais plus important encore, vous ne pouvez pas exécuter chown à moins d'être root. Peut exécuter "chgrp", cependant. Il est assez évident de savoir comment utiliser cela.

Dans la première réponse de ce billet, celle qui est la plus largement acceptée, nous vous suggérons d’utiliser git-cache-meta, un script qui effectue le même travail que les scripts de hook pré/post précédent (analyse des résultats de git ls-files). Ces scripts sont plus faciles à comprendre pour moi, le git-cache-meta code est un peu plus élaboré. Il est possible de garder git-cache-meta dans le chemin et d'écrire les scripts de pré-validation et de post-extraction qui l'utilisent.

Les espaces dans les noms de fichiers posent un problème avec les deux scripts d'Omid. Dans le script post-paiement, vous saurez que vous avez les espaces dans les noms de fichiers si vous voyez des erreurs comme celle-ci.

$ 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

Je vérifie les solutions pour cela. Voici quelque chose qui semble fonctionner, mais je n'ai testé que dans un cas

#!/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

Étant donné que les informations sur les autorisations sont une ligne à la fois, j'ai défini IFS sur $, de sorte que seuls les sauts de ligne sont considérés comme des éléments nouveaux.

J'ai lu qu'il est TRÈS IMPORTANT de définir la variable d'environnement IFS telle qu'elle était! Vous pouvez voir pourquoi une session Shell risque de mal tourner si vous laissez $ comme seul séparateur.

2
pauljohn32

En pré-validation/post-extraction, une option consisterait à utiliser l'utilitaire "mtree" (FreeBSD) ou "fmtree" (Ubuntu) qui "compare une hiérarchie de fichiers à une spécification, crée une spécification pour une hiérarchie de fichiers ou modifie une spécification."

Les ensembles par défaut sont drapeaux, gid, lien, mode, nlink, taille, heure, type et uid. Cela peut être adapté à l'objectif spécifique avec le commutateur -k.

1
Vladimir Botka

Un ajout à la réponse de @Omid Ariyan est les autorisations sur les répertoires. Ajoutez ceci après la for de la boucle done dans son pre-commit script.

for DIR in $(find ./ -mindepth 1 -type d -not -path "./.git" -not -path "./.git/*" | sed 's@^\./@@')
do
    # Save the permissions of all the files in the index
    echo $DIR";"`stat -c "%a;%U;%G" $DIR` >> $DATABASE
done

Cela permettra également d’enregistrer les autorisations de répertoire.

1
Peter Berbec

J'utilise FreeBSD 11.1, le concept de virtualisation jail de FreeBSD rend le système d'exploitation optimal. La version actuelle de Git que j'utilise est la version 2.15.1, je préfère également tout exécuter sur des scripts Shell. Dans cet esprit, j'ai modifié les suggestions ci-dessus comme suit:

git Push: .git/hooks/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";

OLDIFS=$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=$OLDIFS;

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

printf "OK\n";

git pull: .git/hooks/post-fusion

#! /bin/sh -

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

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

OLDIFS=$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=$OLDIFS

pritnf "OK\n";

exit 0;

Si, pour une raison quelconque, vous devez recréer le script, le fichier .permissions en sortie doit avoir le format suivant:

.gitignore;644;0;0

Pour un fichier .gitignore avec 644 permissions accordées à root: wheel

Remarquez que je devais apporter quelques modifications aux options de statistiques.

Prendre plaisir,

1
Albaro Pereyra

Nous pouvons améliorer les autres réponses en modifiant le format du fichier .permissions Pour qu'il soit exécutable chmod et en utilisant le paramètre -printf En find. Voici le fichier plus simple .git/hooks/pre-commit:

#!/usr/bin/env bash

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

cd "$(git rev-parse --show-toplevel)"

find . -printf 'chmod %m "%p"\n' > .permissions

git add .permissions

echo done.

... et voici le fichier simplifié .git/hooks/post-checkout:

#!/usr/bin/env bash

echo -n "Restoring file permissions... "

cd "$(git rev-parse --show-toplevel)"

. .permissions

echo "done."

N'oubliez pas que d'autres outils ont peut-être déjà configuré ces scripts. Vous devrez donc peut-être les fusionner. Par exemple, voici un script post-checkout Qui inclut également les commandes git-lfs:

#!/usr/bin/env bash

echo -n "Restoring file permissions... "

cd "$(git rev-parse --show-toplevel)"

. .permissions

echo "done."

command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on you
r path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-checkout.\n"; exit 2; }
git lfs post-checkout "$@"
1
Tammer Saleh