web-dev-qa-db-ja.com

Gitでファイルのアクセス許可を保持する

Webサーバーのバージョン管理 で説明されているように、/var/www directoryからgitリポジトリを作成して、Webサーバーをバージョン管理します。私の希望は、その後、開発サーバーからgithubにWebコンテンツをプッシュし、それを運用サーバーにプルし、残りの時間をプールで過ごすことができるようになることでした。

どうやら私の計画の欠点は、Gitがファイルのアクセス許可を尊重しないことです(私はそれを試したことはありませんが、今それについて読んでいます)。しかし、サーバーが同じように構成されていることを知って、許可を強制的に伝達したい場合、オプションはありますか?または、私がやろうとしていることに近づく簡単な方法はありますか?

97
Yarin

git-cache-meta SO question " 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

だからあなた:

  • レポをバンドルし 、関連するファイル許可を保存します。
  • これらの2つのファイルをリモートサーバーにコピーします
  • そこにリポジトリを復元し、許可を適用します
43
VonC

Gitはソフトウェア開発用に作成されたバージョン管理システムであるため、モードとアクセス許可のセット全体から、実行可能ビット(通常のファイル用)とシンボリックリンクビットのみを格納します。完全な権限を保存する場合は、 git-cache-metaVonCによる言及 )、または Metastore (- etckeeper )。または、 IsiSetup を使用できます。IIRCはgitをバックエンドとして使用します。

インターフェース、フロントエンド、およびツール Git Wikiのページを参照してください。

60
Jakub Narębski

これはかなり遅いですが、他の人を助けるかもしれません。リポジトリに2つの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 permissions..."

IFS_OLD=$IFS; IFS=$'\n'
for FILE in `git ls-files --full-name`
do
   # Save the permissions of all the files in the index
   echo $FILE";"`stat -c "%a;%U;%G" $FILE` >> $DATABASE
done

for DIRECTORY in `git ls-files --full-name | xargs -n 1 dirname | uniq`
do
   # Save the permissions of all the directories in the index
   echo $DIRECTORY";"`stat -c "%a;%U;%G" $DIRECTORY` >> $DATABASE
done
IFS=$IFS_OLD

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

echo "OK"

。git/hooks/post-checkout:

#!/bin/bash

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

echo -n "Restoring permissions..."

IFS_OLD=$IFS; IFS=$'\n'
while read -r LINE || [[ -n "$LINE" ]];
do
   ITEM=`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/directory permissions
   chmod $PERMISSIONS $ITEM

   # Set the file/directory owner and groups
   chown $USER:$GROUP $ITEM

done < $DATABASE
IFS=$IFS_OLD

echo "OK"

exit 0

最初のフックは、「コミット」するときに呼び出され、リポジトリ内のすべてのファイルの所有権と権限を読み取り、リポジトリのルートにある.permissionsというファイルに保存してから、.permissionsファイルをコミットに追加します。

2番目のフックは、「チェックアウト」するときに呼び出され、.permissionsファイル内のファイルのリストを調べて、それらのファイルの所有権と許可を復元します。

  • Sudoを使用して、コミットとチェックアウトが必要になる場合があります。
  • コミット前およびチェックアウト後のスクリプトに実行権限があることを確認してください。
21
Omid Ariyan

あなたが今ここに来ている場合のために、私は今日それをちょうど通り過ぎて、これが立っている場所を要約することができます。これをまだ試していない場合は、ここで詳細を確認してください。

@Omid Ariyanのアプローチが最良の方法だと思います。コミット前およびチェックアウト後のスクリプトを追加します。 Omidと同じ名前を付けることを忘れないでください。また、実行可能にすることを忘れないでください。これらのいずれかを忘れた場合、効果はなく、何も起こらないので「git commit」を繰り返し実行します。変更されました。

(git commitを実行して)事前コミットスクリプトを1回実行すると、ファイル.permissionsが作成されます。リポジトリに追加できますが、プリコミットスクリプトの最後に何度も追加する必要はないと思います。しかし、それは痛くない、と思います(希望)。

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"

さて、これから何を得るのでしょうか?

.permissionsファイルはgitリポジトリの最上位にあります。ファイルごとに1行あります。ここに私の例の先頭を示します。

$ 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

このアプローチに関するコメントでは、ポスターの1人が、同じユーザー名でしか機能しないと文句を言っています。技術的には正しいですが、修正するのは非常に簡単です。チェックアウト後のスクリプトには2つのアクションがあり、

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

だから私は最初のものだけを保持している、それは私が必要とするすべてです。 Webサーバー上のユーザー名は確かに異なりますが、さらに重要なことは、rootでない限りchownを実行できないことです。ただし、「chgrp」を実行できます。それを使用する方法は十分に明白です。

最も広く受け入れられているこの投稿の最初の回答では、提案はgit-cache-metaを使用することです。このスクリプトは、ここでのプリ/ポストフックスクリプトと同じ作業を行っています(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

私はそのためのソリューションをチェックしています。うまくいくように見えるものがありますが、私は1つのケースでしかテストしていません

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

許可情報は一度に1行なので、IFSを$に設定し、改行のみが新しいものとして認識されるようにします。

IFS環境変数を以前の状態に戻すことは非常に重要だと読みました! $を唯一の区切り文字として残すと、シェルセッションがうまくいかない理由がわかります。

2
pauljohn32

コミット前/チェックアウトのオプションは、「mtree」(FreeBSD)または「fmtree」(Ubuntu)ユーティリティを使用することです。このユーティリティは、「ファイル階層を仕様と比較し、ファイル階層の仕様を作成するか、仕様。"

デフォルトセットは、flags、gid、link、mode、nlink、size、time、type、およびuidです。これは、-kスイッチを使用して特定の目的に適合させることができます。

1
Vladimir Botka

@Omid Ariyanの答えに加えて、ディレクトリのアクセス許可があります。これを彼のpre-commitスクリプトのforループのdoneの後に追加します。

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
Peter Berbec

FreeBSD 11.1を実行しています。freebsdjail仮想化の概念により、オペレーティングシステムが最適になります。私が使用している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

Root:wheelに644権限が付与された.gitignoreファイルの場合

Statオプションにいくつかの変更を加える必要があることに注意してください。

楽しい、

1
Albaro Pereyra

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