LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Go Back   LinuxQuestions.org > Blogs > sag47
User Name
Password

Notices


Rate this Entry

Cloning a git repository in an idempotent way

Posted 05-20-2015 at 02:08 AM by sag47
Updated 05-20-2015 at 02:25 AM by sag47

In config management, it is best to do setup in an idempotent way. After some basic research here's a way to clone a repository in an idempotent way. In this example we'll be cloning my home repository into ${HOME}/git/home.

First, check to see if the repository directory exists. Then change the working directory to it.

Code:
#variables
repo="https://github.com/samrocketman/home.git"
local_repo_location="${HOME}/git/home"
default_branch="master"

#create the repository destination directory
if [ ! -e "${local_repo_location}" ];then
  mkdir -p "${local_repo_location}"
elif [ ! -d "${local_repo_location}" ];then
  echo "ERROR: ${local_repo_location} exists but is not a directory."
  exit 1
fi
cd "${local_repo_location}"
Next you want to check that we're actually in a repository. If not, then initialize an empty repository.

Code:
#ensure it is a git repository
if ! git rev-parse --is-inside-work-tree &> /dev/null;then
  echo "${PWD} is not a git repository.  Running 'git init'."
  git init
else
  echo "${PWD} is already a git repository."
fi
Next you want to check that your origin remote is set up. If it's not then it means this is still a first time clone and we need to add an origin remote.

Code:
#remember we set repo=https://github.com/samrocketman/home
#ensure it has an origin remote configured
if ! git config remote.origin.url &> /dev/null;then
  echo "No origin remote found.  Running 'git remote add origin ${repo}'."
  git remote add origin ${repo}
else
  echo "origin remote already exists."
  git remote -v
fi
Now fetch the latest changes. This won't affect the currently checked out HEAD. It will simply download the entire repository into the origin remote namespace refs/remotes/origin. This is akin to git clone to download your repository.

Code:
#fetch the latest changes
echo "Downloading latest repository changes.  Running 'git fetch'."
git fetch
Check that you have a workspace checked out. That is, your HEAD has a reference checked out. If there is no HEAD reference checked out then check out the default branch on the remote repository. If HEAD already has something checked out then don't do anything.

Code:
#checkout the default branch if no workspace checked out
if ! git rev-parse --abbrev-ref HEAD &> /dev/null;then
  if [ ! -z "${default_branch}" ];then
    echo "HEAD not currently checked out.  Running 'git checkout ${default_branch}'."
    git checkout ${default_branch}
  else
    echo "ERROR: Could not determine remote default branch."
  fi
else
  echo "Workspace HEAD is already checked out."
fi
Here's the full script.

Code:
#this turns an existing directory into a git repository instead of cloning

#variables
repo="https://github.com/samrocketman/home.git"
local_repo_location="${HOME}/git/home"
default_branch="master"

#create the repository destination directory
if [ ! -e "${local_repo_location}" ];then
  mkdir -p "${local_repo_location}"
elif [ ! -d "${local_repo_location}" ];then
  echo "ERROR: ${local_repo_location} exists but is not a directory."
  exit 1
fi
cd "${local_repo_location}"

#ensure it is a git repository
if ! git rev-parse --is-inside-work-tree &> /dev/null;then
  echo "${PWD} is not a git repository.  Running 'git init'."
  git init
else
  echo "${PWD} is already a git repository."
fi

#ensure it has an origin remote configured
if ! git config remote.origin.url &> /dev/null;then
  echo "No origin remote found.  Running 'git remote add origin ${repo}'."
  git remote add origin ${repo}
else
  echo "origin remote already exists."
  git remote -v
fi

#fetch the latest changes
echo "Downloading latest repository changes.  Running 'git fetch'."
git fetch

#checkout the default branch if no workspace checked out
if ! git rev-parse --abbrev-ref HEAD &> /dev/null;then
  #get the default branch of the origin remote
  default_branch="$(git ls-remote origin | awk '$2 == "HEAD" { head=$1; next}; $1 == head {sub(/refs\/heads\//, "",$2);print $2}')"
  if [ ! -z "${default_branch}" ];then
    echo "HEAD not currently checked out.  Running 'git checkout ${default_branch}'."
    git checkout ${default_branch}
  else
    echo "ERROR: Could not determine remote default branch."
  fi
else
  echo "Workspace HEAD is already checked out."
fi
We've just cloned a repository in an idempotent way. If the repository already exists then it doesn't try to do anything funny. In this way, you can break out the different steps and do different things if you like... Or you could just be lazy and do the following.

Code:
[ ! -e "${HOME}/git/home" ] && git clone https://github.com/samrocketman/home.git "${HOME}/git/home"
Posted in Uncategorized
Views 6446 Comments 2
« Prev     Main     Next »
Total Comments 2

Comments

  1. Old Comment
    I was thinking of attempting parsing the default branch with the following.

    Code:
    git ls-remote origin | awk '$2 == "HEAD" { head=$1; next}; $1 == head && $2 ~ /^refs\/heads/ {sub(/refs\/heads\//, "",$2);print $2}'
    However, if more than one branch refers to the same reference then that breaks. It's hard to determine the default branch.
    Posted 05-20-2015 at 02:19 AM by sag47 sag47 is offline
  2. Old Comment
    This blog post is useless due to the advent of the smart git protocol. Since sites using the "dumb protocol" are becomming rare this post has limited, if any, use.
    Posted 12-07-2015 at 01:48 PM by sag47 sag47 is offline
 

  



All times are GMT -5. The time now is 02:15 AM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration