Wie kann ich die Berechtigungen von Dateien und Verzeichnissen in git wiederherstellen, wenn sie geändert wurden?

278

Ich habe eine Git-Kasse. Alle Dateiberechtigungen unterscheiden sich von denen, die Git für richtig hält, daher werden sie alle als geändert angezeigt.

Wie setze ich alle Dateiberechtigungen auf das, was Git für richtig hält, ohne den Inhalt der Dateien zu berühren (ich möchte nur die Berechtigungen ändern)?

Dale Forester
quelle

Antworten:

572

Git verfolgt die Dateiberechtigung und macht Berechtigungsänderungen offen, wenn Patches mit erstellt werden git diff -p. Wir brauchen also nur:

  1. Erstellen Sie einen umgekehrten Patch
  2. Schließen Sie nur die Berechtigungsänderungen ein
  3. Wenden Sie den Patch auf unsere Arbeitskopie an

Als Einzeiler:

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

Sie können es auch als Alias ​​zu Ihrer Git-Konfiguration hinzufügen ...

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'

... und Sie können es aufrufen über:

git permission-reset

Beachten Sie, wenn Sie eine Shell verwenden bash, stellen Sie sicher, dass 'anstelle von "Anführungszeichen um das verwendet !gitwird. Andernfalls wird es durch den zuletzt ausgeführten gitBefehl ersetzt.

Vielen Dank an @Mixologic, um darauf hinzuweisen, dass durch einfaches Verwenden von -Ron git diffder umständliche sedBefehl nicht mehr erforderlich ist.

muhqu
quelle
3
Ich bin in OS X, das funktioniert nicht. Ich habe festgestellt, dass das Problem im Git liegt. Die Änderungen an den Dateiberechtigungen werden nicht angewendet.
Pepper_chico
15
Oh, es hat funktioniert, ich habe versucht, mich aus einem anderen Verzeichnis als dem Repository-Stammverzeichnis zu bewerben. git apply funktioniert nur dort.
Pepper_chico
6
Gibt es einen Grund, warum Sie nicht einfach "git diff -p -R" machen würden, anstatt die sed's zu machen, um es umzukehren?
Mixologic
6
@RobQuist meine lokalen Änderungen wurden nicht entfernt, als ich muhqu's Befehl
benutzte
17
Ich bekommefatal: unrecognized input
Tieme
120

Versuchen git config core.fileMode false

Von der git configManpage:

core.fileMode

Bei false werden die ausführbaren Bitunterschiede zwischen dem Index und der Arbeitskopie ignoriert. nützlich auf kaputten Dateisystemen wie FAT. Siehe git-update-index (1) .

Der Standardwert ist true, außer dass git-clone (1) oder git-init (1) core.fileMode prüfen und gegebenenfalls auf false setzen, wenn das Repository erstellt wird.

Tim Henigan
quelle
Danke, das habe ich letztendlich getan. Sehr gewöhnt an Lebensläufe, die keine Berechtigungen verfolgen, damit dies funktioniert.
Dale Forester
3
@shovas: Ich bin froh, dass dies geholfen hat. Beim Teilen von Repos zwischen Linux und Windows trat ein ähnliches Problem auf. Übrigens: Wenn dies Ihre Frage beantwortet hat, markieren Sie die Antwort bitte als richtig.
Tim Henigan
Ist es möglich, dass git checkout origin/masterfür den Server festgeschriebene Dateiberechtigungen auf meine lokale Arbeitskopie festgelegt werden? Denn jedes Mal, wenn ich V8 für ArangoDB erstelle, werden die Dateiberechtigungen so geändert, dass der Zugriff auf den gesamten Erstellungsordner verweigert wird (auch mit erhöhten Rechten; Windows 7+). Ich muss alle lokalen Dateiberechtigungen korrigieren, bevor ich den Erstellungsprozess fortsetzen kann. Kann das auch core.filemode falsebeheben? Ich vermute, dass Git Linux-Berechtigungen auf meinem Windows-Computer festlegen kann. Die Build-Skripte
behalten
Ich frage mich , ob es irgendeinen Nachteil Einstellung filemodezu false!
Kevoroid
11

