Merge pull request #1816 from tbhaxor/lint/git-plugins

Lint/git plugins
pull/1832/head
Noah Gorny 2021-02-06 00:31:41 +02:00 committed by GitHub
commit fe9ef1e4bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 252 additions and 209 deletions

View File

@ -50,6 +50,7 @@ themes/modern
plugins/available/basher.plugin.bash plugins/available/basher.plugin.bash
plugins/available/cmd-returned-notify.plugin.bash plugins/available/cmd-returned-notify.plugin.bash
plugins/available/docker-machine.plugin.bash plugins/available/docker-machine.plugin.bash
plugins/available/git.plugin.bash
plugins/available/go.plugin.bash plugins/available/go.plugin.bash
plugins/available/goenv.plugin.bash plugins/available/goenv.plugin.bash
plugins/available/history.plugin.bash plugins/available/history.plugin.bash

View File

@ -1,275 +1,317 @@
# shellcheck shell=bash
cite about-plugin cite about-plugin
about-plugin 'git helper functions' about-plugin 'git helper functions'
function git_remote { function git_remote {
about 'adds remote $GIT_HOSTING:$1 to current repo' about "adds remote $GIT_HOSTING:$1 to current repo"
group 'git' group "git"
echo "Running: git remote add origin ${GIT_HOSTING}:$1.git" echo "Running: git remote add origin ${GIT_HOSTING}:$1.git"
git remote add origin $GIT_HOSTING:$1.git git remote add origin "$GIT_HOSTING:$1".git
} }
function git_first_push { function git_first_push {
about 'push into origin refs/heads/master' about 'push into origin refs/heads/master'
group 'git' group 'git'
echo "Running: git push origin master:refs/heads/master" echo "Running: git push origin master:refs/heads/master"
git push origin master:refs/heads/master git push origin master:refs/heads/master
} }
function git_pub() { function git_pub() {
about 'publishes current branch to remote origin' about 'publishes current branch to remote origin'
group 'git' group 'git'
BRANCH=$(git rev-parse --abbrev-ref HEAD) BRANCH=$(git rev-parse --abbrev-ref HEAD)
echo "Publishing ${BRANCH} to remote origin" echo "Publishing ${BRANCH} to remote origin"
git push -u origin $BRANCH git push -u origin "$BRANCH"
} }
function git_revert() { function git_revert() {
about 'applies changes to HEAD that revert all changes after this commit' about 'applies changes to HEAD that revert all changes after this commit'
group 'git' group 'git'
git reset $1 git reset "$1"
git reset --soft HEAD@{1} git reset --soft "HEAD@{1}"
git commit -m "Revert to ${1}" git commit -m "Revert to ${1}"
git reset --hard git reset --hard
} }
function git_rollback() { function git_rollback() {
about 'resets the current HEAD to this commit' about 'resets the current HEAD to this commit'
group 'git' group 'git'
function is_clean() { function is_clean() {
if [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]]; then if [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]]; then
echo "Your branch is dirty, please commit your changes" echo "Your branch is dirty, please commit your changes"
kill -INT $$ kill -INT $$
fi fi
} }
function commit_exists() { function commit_exists() {
git rev-list --quiet $1 git rev-list --quiet "$1"
status=$? status=$?
if [ $status -ne 0 ]; then if [ $status -ne 0 ]; then
echo "Commit ${1} does not exist" echo "Commit ${1} does not exist"
kill -INT $$ kill -INT $$
fi fi
} }
function keep_changes() { function keep_changes() {
while true while true; do
do # shellcheck disable=SC2162
read -p "Do you want to keep all changes from rolled back revisions in your working tree? [Y/N]" RESP read -p "Do you want to keep all changes from rolled back revisions in your working tree? [Y/N]" RESP
case $RESP case $RESP in
in
[yY])
echo "Rolling back to commit ${1} with unstaged changes"
git reset $1
break
;;
[nN])
echo "Rolling back to commit ${1} with a clean working tree"
git reset --hard $1
break
;;
*)
echo "Please enter Y or N"
esac
done
}
if [ -n "$(git symbolic-ref HEAD 2> /dev/null)" ]; then [yY])
is_clean echo "Rolling back to commit ${1} with unstaged changes"
commit_exists $1 git reset "$1"
break
;;
[nN])
echo "Rolling back to commit ${1} with a clean working tree"
git reset --hard "$1"
break
;;
*)
echo "Please enter Y or N"
;;
esac
done
}
while true if [ -n "$(git symbolic-ref HEAD 2> /dev/null)" ]; then
do is_clean
read -p "WARNING: This will change your history and move the current HEAD back to commit ${1}, continue? [Y/N]" RESP commit_exists "$1"
case $RESP
in while true; do
[yY]) # shellcheck disable=SC2162
keep_changes $1 read -p "WARNING: This will change your history and move the current HEAD back to commit ${1}, continue? [Y/N]" RESP
break case $RESP in
;;
[nN]) [yY])
break keep_changes "$1"
;; break
*) ;;
echo "Please enter Y or N" [nN])
esac break
done ;;
else *)
echo "you're currently not in a git repository" echo "Please enter Y or N"
fi ;;
esac
done
else
echo "you're currently not in a git repository"
fi
} }
function git_remove_missing_files() { function git_remove_missing_files() {
about "git rm's missing files" about "git rm's missing files"
group 'git' group 'git'
git ls-files -d -z | xargs -0 git update-index --remove git ls-files -d -z | xargs -0 git update-index --remove
} }
# Adds files to git's exclude file (same as .gitignore) # Adds files to git's exclude file (same as .gitignore)
function local-ignore() { function local-ignore() {
about 'adds file or path to git exclude file' about 'adds file or path to git exclude file'
param '1: file or path fragment to ignore' param '1: file or path fragment to ignore'
group 'git' group 'git'
echo "$1" >> .git/info/exclude echo "$1" >> .git/info/exclude
} }
# get a quick overview for your git repo # get a quick overview for your git repo
function git_info() { function git_info() {
about 'overview for your git repo' about 'overview for your git repo'
group 'git' group 'git'
if [ -n "$(git symbolic-ref HEAD 2> /dev/null)" ]; then if [ -n "$(git symbolic-ref HEAD 2> /dev/null)" ]; then
# print informations # print informations
echo "git repo overview" echo "git repo overview"
echo "-----------------" echo "-----------------"
echo echo
# print all remotes and thier details # print all remotes and thier details
for remote in $(git remote show); do for remote in $(git remote show); do
echo $remote: echo "$remote":
git remote show $remote git remote show "$remote"
echo echo
done done
# print status of working repo # print status of working repo
echo "status:" echo "status:"
if [ -n "$(git status -s 2> /dev/null)" ]; then if [ -n "$(git status -s 2> /dev/null)" ]; then
git status -s git status -s
else else
echo "working directory is clean" echo "working directory is clean"
fi fi
# print at least 5 last log entries # print at least 5 last log entries
echo echo
echo "log:" echo "log:"
git log -5 --oneline git log -5 --oneline
echo echo
else else
echo "you're currently not in a git repository" echo "you're currently not in a git repository"
fi fi
} }
function git_stats { function git_stats {
about 'display stats per author' about 'display stats per author'
group 'git' group 'git'
# awesome work from https://github.com/esc/git-stats # awesome work from https://github.com/esc/git-stats
# including some modifications # including some modifications
if [ -n "$(git symbolic-ref HEAD 2> /dev/null)" ]; then if [ -n "$(git symbolic-ref HEAD 2> /dev/null)" ]; then
echo "Number of commits per author:" echo "Number of commits per author:"
git --no-pager shortlog -sn --all git --no-pager shortlog -sn --all
AUTHORS=$( git shortlog -sn --all | cut -f2 | cut -f1 -d' ') AUTHORS=$(git shortlog -sn --all | cut -f2 | cut -f1 -d' ')
LOGOPTS="" LOGOPTS=""
if [ "$1" == '-w' ]; then if [ "$1" == '-w' ]; then
LOGOPTS="$LOGOPTS -w" LOGOPTS="$LOGOPTS -w"
shift shift
fi fi
if [ "$1" == '-M' ]; then if [ "$1" == '-M' ]; then
LOGOPTS="$LOGOPTS -M" LOGOPTS="$LOGOPTS -M"
shift shift
fi fi
if [ "$1" == '-C' ]; then if [ "$1" == '-C' ]; then
LOGOPTS="$LOGOPTS -C --find-copies-harder" LOGOPTS="$LOGOPTS -C --find-copies-harder"
shift shift
fi fi
for a in $AUTHORS for a in $AUTHORS; do
do echo '-------------------'
echo '-------------------' echo "Statistics for: $a"
echo "Statistics for: $a" echo -n "Number of files changed: "
echo -n "Number of files changed: " # shellcheck disable=SC2086
git log $LOGOPTS --all --numstat --format="%n" --author=$a | cut -f3 | sort -iu | wc -l git log $LOGOPTS --all --numstat --format="%n" --author="$a" | cut -f3 | sort -iu | wc -l
echo -n "Number of lines added: " echo -n "Number of lines added: "
git log $LOGOPTS --all --numstat --format="%n" --author=$a | cut -f1 | awk '{s+=$1} END {print s}' # shellcheck disable=SC2086
echo -n "Number of lines deleted: " git log $LOGOPTS --all --numstat --format="%n" --author="$a" | cut -f1 | awk '{s+=$1} END {print s}'
git log $LOGOPTS --all --numstat --format="%n" --author=$a | cut -f2 | awk '{s+=$1} END {print s}' echo -n "Number of lines deleted: "
echo -n "Number of merges: " # shellcheck disable=SC2086
git log $LOGOPTS --all --merges --author=$a | grep -c '^commit' git log $LOGOPTS --all --numstat --format="%n" --author="$a" | cut -f2 | awk '{s+=$1} END {print s}'
done echo -n "Number of merges: "
else # shellcheck disable=SC2086
echo "you're currently not in a git repository" git log $LOGOPTS --all --merges --author="$a" | grep -c '^commit'
fi done
else
echo "you're currently not in a git repository"
fi
} }
function gittowork() { function gittowork() {
about 'Places the latest .gitignore file for a given project type in the current directory, or concatenates onto an existing .gitignore' about 'Places the latest .gitignore file for a given project type in the current directory, or concatenates onto an existing .gitignore'
group 'git' group 'git'
param '1: the language/type of the project, used for determining the contents of the .gitignore file' param '1: the language/type of the project, used for determining the contents of the .gitignore file'
example '$ gittowork java' example '$ gittowork java'
result=$(curl -L "https://www.gitignore.io/api/$1" 2>/dev/null) result=$(curl -L "https://www.gitignore.io/api/$1" 2> /dev/null)
if [[ $result =~ ERROR ]]; then if [[ $result =~ ERROR ]]; then
echo "Query '$1' has no match. See a list of possible queries with 'gittowork list'" echo "Query '$1' has no match. See a list of possible queries with 'gittowork list'"
elif [[ $1 = list ]]; then elif [[ $1 = list ]]; then
echo "$result" echo "$result"
else else
if [[ -f .gitignore ]]; then if [[ -f .gitignore ]]; then
result=`echo "$result" | grep -v "# Created by http://www.gitignore.io"` result=$(echo "$result" | grep -v "# Created by http://www.gitignore.io")
echo ".gitignore already exists, appending..." echo ".gitignore already exists, appending..."
echo "$result" >> .gitignore echo "$result" >> .gitignore
else else
echo "$result" > .gitignore echo "$result" > .gitignore
fi fi
fi fi
} }
function gitignore-reload() { function gitignore-reload() {
about 'Empties the git cache, and readds all files not blacklisted by .gitignore' about 'Empties the git cache, and readds all files not blacklisted by .gitignore'
group 'git' group 'git'
example '$ gitignore-reload' example '$ gitignore-reload'
# The .gitignore file should not be reloaded if there are uncommited changes. # The .gitignore file should not be reloaded if there are uncommited changes.
# Firstly, require a clean work tree. The function require_clean_work_tree() # Firstly, require a clean work tree. The function require_clean_work_tree()
# was stolen with love from https://www.spinics.net/lists/git/msg142043.html # was stolen with love from https://www.spinics.net/lists/git/msg142043.html
# Begin require_clean_work_tree() # Begin require_clean_work_tree()
# Update the index # Update the index
git update-index -q --ignore-submodules --refresh git update-index -q --ignore-submodules --refresh
err=0 err=0
# Disallow unstaged changes in the working tree # Disallow unstaged changes in the working tree
if ! git diff-files --quiet --ignore-submodules -- if ! git diff-files --quiet --ignore-submodules --; then
then echo >&2 "ERROR: Cannot reload .gitignore: Your index contains unstaged changes."
echo >&2 "ERROR: Cannot reload .gitignore: Your index contains unstaged changes." git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2
git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2 err=1
err=1 fi
fi
# Disallow uncommited changes in the index # Disallow uncommited changes in the index
if ! git diff-index --cached --quiet HEAD --ignore-submodules if ! git diff-index --cached --quiet HEAD --ignore-submodules; then
then echo >&2 "ERROR: Cannot reload .gitignore: Your index contains uncommited changes."
echo >&2 "ERROR: Cannot reload .gitignore: Your index contains uncommited changes." git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2
git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2 err=1
err=1 fi
fi
# Prompt user to commit or stash changes and exit # Prompt user to commit or stash changes and exit
if [ $err = 1 ] if [ $err = 1 ]; then
then echo >&2 "Please commit or stash them."
echo >&2 "Please commit or stash them." fi
fi
# End require_clean_work_tree() # End require_clean_work_tree()
# If we're here, then there are no uncommited or unstaged changes dangling around. # If we're here, then there are no uncommited or unstaged changes dangling around.
# Proceed to reload .gitignore # Proceed to reload .gitignore
if [ $err = 0 ]; then if [ $err = 0 ]; then
# Remove all cached files # Remove all cached files
git rm -r --cached . git rm -r --cached .
# Re-add everything. The changed .gitignore will be picked up here and will exclude the files # Re-add everything. The changed .gitignore will be picked up here and will exclude the files
# now blacklisted by .gitignore # now blacklisted by .gitignore
echo >&2 "Running git add ." echo >&2 "Running git add ."
git add . git add .
echo >&2 "Files readded. Commit your new changes now." echo >&2 "Files readded. Commit your new changes now."
fi fi
}
function git-changelog() {
# ---------------------------------------------------------------
# ORIGINAL ANSWER: https://stackoverflow.com/a/2979587/10362396 |
# ---------------------------------------------------------------
about 'Creates the git changelog from one point to another by date'
group 'git'
example '$ git-changelog origin/master...origin/release [md|txt]'
if [[ "$1" != *"..."* ]]; then
echo "Please include the valid 'diff' to make changelog"
return 1
fi
local NEXT=$(date +%F)
if [[ "$2" == "md" ]]; then
echo "# CHANGELOG $1"
# shellcheck disable=SC2162
git log "$1" --no-merges --format="%cd" --date=short | sort -u -r | while read DATE; do
echo
echo "### $DATE"
git log --no-merges --format=" * (%h) %s by [%an](mailto:%ae)" --since="$DATE 00:00:00" --until="$DATE 24:00:00"
NEXT=$DATE
done
else
echo "CHANGELOG $1"
echo ----------------------
# shellcheck disable=SC2162
git log "$1" --no-merges --format="%cd" --date=short | sort -u -r | while read DATE; do
echo
echo [$DATE]
git log --no-merges --format=" * (%h) %s by %an <%ae>" --since="$DATE 00:00:00" --until="$DATE 24:00:00"
NEXT=$DATE
done
fi
} }