Yerel Git deposunu nasıl yedekleyebilirim?


155

Git'i nispeten küçük bir projede kullanıyorum ve .git dizininin içeriğini sıkıştırmanın projeyi yedeklemek için iyi bir yol olabileceğini düşünüyorum. Ama bu biraz garip çünkü geri döndüğümde yapmam gereken ilk şey git reset --hard.

Bir git deposunu bu şekilde yedeklemede herhangi bir sorun var mı? Ayrıca, bunu yapmanın daha iyi bir yolu var mı (örneğin, taşınabilir bir git formatı veya benzeri bir şey?)?


Neden kimse git paketini kullanmanın açık cevabını vermedi ???
gatopeich

@gatopeich yaptılar. Aşağı kaydır.
Dan Rosenstark

Tüm yükseltilmiş cevaplar, özel komut dosyaları hakkında, hatta söz etmeye başlayan bile bir metin duvarı içerirgit bundle
gatopeich

Yanıtlar:


23

Yar'ın senaryosunda biraz hacklemeye başladım ve sonuç, man sayfaları ve kurulum komut dosyası da dahil olmak üzere github'da:

https://github.com/najamelan/git-backup

Kurulum :

git clone "https://github.com/najamelan/git-backup.git"
cd git-backup
sudo ./install.sh

Tüm önerileri memnuniyetle karşılar ve github ile ilgili istekte bulunur.

#!/usr/bin/env ruby
#
# For documentation please sea man git-backup(1)
#
# TODO:
# - make it a class rather than a function
# - check the standard format of git warnings to be conform
# - do better checking for git repo than calling git status
# - if multiple entries found in config file, specify which file
# - make it work with submodules
# - propose to make backup directory if it does not exists
# - depth feature in git config (eg. only keep 3 backups for a repo - like rotate...)
# - TESTING



# allow calling from other scripts
def git_backup


# constants:
git_dir_name    = '.git'          # just to avoid magic "strings"
filename_suffix = ".git.bundle"   # will be added to the filename of the created backup


# Test if we are inside a git repo
`git status 2>&1`

if $?.exitstatus != 0

   puts 'fatal: Not a git repository: .git or at least cannot get zero exit status from "git status"'
   exit 2


else # git status success

   until        File::directory?( Dir.pwd + '/' + git_dir_name )             \
            or  File::directory?( Dir.pwd                      ) == '/'


         Dir.chdir( '..' )
   end


   unless File::directory?( Dir.pwd + '/.git' )

      raise( 'fatal: Directory still not a git repo: ' + Dir.pwd )

   end

end


# git-config --get of version 1.7.10 does:
#
# if the key does not exist git config exits with 1
# if the key exists twice in the same file   with 2
# if the key exists exactly once             with 0
#
# if the key does not exist       , an empty string is send to stdin
# if the key exists multiple times, the last value  is send to stdin
# if exaclty one key is found once, it's value      is send to stdin
#


# get the setting for the backup directory
# ----------------------------------------

directory = `git config --get backup.directory`


# git config adds a newline, so remove it
directory.chomp!


# check exit status of git config
case $?.exitstatus

   when 1 : directory = Dir.pwd[ /(.+)\/[^\/]+/, 1]

            puts 'Warning: Could not find backup.directory in your git config file. Please set it. See "man git config" for more details on git configuration files. Defaulting to the same directroy your git repo is in: ' + directory

   when 2 : puts 'Warning: Multiple entries of backup.directory found in your git config file. Will use the last one: ' + directory

   else     unless $?.exitstatus == 0 then raise( 'fatal: unknown exit status from git-config: ' + $?.exitstatus ) end

end


# verify directory exists
unless File::directory?( directory )

   raise( 'fatal: backup directory does not exists: ' + directory )

end


# The date and time prefix
# ------------------------

prefix           = ''
prefix_date      = Time.now.strftime( '%F'       ) + ' - ' # %F = YYYY-MM-DD
prefix_time      = Time.now.strftime( '%H:%M:%S' ) + ' - '
add_date_default = true
add_time_default = false

prefix += prefix_date if git_config_bool( 'backup.prefix-date', add_date_default )
prefix += prefix_time if git_config_bool( 'backup.prefix-time', add_time_default )



# default bundle name is the name of the repo
bundle_name = Dir.pwd.split('/').last

# set the name of the file to the first command line argument if given
bundle_name = ARGV[0] if( ARGV[0] )


bundle_name = File::join( directory, prefix + bundle_name + filename_suffix )


puts "Backing up to bundle #{bundle_name.inspect}"


# git bundle will print it's own error messages if it fails
`git bundle create #{bundle_name.inspect} --all --remotes`


end # def git_backup



# helper function to call git config to retrieve a boolean setting
def git_config_bool( option, default_value )

   # get the setting for the prefix-time from git config
   config_value = `git config --get #{option.inspect}`

   # check exit status of git config
   case $?.exitstatus

      # when not set take default
      when 1 : return default_value

      when 0 : return true unless config_value =~ /(false|no|0)/i

      when 2 : puts 'Warning: Multiple entries of #{option.inspect} found in your git config file. Will use the last one: ' + config_value
               return true unless config_value =~ /(false|no|0)/i

      else     raise( 'fatal: unknown exit status from git-config: ' + $?.exitstatus )

   end
end

# function needs to be called if we are not included in another script
git_backup if __FILE__ == $0

1
@Yar Aşağıdaki cevabımda savunduğum git paketini temel alan büyük paket betiği. +1.
VonC

1
Uygulamanızı yerel çıplak depoma zaten yükledim .... kurulduktan sonra nasıl kullanıyorsunuz ... belgelerde bununla ilgili bilgi yok, nasıl yedekleme yapacağınıza dair bir örnek içeren bir bölüm eklemelisiniz
JAF