Git speichert keine anderen Dateiberechtigungen als ausführbare Skripte. Erwägen Sie die Verwendung von git-cache-meta , um den Besitz und die Berechtigungen von Dateien zu speichern.

Git kann nur zwei Arten von Modi speichern: 755 (ausführbar) und 644 (nicht ausführbar). Wenn Ihre Datei 444 Git wäre, würde sie 644 speichern.

Kroger
quelle
14
Entschuldigung, aber das ist falsch. Git verfolgt tatsächlich Berechtigungen.
Will
4
Es ist ungefähr genau, siehe git.wiki.kernel.org/index.php/ContentLimitations . Die genauen Berechtigungen, die festgelegt werden, basieren auf dem Server und möglicherweise dem Client umasksowie einer Konfigurationseinstellung (siehe stackoverflow.com/a/12735291/125150) .
Motti Strom
12
@ Will nein, tut es nicht. Ich kann nicht glauben, dass dein Kommentar so viele positive Stimmen bekommen hat.
Eis
@ Will, das ist ungefähr richtig. Per 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

funktioniert in den meisten Fällen, aber wenn Sie externe Diff-Tools wie meld installiert haben, müssen Sie --no-ext-diff hinzufügen

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

wurde in meiner Situation gebraucht

Zainengineer
quelle
0

Ich benutze Git von Cygwin unter Windows, die git applyLösung funktioniert bei mir nicht. Hier ist meine Lösung: Führen Sie chmodjede Datei aus, um ihre Berechtigungen zurückzusetzen.

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

git diff -pIn Muhqus Antwort werden möglicherweise nicht alle Unstimmigkeiten angezeigt.

  • Ich habe dies in Cygwin für Dateien gesehen, die ich nicht besaß
  • Modusänderungen werden vollständig ignoriert, wenn dies der Fall core.filemodeist false(dies ist die Standardeinstellung für MSysGit).

Dieser Code liest stattdessen die Metadaten direkt:

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

Ein Einzeiler ohne Produktionsqualität (ersetzt Masken vollständig):

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

(Die Gutschrift für "$ '\ 0'" geht an http://transnum.blogspot.ru/2008/11/bashs-read-built-in-supports-0-as.html )

ivan_pozdeev
quelle
-2

Am einfachsten ist es, die Berechtigungen einfach wieder zu ändern. Wie @kroger feststellte, verfolgt git nur ausführbare Bits. Sie müssen also wahrscheinlich nur ausführen chmod -x filename, um das Problem zu beheben (oder +xwenn dies erforderlich ist).

Pat Notz
quelle
Hier ist ein Beispiel aus 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 Das Bit in Fettdruck gibt es die Dateiberechtigungen.
Conrado
Das schien mir auch am einfachsten zu sein. Leider habe ich das gleiche Problem wie Conrado festgestellt - ich konnte die Berechtigung nicht von 100644auf ändern 100755. Ich denke nicht, dass Sie eine Ablehnung verdienen; Git sollte abgewählt werden. Es ist auf so viele Arten auf so vielen verschiedenen Ebenen so kaputt ...
jww
-2

Das etckeeperTool kann Berechtigungen verarbeiten und mit:

etckeeper init -d /mydir

Sie können es für andere Verzeichnisse als verwenden /etc.

Installieren Sie mithilfe Ihres Paketmanagers oder beziehen Sie die Quellen über den obigen Link.

MoreIT
quelle
4
Wofür werden Berechtigungen festgelegt? Wenn es keine Git-Metadaten liest oder Git nicht aufruft, tut es nicht das, was das OP angefordert hat.
ivan_pozdeev