如何备份本地的Git仓库?
我在一个相对较小的项目上使用git,我发现压缩.git目录的内容可能是备份项目的好方法。 但是这有点奇怪,因为当我恢复时,我需要做的第一件事就是git reset --hard
。
以这种方式备份git回购有任何问题吗? 另外,有没有更好的方法来做到这一点(例如,一个便携式的git格式或类似的东西?)?
我开始对Yar的脚本进行一些黑客攻击,结果在github上,包括man页面和安装脚本:
https://github.com/najamelan/git-backup
安装 :
git clone "https://github.com/najamelan/git-backup.git" cd git-backup sudo ./install.sh
欢迎所有的build议和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 bundle
这将创build一个支持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
(这是一个primefaces操作 ,而不是从.git
文件夹中创build一个存档文件,就像由fantabolous所评论的那样 )
警告:我不会推荐Pat Notz的解决scheme ,它是克隆回购。
备份许多文件总是比备份或更新更棘手…只有一个。
如果您查看OP Yar 回答 的编辑历史 ,您会看到Yar首先使用了一个clone --mirror
,编辑:
与Dropbox一起使用是一团糟 。
您将有同步错误,并且不能将目录退回到DROPBOX中。
如果你想备份到你的保pipe箱,请使用git bundle
。
Yar 目前的解决scheme使用了git bundle
。
我rest我的情况。
我这样做的方式是创build一个远程(裸)存储库(在一个单独的驱动器,USB密钥,备份服务器,甚至github),然后使用push --mirror
使远程回购看起来就像我的本地(除远程是一个裸仓库)。
这将推动所有裁判(分支和标签),包括非快进更新。 我用它来创build我的本地存储库的备份。
手册页描述如下:
将
$GIT_DIR/refs/
(包括但不限于refs/heads/
,refs/remotes/
和refs/tags/
)的所有refs/tags/
映射到远程存储库,而不是将每个ref命名为push。 新创build的本地参考将被推送到远端,本地更新的参考将在远端强制更新,删除的参考将从远端移除。 如果设置了configuration选项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
,这给了我所需要的大部分可能性。
这两个问题的答案都是正确的,但我仍然缺less一个完整的简短的解决scheme,将Github存储库备份到本地文件中。 要点在这里,随时叉或适应您的需求。
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
你可以使用git-copy备份git repo。 git-copy将新项目保存为裸回购,这意味着最小的存储成本。
git copy /path/to/project /backup/project.backup
然后你可以用git clone
来恢复你的项目
git clone /backup/project.backup project
通过谷歌来到这个问题。
这是我以最简单的方式做的。
git checkout branch_to_clone
然后从这个分支创build一个新的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 "--"
最好的部分,如果任何事情搞砸了,你可以删除源分支,并移回备份分支!