Merhaba, üzgünüm, işe yaramazsın. Normalde çalıştırın sudo install.sh, sonra hedef dizini ayarlamak için yapılandırın (git config sistemi kullanır) (github'daki benioku dosyasına bakın). Sonra deponuzun git backupiçinde koşarsınız . Bir sidenote olarak, bu git demeti ve bu soruya bir cevaptı, ancak git demeti hiçbir zaman mutlak tam bir kopya yapmaz (örneğin, özellikle git uzaktan kumandalarıyla ilgili iyi hatırlıyorsam), bu yüzden kişisel olarak aslında yedekleme için tar kullanıyorum. git dizinleri.

144

Diğer resmi yol git git paketini kullanmaktır

Bu, ikinci deponuzu destekleyen git fetchve git pullgüncellemek için bir dosya oluşturur .
Artımlı yedekleme ve geri yükleme için kullanışlıdır.

Ancak her şeyi yedeklemeniz gerekiyorsa (daha önce bazı eski içeriğe sahip ikinci bir repoya sahip olmadığınız için), Kent Fredric'in yorumundan sonra, diğer cevabımda belirtildiği gibi, yedekleme biraz daha ayrıntılıdır :

$ git bundle create /tmp/foo master
$ git bundle create /tmp/foo-all --all
$ git bundle list-heads /tmp/foo
$ git bundle list-heads /tmp/foo-all

(Bu bir olan atom operasyon gelen bir arşiv yapma aksine, .gitklasör olarak, yorumladı tarafından fantabolous )


Uyarı: tavsiye etmem Pat Notz 'ın çözüm repo klonlama.
Birçok dosyayı yedeklemek her zaman yedekleme veya güncelleme yapmaktan daha zordur ... sadece bir tane.

Eğer bakarsak düzenlemelerin tarihinin içinde OP Yar cevap , sen Yar ilk a kullanılan olduğunu görürdünüz clone --mirrordüzenleme ile, ...:

Bunu Dropbox ile kullanmak tam bir karmaşa .
Senkronizasyon hatalarınız olacak ve DROPBOX'TA BİR REHBERİ GERİ DÖNAMAZSINIZ. Dropbox'ınıza yedeklemek istiyorsanız
kullanın git bundle.

Yar'ın mevcut çözümü kullanır git bundle.

Diyeceğimi dedim.


Ben sadece bu kontrol ve aslında harika. İkna olmak için biraz demetleme ve ayrıştırma ve liste kafaları denemeliyim ... ama biraz beğendim. Özellikle --all anahtarındaki notlar için tekrar teşekkürler.
Dan Rosenstark

Biraz ilgili, sadece yerel depomun sıkıştırılmasında bir sorun var mı? Tek bir yedekleme dosyasına ihtiyacım var, binlerce dosyayı harici bir sürücüye kopyalamak inanılmaz derecede yavaş. Sadece daha verimli bir şey olup olmadığını merak ediyorum çünkü zip .git klasöründe bu kadar çok dosyayı arşivlemek zorunda.

@ faB: Tek fark, artımlı yedekleme yapabilmenizdir git bundle. Tüm yerel repoların küresel bir fermuarı ile mümkün değildir.
VonC

2
Eski bir yoruma yanıt vermek, ancak paket ve dir'i sıkıştırmak arasındaki başka bir fark, atomiktir, bu nedenle işlemin ortasında birisinin repo'nuzu güncellemesi durumunda karışıklık olmaz.
14'te

1
@fantabolous iyi bir nokta. Daha fazla görünürlük için cevaba ekledim.
VonC

62

Bunu yapmanın yolu, uzak (çıplak) bir havuz oluşturmak (ayrı bir sürücüde, USB Anahtarında, yedekleme sunucusunda veya hatta githubda) oluşturmak ve daha sonra push --mirrorbu uzaktan repoyu yerel olanım gibi görünmesini sağlamaktır (uzaktan kumanda çıplak havuz).

Bu, hızlı ileri olmayan güncellemeler dahil olmak üzere tüm referansları (şubeler ve etiketler) zorlar. Bunu yerel depomun yedeklerini oluşturmak için kullanıyorum.

Adam sayfa şöyle anlatır:

Bunun yerine itme her ref adlandırma, altındaki tüm hakemler o belirtir $GIT_DIR/refs/(kapsar ancak bunlarla sınırlı değildir refs/heads/, refs/remotes/ve refs/tags/) uzaktan depo yansıtılmış. Yeni oluşturulan yerel referanslar uzak tarafa aktarılacak, yerel olarak güncellenen referanslar uzak uçta zorla güncellenecek ve silinen referanslar uzak uçtan kaldırılacak. Yapılandırma seçeneği remote.<remote>.mirrorayarlanmışsa bu varsayılan değerdir.

İtme işlemini yapmak için bir takma ad yaptım:

git config --add alias.bak "push --mirror github"

Sonra, sadece git bakbir yedekleme yapmak istediğimde koşuyorum .


+1. Kabul. git bundle, yedeklemeyi (bir dosya) taşımak güzeldir. Ancak herhangi bir yere takabileceğiniz bir sürücü ile çıplak repo da gayet iyi.
VonC

+1 harika, ben buna bakacağım. Örnekler için de teşekkürler.
Dan Rosenstark

@Pat Notz, sonunda bunu yapma yoluna gitmeye karar verdim ve buraya bir cevap verdim (puan kalıcı olarak sıfırda tutuldu :)
Dan Rosenstark

--mirrorGerçekte, elde ettiği nesneler üzerinde herhangi bir doğrulama yapılmadığını unutmayın . Muhtemelen git fsckyolsuzluğu önlemek için bir noktada koşmalısınız.
Mart'ta

34

[Bunu kendi referansım için burada bırakıyorum.]

Adlı paket betiğim git-backupşöyle görünüyor

#!/usr/bin/env ruby
if __FILE__ == $0
        bundle_name = ARGV[0] if (ARGV[0])
        bundle_name = `pwd`.split('/').last.chomp if bundle_name.nil? 
        bundle_name += ".git.bundle"
        puts "Backing up to bundle #{bundle_name}"
        `git bundle create /data/Dropbox/backup/git-repos/#{bundle_name} --all`
end

Bazen kullanıyorum git backupbazen de kullanıyorum, git backup different-namebu da bana ihtiyacım olan olasılıkların çoğunu veriyor.


2
+1 --globalSeçeneği kullanmadığınız için bu takma ad yalnızca projenizde görünecektir (dosyanızda definded .git/config) - muhtemelen budur. Daha ayrıntılı ve güzel biçimlendirilmiş cevap için teşekkürler.
Pat Notz

1
@yar: Bu görevleri komut satırı olmadan nasıl gerçekleştireceğinizi biliyor musunuz ve bunun yerine yalnızca tortoisegit'i kullanıyorsunuz (komut satırı olmayan windoze kullanıcılarım için çözüm arıyorum)?
pastacool

@pastacool, üzgünüm komut satırı olmadan git'i bilmiyorum. Belki de RubyMine gibi ilgili bir IDE'ye göz atın?
Dan Rosenstark

@intuited, DIRECTORIES'i spideroak ile ya da sadece dosyalarla (Dropbox'ın yaptığı ve size 3GB alan sağlayan) geri alabilirsiniz?
Dan Rosenstark

@Yar: Anladığımdan emin değilim ... Dropbox destekli bir dizini silersem, içinde bulunan dosyaların önceki tüm düzeltmelerini kaybedersem mi? Spideroak'ın sürüm politikaları hakkında daha fazla bilgi burada . TBH SpiderOak'ı çok fazla kullanmadım ve sınırlarından tam olarak emin değilim. Bu tür sorunlara bir çözüm sunacak gibi gözüküyor, teknik yeterliliğe çok önem veriyorlar. Ayrıca: Dropbox'ın ücretsiz hesaplar için geri ödemelerde 30 günlük bir sınırı var mı?
intuited

