mirror of
https://github.com/paulirish/git-open.git
synced 2026-09-11 16:06:15 -04:00
Instead of trying to strip on ':' and '/' to simplify a URL, actually
switch based on whether the remote path is a URL ("scheme://host:port/path")
or an SCP-style path (user@host:path) and parse them separately.
This allows us to handle custom ports in HTTP and HTTPS, but ignore
custom ports in an SSH url and HTTP remotes, instead of always upgrading
them to HTTPS.
164 lines
4.5 KiB
Bash
Executable file
164 lines
4.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
# Use git-sh-setup, similar to git-rebase
|
|
# https://www.kernel.org/pub/software/scm/git/docs/git-sh-setup.html
|
|
# https://github.com/git/git/blob/master/git-rebase.sh
|
|
# shellcheck disable=SC2034
|
|
OPTIONS_STUCKLONG=t
|
|
# shellcheck disable=SC2034
|
|
OPTIONS_KEEPDASHDASH=
|
|
# shellcheck disable=SC2034
|
|
OPTIONS_SPEC="\
|
|
git open [options]
|
|
git open [remote] [branch]
|
|
--
|
|
Opens the GitHub page for a repo/branch in your browser.
|
|
https://github.com/paulirish/git-open/
|
|
|
|
Available options are
|
|
i,issue! open issues page
|
|
"
|
|
|
|
# https://github.com/koalaman/shellcheck/wiki/SC1090
|
|
# shellcheck source=/dev/null
|
|
. "$(git --exec-path)/git-sh-setup"
|
|
|
|
# Defaults
|
|
is_issue=0
|
|
protocol="https"
|
|
|
|
while test $# != 0; do
|
|
case "$1" in
|
|
--issue) is_issue=1;;
|
|
--) shift; break ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# are we in a git repo?
|
|
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
echo "Not a git repository." 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# choose remote. priority to: provided argument, detected tracked remote, 'origin'
|
|
branch_name=$(git name-rev --name-only HEAD 2>/dev/null)
|
|
tracked_remote=$(git config "branch.$branch_name.remote")
|
|
remote=${1:-$tracked_remote}
|
|
remote=${remote:-"origin"}
|
|
|
|
# @TODO ls-remote will also expand "insteadOf" items `giturl=$(git ls-remote --get-url $remote)``
|
|
giturl=$(git config --get "remote.${remote}.url")
|
|
|
|
if [[ -z "$giturl" ]]; then
|
|
echo "Git remote is not set for $remote" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# From git-fetch(5), native protocols:
|
|
# ssh://[user@]host.xz[:port]/path/to/repo.git/
|
|
# git://host.xz[:port]/path/to/repo.git/
|
|
# http[s]://host.xz[:port]/path/to/repo.git/
|
|
# ftp[s]://host.xz[:port]/path/to/repo.git/
|
|
# [user@]host.xz:path/to/repo.git/ - scp-like but is an alternative to ssh.
|
|
|
|
# Determine whether this is a url (https, ssh, git+ssh...) or an scp-style path
|
|
if [[ "$giturl" =~ ^[a-z\+]+://.* ]]; then
|
|
# Trim URL scheme and possible username
|
|
gitprotocol=${giturl%%://*}
|
|
uri=${giturl#*://}
|
|
uri=${uri#*@}
|
|
|
|
# Split on first '/ to get server name and path
|
|
domain=${uri%%/*}
|
|
urlpath=${uri#*/}
|
|
|
|
# Remove port number from non-http/https protocols (ie, ssh)
|
|
if [[ $gitprotocol != 'https' && $gitprotocol != 'http' ]]; then
|
|
domain=${domain%:*}
|
|
fi
|
|
else
|
|
# Trim possible username from SSH path
|
|
uri=${giturl##*@}
|
|
|
|
# Split on first ':' to get server name and path
|
|
domain=${uri%%:*}
|
|
urlpath=${uri#*:}
|
|
fi
|
|
|
|
# Trim "/" from beginning of URL; "/" and ".git" from end of URL
|
|
urlpath=${urlpath#/} urlpath=${urlpath%/} urlpath=${urlpath%.git}
|
|
|
|
# If the URL is provided as "http", preserve that
|
|
if [[ $gitprotocol == 'http' ]]; then
|
|
protocol='http'
|
|
fi
|
|
|
|
# Allow config options to replace the server or the protocol
|
|
openurl="$protocol://$domain"
|
|
|
|
function getConfig() {
|
|
config=$(git config --get-urlmatch "open.$1" "$openurl")
|
|
echo "${config:-${!1}}"
|
|
}
|
|
|
|
domain=$(getConfig "domain")
|
|
protocol=$(getConfig "protocol")
|
|
|
|
# Get current branch
|
|
branch=${2:-$(git symbolic-ref -q --short HEAD)}
|
|
|
|
# Split arguments on '/'
|
|
IFS='/' pathargs=($urlpath)
|
|
|
|
if (( is_issue )); then
|
|
# For issues, take the numbers and preprend 'issues/'
|
|
providerBranchRef="issues/${branch//[^0-9]/}"
|
|
else
|
|
# Make # and % characters url friendly
|
|
# github.com/paulirish/git-open/pull/24
|
|
branch=${branch//%/%25} branch=${branch//#/%23}
|
|
providerBranchRef="tree/$branch"
|
|
fi
|
|
|
|
if [[ "$domain" == 'bitbucket.org' ]]; then
|
|
# Bitbucket, see https://github.com/paulirish/git-open/issues/80 for why ?at is needed.
|
|
providerBranchRef="src?at=$branch"
|
|
elif [[ ${pathargs[0]} == 'scm' ]]; then
|
|
# Bitbucket server, which starts with 'scm'
|
|
# Replace the first element, 'scm', with 'projects'. Keep the first argument, the string 'repos', and finally the rest of the arguments.
|
|
pathargs=('projects' ${pathargs[1]} 'repos' "${pathargs[@]:2}")
|
|
IFS='/' urlpath="${pathargs[*]}"
|
|
providerBranchRef="browse?at=$branch"
|
|
fi
|
|
|
|
openurl="$protocol://$domain/$urlpath"
|
|
|
|
# simplify URL for master
|
|
if [[ $branch != "master" ]]; then
|
|
openurl="$openurl/$providerBranchRef"
|
|
fi
|
|
|
|
# get current open browser command
|
|
case $( uname -s ) in
|
|
Darwin) open='open';;
|
|
MINGW*) open='start';;
|
|
MSYS*) open='start';;
|
|
CYGWIN*) open='cygstart';;
|
|
*) # Try to detect WSL (Windows Subsystem for Linux)
|
|
if uname -r | grep -q Microsoft; then
|
|
open='powershell.exe'
|
|
openopt='Start'
|
|
else
|
|
open='xdg-open'
|
|
fi;;
|
|
esac
|
|
|
|
# Allow printing the url if BROWSER=echo
|
|
if [[ $BROWSER != "echo" ]]; then
|
|
exec &>/dev/null
|
|
fi
|
|
|
|
# open it in a browser
|
|
${BROWSER:-$open} $openopt "$openurl"
|