#!/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, 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. # Trim "/" and ".git" from the end of the url giturl=${giturl%/} giturl=${giturl%.git} # Trim before last '@' and protocol (*://) from beginning uri=${giturl##*@} uri=${uri##*://} # If there isn't a protocol, we can assume it's using the scp syntax which uses ':' to seperate the path. [[ $giturl =~ :// ]] && pathsep='/' || pathsep=':' # Seperate the domain and the urlpath on the first {pathsep}. This also removes the gitport from the domain. domain=${uri%%[:$pathsep]*} urlpath=${uri#*$pathsep} # 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"