Git으로 파일 권한 유지


109

.NET에서 git repo를 만들어 내 웹 서버의 버전 관리에 설명 된대로 내 웹 서버의 버전을 제어하고 싶습니다 /var/www directory. 내 희망은 개발 서버에서 github로 웹 콘텐츠를 푸시하고 프로덕션 서버로 가져 와서 하루 종일 풀에서 보낼 수 있기를 바랍니다.

분명히 내 계획의 꼬임은 Git이 파일 권한을 존중하지 않는다는 것입니다. 하지만 내 서버가 동일하게 구성되어 있음을 알고 권한을 강제로 전파하려는 경우 옵션이 있습니까? 아니면 내가하려는 일에 접근하는 더 쉬운 방법이 있습니까?



1
예, 그들이 지적하는 해결책은 솔직히 무엇을 해야할지 잘 모르겠습니다. 보다 간단한 접근 방식을 원했습니다.
Yarin

파일 소유권 정보가없는 Dev 환경 (예 : Windows-XAMPP 등)에서 소스 코드가 나오는 상황은 어떻습니까? git 프로세스 끝의 파일은 대상 위치에 대한 소유권 및 권한과 일치해야합니다. git-cache-meta가 이것을 다룰 수 있습니까? Yarin과 동의합니다 ... 확실히 이것은 꽤 일반적인 사용 사례입니다. 꽤 간단한 솔루션이 있어야합니까?
user3600150

답변:


43

git-cache-meta"SO 질문에서 언급 ? 자식 - 어떻게 파일이 있어야한다 생각 자식 파일 권한을 복구하는 "(그리고 자식 자주 묻는 질문 ) 더 staightforward 방법입니다.

아이디어는 .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

그래서 당신은:

  • repo를 번들로 묶고 관련 파일 권한을 저장하십시오.
  • 이 두 파일을 원격 서버에 복사하십시오.
  • 거기에 저장소를 복원하고 권한을 적용하십시오.

2
VonC- 감사합니다. 시험해 볼게요. 번들링이 필요한가요? 내 워크 플로 (dev-> github-> production)를 유지하고 메타 파일을 체크인 / 체크 아웃 할 수 없습니까?
Yarin

@Yarin : 아니요, 번들은 필수가 아닙니다. 다른 전송 프로토콜을 사용할 수 없을 때 repo를 전송하는 깔끔한 방법입니다.
VonC

3
여기서 번들을 사용하는 것은 저에게 큰 혼란이었습니다. 사실 그것은 답을 완전히 잃어 버렸습니다. (서버에서 repo를 가져 오는 데 어려움이 없습니다.) 아래 @ omid-ariyan의 사전 / 사후 커밋 후크에 대한 답변은 훨씬 더 이해하기 쉽습니다. 나중에 그 후크 스크립트가 git-cache-meta와 똑같은 작업을 수행한다는 것을 깨달았습니다. 내가 의미하는 바를 확인하십시오 : gist.github.com/andris9/1978266 . 그들은에서 반환을 구문 분석하고 저장하고 있습니다 git ls-files.
pauljohn32

git-cache-meta에 대한 링크가 죽었습니다-이것에 대해 아는 사람이 그것을 찾고 게시물을 편집 할 수 있습니까?
rosuav

@rosuav 물론입니다 : 답변을 수정하고 링크를 복원했습니다. 이 죽은 링크를 알려 주셔서 감사합니다.
VonC

63

Git은 소프트웨어 개발을 위해 만들어진 버전 제어 시스템이므로 전체 모드 및 권한 집합에서 실행 가능한 비트 (일반 파일의 경우) 및 심볼릭 링크 비트 만 저장합니다. 전체 권한을 저장하려면 git-cache-meta( VonC에서 언급 ) 또는 Metastore ( etckeeper에서 사용 ) 와 같은 타사 도구가 필요합니다 . 또는 IIRC가 git을 백엔드로 사용 하는 IsiSetup 을 사용할 수 있습니다 .

참조 인터페이스, 프론트 엔드 및 도구 힘내 위키 페이지.


2
감사합니다 Jakub- Git이 실행 가능한 비트에만 관심을 갖는 이유를 설명해 주시겠습니까?
Yarin

5
@Yarin : 실행 가능한 비트 만? 한 시스템에서 다른 시스템으로 모든 파일 세트를 복제 할 때 "읽기 전용"또는 "읽기-쓰기"라는 개념은 정확히 관련이 없습니다 (질문 : 다른 사용자 / 그룹에서 말했듯이). 그러나 "실행 가능"이라는 개념은 사용자와 그룹에 의존하지 않으며 시스템에서 (원격) 시스템으로 재사용 할 수 있습니다.
VonC

1
Jakub,이 경우 권한을 변경 해서는 안됩니다 . 내 말은, 파마를 그대로 두거나 관리해야하지만 관리하지 않을 거라고해서 엉망이되지 않아야한다는 것입니다.
CommaToast

