Conserver les permissions de fichiers avec Git

je veux contrôler la version de mon serveur web comme décrit dans contrôle de Version pour mon serveur web , en créant un git repo à partir de mon /var/www directory . Mon espoir était que je serais alors en mesure de pousser le contenu web de notre serveur de développement à github, le tirer à notre serveur de production, et passer le reste de la journée à la piscine.

apparemment, un problème dans mon plan est que Git ne respectera pas les permissions de fichiers (Je ne l'ai pas essayé, seulement la lecture à ce sujet maintenant.) Je suppose que cela a du sens du fait que différentes boîtes sont susceptibles d'avoir des configurations d'utilisateur/groupe différentes. Mais si je voulais forcer les permissions à se propager, 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 simple d'aborder ce que j'essaie de faire?

88
demandé sur Community 2010-07-09 00:30:41

7 réponses

Le git-cache-meta mentionné dans la question " git - comment faire pour récupérer les autorisations de fichier git pense que le fichier doit être? "(et la git FAQ ) est l'approche la plus sûre.

l'idée est de stocker dans un fichier .git_cache_meta les permissions des fichiers et répertoires.

Il s'agit d'un fichier séparé non versionné directement dans le dépôt git.

C'est pourquoi son usage 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

Si vous:

  • bundle votre repo et enregistrez le fichier associé autorisations.
  • copier ces deux fichiers sur le serveur distant
  • restaurer la pension là, et appliquer la permission
39
répondu VonC 2017-05-23 12:26:05

Git est un système de contrôle de Version, créé pour le développement de logiciels, donc à partir de l'ensemble des modes et des permissions, il ne stocke que le bit exécutable (pour les fichiers ordinaires) et le bit symlink. Si vous voulez stocker toutes les permissions, vous avez besoin d'un outil tiers, comme git-cache-meta ( mentionné par VonC ), ou Metastore (utilisé par etckeeper ). Ou vous pouvez utiliser IsiSetup , qui L'IIRC utilise git comme backend.

Voir Interfaces, interfaces, et les outils la page sur Git Wiki.

57
répondu Jakub Narębski 2017-05-23 11:54:53

c'est assez tard mais cela pourrait aider d'autres. Je fais ce que vous voulez en ajoutant deux crochets 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 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/hooks/post-paiement:

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

le premier crochet est appelé lorsque vous "commit" et lira la propriété et les permissions pour tous les fichiers du dépôt et les stocker dans un fichier dans le la racine du référentiel appelé .autorisations, puis ajouter le .les autorisations de fichier pour le commettre.

La deuxième hook est appelé lorsque vous "checkout" et parcourez la liste des fichiers dans le .les autorisations de fichiers et de restaurer la propriété et les autorisations de ces fichiers.

  • vous pourriez avoir besoin de faire le commit et le checkout en utilisant sudo.
  • s'assurer que les scripts pre-commit et post-checkout ont la permission d'exécution.
19
répondu Omid Ariyan 2016-09-01 20:27:58

dans le cas où vous êtes en train de venir dans ce droit en ce moment, j'ai juste été à travers elle aujourd'hui et peut 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 de @Omid Ariyan est la meilleure. Ajouter les scripts pre-commit et post-checkout. N'oubliez pas de les nommer exactement comme Omid le fait et n'oubliez pas de les rendre exécutables. Si vous oubliez l'un de ces, ils n'ont aucun effet et que vous l'exécutez "git commit" en outre, si vous coupez et collez hors du navigateur web, veillez à ce que les guillemets et les tiques ne soient pas modifiés.

si vous exécutez le script pre-commit une fois (en exécutant un git commit), puis le fichier .les autorisations seront créés. Vous pouvez l'ajouter au dépôt et je pense qu'il est inutile d'ajouter encore et encore à la fin de la pré-script de validation. Mais cela ne fait pas mal, je pense (à l'espoir).

il y a quelques petites problèmes concernant le nom du répertoire et l'existence d'Espaces Dans les noms de fichiers dans les scripts Omid. Les espaces étaient un problème ici et j'ai eu quelques problèmes avec le fix. Pour mémoire, ce script de pre-commit 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 va en tirer?

The .le fichier permissions se trouve dans le niveau supérieur du git repo. 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, un des posters se plaint qu'elle ne fonctionne qu'avec le même nom d'utilisateur, et c'est techniquement vrai, mais c'est très facile à corriger. Note de la poste-caisse script a 2 morceaux,

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

donc je ne garde 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 lancer "chgrp", cependant. Il est assez évidente comment mettre à utiliser.

dans la première réponse de ce post, celle qui est le plus largement acceptée, la suggestion est donc d'utiliser git-cache-meta, un script qui fait le même travail que les scripts hook pre/post ici (en analysant la sortie 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 pre-commit et des scripts post-checkout qui l'utiliseraient.

Les espaces

dans les noms de fichiers sont un problème avec les deux scripts Omid. Dans le script post-checkout, 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 ça. Voici quelque chose qui semble fonctionner, mais je n'ai testé dans un seul 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

puisque les informations de permissions sont une ligne à la fois, je mets IFS à $ , donc seules les lignes cassées sont considérées comme des choses nouvelles.

j'ai lu qu'il est très IMPORTANT de remettre la variable D'environnement IFS telle qu'elle était! Vous pouvez voir pourquoi une session shell pourrait mal tourner si vous laissez $ comme seul séparateur.

2
répondu pauljohn32 2016-08-30 23:57:14

dans pre-commit/post-checkout une option serait d'utiliser" mtree "(FreeBSD), ou" fmtree "(Ubuntu) utilitaire 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."

Le jeu par défaut sont des drapeaux, gid, lien, mode, nlink, la taille, l'heure, le type, et le uide. Cela peut être ajusté à l'utilisation spécifique avec l'interrupteur-K.

1
répondu Vladimir Botka 2016-07-14 07:41:29

je tourne sous 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 2.15.1, je préfère aussi exécuter tout sur des scripts shell. Avec cela à l'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 .la sortie du fichier de permissions doit avoir le format suivant:

.gitignore;644;0;0

pour A.gitignore fichier avec 644 permissions données à root: wheel

avis j'ai dû apporter quelques modifications aux options stat.

Profiter de,

1
répondu Albaro Pereyra 2018-03-16 00:31:36

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

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 sauvera les permissions de répertoire aussi bien.

1
répondu Peter Berbec 2018-05-24 22:35:00