Skip to content

Instantly share code, notes, and snippets.

@dotysan
Last active November 4, 2016 00:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dotysan/8277858 to your computer and use it in GitHub Desktop.
Save dotysan/8277858 to your computer and use it in GitHub Desktop.
#! /usr/bin/env bash
#
# purpose: fork an already-cloned github repository from shell
#
# itch: You've made changes to someone else's repo that you've already
# cloned. Now you want to share them to github; but without all the
# silly gyrations.
#
# bug: it assumes you use ssh not https; and it creates/caches an api key
#
set -e
this=$(basename $0)
me=${1-dotysan}
now=$(date +%F)
url=$(git config --get remote.origin.url)
if [[ $url =~ .+github\.com.(.+)/(.+)\.git$ ]]
then upstream_user="${BASH_REMATCH[1]}"
repo="${BASH_REMATCH[2]}"
else echo "ERROR: Remote origin is not on github."
exit 1
fi >&2
if ! ghuser=$(git config --get github.user)
then ghuser="$me"
git config --global github.user "$ghuser"
fi
if [ "$upstream_user" = "$ghuser" ]
then echo "ERROR: Can't fork your own repo."
exit 1
fi >&2
gen_tok() {
note="$USER@$HOSTNAME on $now using $this: https://gist.github.com/dotysan/8277858"
data="{\"scopes\":[\"public_repo\"],\"note\":\"$note\"}"
api=https://api.github.com/authorizations
echo "Generating new access token..."
# it will prompt for your github password here
json=$(curl --silent --user "$ghuser" --data "$data" $api)
re='"token": "([0-9a-f]{40})"'
if [[ $json =~ $re ]]
then tok="${BASH_REMATCH[1]}"
else echo "$json"
echo "CRAP! Something went wrong."
exit 1
fi >&2
git config --global github.token "$tok"
git config --global github.toknote "$note"
}
# try and use an API token; otherwise create one and save
tok=$(git config --get github.token) ||gen_tok
do_fork() {
post="https://$ghuser:$tok@api.github.com/repos/$upstream_user/$repo/forks"
json=$(curl --silent --request POST "$post")
}
# TODO: check to see if the fork already exists before creating; in
# order to avoid collissions if the upstream isn't in sync
do_fork
# re-create/retry a failed/stale token
if grep -q '"message": "Bad credentials"' <<<"$json"
then gen_tok
do_fork
fi
# they say it's async...so just in case they're busy...
sleep 1
re=" \"ssh_url\": \"(git@github\.com:$ghuser/$repo\.git)\""
if [[ $json =~ $re ]]
then origin="${BASH_REMATCH[1]}"
fi
if [ "$origin" != "git@github.com:$ghuser/$repo.git" ]
then echo "$json"
echo "CRAP! Something went wrong."
exit 1
fi >&2
git remote set-url origin "$origin"
git remote add upstream "git@github.com:$upstream_user/$repo.git"
# alas! share local changes into the newly forked public repo
git push
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment