Bash-Funk “git” module
This module only loads if the git commandline client is installed.
The following statements are automatically executed when this module loads:
alias -- -git-ls-branches="git branch -a"
alias -- -git-ls-remotes="git remote -v"
alias -- -git-ls-stashes="git stash list"
alias -- -git-ls-tags="git tag"
The following commands are available when this module is loaded:
- -git-branch-name
- -git-change-contributor
- -git-change-date
- -git-cherry-pick
- -git-cleanse
- -git-clone-shallow
- -git-create-empty-branch
- -git-delete-branch
- -git-delete-commit
- -git-delete-local-branch
- -git-delete-remote-branch
- -git-fetch-pr
- -git-log
- -git-ls-conflicts
- -git-ls-modified
- -git-reset-file
- -git-squash
- -git-switch-remote-protocol
- -git-sync-fork
- -git-undo
- -git-update-branch
- -github-upstream-url
- -test-all-git
License
SPDX-FileCopyrightText: © Vegard IT GmbH (https://vegardit.com)
SPDX-License-Identifier: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-git-branch-name
Usage: -git-branch-name [OPTION]... [PATH]
Prints the name of the currently checked out git branch.
Parameters:
PATH (default: '.', directory)
The path to check.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
git -C "$_PATH" rev-parse --symbolic-full-name --abbrev-ref HEAD
-git-change-contributor
Usage: -git-change-contributor [OPTION]... OLD_USER_EMAIL NEW_USER_NAME NEW_USER_EMAIL
Updates the author and/or committer name/e-mail of ALL matching commits.
Parameters:
OLD_USER_EMAIL (required)
Old user e-mail.
NEW_USER_NAME (required)
New user name to set.
NEW_USER_EMAIL (required)
New user e-mail to set.
Options:
--author
Indicates to change the author date of the commit.
--committer
Indicates to change the committer date of the commit.
--global
Performs the change against all tags and branches.
--pull
Execute 'git pull' before altering the commit(s).
--push
Execute 'git push --force' after altering the commit(s).
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Examples:
$ -git-change-contributor --author alice@example.com bob bob@example.com
$ -git-change-contributor --author --committer alice@example.com bob bob@example.com
Implementation:
if [[ $_pull ]]; then
git pull || return 1
fi
if [[ ! $_author && ! $_committer ]]; then
echo "-git-change-contributor: Error: The --author and/or --committer flag need to be specified."
return 1
fi
local filter="
if [ $_committer ] && [ \"\$GIT_COMMITTER_EMAIL\" = '$_OLD_USER_EMAIL' ]; then
export GIT_COMMITTER_NAME='$_NEW_USER_NAME'
export GIT_COMMITTER_EMAIL='$_NEW_USER_EMAIL'
fi
if [ $_author ] && [ \"\$GIT_AUTHOR_EMAIL\" = '$_OLD_USER_EMAIL' ]; then
export GIT_AUTHOR_NAME='$_NEW_USER_NAME'
export GIT_AUTHOR_EMAIL='$_NEW_USER_EMAIL'
fi
"
if [[ $_global ]]; then
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --force --env-filter "$filter" --tag-name-filter cat -- --branches --tags
else
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --force --env-filter "$filter"
fi
if [[ $_push ]]; then
git push
fi
-git-change-date
Usage: -git-change-date [OPTION]... COMMIT_HASH NEW_DATE
Changes the author and/or committer date of the given commit.
Parameters:
COMMIT_HASH (required)
Hash of commit to change.
NEW_DATE (required)
The new date to set.
Options:
--author
Indicates to change the author date of the commit.
--committer
Indicates to change the committer date of the commit.
--pull
Execute 'git pull' before altering the commit.
--push
Execute 'git push --force' after altering the commit.
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Examples:
$ -git-change-date --author fe65a726b8f07cbcedc1d4b76fbdbf53678a31cf "\$(date --date '27 days ago')"
$ -git-change-date --author --committer $(git log --format='%H' -n 1) "\$(date --date '15 hours ago')"
Implementation:
if [[ $_pull ]]; then
git pull || return 1
fi
if [[ ! $_author && ! $_committer ]]; then
echo "-git-change-date: Error: The --author and/or --committer flag need to be specified."
return 1
fi
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --force --env-filter "
if [ \$GIT_COMMIT = $_COMMIT_HASH ]; then
if [ $_author ]; then
export GIT_AUTHOR_DATE='$_NEW_DATE'
fi
if [ $_committer ]; then
export GIT_COMMITTER_DATE='$_NEW_DATE'
fi
fi
"
if [[ $_push ]]; then
git push
fi
-git-cherry-pick
Usage: -git-cherry-pick [OPTION]... COMMIT_HASHES1 [COMMIT_HASHES]...
Cherry picks a commit into the currently checked out branch.
Parameters:
COMMIT_HASHES (1 or more required)
Hashes of commits to cherry pick.
Options:
--pr PR_NUMBER (integer: 1-?)
First fetches the pull request with the given number to be able to cherry pick from that PR.
--pull
Execute 'git pull' before cherry picking.
--push
Execute 'git push --force' after cherry picking.
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
if [[ $_pull ]]; then
git pull || return 1
fi
if [[ $_pr ]]; then
git fetch origin pull/${_pr}/head:pr-${_pr} || return 1
fi
git cherry-pick ${_COMMIT_HASHES[@]} || return 1
if [[ $_push ]]; then
git push
fi
-git-cleanse
Usage: -git-cleanse [OPTION]...
Reverts any uncomitted changes in the local working tree including untracked files.
Options:
--pull
Execute 'git pull' after reset/clean.
-y, --yes
Answer interactive prompts with 'yes'.
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
if [[ ! $_yes ]]; then
read -p "Are you sure you want to erase all uncommitted changes? (y) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "-git-cleanse: Aborting on user request."
return 0
fi
fi
git reset --hard HEAD && git clean -dfx || return 1
if [[ $_pull ]]; then
git pull
fi
-git-clone-shallow
Usage: -git-clone-shallow [OPTION]... REPO_URL [BRANCH_NAME]
Creates a shallow clone of the selected branch of the given repository with a truncated history.
Parameters:
REPO_URL (required)
The URL to the git repository to clone.
BRANCH_NAME (default: 'main')
The name of the branch to clone.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
git clone --depth 1 $_REPO_URL -b $_BRANCH_NAME
-git-create-empty-branch
Usage: -git-create-empty-branch [OPTION]... BRANCH_NAME
Creates a new empty branch in the local repository.
Parameters:
BRANCH_NAME (required)
The name of the new branch.
Options:
--push
Execute 'git push --set-upstream origin <BRANCH_NAME>' after branch creation.
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
if git rev-parse --verify ${_BRANCH_NAME} &>/dev/null; then
echo "-git-create-empty-branch: Error: A branch named [${_BRANCH_NAME}] already exists."
return 1
fi
git checkout --orphan ${_BRANCH_NAME} &&
git clean -fd &&
git rm -rf . &&
git commit -am "Created empty branch." --allow-empty || return 1
if [[ $_push ]]; then
git push --set-upstream origin ${_BRANCH_NAME}
fi
-git-delete-branch
Usage: -git-delete-branch [OPTION]... BRANCH_NAME
Deletes a branch in the local and the remote repository.
Parameters:
BRANCH_NAME (required)
The name of the branch.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
git branch --delete --force $_BRANCH_NAME &&
git fetch origin --prune &&
git push origin --delete $_BRANCH_NAME
-git-delete-commit
Usage: -git-delete-commit [OPTION]... COMMIT_ID
Deletes a specific commit.
Parameters:
COMMIT_ID (required)
The id of the commit to delete.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
git rebase --onto ${_COMMIT_ID}^ ${_COMMIT_ID}
-git-delete-local-branch
Usage: -git-delete-local-branch [OPTION]... BRANCH_NAME
Deletes a branch in the local repository.
Parameters:
BRANCH_NAME (required)
The name of the branch.
Options:
--force
Delete the branch irrespective of its merged status.
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
if [[ $_force ]]; then
git branch --delete --force $_BRANCH_NAME
else
git branch --delete $_BRANCH_NAME
fi
-git-delete-remote-branch
Usage: -git-delete-remote-branch [OPTION]... BRANCH_NAME
Deletes a branch in the remote repository.
Parameters:
BRANCH_NAME (required)
The name of the branch.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
git fetch origin --prune &&
git push origin --delete $_BRANCH_NAME
-git-fetch-pr
Usage: -git-fetch-pr [OPTION]... PR_NUMBER
Fetches the given pull request.
Parameters:
PR_NUMBER (required, integer: 1-?)
The number of the pull request to fetch.
Options:
-c, --checkout
Checkout the PR branch after fetching.
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
git fetch origin pull/${_PR_NUMBER}/head:pr-${_PR_NUMBER} || return 1
if [[ $_checkout ]]; then
git checkout pr-${_PR_NUMBER}
fi
-git-log
Usage: -git-log [OPTION]... [COUNT]
Displays the git log of the current project in a pretty and compact format.
Parameters:
COUNT (default: '10', integer: ?-?)
Number of entries to be displayed.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
git log --graph -${_COUNT} --branches --remotes --tags --pretty=format:'%C(bold black)%h%Creset %<(70,trunc)%s %C(bold black)(%aN, %cr)%Cred%d' --date-order
-git-ls-conflicts
Usage: -git-ls-conflicts [OPTION]... [PATH]
Prints the name of the all conflicting files in the current directory tree.
Parameters:
PATH (default: '.', directory)
The path to check.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
git diff --name-only --diff-filter=U "$_PATH"
-git-ls-modified
Usage: -git-ls-modified [OPTION]... [PATH]
Prints the name of the all deleted, changed and newly created files in the current directory tree.
Parameters:
PATH (default: '.', directory)
The path to check.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
git -C "$_PATH" ls-files -o -m -d --exclude-standard
-git-reset-file
Usage: -git-reset-file [OPTION]... FILE
Reverts the uncommitted changes of the given local FILE to the version of the latest commit.
Parameters:
FILE (required, file)
File to reset.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
git checkout -- "$_FILE"
-git-squash
Usage: -git-squash [OPTION]... NUM_COMMITS
Squashes the last n commits into one.
Requirements:
+ Command 'awk' must be available.
Parameters:
NUM_COMMITS (required, integer: 2-?)
Number of commits to squash.
Options:
-m, --message COMMIT_MESSAGE
The commit message to be used instead of the original ones.
--pull
Execute 'git pull' before squashing.
--push
Execute 'git push --force' after squashing.
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
if [[ $_pull ]]; then
git pull || return 1
fi
if [[ $_message ]]; then
local commitMsg="${_message}"
else
# load the commit messages, remove duplicates and blank lines
local commitMsg="$(git log -${_NUM_COMMITS} --pretty=%B | awk 'NF > 0 && !a[$0]++')"
fi
git reset --soft HEAD~${_NUM_COMMITS} &&
git commit --allow-empty-message -m "${commitMsg}" || return 1
if [[ $_push ]]; then
git push --force
fi
-git-switch-remote-protocol
Usage: -git-switch-remote-protocol [OPTION]... REMOTE_NAME1 [REMOTE_NAME]... PROTOCOL
Switches the protocol of the given remote(s) between HTTPS and SSH.
Parameters:
REMOTE_NAME (1 or more required)
The name of the remote, e.g. 'origin', 'upstream'. If not specified all remotes are changed.
PROTOCOL (required, one of: [https,ssh])
The new protocol to use.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
local url remote
for remote in "${_REMOTE_NAME[@]}"; do
if url=$(git remote get-url $_REMOTE_NAME); then
case "$_PROTOCOL" in
ssh)
case "$url" in
https://*)
echo "Switching protocol of remote [$remote] to SSH..."
git remote set-url origin "git@${url#https://*}" &&
git remote -v | grep "^$remote"
;;
git@*)
echo "Remote [$remote] already uses SSH: $url"
;;
*)
echo "-git-switch-remote-protocol: URL [$url] for remote [$remote] starts with unknown protocol."
return 1
;;
esac
;;
https)
case "$url" in
https://*)
echo "Remote [$remote] already uses HTTPS: $url"
;;
git@*)
echo "Switching protocol of remote [$remote] to HTTPS..."
git remote set-url origin "https://${url#git@*}" &&
git remote -v | grep "^$remote"
;;
*)
echo "-git-switch-remote-protocol: URL [$url] for remote [$remote] starts with unknown protocol."
return 1
;;
esac
;;
esac
else
return 1
fi
done
-git-sync-fork
Usage: -git-sync-fork [OPTION]...
Syncs the currently checked out branch of a forked repository with it's upstream repository. Uses 'git rebase -p' instead of 'git merge' by default to prevent an extra commit for the merge operation.
Options:
-b, --branch NAME
Branch in the forked repository to sync.
--merge
Use 'git merge' instead of 'git rebase -p'.
--push
Push updates to origin after sync.
--upstream_branch NAME
Branch in the upstream repository to sync with.
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
local currBranch currBranch_remote currBranch_remoteURL upstreamURL
# e.g. 'main'
if [[ ${_branch:-} ]]; then
currBranch=$_branch
else
currBranch=$(git rev-parse --symbolic-full-name --abbrev-ref HEAD) || return 1
fi
# e.g. 'origin'
currBranch_remote=$(git config branch.$currBranch.remote) || return 1
currBranch_remoteURL=$(git config --get remote.$currBranch_remote.url) || return 1
upstreamURL=$(git remote get-url "upstream" 2>/dev/null) || true
if [[ ! $upstreamURL ]]; then
# if forked repo is on github try to get the upstream URL via github API
local githubRepo="${currBranch_remoteURL#*github.com/}"
githubRepo="${githubRepo%.git}"
if [[ ! $currBranch_remoteURL == *github.com/* ]] || ! upstreamURL="$(-github-upstream-url "${githubRepo}")"; then
echo "-git-sync-fork: No remote 'upstream' defined. You can add it using 'git remote add upstream [REMOTE_URL]'."
return 1
fi
echo "Adding remote 'upstream $upstreamURL'..."
git remote add upstream $upstreamURL || return 1
fi
local _upstream_branch=${_upstream_branch:-$currBranch}
echo "Fetching updates from 'upstream/$_upstream_branch'..."
git fetch upstream $_upstream_branch &&
git checkout $_branch || return 1
echo "Incorporating updates from 'upstream/$_upstream_branch' into '$currBranch'..."
if [[ $_merge ]]; then
git merge upstream/$_upstream_branch || return 1
else
git rebase -p upstream/$_upstream_branch || return 1
fi
if [[ $_push ]]; then
echo "Pushing updates to 'origin/$currBranch'..."
git push --follow-tags --force origin $currBranch
fi
-git-undo
Usage: -git-undo [OPTION]... [NUM_COMMITS]
Removes the last N commits from the commit history.
Parameters:
NUM_COMMITS (default: '1', integer: 1-?)
Number of commits to undo.
Options:
--push
Push updates to origin after undo.
--reset
Removes any changes from the working tree.
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
if [[ $_reset ]]; then
git reset --hard HEAD~${_NUM_COMMITS} && git clean -dfx || return 1
else
git reset --soft HEAD~${_NUM_COMMITS} || return 1
fi
if [[ $_push ]]; then
git push --force
fi
-git-update-branch
Usage: -git-update-branch [OPTION]... [BRANCH] MAIN
Updates the given branch using 'git rebase -p' by default.
Parameters:
BRANCH
Name of the branch to update.
MAIN (required)
Name of the branch to get updates from.
Options:
--merge
Use 'git merge' instead of 'git rebase -p'. Rule of thumb: use 'git rebase -p' for updating personal branches and 'git merge' for updating shared branches with commits by others.
--push
Push updates to origin after sync.
-----------------------------
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
if [[ ! ${_BRANCH:-} ]]; then
_BRANCH=$(git rev-parse --symbolic-full-name --abbrev-ref HEAD) || return 1
fi
git checkout $_MAIN &&
git pull &&
git checkout $_BRANCH || return 1
echo "Incorporating updates from '$_MAIN' into '$_BRANCH'..."
if [[ $_merge ]]; then
git merge $_MAIN || return 1
else
git rebase -p $_MAIN || return 1
fi
if [[ $_push ]]; then
echo "Pushing updates to 'origin/$_BRANCH'..."
git push --follow-tags --force origin $_BRANCH
fi
-github-upstream-url
Usage: -github-upstream-url [OPTION]... REPO
Prints the upstream URL in case the given GitHub repository is a fork.
Parameters:
REPO (required)
The github repository to check, e.g. 'vegardit/bash-funk'.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
hash wget &>/dev/null && local get="wget -qO-" || local get="curl -fs"
$get https://api.github.com/repos/$_REPO | grep -A100 '"parent":' | grep clone_url | head -n1 | cut -d'"' -f4
return ${PIPESTATUS[0]}
-test-all-git
Usage: -test-all-git [OPTION]...
Performs a selftest of all functions of this module by executing each function with option '--selftest'.
Options:
--help
Prints this help.
--tracecmd
Enables bash debug mode (set -x).
--selftest
Performs a self-test.
--
Terminates the option list.
Implementation:
-git-branch-name --selftest && echo || return 1
-git-change-contributor --selftest && echo || return 1
-git-change-date --selftest && echo || return 1
-git-cherry-pick --selftest && echo || return 1
-git-cleanse --selftest && echo || return 1
-git-clone-shallow --selftest && echo || return 1
-git-create-empty-branch --selftest && echo || return 1
-git-delete-branch --selftest && echo || return 1
-git-delete-commit --selftest && echo || return 1
-git-delete-local-branch --selftest && echo || return 1
-git-delete-remote-branch --selftest && echo || return 1
-git-fetch-pr --selftest && echo || return 1
-git-log --selftest && echo || return 1
-git-ls-conflicts --selftest && echo || return 1
-git-ls-modified --selftest && echo || return 1
-git-reset-file --selftest && echo || return 1
-git-squash --selftest && echo || return 1
-git-switch-remote-protocol --selftest && echo || return 1
-git-sync-fork --selftest && echo || return 1
-git-undo --selftest && echo || return 1
-git-update-branch --selftest && echo || return 1
-github-upstream-url --selftest && echo || return 1