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?
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:
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.
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.
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.
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.
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.
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,
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 "$@"