166 votes

Comment sauvegarder un dépôt Git local ?

J'utilise git sur un projet relativement petit et je trouve que zipper le contenu du répertoire .git peut être un bon moyen de sauvegarder le projet. Mais c'est un peu bizarre parce que, quand je restaure, la première chose que je dois faire c'est git reset --hard .

Y a-t-il des problèmes pour sauvegarder un repo git de cette manière ? Y a-t-il un meilleur moyen de le faire (par exemple, un format git portable ou quelque chose de similaire) ?

0 votes

Pourquoi personne n'a donné la réponse évidente d'utiliser git bundle ? ??

0 votes

@gatopeich ils l'ont fait. Faites défiler vers le bas.

2 votes

Toutes les réponses votées contiennent un mur de texte sur les scripts, même celle qui commence à mentionner git bundle

155voto

VonC Points 414372

L'autre méthode officielle consisterait à utiliser git bundle

Cela créera un fichier qui prendra en charge git fetch y git pull pour mettre à jour votre second repo.
Utile pour la sauvegarde et la restauration incrémentielles.

Mais si vous avez besoin de sauvegarder tout (parce que vous n'avez pas de deuxième repo avec du contenu plus ancien déjà en place), la sauvegarde est un peu plus élaborée à faire, comme mentionné dans mon autre réponse, après que Kent Fredric Le commentaire de l'auteur de l'article :

$ 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'un opération atomique par opposition à la création d'une archive à partir du .git dossier, en tant que commenté par fantabolique )


Avertissement : Je ne recommande pas Pat Notz 's solution qui est en train de cloner le repo.
La sauvegarde de nombreux fichiers est toujours plus délicate que la sauvegarde ou la mise à jour... d'un seul fichier.

Si vous regardez le historique des modifications de la OP Yar responder Vous verrez que Yar a d'abord utilisé une clone --mirror ... avec l'édition :

L'utilisation de ce système avec Dropbox est un véritable gâchis .
Vous aurez des erreurs de synchronisation et vous ne pourrez pas faire revenir un répertoire dans DROPBOX.
Utilisation git bundle si vous souhaitez effectuer une sauvegarde sur votre Dropbox.

Yar's solution actuelle utilise un git bundle .

Je n'en dirai pas plus.

0 votes

Je viens de vérifier cela et c'est en fait très bien. Il faudra que j'essaie de faire des regroupements et des dégroupements et des têtes de liste pour être convaincu... mais je l'aime bien. Merci encore, en particulier pour les notes sur le commutateur --all.

0 votes

Dans le même ordre d'idée, y a-t-il un problème à simplement zipper mon dépôt local ? J'ai besoin d'un seul fichier de sauvegarde, copier des milliers de fichiers sur un disque externe est incroyablement lent. Je me demande juste s'il y a quelque chose de plus efficace car zip doit archiver beaucoup de fichiers dans le dossier .git.

0 votes

@faB : la seule différence est que vous pouvez facilement faire incrémentale sauvegarde avec git bundle . Ce n'est pas possible avec un zip global de tous les repo locaux.

64voto

Pat Notz Points 46841

La façon dont je procède est de créer un dépôt distant (nu) (sur un disque séparé, une clé USB, un serveur de sauvegarde ou même github) et d'utiliser ensuite push --mirror pour que ce repo distant ressemble exactement à mon repo local (sauf que le repo distant est un repo nu ).

Ceci poussera toutes les refs (branches et tags) y compris les mises à jour non fast-forward. Je l'utilise pour créer des sauvegardes de mon dépôt local.

En page de manuel le décrit ainsi :

Au lieu de nommer chaque ref à pousser, spécifie que tous les refs sous la rubrique $GIT_DIR/refs/ (ce qui inclut, mais n'est pas limité à refs/heads/ , refs/remotes/ y refs/tags/ ) soit mis en miroir dans le référentiel distant. Les refs locaux nouvellement créés seront poussés vers l'extrémité distante, les refs mis à jour localement seront mis à jour de force sur l'extrémité distante, et les refs supprimés seront supprimés de l'extrémité distante. C'est la valeur par défaut si l'option de configuration remote.<remote>.mirror est défini.

J'ai créé un alias pour effectuer la poussée :

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

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

0 votes

+1. D'accord. git bundle est utile pour déplacer une sauvegarde (un fichier). Mais avec un disque que l'on peut brancher n'importe où, le repo nu est bien aussi.

0 votes

+1 awesme, je vais me pencher sur la question. Merci aussi pour les exemples.

0 votes

@Pat Notz, j'ai finalement opté pour votre façon de faire, et j'ai mis une réponse ci-dessous (score maintenu en permanence à zéro :)

35voto

Yar Points 25421

(Je le laisse ici pour ma propre référence).

Mon bundle script appelé git-backup se présente comme suit

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

J'utilise parfois git backup et parfois j'utilise git backup different-name qui m'offre la plupart des possibilités dont j'ai besoin.

2 votes

+1 Parce que vous n'avez pas utilisé le --global cet alias ne sera vu que dans votre projet (il est défini dans votre fichier .git/config ) -- c'est probablement ce que vous voulez. Merci pour cette réponse plus détaillée et joliment formatée.

1 votes

@yar : savez-vous comment accomplir ces tâches sans la ligne de commande et en utilisant tortoisegit (je cherche une solution pour les utilisateurs de Windoze qui n'utilisent pas la ligne de commande) ?

0 votes

@pastacool, désolé je ne connais pas du tout git sans la ligne de commande. Vous pourriez peut-être consulter un IDE pertinent comme RubyMine ?

24voto

nus Points 1613

J'ai commencé à travailler un peu sur le script de Yar et le résultat est sur github, avec les pages man et install script :

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

Installation :

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

Toutes les suggestions et pull request sur github sont les bienvenues.

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

@Yar Superbe bundle script, basé sur le bundle git que j'ai préconisé dans ma réponse ci-dessous. +1.

1 votes

J'ai déjà installé votre application dans mon dépôt local....comment l'utiliser une fois qu'elle est installée....il n'y a pas d'information à ce sujet dans la documentation, vous devriez inclure une section avec un exemple sur la façon de faire une sauvegarde.

0 votes

Bonjour, désolé que vous n'arriviez pas à le faire fonctionner. Normalement, vous exécutez sudo install.sh puis le configurer (il utilise le système de configuration de git) pour définir le répertoire de destination (voir le fichier readme sur github). Ensuite, vous exécutez git backup dans votre dépôt. En passant, il s'agissait d'une expérience avec git bundle et d'une réponse à cette question, mais git bundle ne fait jamais une copie exacte absolue (par exemple, si je me souviens bien, en particulier en ce qui concerne git remotes), donc personnellement j'utilise en fait tar pour sauvegarder les répertoires .git.

9voto

Nacho Coloma Points 930

Les deux réponses à ces questions sont correctes, mais il me manquait toujours une solution complète et courte pour sauvegarder un dépôt Github dans un fichier local. Les liste est disponible ici, n'hésitez pas à la forger ou à l'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 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X