web-dev-qa-db-fra.com

Comment sauvegarder un référentiel Git local?

J'utilise git sur un projet relativement petit et je trouve que le fait de compresser le contenu du répertoire .git pourrait être un bon moyen de sauvegarder le projet. Mais c’est un peu bizarre, car lors de la restauration, la première chose à faire est de git reset --hard.

Y at-il des problèmes avec la sauvegarde d’un repo git de cette façon? En outre, y a-t-il une meilleure façon de le faire (par exemple, un format git portable ou quelque chose de similaire?)?

151
Dan Rosenstark

J'ai commencé à travailler un peu sur le script de Yar et le résultat est sur github, y compris les pages de manuel et le script d'installation:

https://github.com/najamelan/git-backup

Installation :

git clone "https://github.com/najamelan/git-backup.git"
cd git-backup
Sudo ./install.sh

Accueillir toutes les suggestions et tirer la demande sur 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
24
user1115652

L'autre façon officielle serait d'utiliser git bundle

Cela créera un fichier qui supporte git fetch Et git pull Afin de mettre à jour votre deuxième référentiel.
Utile pour la sauvegarde et la restauration incrémentielles.

Mais si vous devez sauvegarder tout (car vous n'avez pas de deuxième dépôt avec du contenu plus ancien déjà en place), la sauvegarde est un peu plus élaborée, comme indiqué dans mon autre réponse. , après le commentaire de 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

(Il s’agit d’une opération atomique , par opposition à la création d’une archive à partir du dossier .git, Comme commenté par fantabolous )


Attention: je ne recommanderais pas Pat Notz 's solution , qui clone le repo.
Sauvegarder de nombreux fichiers est toujours plus délicat que de sauvegarder ou de mettre à jour… un seul.

Si vous regardez le historique des modifications du OP Yarréponse , vous verrez que Yar a d'abord utilisé un clone --mirror , ... avec l'édition:

Utiliser ceci avec Dropbox est un gâchis total .
Vous aurez des erreurs de synchronisation et vous NE POUVEZ PAS RECOUVRIR UN RÉPERTOIRE DANS DROPBOX.
Utilisez git bundle Si vous voulez sauvegarder dans votre boîte de dépôt.

Yar solution actuelle utilise git bundle.

Je repose mon cas.

142
VonC

Pour ce faire, je crée un référentiel (nu) distant (sur un lecteur séparé, une clé USB, un serveur de sauvegarde ou même un github), puis j'utilise Push --mirror pour que ce dépôt distant ressemble exactement à mon dépôt local (sauf que le dépôt distant est un référentiel nu ).

Cela va pousser toutes les références (branches et balises), y compris les mises à jour non avancées. J'utilise ceci pour créer des sauvegardes de mon référentiel local.

Le page de manuel le décrit ainsi:

Au lieu de nommer chaque référence en Push, spécifie que toutes les références sous $GIT_DIR/refs/ _ (qui inclut, sans toutefois s'y limiter, refs/heads/, refs/remotes/, et refs/tags/) être mis en miroir sur le référentiel distant. Les références locales nouvellement créées seront poussées vers l'extrémité distante, les références actualisées localement seront mises à jour de force sur l'extrémité distante et les références supprimées seront supprimées de l'extrémité distante. C'est la valeur par défaut si l'option de configuration remote.<remote>.mirror est réglé.

J'ai fait un pseudonyme pour faire le Push:

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

Ensuite, je lance juste git bak chaque fois que je veux faire une sauvegarde.

62
Pat Notz

[Laissons simplement ceci ici pour ma propre référence.]

Mon script de lot appelé git-backup ressemble à ça

#!/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

Parfois, j'utilise git backup et parfois j'utilise git backup different-name qui me donne la plupart des possibilités dont j'ai besoin.

35
Dan Rosenstark

Les deux réponses à cette question sont correctes, mais il me manquait encore une solution complète et courte pour sauvegarder un référentiel Github dans un fichier local. Le Gist est disponible ici, n'hésitez pas à bifurquer ou à vous adapter à vos besoins.

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

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
9
Nacho Coloma

Vous pouvez sauvegarder le repo git avec git-copy . git-copy a sauvegardé le nouveau projet en tant que dépôt nu, cela signifie un coût de stockage minimum.

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

Ensuite, vous pouvez restaurer votre projet avec git clone

git clone /backup/project.backup project
4
Quanlong

est venu à cette question via google.

Voici ce que j'ai fait de la manière la plus simple.

git checkout branch_to_clone

puis créez une nouvelle branche git à partir de cette branche

git checkout -b new_cloned_branch
Switched to branch 'new_cloned_branch'

revenez à la branche d'origine et continuez:

git checkout branch_to_clone

En supposant que vous ayez foiré et que vous ayez besoin de restaurer quelque chose depuis une branche de sauvegarde:

git checkout new_cloned_branch -- <filepath>  #notice the space before and after "--"

La meilleure partie si quelque chose est foiré, vous pouvez simplement supprimer la branche source et revenir à la branche de sauvegarde !!

1
NoobEditor