로컬 Git 리포지토리를 백업하는 방법?


155

비교적 작은 프로젝트에서 git을 사용하고 있으며 .git 디렉토리의 내용을 압축하면 프로젝트를 백업하는 좋은 방법 일 수 있습니다. 그러나 복원 할 때 가장 먼저해야 할 일은이므로 이는 이상 git reset --hard합니다.

이런 식으로 git repo를 백업하는 데 문제가 있습니까? 또한 더 좋은 방법이 있습니까 (예 : 휴대용 git 형식 또는 이와 유사한 것)?


왜 아무도 git bundle 사용에 대한 명확한 대답을하지 않았 습니까 ???
가토 피치

@gatopeich 그들은했다. 아래로 스크롤.
Dan Rosenstark

모든 upvoted 답변, 사용자 정의 스크립트에 대한 시작이 언급하는 것을조차 하나를 텍스트의 벽을 포함git bundle
gatopeich

답변:


23

나는 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

1
@Yar 아래의 답변에서 내가 주장한 자식 번들을 기반으로 한 위대한 번들 스크립트. +1.
VonC

1
나는 이미 내 로컬 베어 저장소에 응용 프로그램을 설치 .... 그것이 설치되면 당신이 그것을 어떻게 사용합니까 .... 설명서에 백업을 만드는 방법에 대한 예 withg입니다 섹션을 포함해야한다고 관한 어떤 정보가 없습니다
JAF

안녕하세요, 죄송합니다. 작동하지 않습니다. 일반적으로을 실행 sudo install.sh한 다음 대상 디렉토리를 설정하도록 구성합니다 (git config 시스템 사용) (github의 readme 파일 참조). 다음으로 git backup저장소 내에서 실행 합니다. 참고로, 이것은 git bundle을 사용한 실험 과이 질문에 대한 응답이지만 git bundle은 절대 정확한 사본을 만들지 않습니다 (예를 들어, 특히 git remote와 관련하여 잘 기억한다면) 실제로 tar를 사용하여 백업합니다. 자식 디렉토리.

144

다른 공식적인 방법은 git bundle을 사용하는 것입니다.

그러면 두 번째 리포지토리 를 지원 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

( fantabolous에 의해 언급 된 것처럼 폴더 에서 아카이브를 만드는 것과는 반대로 원자 작업입니다 . ).git


경고 : 나는 저장소를 복제하는 Pat Notz솔루션을 권장하지 않습니다 .
많은 파일을 백업하는 것은 하나의 백업 또는 업데이트보다 항상 까다 롭습니다.

OP Yar answer 의 편집 히스토리 를 보면 Yar처음에 편집 에 사용 된 것을 볼 수 있습니다.clone --mirror

이것을 Dropbox와 함께 사용하는 것은 완전히 혼란 입니다.
동기화 오류가 발생하여 DROPBOX에서 디렉토리를 롤백 할 수 없습니다. 보관 용 계정에 백업
하려면 사용하십시오 git bundle.

Yar의 현재 솔루션 은을 사용합니다 git bundle.

난 내 경우를 휴식.


방금 이것을 확인했는데 실제로 훌륭합니다. 확신을 갖기 위해 번들링 및 번들링 해제 및 목록 헤드를 시도해야하지만 ... 나는 그것을 아주 좋아합니다. 특히 --all 스위치에 대한 참고 사항에 대해 다시 한 번 감사드립니다.
Dan Rosenstark

다소 관련이 있습니다. 로컬 저장소를 압축하는 데 문제가 있습니까? 단일 백업 파일이 필요합니다. 외장 드라이브에 수천 개의 파일을 복사하는 것이 엄청나게 느립니다. zip이 .git 폴더에 많은 파일을 보관해야하기 때문에 더 효율적인 것이 있는지 궁금합니다.

@faB : 유일한 차이점은로 증분 백업을 쉽게 수행 할 수 있다는 것 입니다 git bundle. 모든 지역 리포지토리의 글로벌 우편으로는 불가능합니다.
VonC

