Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to clone a git repo with all branches and tags from refs/remotes?

I have a local git repo that I created from an svn repo:

$ git svn clone -s svn:...

I then created a backup remote and pushed everything to it:

$ git remote add backup git@myhost:mybackup.git
$ git push --mirror backup

Now, when I try to clone from my backup, it is missing all svn tags and branches.

$ git clone git@myhost:mybackup.git
$ cd mybackup
$ git branch -a
* master
  origin
  remotes/origin/HEAD -> origin/master
  remotes/origin/master

How do I clone the repo with all tags and branches?

The only way I have found is to mirror the repo:

$ git clone --mirror git@myhost:mybackup.git

This creates a local mybackup.git directory, which knows about all tags/branches (I can use tab completion to get the entire list) but it is not a valid usable repo:

$ git checkout mytag
fatal: This operation must be run in a work tree

There must be command line option to truly clone the repo with all branches/tags???

I have found several related questions here but none of the answers work for this situation. I assume the difference is that my clone was created with --mirror?

like image 536
Shadow Man Avatar asked Aug 02 '13 00:08

Shadow Man


2 Answers

After a lot of searching, I finally found an answer...

git clone git@myhost:mybackup.git newdirectory
cd newdirectory
git fetch origin refs/remotes/*:refs/remotes/*
git init

Now a git branch -a shows all of my remote branches.

I'm not sure if the git init is needed here or if it is only needed in the git init --bare variant (see the commented out lines in the shell script below), but I am sure that it harms nothing to leave it in if it is not needed.

My main reason in doing this is to get my SVN tags/branches copied over rather than only having master pointing to SVN trunk and without having to parse the entire SVN history (very slow for projects with a lot of history, tags and branches). So to copy over my SVN info:

git svn init -s "svn://mysvnhost/mysvnrepo/myproject"
git svn fetch
git checkout master

To speed this process up, I created a shell script:

#!/bin/sh
#
# git-clone-svn-based-repo.sh:
#
# clones a git-svn based repo including all SVN commits without pounding
# the SVN server for hours (just a quick refresh taking seconds)
#

usage_exit ()
{
   echo "Usage: $0 <git-repo> <dest-directory> <svn-project>"
   exit 1
}


if ! git ls-remote "$1" > /dev/null  2>&1
then
   echo "No git repo found at: $1"
   usage_exit
fi

if [ -r "$2" ]
then
   echo "File or directory already exists: $2"
   usage_exit
fi

if ! svn ls "$3" 2> /dev/null | grep -q trunk
then
   echo "No SVN project found at: $3"
   usage_exit
fi

# create new bare git repo
mkdir "$2"
cd "$2"
git init --bare .git

# fetch everything from backup
git remote add backup "$1"
git fetch backup refs/remotes/*:refs/remotes/*
git fetch backup refs/heads/*:refs/heads/*
git fetch backup refs/tags/*:refs/tags/*

# disable future fetching from backup
# setup to push all remote refs to backup by default
git config remote.backup.fetch do_not_fetch_from_backup
git config remote.backup.push '+refs/remotes/*:refs/remotes/*'

# initialize git repo to usable (non-bare) state
git init

# update SVN references
git svn init -s "svn://svn.crc-corp.com/carsrepository/$3"
git config svn.authorsfile $HOME/projects/authors.txt
git svn fetch

# update master to current SVN trunk
git checkout master
git svn rebase
# update ignore properties from SVN
git svn show-ignore >> .git/info/exclude

In order to create such a backup from an existing git SVN repo:

# create a bare backup repo at git@myhost:mybackup.git
git remote add backup git@myhost:mybackup.git
git config remote.backup.fetch do_not_fetch_from_backup
git config remote.backup.push '+refs/remotes/*:refs/remotes/*'
git push backup
like image 86
Shadow Man Avatar answered Oct 21 '22 19:10

Shadow Man


There are two ways to improve your command git clone --mirror git@myhost:mybackup.git The one I found is this one, knowing that your command created a mybackup.git directory :

mkdir mybackup
mv mybackup.git mybackup/.git
cd mybackup
git init

There, you have a full working directory.

Alternatively as you can read on this page : https://git.wiki.kernel.org/index.php/Git_FAQ#How_do_I_clone_a_repository_with_all_remotely_tracked_branches.3F

git clone --mirror git@myhost:mybackup.git mybackup/.git
cd mybackup
git config --bool core.bare false

I think both are equivalent up to the last line, and probably the command git config --bool core.bare false is cleaner than doing a git init.

It all sums up to the fact that --mirror creates a bare repository and not a working repository, so you need to transform it into a working repository.

like image 22
Yth Avatar answered Oct 21 '22 17:10

Yth