2010-07-08 9 views
83

Ich möchte meinen Webserver wie unter Version control for my web server beschrieben steuern, indem ich einen Git Repo aus meinem /var/www directory erstelle. Meine Hoffnung war, dass ich dann in der Lage sein würde, Web-Inhalte von unserem Dev-Server nach Github zu pushen, auf unseren Produktionsserver zu ziehen und den Rest des Tages am Pool zu verbringen.Dateiberechtigungen mit Git beibehalten

Offensichtlich ein Knick in meinem Plan ist, dass Git nicht Dateiberechtigungen respektieren wird (ich habe es nicht versucht, nur jetzt darüber zu lesen.) Ich denke, das macht Sinn, dass verschiedene Boxen unterschiedliche Benutzer haben können Gruppenkonfigurationen. Aber wenn ich die Weitergabe von Berechtigungen erzwingen möchte, wenn ich weiß, dass meine Server gleich konfiguriert sind, habe ich dann irgendwelche Optionen? Oder gibt es eine einfachere Möglichkeit, sich dem zu nähern, was ich versuche?

+1

möglich Duplikat [git - wie die Dateiberechtigungen git wiederherstellen denkt, dass die Datei enthalten sein sollte?] (Http://stackoverflow.com/questions/2517339/git-how-to-recover- the-file-permissions-git-thinks-the-file-sollte-sein) – kennytm

+0

Yeah rate so, obwohl die Lösung, auf die sie hinweisen, mir ehrlich gesagt nicht sicher ist, was ich damit anfangen soll. Hatte auf einen geradlinigeren Ansatz gehofft. – Yarin

+0

Wie sieht es mit der Situation aus, in der der Quellcode aus einer Entwicklungsumgebung stammt (z. B. Windows - XAMPP usw.), die keine Dateieigentümerinformationen hat? Dateien am Ende des Git-Prozesses müssen dem Besitz und den Berechtigungen für den Zielspeicherort entsprechen. Kann git-cache-meta damit umgehen? Stimme mit Yarin ... sicherlich ist das ein ziemlich Mainstream-Anwendungsfall, der eine ziemlich einfache Lösung haben sollte? – user3600150

Antwort

37

Die git-cache-meta in SO Frage "git - how to recover the file permissions git thinks the file should be?" (und die git FAQ erwähnt) ist die eher direkte Ansatz.

Die Idee ist, in einer .git_cache_meta Datei die Berechtigungen der Dateien und Verzeichnisse zu speichern.
Es ist eine separate Datei, die nicht direkt im Git Repo versioniert wird.

Aus diesem Grund dafür ist die Nutzung ist:

$ 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 

So Sie:

  • bundle your repo und die zugehörigen Dateiberechtigungen speichern.
  • kopieren, diese beiden Dateien auf dem entfernten Server
  • den Repo dort wieder herzustellen, und wenden Sie die Erlaubnis
+1

VonC - Danke dafür, ich werde es ausprobieren - aber ist das Bündeln notwendig? Konnte ich meinen Workflow nicht beibehalten (dev -> github -> production) und einfach die Metadatei checken/checken? – Yarin

+0

@Yarin: Nein, das Bündel ist nicht obligatorisch. Es ist eine gute Möglichkeit, Repo zu übertragen, wenn kein anderes Übertragungsprotokoll verfügbar ist. – VonC

+2

Die Verwendung von Bündel hier war eine große Ablenkung für mich. Das hat mich eigentlich völlig von der Antwort abgehalten. (Ich habe keine Schwierigkeiten, Repo vom Server zu ziehen.) @ Omid-ariyan's Antwort unten mit Pre/Post Commits war viel verständlicher. Später wurde mir klar, dass diese Hook-Skripte exakt die gleiche Arbeit machen wie git-cache-meta. Geh, was ich meine: https://gist.github.com/andris9/1978266. Sie analysieren und speichern die Rückgabe von 'git ls-files'. – pauljohn32

56

Git ist Version Control System, für die Softwareentwicklung erstellt, so aus dem ganzen Satz von Moden und Berechtigungen speichert nur das ausführbare Bit (für normale Dateien) und das Symlink-Bit. Wenn Sie die vollständigen Berechtigungen speichern möchten, benötigen Sie ein Tool von Drittanbietern, z. B. git-cache-meta (mentioned by VonC) oder Metastore (verwendet von etckeeper). Oder Sie können IsiSetup verwenden, die IIRC verwendet Git als Backend.

Siehe Interfaces, frontends, and tools Seite auf Git-Wiki.

+2

Danke Jakub - kannst du mir erklären, warum Git sich um das ausführbare Bit kümmert und nur das? – Yarin

+5

@Yarin: nur ausführbares Bit? Wenn Sie eine ganze Reihe von Dateien von einem System in ein anderes klonen, ist der Begriff "nur lesen" oder "lesen/schreiben" nicht genau relevant (wie Sie in Ihrer Frage sagten: verschiedene Benutzer/Gruppen). Aber der Begriff "ausführbar" hängt nicht von Benutzern und Gruppen ab und kann vom System zum (entfernten) System wiederverwendet werden. – VonC

+0

Ah richtig - das würde Sinn machen! – Yarin

16

Dies ist ziemlich spät, könnte aber einigen anderen helfen. Ich mache was du tun willst, indem du zwei Git-Hooks zu meinem Repository hinzufügst.

.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-Kasse:

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

Der erste Haken aufgerufen wird, wenn Sie "commit" und liest die Eigentumsrechte und Berechtigungen für alle Dateien im Repository und speichert sie in einer Datei im Stammverzeichnis des Repositorys namens .permissions und fügt dann die .permissions-Datei zum Commit hinzu.

Der zweite Hook wird aufgerufen, wenn Sie "auschecken" und die Liste der Dateien in der .permissions-Datei durchgehen und die Eigentumsrechte und Berechtigungen dieser Dateien wiederherstellen.

  • Möglicherweise müssen Sie das Commit und Checkout mit sudo durchführen.
  • Stellen Sie sicher, dass die Pre-Commit- und Post-Checkout-Skripten Ausführungsberechtigungen haben.
+0

Omid ... danke! Ich fand, dass dein Code eine perfekte Lösung für mich ist. – Ricalsin

+0

@Ricalsin Sie sind herzlich willkommen! Ich bin froh, dass ich geholfen habe :) –

