ローカルGitリポジトリをバックアップする方法は?


155

私は比較的小さなプロジェクトでgitを使用していますが、.gitディレクトリの内容を圧縮することは、プロジェクトをバックアップするための良い方法であることに気づきました。しかし、これは奇妙なことです。なぜなら、復元するときに最初に行う必要があるのはだからですgit reset --hard

この方法でgitリポジトリをバックアップすることに問題はありますか?また、それを行うためのより良い方法はありますか(たとえば、移植可能なgit形式または同様の何か?)?


なぜ誰もがgit bundleを使用する明らかな答えを出さなかったのですか???
ガトペイヒ

@gatopeich彼らがやった。下へスクロール。
Dan Rosenstark

すべての賛成投票の回答には、カスタムスクリプトに関するテキストの壁が含まれています。言及し始めたものも含みますgit bundle
gatopeich

回答:


23

私は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

1
@Yar素晴らしいバンドルスクリプト。以下の回答で私が提唱したgitバンドルに基づいています。+1。
VonC、2014年

1
私はすでにローカルベアリポジトリにアプリをインストールしました...インストール後、どのように使用しますか...ドキュメントにはそれに関する情報がありません。バックアップを作成する方法の例を含むセクションを含める必要があります
JAF

こんにちは、ごめんなさい。通常はを実行してからsudo install.sh、それを構成し(git config systemを使用)、宛先ディレクトリーを設定します(githubのreadmeファイルを参照)。次にgit backup、リポジトリ内で実行します。補足として、これはgit bundleの実験とこの質問への応答でしたが、git bundleは絶対に正確なコピーを作成することはありません(たとえば、特にgitリモートに関してよく思い出す場合)、個人的に実際にtarを使用してバックアップします。 gitディレクトリ。

144

他の公式な方法はgit bundleを使用することです

これにより、2番目のリポジトリをサポートgit fetchおよびgit pull更新するためのファイルが作成されます。
増分バックアップと復元に役立ちます。

しかし、すべてをバックアップする必要がある場合(古いコンテンツが既にある2番目のリポジトリがないため)、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


警告:リポジトリを複製するPat Notzソリューションはお勧めしません。
多くのファイルのバックアップは、バックアップや更新よりも常に注意が必要です。1つだけです。

あなたが見れば編集の歴史OPヤールの 答えは、あなたはヤールは、最初のAで使用していることがわかりますclone --mirror編集で、...:

Dropboxでこれを使用するのは、まったく厄介です
同期エラーが発生し、DROPBOXでディレクトリをロールバックすることはできません。Dropboxにバックアップ
するgit bundle場合に使用します。

Yarの現在のソリューションではを使用していgit bundleます。

私はケースを休ませる。


私はこれをチェックしました、そしてそれは実際に素晴らしいです。確信するためには、いくつかのバンドル化とアンバンドル化、およびリストヘッドを試さなければなりません...しかし、私はそれがかなり好きです。特に--allスイッチに関するメモをありがとうございます。
Dan Rosenstark、2010年

ある程度関連していますが、ローカルリポジトリを圧縮するだけで何か問題がありますか?1つのバックアップファイルが必要です。外部ドライブに何千ものファイルをコピーすると、非常に遅くなります。zipは.gitフォルダー内の非常に多くのファイルをアーカイブする必要があるため、もっと効率的なものがあるかどうか疑問に思っています。

@faB:唯一の違いは、を使用して簡単に増分バックアップを実行できることですgit bundle。すべてのローカルリポジトリのグローバルzipでは不可能です。
VonC 2010

2
古いコメントに返信しますが、bundleとdirの圧縮のもう1つの違いはbundleがアトミックであるため、誰かが操作の途中でリポジトリを更新した場合に混乱することはありません。
幻想的な2014

1
@幻想的な良い点。私はより多くの可視性のために答えにそれを含めました。
VonC、2014

62

これを行う方法は、リモート(ベア)リポジトリを(別のドライブ、USBキー、バックアップサーバー、またはgithubに)作成し、それを使用push --mirrorしてそのリモートリポジトリをローカルのリポジトリとまったく同じに見えるようにすることです(リモートが裸の場合を除く)。リポジトリ)。

これにより、早送り以外の更新を含むすべての参照(ブランチとタグ)がプッシュされます。これを使用して、ローカルリポジトリのバックアップを作成します。

manページにはこのようにそれを説明します。

プッシュする各参照に名前を付ける代わりに、その下にあるすべての参照$GIT_DIR/refs/(、、およびが含まれますがrefs/heads/、これらに限定されません)がリモートリポジトリにミラーリングされることを指定します。新しく作成されたローカル参照はリモートエンドにプッシュされ、ローカルで更新された参照はリモートエンドで強制的に更新され、削除された参照はリモートエンドから削除されます。これは、構成オプションが設定されている場合のデフォルトです。refs/remotes/refs/tags/remote.<remote>.mirror

