Dosya izinlerini Git ile koruma


109

Web sunucumun sürüm kontrolü bölümünde açıklandığı gibi web sunucumdan bir git deposu oluşturarak sürüm kontrolü yapmak istiyorum /var/www directory. Umudum, web içeriğini dev sunucumuzdan github'a aktarabilmem, üretim sunucumuza çekebilmem ve günün geri kalanını havuzda geçirebilmemdi.

Görünüşe göre planımdaki bir karışıklık, Git'in dosya izinlerine saygı göstermemesidir (denemedim, sadece şimdi okuyorum). Sanırım bu, farklı kutuların farklı kullanıcı / grup kurulumlarına sahip olması nedeniyle mantıklı geliyor. Ancak, sunucularımın aynı şekilde yapılandırıldığını bilerek izinleri yaymaya zorlamak istersem, herhangi bir seçeneğim var mı? Yoksa yapmaya çalıştığım şeye yaklaşmanın daha kolay bir yolu var mı?



1
Evet, sanırım öyle, işaret ettikleri çözüm açıkçası ne yapacağımdan emin değilim. Daha basit bir yaklaşım umuyordum.
Yarin

Kaynak kodun dosya sahipliği bilgisine sahip olmayan Dev ortamından (örn. Windows - XAMPP vb.) Geldiği durum ne olacak? Git işleminin sonundaki dosyalar, hedef konum için sahiplik ve izinlerle eşleşmelidir. Git-cache-meta bununla başa çıkabilir mi? Yarin ile aynı fikirdeyim ... kesinlikle bu oldukça yaygın bir kullanım durumu, oldukça basit bir çözümü olmalı?
user3600150

Yanıtlar:


43

git-cache-meta"SO soru sözü ? GIT - nasıl dosya olması gerektiğini düşünüyor git dosya izinlerini kurtarmak için " (ve git SSS ) daha staightforward yaklaşımdır.

Buradaki fikir, .git_cache_metadosyaların ve dizinlerin izinlerini bir dosyada saklamaktır .
Doğrudan Git deposunda sürümü olmayan ayrı bir dosyadır.

Bunun için kullanım nedeni budur:

$ 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

Yani sen:

  • deponuzu paketleyin ve ilişkili dosya izinlerini kaydedin.
  • bu iki dosyayı uzak sunucuya kopyala
  • depoyu oraya geri yükle ve izni uygula

2
VonC- Bunun için teşekkürler, deneyeceğim- ama paket gerekli mi? İş akışımı (dev -> github -> üretim) saklayıp sadece meta dosyasını kontrol edemez miyim?
Yarin

@Yarin: hayır, paket zorunlu değil. Başka bir aktarım protokolü bulunmadığında repo aktarmanın düzgün bir yoludur.
VonC

3
Burada bohça kullanımı benim için büyük bir dikkat dağıtıcı oldu. Aslında beni tamamen cevaptan uzaklaştırdı. (Sunucudan repo çekmekte zorlanmıyorum.) @ Omid-ariyan'ın aşağıdaki ön / son commit kancaları ile cevabı çok daha anlaşılırdı. Daha sonra bu kanca betiklerinin git-cache-meta ile tamamen aynı işi yaptığını fark ettim. Ne demek istediğimi görün: gist.github.com/andris9/1978266 . Geri dönüşü ayrıştırıyor ve depoluyorlar git ls-files.
pauljohn32

Git-cache-meta bağlantısı kesildi - bunu bilen biri onu bulabilir ve gönderiyi düzenleyebilir mi?
rosuav

@rosuav Elbette: Cevabı düzenledim ve bağlantıyı geri yükledim. Bu ölü bağlantıyı bana bildirdiğiniz için teşekkür ederim.
VonC

63

Git, yazılım geliştirme için oluşturulmuş Sürüm Kontrol Sistemidir, bu nedenle tüm modlar ve izinlerden yalnızca çalıştırılabilir biti (sıradan dosyalar için) ve symlink bitini depolar. Tam izinleri saklamak istiyorsanız, git-cache-meta( VonC tarafından bahsedilir ) veya Metastore ( etckeeper tarafından kullanılır ) gibi üçüncü taraf araca ihtiyacınız vardır . Veya IIRC'nin git'i arka uç olarak kullandığı IsiSetup'ı kullanabilirsiniz .

Bkz arabirimleri, önyüzleridir ve araçlar Git Wiki sayfa.


2
Teşekkürler Jakub- Git'in çalıştırılabilir biti neden önemsediğini ve sadece bunu açıklar mısınız?
Yarin

5
@Yarin: sadece çalıştırılabilir bit mi? Bir sistemden diğerine tüm dosya kümelerini klonladığınızda, "salt okunur" veya "okuma-yazma" kavramı tam olarak alakalı değildir (sorunuzda söylediğiniz gibi: farklı kullanıcılar / gruplar). Ancak "yürütülebilir" kavramı, kullanıcılara ve gruplara bağlı değildir ve sistemden (uzak) sisteme yeniden kullanılabilir.
VonC