+1

'$ SELF_DIR /../../' ist nicht unbedingt die Wurzel des Repository ... aber 'git rev-parse --show-toplevel' ist. (Nicht sicher, warum Sie 'pwd' nicht einfach für das aktuelle Verzeichnis verwenden würden, aber das ist sowieso egal.) – PJSCopeland

1

In pre-commit/Post-Kasse wäre eine Option "mtree" (FreeBSD) oder "fmtree" (Ubuntu) Dienstprogramm, das „vergleicht eine Dateihierarchie gegen eine Spezifikation zu verwenden ist, erstellt eine Spezifikation für eine Dateihierarchie oder ändert eine Spezifikation. "

Die Standardeinstellungen sind Flags, GID, Link, Modus, Nlink, Größe, Zeit, Typ und UID. Dies kann für den speziellen Zweck mit dem Schalter -k angepasst werden.

2

Für den Fall, dass Sie gerade jetzt kommen, ich habe es gerade durchgemacht und kann zusammenfassen, wo das steht. Wenn Sie dies noch nicht versucht haben, könnten einige Details hier helfen.

Ich denke @Omid Ariyan Ansatz ist der beste Weg. Fügen Sie die Skripts vor und nach der Überprüfung hinzu. Vergessen Sie NICHT, sie genau so zu benennen wie Omid und vergessen Sie nicht, sie ausführbar zu machen. Wenn Sie eines davon vergessen, haben sie keine Wirkung und Sie lassen "git commit" immer wieder laufen und fragen sich, warum nichts passiert :) Wenn Sie aus dem Webbrowser ausschneiden und einfügen, achten Sie darauf, dass die Anführungszeichen und Ticks nicht sind verändert.

