Сохранение прав доступа к файлам с помощью Git

Я хочу контролировать версию моего веб-сервера, как описано в контроля версий для моего веб-сервера, создав git-РЕПО из моего /var/www directory. Я надеялся, что тогда я смогу перенести веб-контент с нашего dev-сервера на github, вытащить его на наш производственный сервер и провести остаток дня в пуле.

по-видимому, излом в моем плане заключается в том, что Git не будет уважать права доступа к файлам (я не пробовал, только читал об этом сейчас.) Я думаю, это имеет смысл в что разные коробки могут иметь разные настройки пользователя/группы. Но если бы я хотел заставить разрешения распространяться, зная, что мои серверы настроены одинаково, есть ли у меня какие-либо варианты? Или есть более простой способ, что я пытаюсь сделать?

7 ответов


на git-cache-meta упоминается в так вопрос"git-как восстановить права доступа к файлу git думает, что файл должен быть?" (и git FAQ) является более staightforward подход.

идея в том, чтобы хранить в .git_cache_meta file разрешения файлов и каталогов.
Это отдельный файл, не версионный непосредственно в репозитории Git.

вот почему использование это:

$ 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

Так ты:

  • bundle ваше РЕПО и сохраните соответствующие права доступа к файлам.
  • скопируйте эти два файла на удаленный сервер
  • восстановить РЕПО там, и применить разрешение

Git-это система управления версиями, созданная для разработки программного обеспечения, поэтому из всего набора режимов и разрешений она хранит только исполняемый бит (для обычных файлов) и бит символической ссылки. Если вы хотите сохранить полные разрешения, вам нужен сторонний инструмент, например git-cache-meta (упоминается VonC), или Метахранилища (используется etckeeper). Или вы можете использовать IsiSetup, который IIRC использует git в качестве бэкэнда.

посмотреть интерфейсы, интерфейсы и инструменты страница на Git Wiki.


Это довольно поздно, но может помочь некоторым другим. Я делаю то, что вы хотите сделать, добавив два крючка git в мой репозиторий.

.git / hooks / предварительная фиксация:

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

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

первый крючок вызывается, когда вы" фиксируете " и будете читать права собственности и разрешения для всех файлов в репозитории и хранить их в файле в корне вызываемого репозитория .разрешения, а затем добавить .файл разрешений для фиксации.

второй крюк вызывается, когда вы "checkout" и будет проходить через список файлов в .файл разрешений и восстановить права собственности и разрешения этих файлов.

  • вам может потребоваться выполнить фиксацию и проверку с помощью sudo.
  • убедитесь, что сценарии pre-commit и post-checkout имеют разрешение на выполнение.

в случае, если вы входите в это прямо сейчас, я только что прошел через это сегодня и могу подвести итог, где это стоит. Если вы еще не пробовали это, некоторые детали здесь могут помочь.

Я думаю, что подход @Omid Ariyan-лучший способ. Добавьте сценарии pre-commit и post-checkout. Не забудьте назвать их точно так же, как это делает Omid, и не забудьте сделать их исполняемыми. Если вы забудете любой из них, они не имеют никакого эффекта, и вы запускаете "git commit" снова и снова, задаваясь вопросом, почему ничего не происходит:) кроме того, если вы вырезаете и вставляете из веб-браузера, будьте осторожны, чтобы кавычки и галочки не были изменены.

если вы запустите сценарий предварительной фиксации один раз (запустив git commit), то файл .будут созданы разрешения. Вы можете добавить его в репозиторий, и я думаю, что нет необходимости добавлять его снова и снова в конце сценария предварительной фиксации. Но это не больно, я думаю (надеюсь).

есть несколько небольших проблем с именем каталога и наличие пробелов в именах файлов в сценариях Omid. Пробелы были проблемой здесь, и у меня были некоторые проблемы с исправлением IFS. Для записи этот сценарий предварительной фиксации работал правильно для меня:

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

теперь, что мы получим от этого?

The .файл разрешений находится на верхнем уровне репозитория git. Он имеет одну строку на файл, вот верхняя часть моего примера:

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

как вы можете видеть, у нас есть

filepath;perms;owner;group

в комментариях о этот подход, один из плакатов жалуется, что он работает только с тем же именем пользователя, и это технически верно, но это очень легко исправить. Обратите внимание, что скрипт post-checkout имеет 2 части действия,

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

поэтому я оставляю только первый, это все, что мне нужно. Мое имя пользователя на веб-сервере действительно отличается, но что более важно, вы не можете запустить chown, если вы не корень. Может запустить "chgrp", однако. Достаточно ясно, как это использовать.

в первом ответ в этом посте, тот, который наиболее широко принят, предложение так использовать git-cache-meta, скрипт, который выполняет ту же работу, что и скрипты крючка pre / post здесь (разбор вывода из git ls-files). Эти скрипты мне легче понять, код git-cache-meta более сложный. Можно сохранить git-cache-meta в пути и написать сценарии предварительной фиксации и после проверки, которые будут его использовать.

пробелы в именах файлов-это проблема с обоими Скрипты этого Omid. В сценарии post-checkout вы будете знать, что у вас есть пробелы в именах файлов, если вы видите такие ошибки

$ 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

Я проверяю решения для этого. Вот то, что, кажется, работает, но я тестировал только в одном случае

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

поскольку информация о разрешениях является одной строкой за раз, я устанавливаю IFS в$, Поэтому только разрывы строк рассматриваются как новые вещи.

Я читал, что очень важно установить переменную среды IFS обратно так, как она был! Вы можете понять, почему сеанс оболочки может пойти плохо, если вы оставите $ единственным разделителем.


в pre-commit / post-checkout опция будет использовать утилиту" mtree "(FreeBSD) или" Fmtree "(Ubuntu), которая " сравнивает файловую иерархию со спецификацией, создает спецификацию для файловой иерархии или изменяет спецификацию."

по умолчанию установлены флаги, gid, link, mode, nlink, size, time, type и uid. Это можно приспосабливать к специфической цели с переключателем-k.


Я работаю на FreeBSD 11.1, концепция виртуализации тюрьмы freebsd делает операционную систему оптимальной. Текущая версия Git, которую я использую, - 2.15.1, я также предпочитаю запускать все на сценариях оболочки. Имея это в виду, я изменил приведенные выше предложения следующим образом:

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-merge

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

Если по какой-то причине вам нужно, чтобы воссоздать сценарий .разрешения вывод файла должен иметь следующий формат:

.gitignore;644;0;0

для a .файл gitignore с 644 разрешениями, предоставленными root: wheel

обратите внимание, что мне пришлось внести несколько изменений в параметры stat.

наслаждайтесь,


одно дополнение к ответу @Omid Ariyan-это разрешения на каталоги. Добавьте это после for петли done в своем 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

Это также сохранит разрешения каталога.