1
Jakub, bu durumda izinleri değiştirmemeli . Demek istediğim, permaları yalnız bırakmalı veya yönetmeli, ancak onları yönetmeyecekse onlarla uğraşmamalı.
CommaToast

3
Ayrıca, ben buldum /usr/share/git-core/contrib/hooks/setgitperms.perlbenim de git-contribbenzer bir amaç için package-- bir senaryo. ("Bu komut dosyası, bir git çalışma ağacındaki tüm izinleri ve sahiplik verilerini kaydetmek / geri yüklemek için kullanılabilir.")
imz - Ivan Zakharyaschev

Bu hala doğru mu yoksa github bir şekilde git üzerine bir şeyler yapıyor mu? Bir dosyayı çalıştırılabilir olarak değiştirdim ve teslim ettim ve commit için değişiklik günlüğü dosya için 0 satır değişti olarak görünüyor, ancak dosya adının yanında 100644 → 100755 var. Bu gerçekten tam izinler dosyada saklanmış gibi görünüyor.
Cruncher

23

Bu oldukça geç ama bazılarına yardımcı olabilir. Depomuza iki git kancası ekleyerek yapmak istediğinizi yapıyorum.

.git / kanca / pre-tamamlama:

#!/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 / kanca / sonrası çıkış:

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

İlk kanca "commit" yaptığınızda çağrılır ve depodaki tüm dosyaların sahipliğini ve izinlerini okuyacak ve bunları deponun kökünde .permissions olarak adlandırılan bir dosyada saklayacak ve ardından .permissions dosyasını commit'e ekleyecektir.

İkinci kanca, "teslim aldığınızda" çağrılır ve .permissions dosyasındaki dosyaların listesinden geçecek ve bu dosyaların sahipliğini ve izinlerini geri yükleyecektir.

  • Kaydetmeyi ve kontrol etmeyi sudo kullanarak yapmanız gerekebilir.
  • İşlem öncesi ve teslim sonrası komut dosyalarının yürütme iznine sahip olduğundan emin olun.

Omid ... teşekkür ederim! Kodunuzu benim için mükemmel bir çözüm olarak buldum.
Ricalsin

@Ricalsin Çok hoş geldiniz!
Yardımcı

1
$SELF_DIR/../../havuzun kökü olmak zorunda değil ... ama git rev-parse --show-toplevelöyle. (Neden sadece pwdgeçerli dizin için kullanmayacağınızdan emin değilim , ama yine de tartışmalı.)
PJSCopeland

Olduğu gibi, yukarıdakiler dosya adlarını boşluklarla bölecektir. Gereğince bu cevap , ayarlayabilirsiniz IFS=$'\n'önce for(ve o durdurmak için döngü unset IFSgüvenli olması için sonradan).
PJSCopeland

Bu, izinleri farklı bir kullanıcı adına sahip olduğunuz farklı bir işletim sistemi ile farklı bir sisteme taşımanıza hemen izin vermez. Kendime "gerçekten neye ihtiyacım var?" Diye sordum. ve tamamını çözüm aşağı kesti chmod 0600 .pgpassiçinde post-checkout. Evet, belirli izinlere ihtiyaç duyan bir dosyam olduğunda onu manuel olarak güncellemem gerekecek, ancak bunlar molalar.
PJSCopeland

2

Şu anda bu konuya giriyorsanız, ben bugün bunun üzerinden geçtim ve bunun nerede durduğunu özetleyebilirim. Bunu henüz denemediyseniz, buradaki bazı ayrıntılar yardımcı olabilir.

@Omid Ariyan'ın yaklaşımının en iyi yol olduğunu düşünüyorum. Ön işlem ve ödeme sonrası komut dosyalarını ekleyin. Onları tam olarak Omid'in yaptığı gibi adlandırmayı ve çalıştırılabilir hale getirmeyi UNUTMAYIN. Bunlardan herhangi birini unutursanız, hiçbir etkisi olmaz ve neden hiçbir şey olmadığını merak ederek "git commit" i tekrar tekrar çalıştırırsınız :) Ayrıca, web tarayıcısından kesip yapıştırırsanız, tırnak işaretlerinin ve tiklerin olmamasına dikkat edin. değişmiş.

Pre-commit komut dosyasını bir kez çalıştırırsanız (bir git commit çalıştırarak), o zaman .permissions dosyası oluşturulur. Onu arşive ekleyebilirsiniz ve bence bunu ön-kaydetme betiğinin sonuna tekrar tekrar eklemenin gereksiz olduğunu düşünüyorum. Ama acıtmıyor, bence (umut).