Wenn Sie das Vorab-Commit-Skript einmal ausführen (indem Sie einen Git-Commit ausführen), wird die Datei .permissions erstellt. Sie können es dem Repository hinzufügen und ich denke, es ist nicht notwendig, es am Ende des Vorab-Commits-Skripts immer wieder hinzuzufügen. Aber es tut nicht weh, denke ich (hoffe).

Es gibt ein paar kleine Probleme mit dem Verzeichnisnamen und dem Vorhandensein von Leerzeichen in den Dateinamen in Omids Skripten. Die Leerzeichen waren hier ein Problem und ich hatte einige Probleme mit dem IFS-Update. Für die Aufzeichnung dieses Skript pre-commit richtig für mich arbeiten:

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

Nun, was wir daraus herauskommen?

Die Datei .permissions befindet sich auf der obersten Ebene des Git Repos. Es hat eine Zeile pro Datei, hier ist die Spitze von meinem Beispiel:

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

Wie Sie sehen können, wir

filepath;perms;owner;group 

In den Kommentaren zu diesem Ansatz haben, einer des Plakats beklagt, dass es funktioniert nur mit demselben Benutzernamen, und das ist technisch wahr, aber es ist sehr einfach, es zu beheben. Beachten Sie die Post-Kasse Skript 2 Aktion Stücke hat,

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

So bin ich nur die erste zu halten, das ist alles, was ich brauche. Mein Benutzername auf dem Web-Server ist in der Tat anders, aber was noch wichtiger ist, Sie können Chown nicht ausführen, wenn Sie root sind. Kann "chgrp" jedoch ausführen. Es ist klar genug, wie man das verwenden kann.

In der ersten Antwort in diesem Post, die am weitesten akzeptiert wird, ist der Vorschlag, so git-cache-meta, ein Skript, das die gleiche Arbeit macht, die die Pre/Post-Hook-Skripte hier tun (Analyseausgabe von git ls-files). Diese Skripte sind für mich einfacher zu verstehen, der Git-Cache-Meta-Code ist etwas aufwendiger. Es ist möglich, git-cache-meta im Pfad zu belassen und Skripts für die Vorab-Commits und Post-Checkouts zu schreiben, die es verwenden würden.

Leerzeichen in Dateinamen sind ein Problem mit beiden Skripten von Omid. In der Post-Checkout-Skript, wissen Sie, Sie die Leerzeichen in Dateinamen, wenn Sie Fehler wie diese sehen

$ 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 

ich auf Lösungen für die ich überprüft. Hier ist etwas, das scheint zu funktionieren, aber ich habe nur in einem Fall

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

Da die Berechtigungsinformationen sind eine Zeile zu einem Zeitpunkt getestet, habe ich IFS auf $, so dass nur Zeilenumbrüche werden als neue Dinge gesehen.

Ich habe gelesen, dass es sehr wichtig ist, die IFS-Umgebungsvariable zurückzusetzen, wie es war! Sie können sehen, warum eine Shell-Session schlecht läuft, wenn Sie $ als einziges Trennzeichen beibehalten.

1

Ich bin auf FreeBSD 11.1 ausgeführt, das freebsd jail Virtualisierungskonzept macht das Betriebssystem optimal. Die aktuelle Version von Git, die ich benutze, ist 2.15.1, ich bevorzuge es auch, alles mit Shell-Skripten auszuführen. In diesem Sinne geändert ich die Vorschläge oben wie folgt:

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"; 

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

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

printf "OK\n"; 

git pull: .git/hooks/post-merge

#! /bin/sh - 

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

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

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

pritnf "OK\n"; 

exit 0 

Wenn aus irgendeinem Grund müssen Sie das Skript die .permissions Dateiausgabe erstellen sollte folgendes Format haben:

.gitignore;644;0;0 

Für eine .gitignore-Datei mit 644 Berechtigungen für root: rad

Beachten Sie, dass ich einige Änderungen an den Statistikoptionen vornehmen musste.

Genießen,

Verwandte Themen