Как сделать резервную копию локального репозитория Git? - PullRequest
149 голосов
/ 25 января 2010

Я использую git в относительно небольшом проекте и обнаружил, что архивирование содержимого каталога .git может быть хорошим способом для резервного копирования проекта. Но это немного странно, потому что, когда я восстанавливаюсь, первое, что мне нужно сделать, это git reset --hard.

Есть ли проблемы с резервным копированием git-репо таким способом? Кроме того, есть ли лучший способ сделать это (например, портативный формат Git или что-то подобное?)?

Ответы [ 7 ]

140 голосов
/ 25 января 2010

Другим официальным способом будет использование git bundle

Это создаст файл, поддерживающий git fetch и git pull для обновления вашего второго репо.
Полезно для инкрементного резервного копирования и восстановления.

Но если вам нужно выполнить резервное копирование всего (поскольку у вас нет второго репо с уже существующим содержимым), резервное копирование будет более сложным, как упоминалось в моем другом ответе после комментария Kent Fredric :

$ 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

(Это атомарная операция , в отличие от создания архива из папки .git, как прокомментировал fantabolous )


Предупреждение: я бы не рекомендовал Pat Notz решение , которое клонирует репо.
Резервное копирование многих файлов всегда сложнее, чем резервное копирование или обновление ... только один.

Если вы посмотрите на историю изменений OP Yar answer , вы увидите, что Yar сначала использовал clone --mirror, .. с редактированием:

Использование этого с Dropbox - полный беспорядок .
У вас будут ошибки синхронизации, и вы НЕ МОЖЕТЕ ЗАВЕРШИТЬ СПРАВОЧНИК В СПИСОК.
Используйте git bundle, если вы хотите выполнить резервное копирование в свой дропбокс.

Текущее решение Яр использует git bundle.

Я отдыхаю.

62 голосов
/ 25 января 2010

Способ, которым я делаю это, - создать удаленный (пустой) репозиторий (на отдельном диске, USB-ключе, сервере резервного копирования или даже github), а затем использовать push --mirror, чтобы сделать это удаленное репо точно таким же, как мое локальное кроме удаленного хранилища bare ).

Это подтолкнет все ссылки (ветки и теги), включая обновления без ускоренной перемотки. Я использую это для создания резервных копий моего локального хранилища.

Справочная страница описывает это так:

Вместо того, чтобы называть каждую ссылку push, указывает, что все ссылки в $GIT_DIR/refs/ (включая, но не ограничиваясь refs/heads/, refs/remotes/ и refs/tags/) будут отражаться в удаленном репозитории. Вновь созданные локальные ссылки будут отправлены на удаленный конец, локально обновленные ссылки будут принудительно обновлены на удаленном конце, а удаленные ссылки будут удалены с удаленного конца. Это значение по умолчанию, если задан параметр конфигурации remote.<remote>.mirror.

Я сделал псевдоним, чтобы сделать push:

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

Затем я просто запускаю git bak всякий раз, когда я хочу сделать резервную копию.

35 голосов
/ 01 февраля 2010

[Просто оставлю это здесь для моей справки.]

Мой пакетный скрипт с именем git-backup выглядит так

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

Иногда я использую git backup, а иногда - git backup different-name, что дает мне большинство возможностей, которые мне нужны.

24 голосов
/ 05 мая 2012

Я начал немного взламывать скрипт Yar, и в результате получился github, включая man-страницы и скрипт установки:

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

Установка

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

Приветствую все предложения и вытащить запрос на github.

#!/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
9 голосов
/ 17 июля 2015

Оба ответа на эти вопросы верны, но мне все еще не хватает полного, короткого решения для резервного копирования Github-репозитория в локальный файл. gist доступен здесь, не стесняйтесь раскошелиться или адаптироваться к вашим потребностям.

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
4 голосов
/ 03 июня 2015

Вы можете сделать резервную копию git repo с помощью git-copy . git-copy новый проект сохранен как репо, это означает минимальную стоимость хранения.

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

Затем вы можете восстановить свой проект с помощью git clone

git clone /backup/project.backup project
1 голос
/ 24 сентября 2015

пришел к этому вопросу через гугл.

Вот что я сделал самым простым способом.

git checkout branch_to_clone

затем создайте новую ветку git из этой ветки

git checkout -b new_cloned_branch
Switched to branch 'new_cloned_branch'

вернитесь в исходную ветку и продолжайте:

git checkout branch_to_clone

Если вы облажались и вам нужно что-то восстановить из резервной ветки:

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

Лучшая часть, если что-то облажалось, вы можете просто удалить исходную ветку и вернуться в резервную ветвь !!

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