Сохранение прав доступа к файлам с помощью Git - PullRequest
95 голосов
/ 09 июля 2010

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

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

Ответы [ 8 ]

59 голосов
/ 09 июля 2010

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

См. Интерфейсы, веб-интерфейсы и инструменты страница на Git Wiki.

42 голосов
/ 09 июля 2010

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

Идея состоит в том, чтобы сохранить в файле .git_cache_meta разрешения для файлов и каталогов.
Это отдельный файл, не имеющий версий непосредственно в репозитории 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

Таким образом, вы:

  • связываете репо и сохраняете соответствующие разрешения на файлы.
  • скопировать эти два файла на удаленный сервер
  • восстановить репозиторий и применить разрешение
20 голосов
/ 02 июля 2016

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

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

Первый ловушка вызывается, когда вы «фиксируете» и считывает владельца и разрешения для всех файлов в хранилище и сохраняет их в файлев корне хранилища с именем .permissions, а затем добавьте файл .permissions в коммит.

Второй хук вызывается при «извлечении» и просматривает список файлов в файле .permissions ивосстановить владение и права доступа к этим файлам.

  • Возможно, вам потребуется выполнить фиксацию и извлечение с помощью sudo.
  • Убедитесь, что у сценариев до и после проверки есть разрешение на выполнение.,
2 голосов
/ 31 августа 2016

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

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

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

Есть несколько небольших проблем с именем каталога и наличием пробелов в именах файлов в скриптах Омида.Пространства были проблемой здесь, и у меня были некоторые проблемы с исправлением 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"

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

Файл .permissions находится на верхнем уровне 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

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

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

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

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

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

$ 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, как это было!Вы можете понять, почему сеанс оболочки может работать плохо, если вы оставите $ в качестве единственного разделителя.

1 голос
/ 17 мая 2019

Мы можем улучшить другие ответы, изменив формат файла .permissions на выполняемые операторы chmod и используя параметр -printf на find. Вот простой файл .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.

... а вот упрощенный .git/hooks/post-checkout файл:

#!/usr/bin/env bash

echo -n "Restoring file permissions... "

cd "$(git rev-parse --show-toplevel)"

. .permissions

echo "done."

Помните, что другие инструменты, возможно, уже настроили эти сценарии, поэтому вам может потребоваться объединить их. Например, вот скрипт post-checkout, который также включает команды 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 "$@"
1 голос
/ 25 мая 2018

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

Это также сохранит права доступа к каталогу.

1 голос
/ 19 февраля 2018

Я работаю на FreeBSD 11.1, концепция виртуализации freebsd jail делает операционную систему оптимальной.Текущая версия 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;

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

.gitignore;644;0;0

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

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

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

1 голос
/ 14 июля 2016

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...