Git shortcut to pull with clone if no local there yet?
GitJenkinsGit Problem Overview
Is there a one-command way to get an up-to-date mirror of a remote repo? That is
- if local repo not there yet: clone
- if it's there: pull
I know I could script this around (e.g if [ -d repo ]; then (cd repo && git pull); else git clone $repourl;fi
) , but I need the simplest possible cross-platform way (actually used for Jenkins-CI, which I know does this by default, however I need 2 repos for which support is limited).
Git has similar shortcuts for other things (eg. checkout -b, and pull itself), so I'm wondering if I missed something. Thanks!
Git Solutions
Solution 1 - Git
There is not, given that the commands which operate on existing repos all assume that they're being run inside a given repo.
That said, if you're running in a shell, you could simply make use of the shell built-ins. For instance, here's bash:
if cd repo; then git pull; else git clone https://server/repo repo; fi
This checks to see if repo
is a valid directory, and if so, does a pull
within it; otherwise it does a clone
to create the directory.
Solution 2 - Git
The cleanest one-liner might be
git -C repo pull || git clone https://server/repo repo
Solution 3 - Git
git -C repo pull
will only work on git 1.8.5 or above. To achieve this on earlier versions, try:
remote_repo=https://server/repo
local_repo=repo
if [ -d $local_repo/.git ]; then pushd $local_repo; git pull; popd; else git clone $remote_repo; fi
Solution 4 - Git
If upgrading git is not an option, and you don't want to pass an argument for a repo, a scripting approach could be:
#!/bin/bash
function clone_pull {
DIRECTORY=$(basename "$1" .git)
if [ -d "$DIRECTORY" ]; then
cd "$DIRECTORY"
git pull
cd ../
else
git clone "$1"
fi
}
clone_pull https://github.com/<namespace>/<repo>
# or
clone_pull [email protected]:<namespace>/<repo>.git
Solution 5 - Git
git pull
knows from where to clone because the local repo has a remote registered in its local config. It operates from a working tree.
But git clone
doesn't, it must have an explicit remote url passed in parameter in order to clone. It operates outside the working tree.
The main reason for such a shortcut to not exist is that:
- you
git init
rarely for a given repo: it is a one-time command in the life of the repo.
Plus it might need additional command to be complete: if you havesubmodules, for instance, you would need to add agit submodule update --init
. - you
git pull
often within a given repo. git pull is in itself a shortcut (forgit fetch
+git merge
). Evengit pull --rebase
is another shortcut forgit fetch
+git rebase
.
Considering the number of times you are to use git init
, such a shortcut is not an high priority.
So a script remains the surest way to define what you need.
Solution 6 - Git
Since you mentioned Jenkins, it is possible to clone or pull using the Jenkins SCM API. The checkout
method does exactly what you want.
You can run it from a groovy script like so:
dir (targetFolder) {
checkout(scm: [$class: 'GitSCM', branches: [[name: 'master']], ...])
}
Note that it does not check out the specified branch in the git sense, but rather leaves the workspace on a detached head at the corresponding commit.
Solution 7 - Git
Here is another 1-liner. In contrast to other solutions here, this code does not output an error in the terminal:
(test -d my-repo && git -C my-repo pull --rebase) || \
git clone https://github.com/my-repo my-repo
Here is a variation where the repo and source URL are variables, so you don't need to repeat the repo-folder three times:
DIR=my-repo && ORIGIN=https://github.com/my-repo/ && \
(test -d $DIR && git -C $DIR pull --rebase) || git clone $ORIGIN $DIR