Omid'in komut dosyalarında dizin adı ve dosya adlarında boşlukların varlığı hakkında birkaç küçük sorun vardır. Boşluklar burada bir sorundu ve IFS düzeltmesiyle ilgili bazı sorunlar yaşadım. Kayıt için, bu ön işleme betiği benim için doğru çalıştı:

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

Şimdi, bundan ne çıkaracağız?

.Permissions dosyası git deposunun en üst düzeyindedir. Dosya başına bir satırı var, işte örneğimin en üstünde:

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

Gördüğünüz gibi bizde

filepath;perms;owner;group

Bu yaklaşımla ilgili yorumlarda, bir posterin yalnızca aynı kullanıcı adıyla çalıştığından ve bunun teknik olarak doğru olduğundan, ancak düzeltmenin çok kolay olduğundan şikayet ediyor. Ödeme sonrası komut dosyasının 2 işlem parçası olduğunu unutmayın,

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

Bu yüzden sadece ilkini saklıyorum, tek ihtiyacım olan bu. Web sunucusundaki kullanıcı adım gerçekten farklı, ancak daha da önemlisi, root değilseniz chown'u çalıştıramazsınız. Ancak "chgrp" çalıştırabilir. Bunun nasıl kullanılacağı yeterince açık.

Bu gönderideki ilk cevapta, en yaygın olarak kabul edilen öneri, buradaki ön / son kanca komut dosyalarının yaptığı işi yapan bir komut dosyası olan git-cache-meta'yı kullanmaktır (çıktının ayrıştırılması git ls-files) . Bu komut dosyalarını anlamak benim için daha kolay, git-cache-meta kodu oldukça ayrıntılı. Git-cache-meta'yı yolda tutmak ve onu kullanacak pre-commit ve post-checkout betikleri yazmak mümkündür.

Dosya adlarındaki boşluklar Omid'in her iki komut dosyasıyla ilgili bir sorundur. Kontrol sonrası komut dosyasında, bunun gibi hatalar görürseniz dosya adlarında boşluklar olduğunu anlarsınız.

$ 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

Bunun için çözümleri kontrol ediyorum. İşte işe yarayan bir şey var, ancak yalnızca bir durumda test ettim

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

İzin bilgileri her seferinde bir satır olduğundan, IFS'yi $ olarak ayarladım, bu nedenle yalnızca satır sonları yeni şeyler olarak görülüyor.

IFS ortam değişkenini eski haline getirmenin ÇOK ÖNEMLİ olduğunu okudum! $ Tek ayırıcı olarak bırakırsanız, kabuk oturumunun neden kötü gidebileceğini görebilirsiniz.


2

.permissionsDosyanın biçimini çalıştırılabilir chmodifadeler olacak şekilde değiştirerek ve -printfparametresini olarak kullanarak diğer yanıtları geliştirebiliriz find. İşte daha basit .git/hooks/pre-commitdosya:

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

... ve işte basitleştirilmiş .git/hooks/post-checkoutdosya:

#!/usr/bin/env bash

echo -n "Restoring file permissions... "

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

. .permissions

echo "done."

Diğer araçların bu komut dosyalarını önceden yapılandırmış olabileceğini, bu nedenle bunları bir araya getirmeniz gerekebileceğini unutmayın. Örneğin post-checkout, git-lfskomutları da içeren bir komut dosyası aşağıda verilmiştir :

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

Önceden teslim etme / teslim alma işleminde bir seçenek, "mtree" (FreeBSD) veya "bir dosya hiyerarşisini bir spesifikasyona göre karşılaştıran, bir dosya hiyerarşisi için spesifikasyon oluşturan veya bir Şartname."

Varsayılan küme, bayraklar, gid, bağlantı, mod, nlink, boyut, zaman, tür ve uid'dir. Bu, -k anahtarı ile belirli bir amaca uygun hale getirilebilir.


1

FreeBSD 11.1 üzerinde çalışıyorum, freebsd hapishane sanallaştırma konsepti işletim sistemini optimum hale getiriyor. Kullandığım Git'in şu anki sürümü 2.15.1, ayrıca her şeyi kabuk betikleri üzerinde çalıştırmayı tercih ediyorum. Bunu göz önünde bulundurarak yukarıdaki önerileri aşağıdaki gibi değiştirdim:

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 çekme: .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;

Herhangi bir nedenle komut dosyasını yeniden oluşturmanız gerekirse .permissions dosya çıktısı aşağıdaki biçime sahip olmalıdır:

.gitignore;644;0;0

Root'a 644 izin verilen bir .gitignore dosyası için: tekerlek

İstatistik seçeneklerinde birkaç değişiklik yapmam gerektiğine dikkat edin.

Zevk almak,


1

@Omid Ariyan'ın cevabına bir ekleme, dizinler üzerindeki izinlerdir. Bunu , komut fordizisindeki döngüden sonra ekleyin .donepre-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

Bu, dizin izinlerini de kaydedecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.