Asked  6 Months ago    Answers:  5   Viewed   27 times

I am using git on a relatively small project and I find that zipping the .git directory's contents might be a fine way to back up the project. But this is kind of weird because, when I restore, the first thing I need to do is git reset --hard.

Are there any problems with backing up a git repo this way? Also, is there any better way to do it (e.g., a portable git format or something similar?)?

 Answers

13

I started hacking away a bit on Yar's script and the result is on github, including man pages and install script:

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

Installation:

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

Welcoming all suggestions and pull request on 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
Tuesday, June 1, 2021
 
Packy
answered 6 Months ago
14

To create the mirror:

git clone --mirror git://github.com/user/project.git

To update:

cd project.git
git remote update

To update without changing the current directory:

git --git-dir project.git remote update
Tuesday, June 1, 2021
 
cusejuice
answered 6 Months ago
71

If you have access to a shared directory, you can (see git clone and git remote):

git clone --bare /path/to/your/laptop/repo /shared/path/to/desktop/repo.git
git remote add desktop  /shared/path/to/desktop/repo.git

That will create a bare repo, referenced in your local repo as "desktop".
Since it is bare, you can push to it (as well as pull from it if needed)

git push desktop

As the ProGit book mentions, git does support the file protocol:

The most basic is the Local protocol, in which the remote repository is in another directory on disk.
This is often used if everyone on your team has access to a shared filesystem such as an NFS mount, or in the less likely case that everyone logs in to the same computer.

Saturday, June 12, 2021
 
hillz
answered 6 Months ago
40

You can use git-sync

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: git-sync-test
spec:
  selector:
    matchLabels:
      app: git-sync-test
  serviceName: "git-sync-test"
  replicas: 1
  template:
    metadata:
      labels:
        app: git-sync-test
    spec:
      containers:
      - name: git-sync-test
        image: <your-main-image>
        volumeMounts:
        - name: service
          mountPath: /var/magic
      initContainers:
      - name: git-sync
        image: k8s.gcr.io/git-sync-amd64:v2.0.6
        imagePullPolicy: Always
        volumeMounts:
        - name: service
          mountPath: /magic
        - name: git-secret
          mountPath: /etc/git-secret
        env:
        - name: GIT_SYNC_REPO
          value: <repo-path-you-want-to-clone>
        - name: GIT_SYNC_BRANCH
          value: <repo-branch>
        - name: GIT_SYNC_ROOT
          value: /magic
        - name: GIT_SYNC_DEST
          value: <path-where-you-want-to-clone>
        - name: GIT_SYNC_PERMISSIONS
          value: "0777"
        - name: GIT_SYNC_ONE_TIME
          value: "true"
        - name: GIT_SYNC_SSH
          value: "true"
        securityContext:
          runAsUser: 0
      volumes:
      - name: service
        emptyDir: {}
      - name: git-secret
        secret:
          defaultMode: 256
          secretName: git-creds # your-ssh-key

For more details check this link.

Wednesday, August 11, 2021
 
Boris
answered 4 Months ago
56

I think the clone --mirror approach is worth looking back at. If you want to recover a past position of a branch which was force-pushed, just have a look at the reflogs. To be absolutely sure about this, you can set gc.pruneExpire to never, and the same for gc.reflogExpireUnreachable, so that reflogs and unreachable objects will never be removed. That ought to cover you. Important note: reflogs are by default disabled in bare repositories. You can enable them by setting core.logAllRefUpdates.

Do note that the reflogs in the pushed-to repository will contain records of any forced pushes that happen. If you want to be even more sure about this, you could even write an update hook that detects incoming forced updates and records them somewhere special, perhaps by creating a ref, something like refs/backups/mybranch-{n}.

And really, there's nothing wrong with some branches being rebased frequently, as long as it's in a well-defined way, so that no one is caught off guard. The pu branch in git.git is a perfect example of this.

Sunday, October 3, 2021
 
HamidR
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share