9

Bu soruların her iki yanıtı da doğru, ancak yine de bir Github deposunu yerel bir dosyaya yedeklemek için eksiksiz, kısa bir çözüm eksikti. Özü , çatal veya ihtiyaçlarınıza uygulamaktan çekinmeyin burada mevcuttur.

backup.sh:

#!/bin/bash
# Backup the repositories indicated in the command line
# Example:
# bin/backup user1/repo1 user1/repo2
set -e
for i in $@; do
  FILENAME=$(echo $i | sed 's/\//-/g')
  echo "== Backing up $i to $FILENAME.bak"
  git clone git@github.com:$i $FILENAME.git --mirror
  cd "$FILENAME.git"
  git bundle create ../$FILENAME.bak --all
  cd ..
  rm -rf $i.git
  echo "== Repository saved as $FILENAME.bak"
done

restore.sh:

#!/bin/bash
# Restore the repository indicated in the command line
# Example:
# bin/restore filename.bak
set -e

FOLDER_NAME=$(echo $1 | sed 's/.bak//')
git clone --bare $1 $FOLDER_NAME.git

1
İlginç. Cevabımdan daha kesin. +1
VonC

Teşekkürler, bu Github için yararlıdır. Kabul edilen cevap mevcut soruya aittir.
Dan Rosenstark

5

Git kopyasını git-copy ile yedekleyebilirsiniz . git-copy yeni projeyi çıplak bir repo olarak kaydetti, minimum depolama maliyeti demektir.

git copy /path/to/project /backup/project.backup

Ardından projenizi git clone

git clone /backup/project.backup project

Ahh! bu cevap beni "git copy" in resmi bir git komutu olduğuna inandırdı.
gatopeich

2

Yukarıdaki metin duvarlarından geçtikten sonra basit bir resmi yol buldum, bu da hiç olmadığını düşünmenizi sağlayacaktır.

Şununla eksiksiz bir paket oluşturun:

$ git bundle create <filename> --all

Şununla geri yükleyin:

$ git clone <filename> <folder>

Bu işlem atomik AFAIK. Kontrol resmi belgeler cesur detayları için.

"Zip" ile ilgili olarak: git paketleri .git klasör boyutuna göre sıkıştırılmış ve şaşırtıcı derecede küçüktür.


Bu, zip hakkındaki tüm soruyu cevaplamaz ve diğer cevapları da okuduğumuzu varsayar. Lütfen düzeltin, böylece atomik ve tüm soruyu işliyor ve cevap kabul etmesini sevindim (10 yıl sonra). Teşekkürler
Dan Rosenstark

0

bu soruya google üzerinden geldi.

İşte en basit şekilde yaptığım şey.

git checkout branch_to_clone

sonra bu daldan yeni bir git dalı oluşturun

git checkout -b new_cloned_branch
Switched to branch 'new_cloned_branch'

orijinal şubeye geri dönün ve devam edin:

git checkout branch_to_clone

Berbat olduğunuzu ve yedekleme dalından bir şey geri yüklemeniz gerektiğini varsayarsak:

git checkout new_cloned_branch -- <filepath>  #notice the space before and after "--"

En iyi bölüm bir şey berbat ise, sadece kaynak dalı silebilir ve yedek şubeye geri dönebilirsiniz !!


1
Bu yaklaşımı seviyorum - ama en iyi uygulama olup olmadığından emin değilim? Git şubelerini oldukça sık yedekliyorum ve sonunda birçok yedek şubem olacak. Bunun iyi olup olmadığından emin değilim (farklı tarihlerde ~ 20 yedek şubeye sahip olmak). Sanırım her zaman eski yedeklemeleri silebilirdim - ama hepsini saklamak istersem - sorun değil mi? Şimdiye kadar güzel oynuyor - ama iyi mi kötü mü olduğunu bilmek güzel olurdu.
Kyle Vassella

en iyi uygulama olarak adlandırılacak bir şey değil , daha fazla şeyler yapma alışkanlıkları olanlarla ilgili olduğunu varsayıyorum. Genellikle iş bitene kadar bir dalda kod yazar ve adhoc istekleri için başka bir dal tutarım . Her ikisinin de yedekleri var, tamamlandığında ana dalı silin! :)
NoobEditor
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.