mirror of
https://github.com/paulirish/git-open.git
synced 2026-09-10 15:36:16 -04:00
Please see the unit tests for more details. Basically, take the context parts before 'scm' and add them to the new URL before the other parts. Instead of taking fixed indexes for the path elements, base everything off the index of the found 'scm' path element.
187 lines
5.6 KiB
Bash
Executable file
187 lines
5.6 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
|
|
SUBDIRECTORY_OK='Yes' . "$(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, default in config, detected tracked remote, 'origin'
|
|
branch_name=$(git name-rev --name-only HEAD 2>/dev/null)
|
|
tracked_remote=$(git config "branch.$branch_name.remote")
|
|
default_remote=$(git config open.default.remote)
|
|
remote=${1:-$default_remote}
|
|
remote=${remote:-$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[@]}" -ge 3 && ${pathargs[${#pathargs[@]} - 3]} == 'scm' ]]; then
|
|
# Bitbucket server always has /scm/ as the third to last segment in the url path, e.g. /scm/ppp/test-repo.git
|
|
# Anything before the 'scm' is part of the server's root context
|
|
|
|
# Check whether there are other context parts before the 'scm' part
|
|
pathPref=()
|
|
if [[ "${#pathargs[@]}" -gt 3 ]]; then
|
|
# If there are other context parts, add them, up to (but not including) the found 'scm'
|
|
pathPref=("${pathargs[*]:0:${#pathargs[@]} - 3}")
|
|
fi
|
|
|
|
# Replace the 'scm' element, with 'projects'. Keep the first argument, the string 'repos', and finally the rest of the arguments.
|
|
pathargs=(${pathPref[@]} 'projects' ${pathargs[${#pathargs[@]} - 2]} 'repos' "${pathargs[@]:${#pathargs[@]} - 1}")
|
|
IFS='/' urlpath="${pathargs[*]}"
|
|
providerBranchRef="/browse?at=$branch"
|
|
elif [[ "${#pathargs[@]}" -ge '2' && ${pathargs[${#pathargs[@]} - 2]} == '_git' ]]; then
|
|
# Visual Studio Team Services and Team Foundation Server always have /_git/ as the second to last segment in the url path
|
|
if (( is_issue )); then
|
|
# Switch to workitems, provide work item id if specified
|
|
urlpath="${urlpath%%/_git/*}/_workitems"
|
|
providerBranchRef="?id=${branch//[^0-9]/}"
|
|
else
|
|
# Keep project and repository name, append branch selector.
|
|
providerBranchRef="?version=GB$branch"
|
|
fi
|
|
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"
|
|
|
|
unset openopt
|