私はエイリアスを作ってプッシュを行いました:

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

その後、git bakバックアップを実行したいときに実行します。


+1。同意した。git bundleは、バックアップを移動するのに適しています(1つのファイル)。しかし、どこにでも差し込めるドライブがあれば、ベアリポジトリも問題ありません。
VonC、2010年

+1 awesme、これを調べます。例もありがとう。
Dan Rosenstark、2010年

@Pat Notz、結局私はあなたのやり方で行くことに決めました、そして私はここに答えを
書き

--mirror実際には、取得したオブジェクトに対していかなる種類の検証も実行しないことに注意してください。git fsck破損を防ぐために、ある時点で実行する必要があります。
docwhat

34

[これを私自身の参照のためにここに残しておくだけです。]

呼び出されたバンドルスクリプトは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ので、必要な可能性のほとんどが得られます。


2
+1 --globalオプションを使用しなかったため、このエイリアスはプロジェクトでのみ表示されます(.git/configファイルで定義されています)。より詳細で適切にフォーマットされた回答をありがとう。
Pat Notz、2010

1
@yar:コマンドラインなしでこれらのタスクを実行し、代わりにTortoisegitを使用する方法を知っていますか(コマンドラインウィンドウ以外のユーザーのためのソリューションを探しています)?
pastacool 2010

@pastacool、申し訳ありませんが、コマンドラインがないとgitについてはまったくわかりません。おそらく、RubyMineのような関連するIDEをチェックしてください。
Dan Rosenstark、2010

@ intuited、spideroak、またはファイルのみでディレクトリをロールバックできます(Dropboxが実行し、3GBのスペースを提供します)?
Dan Rosenstark、2011

@Yar:わかりません。Dropboxでバックアップされたディレクトリを削除すると、それに含まれるファイルの以前のリビジョンがすべて失われるということですか?spideroakのバージョン管理ポリシーの詳細については、こちらをご覧ください。TBH私は実際にはSpiderOakをあまり使用していません。その制限については完全にはわかりません。彼らはそのような問題の解決策を提供していたように見えますが、彼らは技術的能力に多くの重点を置いています。また、Dropboxには無料アカウントのロールバックに30日間の制限がありますか?
2010

9

この質問に対する答えはどちらも正しいですが、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

1
面白い。私の答えよりも正確です。+1
VonC、2015

ありがとう、これはGithubに役立ちます。受け入れられた答えは、現在の質問に対するものです。
Dan Rosenstark、2015

5

git-copyで git repoをバックアップできますgit-copyは新しいプロジェクトをベアリポジトリとして保存しました。これは最小のストレージコストを意味します。

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

次に、プロジェクトを復元できます git clone

git clone /backup/project.backup project

ああ!この答えは、「git copy」が公式のgitコマンドであると私に信じさせました。
gatopeich

2

上記のテキストの壁を通り抜けた後、簡単な公式の方法を見つけました。

以下を使用して完全なバンドルを作成します。

$ git bundle create <filename> --all

次の方法で復元します。

$ git clone <filename> <folder>

この操作はアトミックなAFAIKです。詳細については、公式ドキュメントを確認してください。

「zip」について:gitバンドルは圧縮されており、.gitフォルダーのサイズに比べて驚くほど小さいです。


これはzipに関するすべての質問に答えるものではなく、他の回答も読んだことを前提としています。アトミックで問題全体を処理できるように修正してください(10年後)。ありがとう
Dan Rosenstark

0

グーグル経由でこの質問に来ました。

これが私が最も簡単な方法でやったことです。

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

何かが台無しになった場合の最良の部分は、ソースブランチを削除してバックアップブランチに戻るだけです!!


1
私はこのアプローチが好きですが、それがベストプラクティスであるかどうかわかりません。私は「バックアップ」のgitブランチをかなり頻繁に作成し、最終的には多くのバックアップブランチを作成します。これが問題ないかどうかはわかりません(異なる日付から最大20のバックアップブランチがあるため)。私はいつでも古いバックアップをいつでも削除できると思いますが、それらをすべて保持したいのであれば、大丈夫ですか?これまでのところ、うまく再生されていますが、それが良い練習か悪い練習かを知っておくといいでしょう。
カイルヴァセッラ2018

これはベストプラクティスと呼ばれるものではありません。個人的なものをやることに関係していると思います。私は通常、ジョブが完了するまで1つのブランチでのみコーディングし、アドホックリクエスト用に別のブランチを保持します。どちらにもバックアップがあります。完了したら、メインブランチを削除してください!:)
NoobEditor 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.