Comment restaurer les permissions des fichiers et répertoires dans git s'ils ont été modifiés?

279

J'ai une caisse git. Toutes les autorisations de fichiers sont différentes de ce que git pense qu'elles devraient être, elles apparaissent donc toutes comme modifiées.

Sans toucher au contenu des fichiers (je veux juste modifier les autorisations), comment puis-je définir toutes les autorisations de fichiers sur ce que git pense qu'elles devraient être?

Dale Forester
la source

Réponses:

572

Git garde une trace de la permission des fichiers et expose les changements de permission lors de la création de correctifs à l'aide de git diff -p. Il nous suffit donc de:

  1. créer un patch inversé
  2. inclure uniquement les modifications d'autorisation
  3. appliquer le patch à notre copie de travail

En une ligne:

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

vous pouvez également l'ajouter comme alias à votre configuration 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'

... et vous pouvez l'invoquer via:

git permission-reset

Notez que si votre shell est bash, assurez-vous d'utiliser 'au lieu de "guillemets autour du !git, sinon il sera remplacé par la dernière gitcommande que vous avez exécutée.

Merci à @Mixologic pour avoir souligné qu'en utilisant simplement -Ron git diff, la sedcommande encombrante n'est plus requise.

muhqu
la source
3
Je suis sous OS X, cela ne fonctionne pas. J'ai identifié le problème dans le git apply. Il n'applique pas les modifications des autorisations de fichier.
pepper_chico
15
Oh, cela a fonctionné, j'essayais de postuler à partir d'un répertoire différent de la racine du référentiel. git appliquer ne fonctionne que là-bas.
pepper_chico
6
Y a-t-il une raison pour laquelle vous ne feriez pas simplement "git diff -p -R" au lieu de faire le sed pour le faire inverser?
Mixologic
6
@RobQuist mes modifications locales n'ont pas été supprimées lors de l'utilisation de la commande de muhqu
logion
17
Je reçoisfatal: unrecognized input
Tieme
121

Essayer git config core.fileMode false

Depuis la git configpage de manuel:

core.fileMode

Si false, les différences de bits exécutables entre l'index et la copie de travail sont ignorées; utile sur les systèmes de fichiers cassés comme FAT. Voir git-update-index (1) .

La valeur par défaut est true, sauf que git-clone (1) ou git-init (1) va sonder et définir core.fileMode false si approprié lorsque le référentiel est créé.

Tim Henigan
la source
Merci, c'est ce que j'ai fini par faire. Très utilisé pour les CV ne suivant pas les autorisations, cela fonctionne.
Dale Forester
3
@shovas: Je suis heureux que cela ait aidé. J'ai rencontré un problème similaire lors du partage de dépôts entre Linux et Windows. BTW: si cela répond à votre question, veuillez marquer la réponse comme correcte.
Tim Henigan
Est-il possible que git checkout origin/masterles autorisations de fichier affectées au serveur soient définies sur ma copie de travail locale? Parce que chaque fois que je construis V8 pour ArangoDB, les autorisations de fichier sont modifiées afin que l'accès soit refusé à l'ensemble du dossier de construction (même avec des droits élevés; Windows 7+ c'est-à-dire). J'ai besoin de corriger toutes les autorisations de fichiers locaux avant de pouvoir continuer le processus de génération. Pouvez-vous core.filemode falserésoudre ce problème aussi? Je soupçonne git de définir des autorisations Linux sur ma machine Windows. Les scripts de construction pourraient simplement les conserver et appliquer les mêmes autorisations aux fichiers nouvellement créés ...
CodeManX
Je me demande s'il y a un inconvénient à se mettre filemodeà false!
kevoroid
11

Git ne stocke pas les autorisations de fichiers autres que les scripts exécutables. Pensez à utiliser quelque chose comme git-cache-meta pour enregistrer la propriété et les autorisations des fichiers.

Git ne peut stocker que deux types de modes: 755 (exécutable) et 644 (non exécutable). Si votre fichier était de 444 git, il en aurait 644.

kroger
la source
14
Désolé, mais c'est incorrect. Git suit effectivement les autorisations.
Will
4
C'est à peu près précis, voir git.wiki.kernel.org/index.php/ContentLimitations . Les autorisations exactes qui sont définies apparaissent en fonction du serveur et éventuellement du client umaskainsi que d'un paramètre de configuration, voir stackoverflow.com/a/12735291/125150 .
Motti Strom
12
@Ne le fera pas. Je ne peux pas croire que votre commentaire ait eu autant de votes positifs.
eis
@Will, c'est à peu près correct. Par les docs ...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

fonctionnera dans la plupart des cas, mais si vous avez des outils de diff externes comme meld installés, vous devez ajouter --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

était nécessaire dans ma situation

zainengineer
la source
0

J'utilise git de cygwin sur Windows, la git applysolution ne fonctionne pas pour moi. Voici ma solution, exécutez chmodsur chaque fichier pour réinitialiser ses autorisations.

#!/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
la source
-1

git diff -putilisé dans la réponse de muhqu peut ne pas montrer toutes les divergences.

  • vu cela dans Cygwin pour les fichiers que je ne possédais pas
  • les changements de mode sont complètement ignorés si core.filemodeest false(qui est la valeur par défaut pour MSysGit)

Ce code lit directement les métadonnées à la place:

(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)

Une doublure non destinée à la production (remplace entièrement les masques):

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

(Le crédit pour "$ '\ 0'" va à http://transnum.blogspot.ru/2008/11/bashs-read-built-in-supports-0-as.html )

ivan_pozdeev
la source
-2

La chose la plus simple à faire est de simplement revenir sur les autorisations. Comme @kroger l'a noté, git ne suit que les bits exécutables. Donc, vous avez probablement juste besoin de l'exécuter chmod -x filename(ou +xsi c'est ce qui est nécessaire).

Pat Notz
la source
Voici un exemple 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 peu en gras, il y a les autorisations de fichier.
Conrado
Cela me semblait aussi plus facile. Malheureusement, j'ai rencontré le même problème que Conrado - je ne pouvais pas changer l'autorisation de 100644à 100755. Je ne pense pas que vous méritez un downvote; Git devrait être rejeté. Il est tellement cassé à bien des égards à tellement de niveaux différents ...
jww
-2

L' etckeeperoutil peut gérer les autorisations et avec:

etckeeper init -d /mydir

Vous pouvez l'utiliser pour d'autres répertoires que /etc.

Installez en utilisant votre gestionnaire de paquets ou obtenez les sources du lien ci-dessus.

En savoir plus
la source
4
À quoi attribue-t-il les autorisations? S'il ne lit pas les métadonnées Git ou n'appelle pas Git, il ne fait pas ce que l'OP a demandé.
ivan_pozdeev