3
또한 /usr/share/git-core/contrib/hooks/setgitperms.perlgit-contrib패키지에서 비슷한 목적을위한 스크립트를 찾았 습니다 . ( "이 스크립트는 git 작업 트리 내에서 전체 권한 및 소유권 데이터를 저장 / 복원하는 데 사용할 수 있습니다.")
imz-Ivan Zakharyaschev

이것이 여전히 정확합니까, 아니면 github가 어떻게 든 git 위에 뭔가를합니까? 방금 파일을 실행 파일로 변경하고 커밋했는데 커밋에 대한 변경 로그가 파일에 대해 0 줄이 변경된 것으로 표시되지만 파일 이름 옆에 100644 → 100755가 있습니다. 이것은 실제로 전체 권한이 파일과 함께 저장된 것처럼 보입니다.
Cruncher

23

이것은 꽤 늦었지만 다른 사람들에게 도움이 될 수 있습니다. 내 저장소에 두 개의 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 파일을 커밋에 추가합니다.

두 번째 후크는 "체크 아웃"할 때 호출되며 .permissions 파일의 파일 목록을 살펴보고 해당 파일의 소유권과 권한을 복원합니다.

  • sudo를 사용하여 커밋 및 체크 아웃을 수행해야 할 수도 있습니다.
  • 사전 커밋 및 사후 체크 아웃 스크립트에 실행 권한이 있는지 확인합니다.

오 미드 ... 감사합니다! 귀하의 코드가 저에게 완벽한 솔루션이라는 것을 알았습니다.
Ricalsin 2016-07-04

@Ricalsin 천만에요! 나는 :) 도움이 기쁘다
오 미드 아리 얀족

1
$SELF_DIR/../../반드시 저장소의 루트가 아닌 ...하지만 git rev-parse --show-toplevel입니다. (왜 pwd현재 디렉토리를 사용하지 않는지 확실하지 않지만 어쨌든 문제가 있습니다.)
PJSCopeland

위의 내용은 파일 이름을 공백으로 분할합니다. 당 이 답변 , 당신은 설정할 수 있습니다 IFS=$'\n'전과 for(그 중지 루프 unset IFS안전을 위해 이후).
PJSCopeland

이것은 다른 사용자 이름을 가진 다른 OS를 사용하는 다른 시스템으로 권한을 쉽게 전달할 수 없습니다. "정말 필요한 게 뭐야?" 전체 솔루션 chmod 0600 .pgpasspost-checkout. 예, 특정 권한이 필요한 파일이있을 때마다 수동으로 업데이트해야하지만 그게 바로 중단입니다.
PJSCopeland

2

지금 당장이 문제를 겪고 계신다면, 저는 오늘 그것을 겪었고 이것이 어디에 있는지 요약 할 수 있습니다. 아직 시도하지 않았다면 여기에 몇 가지 세부 정보가 도움이 될 수 있습니다.

@Omid Ariyan의 접근 방식이 가장 좋은 방법이라고 생각합니다. 사전 커밋 및 사후 체크 아웃 스크립트를 추가합니다. Omid가하는 것과 정확히 같은 이름을 지정하는 것을 잊지 말고 실행 가능하게 만드는 것을 잊지 마십시오. 둘 중 하나를 잊어 버리면 효과가없고 "git commit"을 계속 실행하여 아무 일도 일어나지 않는 이유를 궁금해합니다. :) 또한 웹 브라우저에서 잘라내어 붙여 넣는 경우 따옴표와 틱이 표시되지 않도록주의하십시오. 변경.

git commit을 실행하여 pre-commit 스크립트를 한 번 실행하면 .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 repo의 최상위 수준에 있습니다. 파일 당 한 줄이 있으며 여기에 내 예제의 맨 위가 있습니다.

$ 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

이 접근 방식에 대한 의견에서 한 포스터는 동일한 사용자 이름으로 만 작동하며 기술적으로는 사실이지만 고치는 것은 매우 쉽다고 불평합니다. 체크 아웃 후 스크립트에는 2 개의 작업 부분이 있습니다.

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

그래서 나는 첫 번째 것만 유지하고 있습니다. 그게 내가 필요한 전부입니다. 웹 서버의 사용자 이름은 실제로 다르지만 더 중요한 것은 루트가 아니면 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

나는 그것에 대한 해결책을 확인하고 있습니다. 작동하는 것처럼 보이지만 한 가지 경우에만 테스트했습니다.

#!/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 환경 변수를 원래대로 설정하는 것이 매우 중요하다는 것을 읽었습니다! $를 유일한 구분자로 남겨두면 쉘 세션이 왜 잘못 될 수 있는지 알 수 있습니다.


2

.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

사전 커밋 / 사후 체크 아웃에서 옵션은 "파일 계층 구조를 사양과 비교하거나, 파일 계층 구조에 대한 사양을 생성하거나, 사양."

기본 세트는 flags, gid, 링크, 모드, nlink, 크기, 시간, 유형 및 uid입니다. -k 스위치를 사용하여 특정 목적에 맞출 수 있습니다.


1

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

root : wheel에 644 권한이 부여 된 .gitignore 파일의 경우

통계 옵션을 몇 가지 변경해야했습니다.

즐겨,


1

@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

이렇게하면 디렉토리 권한도 저장됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.