如何备份本地 Git 存储库?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2129214/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to backup a local Git repository?
提问by Dan Rosenstark
I am using git on a relatively small project and I find that zipping the .git directory's contents might be a fine way to back up the project. But this is kind of weird because, when I restore, the first thing I need to do is git reset --hard
.
我在一个相对较小的项目上使用 git,我发现压缩 .git 目录的内容可能是备份项目的好方法。但这有点奇怪,因为当我恢复时,我需要做的第一件事是git reset --hard
.
Are there any problems with backing up a git repo this way? Also, is there any better way to do it (e.g., a portable git format or something similar?)?
以这种方式备份 git repo 有什么问题吗?另外,有没有更好的方法来做到这一点(例如,便携式 git 格式或类似的东西?)?
采纳答案by Dan Rosenstark
I started hacking away a bit on Yar's script and the result is on github, including man pages and install script:
我开始对 Yar 的脚本进行一些修改,结果在 github 上,包括手册页和安装脚本:
https://github.com/najamelan/git-backup
https://github.com/najamelan/git-backup
Installation:
安装:
git clone "https://github.com/najamelan/git-backup.git"
cd git-backup
sudo ./install.sh
Welcoming all suggestions and pull request on github.
欢迎在 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__ == $ 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
回答by VonC
The other offical way would be using git bundle
另一种官方方法是使用git bundle
That will create a file that support git fetch
and git pull
in order to update your second repo.
Useful for incremental backup and restore.
这将创建一个支持git fetch
并git pull
更新您的第二个存储库的文件。
用于增量备份和恢复。
But if you need to backup everything(because you do not have a second repo with some older content already in place), the backup is a bit more elaborate to do, as mentioned in my other answer, after Kent Fredric's comment:
但是,如果您需要备份所有内容(因为您没有第二个已准备好一些较旧内容的存储库),则备份要复杂一些,正如我在Kent Fredric的评论之后的另一个答案中所述:
git config --add alias.bak "push --mirror github"
(It is an atomic operation, as opposed to making an archive from the .git
folder, as commentedby fantabolous)
(这是一个原子操作,而不是.git
像fantabolous所评论的那样从文件夹中创建存档)
Warning: I wouldn't recommend Pat Notz's solution, which is cloning the repo.
Backup many files is always more tricky than backing up or updating... just one.
警告:我不推荐Pat Notz的解决方案,它是克隆存储库。
备份多个文件总是比备份或更新更棘手……只有一个。
If you look at the history of editsof the OP Yaranswer, you would see that Yar used at first a clone --mirror
, ... with the edit:
如果你看一下编辑的历史的的OP亚尔的答案,你会看到亚尔使用起初clone --mirror
,......与编辑:
Using this with Dropbox is a total mess.
You will have sync errors, and you CANNOT ROLL A DIRECTORY BACK IN DROPBOX.
Usegit bundle
if you want to back up to your dropbox.
将它与 Dropbox 一起使用是一团糟。
您将遇到同步错误,并且您无法在 DROPBOX 中回滚目录。
使用git bundle
,如果你想备份到您的Dropbox。
Yar's current solutionuses git bundle
.
Yar目前的解决方案使用git bundle
.
I rest my case.
我休息一下。
回答by Pat Notz
The way I do this is to create a remote (bare) repository (on a separate drive, USB Key, backup server or even github) and then use push --mirror
to make that remote repo look exactly like my local one (except the remote is a barerepository).
我这样做的方法是创建一个远程(裸)存储库(在单独的驱动器、USB 密钥、备份服务器甚至 github 上),然后使用push --mirror
该远程存储库看起来与我的本地存储库完全一样(除了远程是一个裸存储库)存储库)。
This will push all refs (branches and tags) including non-fast-forward updates. I use this for creating backups of my local repository.
这将推送所有引用(分支和标签),包括非快进更新。我用它来创建我的本地存储库的备份。
The man pagedescribes it like this:
该手册页描述它是这样的:
Instead of naming each ref to push, specifies that all refs under
$GIT_DIR/refs/
(which includes but is not limited torefs/heads/
,refs/remotes/
, andrefs/tags/
) be mirrored to the remote repository. Newly created local refs will be pushed to the remote end, locally updated refs will be force updated on the remote end, and deleted refs will be removed from the remote end. This is the default if the configuration optionremote.<remote>.mirror
is set.
代替命名每个裁判推的,则指定下的所有参考文献
$GIT_DIR/refs/
(包括但不限于refs/heads/
,refs/remotes/
和refs/tags/
)被镜像到远程存储库。新创建的本地 refs 将被推送到远程端,本地更新的 refs 将在远程端强制更新,删除的 refs 将从远程端删除。如果remote.<remote>.mirror
设置了配置选项,则这是默认设置。
I made an alias to do the push:
我做了一个别名来做推送:
#!/usr/bin/env ruby
if __FILE__ == #!/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 [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
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
Then, I just run git bak
whenever I want to do a backup.
然后,我git bak
只要想备份就跑。
回答by Dan Rosenstark
[Just leaving this here for my own reference.]
[只是留在这里供我自己参考。]
My bundle script called git-backup
looks like this
我的捆绑脚本称为git-backup
如下所示
#!/bin/bash
# Restore the repository indicated in the command line
# Example:
# bin/restore filename.bak
set -e
FOLDER_NAME=$(echo | sed 's/.bak//')
git clone --bare $FOLDER_NAME.git
Sometimes I use git backup
and sometimes I use git backup different-name
which gives me most of the possibilities I need.
有时我使用git backup
,有时我使用git backup different-name
这给了我我需要的大部分可能性。
回答by Nacho Coloma
Both answers to this questions are correct, but I was still missing a complete, short solution to backup a Github repository into a local file. The gistis available here, feel free to fork or adapt to your needs.
这个问题的两个答案都是正确的,但我仍然缺少一个完整的、简短的解决方案来将 Github 存储库备份到本地文件中。该要点可在这里,随意叉子或适应您的需求。
backup.sh:
备份.sh:
git copy /path/to/project /backup/project.backup
restore.sh:
恢复.sh:
git clone /backup/project.backup project
回答by Quanlong
You can backup the git repo with git-copy. git-copysaved new project as a bare repo, it means minimum storage cost.
您可以使用git-copy备份 git repo 。git-copy将新项目保存为裸仓库,这意味着最低存储成本。
git checkout branch_to_clone
Then you can restore your project with git clone
然后你可以恢复你的项目 git clone
git checkout -b new_cloned_branch
Switched to branch 'new_cloned_branch'
回答by NoobEditor
came to this question via google.
通过谷歌来到这个问题。
Here is what i did in the simplest way.
这是我以最简单的方式所做的。
git checkout branch_to_clone
then create a new git branch from this branch
然后从这个分支创建一个新的 git 分支
git checkout new_cloned_branch -- <filepath> #notice the space before and after "--"
come back to original branch and continue:
回到原来的分支并继续:
##代码##Assuming you screwed up and need to restore something from backup branch :
假设你搞砸了,需要从备份分支恢复一些东西:
##代码##Best part if anything is screwed up, you can just delete the source branch and move back to backup branch!!
最好的部分,如果有任何问题,您可以删除源分支并移回备份分支!