2
오래된 의견에 대답하지만 번들과 디렉토리 압축의 또 다른 차이점은 번들이므로 원 자성이므로 누군가가 작업 중간에 저장소를 업데이트하면 엉망이되지 않습니다.
환상적인

1
@ 환상적인 좋은 지적. 더 많은 가시성을 위해 답변에 포함 시켰습니다.
VonC

62

나는이 작업을 수행하는 방법은 원격 (베어) 저장소를 생성하는 것입니다 (별도의 드라이브를 USB 키, 백업 서버 또는 GitHub의) 한 다음 사용 push --mirror(가) 멀리 떨어진입니다 제외하고 (정확히 내 지역과 같은 해당 원격 REPO 모양을 만들기 위해 베어 저장소).

이렇게하면 빨리 감기가 아닌 업데이트를 포함한 모든 참조 (분기 및 태그)가 푸시됩니다. 로컬 리포지토리의 백업을 생성하는 데 사용합니다.

매뉴얼 페이지 이런 식으로 설명 :

대신 밀어 각 REF 네이밍, 심판 미만임을 지정 $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은 백업을 하나의 파일로 옮기는 것이 좋습니다. 그러나 드라이브를 사용하면 어디서나 플러그를 꽂을 수 있습니다. 맨손으로도 괜찮습니다.
VonC

+1 경외감, 이것에 대해 살펴 보겠습니다. 예제도 감사합니다.
Dan Rosenstark

Notz @Pat, 결국 나는 그 일을 당신의 방법을 가기로 결정하고, 여기 아래에 (영구적으로 :) 제로에서 개최 점수 대답을 넣어
댄 Rosenstark는

참고 --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

1
@ yar : 명령 줄 없이이 작업을 수행하는 방법을 알고 대신 tortoisegit 만 사용합니다 (명령어가 아닌 Windows 사용자를위한 솔루션을 찾고 있습니다)?
pastacool

@pastacool, 미안하지만 명령 줄이 없으면 git에 대해 전혀 모른다. 아마도 RubyMine과 같은 관련 IDE를 확인 하시겠습니까?
Dan Rosenstark

@intuited, spideroak 또는 Dropbox가있는 파일 또는 Dropbox가 3GB의 공간을 제공하는 디렉토리로 롤백 할 수 있습니까?
Dan Rosenstark

@Yar : 잘 모르겠습니다. Dropbox 지원 디렉토리를 삭제하면 이전에 포함 된 파일의 모든 개정판이 손실된다는 것을 의미합니까? spideroak의 버전 관리 정책에 대한 자세한 내용은 여기를 참조하십시오 . TBH 나는 SpiderOak을 많이 사용하지 않았으며 그 한계를 완전히 확신하지 못합니다. 그러나 이러한 문제에 대한 해결책을 제시 한 것처럼 보이며 기술 역량에 많은 중점을 둡니다. 또한 : Dropbox는 여전히 무료 계정 롤백에 30 일 제한이 있습니까?
intuited

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

감사합니다. 이것은 Github에 유용합니다. 허용되는 답변은 현재 질문에 대한 것입니다.
댄 Rosenstark는

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 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
이 방법이 마음에 들지만 최선의 방법인지 잘 모르겠습니다. '백업'자식 ​​분기를 자주 만들고 결국에는 많은 백업 분기를 갖게됩니다. 이것이 올바른지 확실하지 않습니다 (다른 날짜에서 ~ 20 개의 백업 분기가 있음). 나는 항상 오래된 백업을 삭제할 수 있다고 생각합니다. 그러나 모든 백업을 유지하려면 괜찮습니까? 지금까지는 훌륭하게 연주하고 있지만 좋은 습관인지 나쁜 습관인지 아는 것이 좋습니다.
Kyle Vassella

모범 사례 라고 불리는 것이 아니라 , 나는 일을하는 개인의 습관 과 더 관련이 있다고 가정합니다. 나는 일반적으로 작업이 완료 될 때까지 한 지점에서만 코딩하고 임시 요청을 위해 다른 지점을 유지 합니다. 둘 다 백업이 완료되면 메인 브랜치를 삭제하십시오! :)
NoobEditor
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.