如何备份本地 Git 存储库?

我在一个相对较小的项目中使用 git,我发现压缩。Git 目录的内容可能是备份项目的好方法。但是这有点奇怪,因为当我恢复时,我需要做的第一件事是 git reset --hard

用这种方式备份 Git 回购有什么问题吗?还有,有没有更好的方法来做到这一点(例如,一个可移植的 git 格式或类似的东西?)?

142127 次浏览

另一种官方方式是使用 Git bundle

这将创建一个支持 git fetchgit 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文件夹制作一个归档文件,如 评论太棒了)


警告: 我不推荐 帕特 · 诺茨解决方案,它正在克隆回购。
备份许多文件总是比备份或更新更棘手... 只有一个。

如果你看看 操作室回答编辑史,你会看到 Yar 在第一次使用 clone --mirror,... 与编辑:

在 Dropbox 中使用这种方法完全是一团糟。
您将会有同步错误,并且您不能在 DROPBOX 中滚回目录。
如果您想备份到您的下拉框,请使用 git bundle

Yar 的 目前的解决方案使用 git bundle

我说完了。

我这样做的方式是创建一个远程(裸)存储库(在一个单独的驱动器,USB 密钥,备份服务器,甚至 github) ,然后使用 push --mirror使远程回购看起来完全像我的本地(除了远程是一个 光秃秃的存储库)。

这将推送所有参考(分支和标记) ,包括非快进更新。我使用它来创建本地存储库的备份。

手册是这样描述的:

指定将 $GIT_DIR/refs/下的所有引用(包括但不限于 refs/heads/refs/remotes/refs/tags/)镜像到远程存储库,而不是将每个引用命名为 push。新创建的本地参考文献将被推送到远程端,本地更新的参考文献将在远程端强制更新,删除的参考文献将从远程端删除。如果设置了配置选项 remote.<remote>.mirror,则这是默认值。

我用了个假名:

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

然后,只要我想做备份,就可以运行 git bak

[只是把这个留在这里供我自己参考。]

我的捆绑包脚本 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,它给了我大多数我需要的可能性。

我开始修改 Yar 的脚本,结果是在 github 上,包括手册页和安装脚本:

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

您可以使用 收到备份 git 回购。收到节省了新项目作为一个裸回购,这意味着最低的存储成本。

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

然后您可以用 git clone恢复您的项目

git clone /backup/project.backup project

这两个问题的答案都是正确的,但是我仍然缺少一个完整的、简短的解决方案来将 Github 存储库备份到一个本地文件中。大意在这里可以买到,请随意使用叉子或根据您的需要进行调整。

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

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

这个问题是通过谷歌得到的。

这是我用最简单的方法做的。

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 "--"

最好的部分是,如果任何事情搞砸了,您可以只删除源分支,并移回到备份分支! !

发现简单的官方方式后,涉水通过上面的文字墙壁,会让你认为没有。

创建一个完整的捆绑包:

$ git bundle create <filename> --all

用以下方法恢复:

$ git clone <filename> <folder>

这个操作是原子 AFAIK。检查 官方文件的细节。

关于“ zip”: 与.git 文件夹大小相比,git 包是压缩的,而且令人惊讶的小。