Как создать резервную копию локального хранилища Git?
Я использую git в относительно небольшом проекте, и я обнаружил, что zip-содержимое каталога .git может быть прекрасным способом резервного копирования проекта. Но это довольно странно, потому что, когда я восстанавливаю, первое, что мне нужно сделать, это git reset --hard
.
Есть ли проблемы с резервным копированием репозитория git таким образом? Кроме того, есть ли лучший способ сделать это (например, переносимый формат git или что-то подобное?)?
Ответы
Ответ 1
Я начал немного взломать Yar script, а результат - на github, включая man-страницы и установить script:
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 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 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
Ответ 2
Другим официальным способом будет использование git bundle
Это создаст файл, поддерживающий git fetch
и git pull
, чтобы обновить ваше второе репо.
Полезно для инкрементного резервного копирования и восстановления.
Но если вам нужно сделать резервную копию всего (потому что у вас нет второго репо с некоторым старым контентом уже на месте), резервная копия будет более сложной, как указано в моем другом ответе, после Кент Фредрик комментарий:
$ 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, вы увидите, что Яр сначала использовал clone --mirror
,... с помощью edit:
Использование этого с Dropbox - это полный беспорядок.
У вас будут ошибки синхронизации, и вы НЕ МОЖЕТЕ ВЕРНУТЬ СПРАВОЧНИК В СПИСКЕ DROPBOX.
Используйте git bundle
, если вы хотите создать резервную копию своего Dropbox.
Яр текущее решение использует git bundle
.
Я оставлю свой случай.
Ответ 3
Как я делаю это, нужно создать удаленный (голый) репозиторий (на отдельном диске, USB-ключ, сервер резервного копирования или даже github), а затем использовать push --mirror
, чтобы сделать это удаленное репо похожим на мой локальный ( кроме удаленного - это голый репозиторий).
Это приведет к удалению всех ссылок (ветвей и тегов), включая обновления без пересылки. Я использую это для создания резервных копий моего локального репозитория.
Страница описывает это следующим образом:
Вместо того, чтобы называть каждый ref для push, указывает, что все refs под $GIT_DIR/refs/
(который включает, но не ограничивается refs/heads/
, refs/remotes/
и refs/tags/
), зеркалируются в удаленный репозиторий. Недавно созданные локальные ссылки будут перенесены в удаленный конец, локально обновленные refs будут принудительно обновлены на удаленном конце, и удаленные ссылки будут удалены с удаленного конца. Это значение по умолчанию, если установлен параметр конфигурации remote.<remote>.mirror
.
Я сделал псевдоним, чтобы сделать push:
git config --add alias.bak "push --mirror github"
Затем я просто запускаю git bak
всякий раз, когда хочу сделать резервную копию.
Ответ 4
[Просто оставив это здесь для моей справки.]
Мой пакет script, называемый 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
, который дает мне большую часть возможностей, которые мне нужны.
Ответ 5
Оба ответа на эти вопросы верны, но мне все еще не хватает полного короткого решения для резервного копирования репозитория 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 [email protected]; do
FILENAME=$(echo $i | sed 's/\//-/g')
echo "== Backing up $i to $FILENAME.bak"
git clone [email protected]:$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
Ответ 6
Вы можете создать резервную копию git с git-copy. git -copy сохранил новый проект как голый репо, это означает минимальную стоимость хранения.
git copy /path/to/project /backup/project.backup
Затем вы можете восстановить свой проект с помощью git clone
git clone /backup/project.backup project
Ответ 7
пришел к этому вопросу через google.
Вот что я сделал простейшим способом.
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 "--"
Лучшая часть, если что-то прикручено, вы можете просто удалить ветвь источника и вернуться обратно в отделение резервного копирования!!