diff --git a/Commands.md b/Commands.md index 9f58bc557..c6a1be7aa 100644 --- a/Commands.md +++ b/Commands.md @@ -19,6 +19,7 @@ - [`git extras`](#git-extras) - [`git feature|refactor|bug|chore`](#git-featurerefactorbugchore) - [`git fork`](#git-fork) + - [`git force-clone`](#git-force-clone) - [`git fresh-branch`](#git-fresh-branch) - [`git gh-pages`](#git-gh-pages) - [`git graft`](#git-graft) @@ -344,6 +345,21 @@ upstream git@github.com:LearnBoost/expect.js (fetch) upstream git@github.com:LearnBoost/expect.js (push) ``` +## git force-clone + +If the clone target directory exists and is a git repository, reset its +contents to a clone of the remote. + +``` bash +$ git force-clone [-b {branch_name}] {remote_url} {destination_path} +$ git force-clone -b master https://github.com/tj/git-extras ./target-directory +``` + +**CAUTION**: If the repository exists, this will destroy *all* local changes +to the repository - changed files will be reset and local branches will be +removed. + +[More information](man/git-force-clone.md). ## git release diff --git a/bin/git-force-clone b/bin/git-force-clone new file mode 100755 index 000000000..0f7568560 --- /dev/null +++ b/bin/git-force-clone @@ -0,0 +1,108 @@ +#! /usr/bin/env bash + +set -euo pipefail + +_usage() { + echo " +Usage: + git-force-clone -b branch remote_url destination_path + +Example: + git-force-clone -b master git@github.com:me/repo.git ./repo_dir + +Provides the basic functionality of 'git clone', but if the destination git +repository already exists it will force-reset it to resemble a clone of the +remote. + +Because it doesn't actually delete the directory, it is usually significantly +faster than the alternative of deleting the directory and cloning the +repository from scratch. + +**CAUTION**: If the repository exists, this will destroy *all* local work: +changed files will be reset, local branches and other remotes will be removed. + +OPTIONS: + -b, --branch The branch to pull from the remote (default: master) + -h, --help Display this help message +" +} + +_check() { + if [ -z "$1" ]; then + echo "Error: Missing ${2}" + _usage + exit 1 + fi +} + +main() { + while [[ -n "${1:-}" ]] && [[ "${1:0:1}" == "-" ]]; do + case $1 in + -b | --branch ) + branch=${2:-} + shift + ;; + -h | --help ) + _usage + exit 0 + ;; + * ) + echo "Error: Invalid option: $1" >>/dev/stderr + _usage + exit 1 + ;; + esac + shift + done + + remote_url=${1:-} + destination_path=${2:-} + + _check "${remote_url}" "remote_url" + _check "${destination_path}" "destination_path" + + if [ -d "${destination_path}/.git" ]; then + ( + cd ${destination_path} + + # Delete all remotes + for remote in `git remote`; do + git remote rm ${remote} + done + + # Add origin + git remote add origin ${remote_url} + git fetch origin + + # Set default branch + if [ -z "${branch:-}" ]; then + branch=`LC_ALL=C git remote show origin | grep -oP '(?<=HEAD branch: )[^ ]+$'` + git remote set-head origin ${branch} + else + git remote set-head origin -a + fi + + # Make sure current branch is clean + git clean -fd + git reset --hard HEAD + + # Get on the desired branch + git checkout ${branch} + git reset --hard origin/${branch} + + # Delete all other branches + branches=`git branch | grep -v \* | xargs` + if [ -n "${branches}" ]; then + git branch -D ${branches} + fi + ) + elif [ -n "${branch:-}" ]; then + git clone -b ${branch} ${remote_url} ${destination_path} + else + git clone ${remote_url} ${destination_path} + fi +} + +main "$@" + +exit 0 diff --git a/etc/git-extras-completion.zsh b/etc/git-extras-completion.zsh index 9465cab3c..03d760d38 100644 --- a/etc/git-extras-completion.zsh +++ b/etc/git-extras-completion.zsh @@ -259,7 +259,6 @@ _git-feature() { esac } - _git-graft() { _arguments \ ':src-branch-name:__gitex_branch_names' \ @@ -373,6 +372,7 @@ zstyle ':completion:*:*:git:*' user-commands \ effort:'show effort statistics on file(s)' \ extras:'awesome git utilities' \ feature:'create/merge feature branch' \ + force-clone:'overwrite local repositories with clone' \ fork:'fork a repo on github' \ fresh-branch:'create fresh branches' \ gh-pages:'create the github pages branch' \ diff --git a/man/git-force-clone.1 b/man/git-force-clone.1 new file mode 100644 index 000000000..1f57ccf42 --- /dev/null +++ b/man/git-force-clone.1 @@ -0,0 +1,57 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "GIT\-FORCE\-CLONE" "1" "2016-10-29" "" "Git Extras" +. +.SH "NAME" +\fBgit\-force\-clone\fR \- overwrite local repositories with clone +. +.SH "SYNOPSIS" +\fBforce\-clone \-\-help\fR \fBforce\-clone {remote_url} {destination_path}\fR \fBforce\-clone \-\-branch {branch_name} {remote_url} {destination_path}\fR +. +.SH "DESCRIPTION" +Provides the basic functionality of \fBgit clone\fR, but if the destination git repository already exists it will force\-reset it to resemble a clone of the remote\. +. +.P +Because it doesn\'t actually delete the directory, it is usually significantly faster than the alternative of deleting the directory and cloning the repository from scratch\. +. +.P +\fBCAUTION\fR: If the repository exists, this will destroy \fIall\fR local work: changed files will be reset, local branches and other remotes will be removed\. +. +.SH "PROCESS" +If \fBtarget\-directory\fR doesn\'t exist or isn\'t a git repository then the arguments will simply be passed through to \fBgit clone\fR\. +. +.P +If \fBtarget\-directory\fR exists and is a git repository then this will: +. +.IP "\(bu" 4 +Remove all remotes +. +.IP "\(bu" 4 +Set the origin remote to \fB{remote_url}\fR and fetch the remote +. +.IP "\(bu" 4 +Discover the default branch, if no branch was specified +. +.IP "\(bu" 4 +Check out the selected branch +. +.IP "\(bu" 4 +Delete all other local branches +. +.IP "" 0 +. +.SH "OPTIONS" +\fB{remote_url}\fR \- The URL for a git remote repository of which to make a clone\. \fB{destination_path}\fR \- A path to the local git repository location to clone into\. \fB\-\-branch {branch_name}\fR \- After cloning, checkout this branch\. +. +.SH "EXAMPLES" +\fBgit\-force\-clone \-b master git@github\.com:me/repo\.git \./repo_dir\fR +. +.SH "AUTHOR" +Written by Robin Winslow \fIrobin@robinwinslow\.co\.uk\fR\. +. +.SH "REPORTING BUGS" +\fIhttps://github\.com/tj/git\-extras/issues\fR +. +.SH "SEE ALSO" +\fIhttps://github\.com/tj/git\-extras\fR diff --git a/man/git-force-clone.html b/man/git-force-clone.html new file mode 100644 index 000000000..068b50694 --- /dev/null +++ b/man/git-force-clone.html @@ -0,0 +1,144 @@ + + +
+ + +
+ git-force-clone
- overwrite local repositories with clone
+
force-clone --help
+force-clone {remote_url} {destination_path}
+force-clone --branch {branch_name} {remote_url} {destination_path}
Provides the basic functionality of git clone
, but if the destination git
+repository already exists it will force-reset it to resemble a clone of the
+remote.
Because it doesn't actually delete the directory, it is usually significantly +faster than the alternative of deleting the directory and cloning the +repository from scratch.
+ +CAUTION: If the repository exists, this will destroy all local work: +changed files will be reset, local branches and other remotes will be removed.
+ +If target-directory
doesn't exist or isn't a git repository then the
+arguments will simply be passed through to git clone
.
If target-directory
exists and is a git repository then this will:
{remote_url}
and fetch the remote{remote_url}
- The URL for a git remote repository of which to make a clone.
+{destination_path}
- A path to the local git repository location to clone into.
+--branch {branch_name}
- After cloning, checkout this branch.
git-force-clone -b master git@github.com:me/repo.git ./repo_dir
Written by Robin Winslow robin@robinwinslow.co.uk.
+ +https://github.com/tj/git-extras/issues
+ +https://github.com/tj/git-extras
+ + +