Moves binaries for use with gnu stow
This commit is contained in:
parent
f528ba793c
commit
4fd9f4809b
89 changed files with 0 additions and 0 deletions
26
bin/.bin/git/git-branch-summary
Executable file
26
bin/.bin/git/git-branch-summary
Executable file
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Prints the number of commits between branches and a main branch (master by defaunt)
|
||||
|
||||
mainBranch="${1-master}"
|
||||
|
||||
|
||||
for branch in $(git branch -a --format "%(refname:short)"); do
|
||||
|
||||
if [ "$branch" = "$mainBranch" ]; then
|
||||
continue;
|
||||
fi
|
||||
|
||||
masterInFront=$(git log --oneline "$branch".."$mainBranch" | wc -l)
|
||||
branchInFront=$(git log --oneline "$mainBranch".."$branch" | wc -l)
|
||||
|
||||
if [ "$masterInFront" = "0" ] && [ "$branchInFront" = "0" ]; then
|
||||
echo "$mainBranch and $branch are in sync"
|
||||
else
|
||||
echo "$mainBranch is $masterInFront commits in front of $branch"
|
||||
echo "$branch is $branchInFront commits in front of $mainBranch"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
done
|
19
bin/.bin/git/git-cat-all
Executable file
19
bin/.bin/git/git-cat-all
Executable file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
toplevel=$(git rev-parse --show-toplevel 2> /dev/null)
|
||||
if [ ! -d "${toplevel}/.git" ]; then
|
||||
echo "Can't find .git folder"
|
||||
exit
|
||||
fi
|
||||
|
||||
gitFolder="${toplevel}/.git"
|
||||
{
|
||||
find $gitFolder/objects/pack/ -name "*.idx" | while read i; do
|
||||
git show-index < "$i" | awk '{print $2}';
|
||||
done
|
||||
|
||||
find $gitFolder/objects/ -type f | grep -v '/pack/' | awk -F'/' '{print $(NF-1)$NF}'
|
||||
} | while read o; do
|
||||
git cat-file -p $o
|
||||
done
|
||||
|
75
bin/.bin/git/git-cleaner
Executable file
75
bin/.bin/git/git-cleaner
Executable file
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
function help() {
|
||||
cat <<HELP
|
||||
Git Clean
|
||||
https://jonathanh.co.uk
|
||||
|
||||
Some code came from Ben Alman
|
||||
http://benalman.com/
|
||||
|
||||
|
||||
Usage: $(basename "$0") [command]
|
||||
|
||||
Commands:
|
||||
clean Remove current unstaged changes/untracked files**
|
||||
cleanall Remove all saved tags, unstaged changes and untracked files**
|
||||
|
||||
** This action is destructive and cannot be undone!
|
||||
|
||||
Description:
|
||||
Cleans unstaged changes and untracked files
|
||||
|
||||
Copyright (c) 2014 "Cowboy" Ben Alman
|
||||
Licensed under the MIT license.
|
||||
http://benalman.com/about/license/
|
||||
HELP
|
||||
}
|
||||
|
||||
function usage() {
|
||||
echo "Usage: $(basename "$0") [clean | cleanall]"
|
||||
}
|
||||
|
||||
function git_head_sha() {
|
||||
git rev-parse --short HEAD
|
||||
}
|
||||
|
||||
# Get absolute path to root of Git repo
|
||||
function git_repo_toplevel() {
|
||||
git rev-parse --show-toplevel
|
||||
}
|
||||
|
||||
# Clean (permanently) current changes and remove the current saved tag
|
||||
function clean() {
|
||||
local head_sha=$(git_head_sha)
|
||||
git tag -d "git-jump-$head_sha" &>/dev/null
|
||||
if [[ $? == 0 ]]; then
|
||||
echo "Removed stored data for commit $head_sha."
|
||||
fi
|
||||
local repo_root="$(git_repo_toplevel)"
|
||||
git reset HEAD "$repo_root" >/dev/null
|
||||
git clean -f -d -q -- "$repo_root" >/dev/null
|
||||
git checkout -- "$repo_root" >/dev/null
|
||||
echo "Unstaged changes and untracked files removed."
|
||||
}
|
||||
|
||||
# Remove (permanently) all saved tags
|
||||
function clean_all_tags() {
|
||||
git for-each-ref refs/tags --format='%(refname:short)' | \
|
||||
while read tag; do
|
||||
if [[ "$tag" =~ ^git-jump- ]]; then
|
||||
git tag -d "$tag"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Handle CLI arguments
|
||||
if [[ "$1" == "clean" ]]; then
|
||||
clean
|
||||
elif [[ "$1" == "cleanall" ]]; then
|
||||
clean_all_tags
|
||||
clean
|
||||
else
|
||||
usage
|
||||
exit 1
|
||||
fi
|
24
bin/.bin/git/git-delete-submodule
Executable file
24
bin/.bin/git/git-delete-submodule
Executable file
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
test -z "$1" && echo "submodule required" 1>&2 && exit 1
|
||||
#cd "$(git root)"
|
||||
test ! -f .gitmodules && echo ".gitmodules file not found" 1>&2 && exit 2
|
||||
|
||||
NAME="$(echo "$1" | sed 's/\/$//g')"
|
||||
test -z \
|
||||
"$(git config --file=.gitmodules submodule."$NAME".url)" \
|
||||
&& echo "submodule not found" 1>&2 && exit 3
|
||||
|
||||
# 1. Delete the relevant section from .git/config and clean submodule files
|
||||
git submodule deinit -f "$NAME" || exit 4
|
||||
rmdir "$NAME"
|
||||
rm -rf .git/modules/"$NAME"
|
||||
# 2. Delete the relevant line from .gitmodules
|
||||
git config --file=.gitmodules --remove-section submodule."$NAME"
|
||||
git add .gitmodules
|
||||
# 3. Run git rm --cached path_to_submodule
|
||||
git rm --cached -rf "$NAME"
|
||||
# 4. Need to confirm and commit the changes for yourself
|
||||
echo
|
||||
echo "Now submodule $NAME is deleted."
|
||||
echo 'Confirm with `git submodule status` and commit the changes for yourself.'
|
30
bin/.bin/git/git-initial-commit
Executable file
30
bin/.bin/git/git-initial-commit
Executable file
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
# What should the initial commit be for a repo?
|
||||
#
|
||||
# Idea came after reading this blog post: https://blog.no-panic.at/2014/10/20/funny-initial-git-commit-messages/
|
||||
|
||||
commits=(
|
||||
"This is where it all begins..."
|
||||
"Commit committed"
|
||||
"Version control is awful"
|
||||
"COMMIT ALL THE FILES!"
|
||||
"The same thing we do every night, Pinky - try to take over the world!"
|
||||
"Lock S-foils in attack position"
|
||||
"This commit is a lie"
|
||||
"I'll explain when you're older!"
|
||||
"Here be Dragons"
|
||||
"Reinventing the wheel. Again."
|
||||
"This is not the commit message you are looking for"
|
||||
"Batman! (this commit has no parents)"
|
||||
"In the beginning, the code was without form and was void()…"
|
||||
)
|
||||
|
||||
# Seed random generator
|
||||
RANDOM=$$$(date +%s)
|
||||
|
||||
# Get random expression...
|
||||
selectedexpression=${commits[$RANDOM % ${#commits[@]} ]}
|
||||
|
||||
# Write to Shell
|
||||
git commit --allow-empty -m "$selectedexpression"
|
158
bin/.bin/git/git-jump
Executable file
158
bin/.bin/git/git-jump
Executable file
|
@ -0,0 +1,158 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
function help() {
|
||||
cat <<HELP
|
||||
Git Jump (Forward & Back)
|
||||
http://benalman.com/
|
||||
|
||||
Modified slightly by Jonathan Hodgson
|
||||
https://jonathanh.co.uk/
|
||||
|
||||
Copyright (c) 2017 Jonathan Hodgson
|
||||
Licensed under the MIT license.
|
||||
https://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
Usage: $(basename "$0") [command]
|
||||
|
||||
Commands:
|
||||
next Jump forward to the next commit in this branch
|
||||
prev Jump backward to the next commit in this branch
|
||||
|
||||
|
||||
Git config:
|
||||
git-jump.branch Branch to jump through. If not set, defaults to master
|
||||
|
||||
Description:
|
||||
"Replay" Git commits by moving forward / backward through a branch's
|
||||
history. Before jumping, any current unstaged changes and untracked
|
||||
files are saved in a tag for later retrieval, which is restored when
|
||||
jumped back to.
|
||||
|
||||
Original Licence:
|
||||
Copyright (c) 2014 "Cowboy" Ben Alman
|
||||
Licensed under the MIT license.
|
||||
http://benalman.com/about/license/
|
||||
HELP
|
||||
}
|
||||
|
||||
function usage() {
|
||||
echo "Usage: $(basename "$0") [next | prev]"
|
||||
}
|
||||
|
||||
# Get branch stored in Git config or default to master
|
||||
git_branch="$(git config git-jump.branch || echo "master")"
|
||||
|
||||
# Get some (short) SHAs
|
||||
function git_branch_sha() {
|
||||
git rev-parse --short "$git_branch"
|
||||
}
|
||||
function git_head_sha() {
|
||||
git rev-parse --short HEAD
|
||||
}
|
||||
function git_prev_sha() {
|
||||
git log --format='%h' "$git_branch" "$@" | awk "/^$(git_head_sha)/{getline; print}"
|
||||
}
|
||||
function git_next_sha() {
|
||||
git_prev_sha --reverse
|
||||
}
|
||||
|
||||
# Get absolute path to root of Git repo
|
||||
function git_repo_toplevel() {
|
||||
git rev-parse --show-toplevel
|
||||
}
|
||||
|
||||
# Get subject of specified commit
|
||||
function git_commit_subject() {
|
||||
git log --format='%s' -n 1 $1
|
||||
}
|
||||
|
||||
# Save changes for later retrieval
|
||||
function save() {
|
||||
local status=""
|
||||
local head_sha=$(git_head_sha)
|
||||
# Checkout current HEAD by SHA to force detached state
|
||||
git checkout -q $head_sha
|
||||
# Add all files in repo
|
||||
git add "$(git_repo_toplevel)"
|
||||
# Commit changes (if there were any)
|
||||
git commit --no-verify -m "Git Jump: saved changes for $head_sha" >/dev/null
|
||||
# If the commit was successful, tag it (overwriting any previous tag)
|
||||
if [[ $? == 0 ]]; then
|
||||
status="*"
|
||||
git tag -f "git-jump-$head_sha" >/dev/null
|
||||
fi
|
||||
echo "Previous HEAD was $head_sha$status, $(git_commit_subject $head_sha)"
|
||||
}
|
||||
|
||||
# Restore previously-saved changes
|
||||
function restore() {
|
||||
local status=""
|
||||
# Save current changes before restoring
|
||||
save
|
||||
# Attempt to restore saved changes for specified commit
|
||||
git checkout "git-jump-$1" 2>/dev/null
|
||||
if [[ $? == 0 ]]; then
|
||||
# If the restore was successful, figure out exactly what was saved, check
|
||||
# out the original commit, then restore the saved changes on top of it
|
||||
status="*"
|
||||
local patch="$(git format-patch HEAD^ --stdout)"
|
||||
git checkout HEAD^ 2>/dev/null
|
||||
echo "$patch" | git apply -
|
||||
else
|
||||
# Otherwise, just restore the original commit
|
||||
git checkout "$1" 2>/dev/null
|
||||
fi
|
||||
echo "HEAD is now $1$status, $(git_commit_subject $1)"
|
||||
}
|
||||
|
||||
# Jump to next commit
|
||||
function next() {
|
||||
local next_sha=$(git_next_sha)
|
||||
if [[ "$next_sha" == "$(git_head_sha)" ]]; then
|
||||
# Abort if no more commits
|
||||
echo "Already at last commit in $git_branch. Congratulations!"
|
||||
else
|
||||
# Checkout branch by name if at its HEAD
|
||||
if [[ "$next_sha" == "$(git_branch_sha)" ]]; then
|
||||
next_sha="$git_branch"
|
||||
fi
|
||||
echo "Jumping ahead to next commit."
|
||||
restore $next_sha
|
||||
fi
|
||||
}
|
||||
|
||||
# Jump to previous commit
|
||||
function prev() {
|
||||
local prev_sha=$(git_prev_sha)
|
||||
if [[ "$prev_sha" == "$(git_head_sha)" ]]; then
|
||||
# Abort if no more commits
|
||||
echo "Already at first commit in $git_branch."
|
||||
else
|
||||
echo "Jumping back to previous commit."
|
||||
restore $prev_sha
|
||||
fi
|
||||
}
|
||||
|
||||
# Show help if requested
|
||||
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
help
|
||||
exit
|
||||
fi
|
||||
|
||||
# Check if branch is valid
|
||||
git rev-parse "$git_branch" &>/dev/null
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "Error: Branch \"$git_branch\" does not appear to be valid."
|
||||
echo "Try $(basename "$0") --help for more information."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Handle CLI arguments
|
||||
if [[ "$1" == "next" ]]; then
|
||||
next
|
||||
elif [[ "$1" == "prev" ]]; then
|
||||
prev
|
||||
else
|
||||
usage
|
||||
exit 1
|
||||
fi
|
12
bin/.bin/git/git-nuke
Executable file
12
bin/.bin/git/git-nuke
Executable file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Nukes a branch locally and on the origin remote.
|
||||
#
|
||||
# $1 - Branch name.
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# git nuke add-git-nuke
|
||||
|
||||
git branch -D $1
|
||||
git push origin :$1
|
149
bin/.bin/git/git-open
Executable file
149
bin/.bin/git/git-open
Executable file
|
@ -0,0 +1,149 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Opens the BitBucket/GitHub page for a repo/branch in your browser.
|
||||
#
|
||||
# git open
|
||||
# git open [remote] [branch]
|
||||
|
||||
|
||||
# are we in a git repo?
|
||||
git rev-parse --is-inside-work-tree &>/dev/null
|
||||
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "Not a git repository." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# assume origin if not provided
|
||||
# fallback to upstream if neither is present.
|
||||
remote="origin"
|
||||
if [ -n "$1" ]; then
|
||||
if [ "$1" == "issue" ]; then
|
||||
currentBranch=$(git symbolic-ref -q --short HEAD)
|
||||
regex='^issue'
|
||||
if [[ $currentBranch =~ $regex ]]; then
|
||||
issue=${currentBranch#*#}
|
||||
else
|
||||
echo "'git open issue' expect branch naming to be issues/#123" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
remote="$1"
|
||||
fi
|
||||
fi
|
||||
|
||||
remote_url="remote.${remote}.url"
|
||||
|
||||
giturl=$(git config --get "$remote_url")
|
||||
if [ -z "$giturl" ]; then
|
||||
echo "$remote_url not set." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# get current branch
|
||||
if [ -z "$2" ]; then
|
||||
branch=$(git symbolic-ref -q --short HEAD)
|
||||
else
|
||||
branch="$2"
|
||||
fi
|
||||
|
||||
# Make # and % characters url friendly
|
||||
# github.com/paulirish/git-open/pull/24
|
||||
branch=${branch//%/%25} && branch=${branch//#/%23}
|
||||
|
||||
# URL normalization
|
||||
# GitHub gists
|
||||
if grep -q gist.github <<<$giturl; then
|
||||
giturl=${giturl/git\@gist.github\.com\:/https://gist.github.com/}
|
||||
providerUrlDifference=tree
|
||||
|
||||
# GitHub
|
||||
elif grep -q github <<<$giturl; then
|
||||
giturl=${giturl/git\@github\.com\:/https://github.com/}
|
||||
|
||||
# handle SSH protocol (links like ssh://git@github.com/user/repo)
|
||||
giturl=${giturl/#ssh\:\/\/git\@github\.com\//https://github.com/}
|
||||
|
||||
providerUrlDifference=tree
|
||||
|
||||
# Bitbucket
|
||||
elif grep -q bitbucket <<<$giturl; then
|
||||
giturl=${giturl/git\@bitbucket\.org\:/https://bitbucket.org/}
|
||||
# handle SSH protocol (change ssh://https://bitbucket.org/user/repo to https://bitbucket.org/user/repo)
|
||||
giturl=${giturl/#ssh\:\/\/git\@/https://}
|
||||
|
||||
rev="$(git rev-parse HEAD)"
|
||||
git_pwd="$(git rev-parse --show-prefix)"
|
||||
providerUrlDifference="src/${rev}/${git_pwd}"
|
||||
branch="?at=${branch}"
|
||||
|
||||
# Atlassian Bitbucket Server
|
||||
elif grep -q "/scm/" <<<$giturl; then
|
||||
re='(.*)/scm/(.*)/(.*)\.git'
|
||||
if [[ $giturl =~ $re ]]; then
|
||||
giturl=${BASH_REMATCH[1]}/projects/${BASH_REMATCH[2]}/repos/${BASH_REMATCH[3]}
|
||||
providerUrlDifference=browse
|
||||
branch="?at=refs%2Fheads%2F${branch}"
|
||||
fi
|
||||
|
||||
# GitLab
|
||||
else
|
||||
# custom GitLab
|
||||
gitlab_domain=$(git config --get gitopen.gitlab.domain)
|
||||
gitlab_ssh_domain=$(git config --get gitopen.gitlab.ssh.domain)
|
||||
gitlab_ssh_domain=${gitlab_ssh_domain:-$gitlab_domain}
|
||||
gitlab_ssh_port=$(git config --get gitopen.gitlab.ssh.port)
|
||||
|
||||
gitlab_protocol=$(git config --get gitopen.gitlab.protocol)
|
||||
if [ -z "$gitlab_protocol" ]; then
|
||||
gitlab_protocol=https
|
||||
fi
|
||||
|
||||
if [ -n "$gitlab_domain" ]; then
|
||||
if egrep -q "${gitlab_domain}|${gitlab_ssh_domain}" <<<$giturl; then
|
||||
|
||||
# Handle GitLab's default SSH notation (like git@gitlab.domain.com:user/repo)
|
||||
giturl=${giturl/git\@${gitlab_ssh_domain}\:/${gitlab_protocol}://${gitlab_domain}/}
|
||||
|
||||
# handle SSH protocol (links like ssh://git@gitlab.domain.com/user/repo)
|
||||
giturl=${giturl/#ssh\:\/\//${gitlab_protocol}://}
|
||||
|
||||
# remove git@ from the domain
|
||||
giturl=${giturl/git\@${gitlab_ssh_domain}/${gitlab_domain}/}
|
||||
|
||||
# remove SSH port
|
||||
if [ -n "$gitlab_ssh_port" ]; then
|
||||
giturl=${giturl/\/:${gitlab_ssh_port}\///}
|
||||
fi
|
||||
providerUrlDifference=tree
|
||||
fi
|
||||
# hosted GitLab
|
||||
elif grep -q gitlab <<<$giturl; then
|
||||
giturl=${giturl/git\@gitlab\.com\:/https://gitlab.com/}
|
||||
providerUrlDifference=tree
|
||||
fi
|
||||
fi
|
||||
giturl=${giturl%\.git}
|
||||
|
||||
if [ -n "$issue" ]; then
|
||||
giturl="${giturl}/issues/${issue}"
|
||||
elif [ -n "$branch" ]; then
|
||||
giturl="${giturl}/${providerUrlDifference}/${branch}"
|
||||
fi
|
||||
|
||||
# simplify URL for master
|
||||
giturl=${giturl/tree\/master/}
|
||||
|
||||
# get current open browser command
|
||||
case $( uname -s ) in
|
||||
Darwin) open=open;;
|
||||
MINGW*) open=start;;
|
||||
CYGWIN*) open=cygstart;;
|
||||
MSYS*) open="powershell.exe –NoProfile Start";;
|
||||
*) open=${BROWSER:-xdg-open};;
|
||||
esac
|
||||
|
||||
# open it in a browser
|
||||
$open "$giturl" &> /dev/null
|
||||
exit $?
|
349
bin/.bin/git/git-recall
Executable file
349
bin/.bin/git/git-recall
Executable file
|
@ -0,0 +1,349 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
|
||||
# usage info
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: git recall [options]
|
||||
Options:
|
||||
-d, --date Show logs for last n days.
|
||||
-a, --author Author name.
|
||||
-f, --fetch fetch commits.
|
||||
-h, --help This message.
|
||||
-v, --version Show version.
|
||||
-- End of options.
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
# Global variables
|
||||
SINCE="1 days ago" # show logs for last day by default
|
||||
AUTHOR=""
|
||||
FETCH=false
|
||||
GIT_FORMAT=""
|
||||
GIT_LOG=""
|
||||
COMMITS=""
|
||||
COMMITS_UNCOL=() # commits without colors
|
||||
LESSKEY=false
|
||||
SED_BIN="" # Sed option to use according OS.
|
||||
VERSION="1.1.10"
|
||||
|
||||
# Are we in a git repo?
|
||||
if [[ ! -d ".git" ]] && ! git rev-parse --git-dir &>/dev/null; then
|
||||
echo "abort: not a git repository." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse options
|
||||
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do
|
||||
case $1 in
|
||||
-v | --version )
|
||||
echo "$version"
|
||||
exit
|
||||
;;
|
||||
-d | --date )
|
||||
SINCE="$2 days ago"
|
||||
shift;
|
||||
;;
|
||||
-a | --author )
|
||||
AUTHOR="$2"
|
||||
shift
|
||||
;;
|
||||
-f | --fetch )
|
||||
FETCH=true
|
||||
;;
|
||||
-h | --help )
|
||||
usage
|
||||
exit
|
||||
;;
|
||||
* )
|
||||
echo "abort: unknown argument" 1>&2
|
||||
exit 1
|
||||
esac
|
||||
shift
|
||||
done
|
||||
if [[ "$1" == "--" ]]; then shift; fi
|
||||
|
||||
|
||||
# Colored output.
|
||||
function colored() {
|
||||
GREEN=$(tput setaf 4)
|
||||
YELLOW=$(tput setaf 3)
|
||||
NORMAL=$(tput sgr0)
|
||||
REVERSE=$(tput rev)
|
||||
}
|
||||
|
||||
# Uncolored output.
|
||||
function uncolored() {
|
||||
GREEN=""
|
||||
YELLOW=""
|
||||
NORMAL=""
|
||||
REVERSE=""
|
||||
}
|
||||
|
||||
# Enable colors if supported by terminal.
|
||||
if [[ -t 1 ]] && [[ -n "$TERM" ]] && which tput &>/dev/null && tput colors &>/dev/null; then
|
||||
ncolors=$(tput colors)
|
||||
if [[ -n "$ncolors" ]] && [[ "$ncolors" -ge 8 ]] ; then
|
||||
colored
|
||||
else
|
||||
uncolored
|
||||
fi
|
||||
else
|
||||
uncolored
|
||||
fi
|
||||
|
||||
# Check if lesskey is installed.
|
||||
if command -v lesskey &> /dev/null; then
|
||||
LESSKEY=true
|
||||
fi
|
||||
|
||||
# Set AUTHOR to current user if no param passed or display for all users if param equal to "all".
|
||||
if [[ ! -n $AUTHOR ]]; then
|
||||
AUTHOR=$(git config user.name 2>/dev/null)
|
||||
elif [[ $AUTHOR = "all" ]]; then
|
||||
AUTHOR=".*"
|
||||
fi
|
||||
|
||||
# Fetch changes before.
|
||||
if [[ $FETCH == true ]]; then
|
||||
echo "${GREEN}Fetching changes...${NORMAL}"
|
||||
git fetch --all &> /dev/null
|
||||
tput cuu1
|
||||
tput ed # clear screen
|
||||
fi
|
||||
|
||||
# Log template.
|
||||
GIT_FORMAT="%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset"
|
||||
|
||||
# Log command.
|
||||
GIT_LOG="git log --pretty=format:'${GIT_FORMAT}'
|
||||
--author \"$AUTHOR\"
|
||||
--since \"$SINCE\" --abbrev-commit"
|
||||
|
||||
# Change temporary the IFS to store GIT_LOG's output into an array.
|
||||
IFS=$'\n'
|
||||
COMMITS=($(eval ${GIT_LOG} 2>/dev/null))
|
||||
unset IFS
|
||||
|
||||
NI=${#COMMITS[@]} # Total number of items.
|
||||
SN=$(( `tput lines` - 1 )) # Screen's number of lines.
|
||||
CN=$(tput cols) # Screen's number of columns.
|
||||
TN=$(( $NI < $((SN -1)) ? $NI : $((SN -1)))) # Number of lines that we will display.
|
||||
OFFSET=0 #Incremented by one each time a commit's length is higher than teminal width.
|
||||
|
||||
# If there is no items, exit.
|
||||
if [[ $NI = 0 ]]; then
|
||||
if [[ $AUTHOR = ".*" ]]; then
|
||||
echo "${YELLOW}All contributors did nothing during this period.${NORMAL}" && exit 0
|
||||
else
|
||||
echo "${YELLOW}The contributor \"${AUTHOR}\" did nothing during this period.${NORMAL}" && exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set correct sed option according OS's type
|
||||
case "$OSTYPE" in
|
||||
darwin*) SED_BIN="sed -E" ;;
|
||||
*) SED_BIN="sed -r" ;;
|
||||
esac
|
||||
|
||||
# Create array with uncolred commits (removing escape sequences using sed)
|
||||
for elt in "${COMMITS[@]}"
|
||||
do
|
||||
ELT="$(echo "$elt" | $SED_BIN "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")" # remove colors escape codes
|
||||
COMMITS_UNCOL+=("$ELT")
|
||||
done
|
||||
# Add +1 to OFFSET if a commit's length is bigger than the current terminal session's width. (This is to fix a redraw issue)
|
||||
for C in "${COMMITS_UNCOL[@]}"
|
||||
do
|
||||
if [[ ${#C} -gt $CN ]]; then
|
||||
OFFSET=$(( OFFSET + 1 ))
|
||||
fi
|
||||
done
|
||||
|
||||
# Set keys.
|
||||
au="`echo -e '\e[A'`" # arrow up
|
||||
au_1="k" # arrow up
|
||||
ad="`echo -e '\e[B'`" # arrow down
|
||||
ad_1="j" # arrow down
|
||||
ec="`echo -e '\e'`" # escape
|
||||
nl="`echo -e '\n'`" # newline
|
||||
nl_1="e" # expand
|
||||
co="c" # checkout
|
||||
|
||||
# Create a temporary lesskey file to change the keybindings so the user can use the TAB key to quit less. (more convenient)
|
||||
if [[ $LESSKEY = true ]]; then
|
||||
echo "\t quit" | lesskey -o $HOME/.lsh_less_keys_tmp -- - &> /dev/null
|
||||
fi
|
||||
|
||||
## Get commit's diff.
|
||||
function get_diff() {
|
||||
ELT="$(echo "${COMMITS_UNCOL[$CP-1]}")"
|
||||
DIFF_TIP=${ELT:0:7}
|
||||
DIFF_CMD="git show $DIFF_TIP --color=always"
|
||||
DIFF=$(eval ${DIFF_CMD} 2>/dev/null)
|
||||
tmp_diff="$(echo "$DIFF" | $SED_BIN "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")" # remove colors escape codes
|
||||
off=$(echo "$tmp_diff" | grep -c ".\{$CN\}") #Number of lines in the diff that are longer than terminal width.
|
||||
DIFF_LINES_NUMBER="$(echo "$DIFF" | wc -l)"
|
||||
DIFF_LINES_NUMBER=$(( DIFF_LINES_NUMBER + off ))
|
||||
}
|
||||
|
||||
## This function will print the diff according the commit's tip. If the diff is too long, the result will be displayed using 'less'.
|
||||
function print_diff() {
|
||||
get_diff # get commit's diff
|
||||
if [[ $(( TN + DIFF_LINES_NUMBER + OFFSET )) -ge $(( `tput lines` - 1 )) ]]; then
|
||||
if [[ $LESSKEY = true ]]; then
|
||||
echo "$DIFF" | less -r -k $HOME/.lsh_less_keys_tmp
|
||||
else
|
||||
echo "$DIFF" | less -r
|
||||
fi
|
||||
tput ed # Clear screen
|
||||
else
|
||||
stop=false
|
||||
tput ed
|
||||
for i in `seq 1 $TN`
|
||||
do
|
||||
echo -n "$NORMAL"
|
||||
[[ $CP == "$i" ]] && echo -n "$REVERSE"
|
||||
echo "${COMMITS[$i - 1]}"
|
||||
[[ $CP == "$i" ]] && echo "$DIFF"
|
||||
done
|
||||
# Wait for user action.
|
||||
while ! $stop
|
||||
do
|
||||
read -sn 1 key
|
||||
case "$key" in
|
||||
"$nl" | "$nl_1")
|
||||
stop=true
|
||||
;;
|
||||
"q")
|
||||
stop=true
|
||||
END=true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
[[ $END = false ]] && tput cuu $(( TN + DIFF_LINES_NUMBER + OFFSET )) && tput ed
|
||||
[[ $END = true ]] && tput cuu 1
|
||||
fi
|
||||
}
|
||||
|
||||
function do_checkout(){
|
||||
ELT="$(echo "${COMMITS_UNCOL[$CP-1]}")"
|
||||
DIFF_TIP=${ELT:0:7}
|
||||
eval "git checkout $DIFF_TIP 2> /dev/null"
|
||||
}
|
||||
|
||||
# Calculate OFFSET to avoid bad redraw.
|
||||
function calculate_offset {
|
||||
tmp=1
|
||||
index=$(( SI -1 ))
|
||||
while [[ $tmp -lt $SN ]]
|
||||
do
|
||||
el=${COMMITS_UNCOL[$index]}
|
||||
if [[ ${#el} -gt $CN ]] && [[ $CP -lt $((SN -1)) ]]; then
|
||||
OFFSET_2=$(( OFFSET_2 + 1 ))
|
||||
tmp=$(( tmp + 1 ))
|
||||
fi
|
||||
tmp=$(( tmp + 1 ))
|
||||
index=$(( index + 1 ))
|
||||
done
|
||||
}
|
||||
|
||||
{ # capture stdout to stderr
|
||||
|
||||
tput civis # hide cursor.
|
||||
CP=1 # current position
|
||||
SI=1 # index
|
||||
END=false # end while loop
|
||||
EXT=0 # Used to extend the number of lines to display.
|
||||
|
||||
## Loops, reads inputs and prints commits until user presses 'q' to exit or TAB to show the diff.
|
||||
while ! $END
|
||||
do
|
||||
END_INDEX=0 # Index for the last item to display
|
||||
# When the number of item is higher than screen's number of lines, OFFSET_2 is recalculated each time we select a new item
|
||||
# Set last index to print. (based on OFFSET)
|
||||
if [[ $TN == $NI ]]; then
|
||||
END_INDEX=$TN
|
||||
OFFSET_2=$OFFSET
|
||||
elif [[ $TN == $(( SN - 1 )) ]]; then
|
||||
# Calculate new OFFSET.
|
||||
if [[ $OFFSET != 0 ]]; then
|
||||
[[ $CP -lt $((SN -1)) ]] && OFFSET_2=0
|
||||
EXT=1
|
||||
calculate_offset
|
||||
fi
|
||||
END_INDEX=$(( TN + SI -1 + EXT - OFFSET_2 ))
|
||||
fi
|
||||
|
||||
# Loop and echo commits
|
||||
for i in `seq $SI $END_INDEX`
|
||||
do
|
||||
echo -n "$NORMAL"
|
||||
[[ $CP == $i ]] && echo -n "$REVERSE"
|
||||
echo "${COMMITS[$i - 1]}"
|
||||
done
|
||||
|
||||
read -sn 1 key
|
||||
[[ "$key" == "$ec" ]] &&
|
||||
{
|
||||
read -sn 2 k2
|
||||
key="$key$k2"
|
||||
}
|
||||
|
||||
case "$key" in
|
||||
|
||||
"$au" | "$au_1")
|
||||
CP=$(( CP - 1 ))
|
||||
[[ $CP == 0 ]] && [[ $SI == 1 ]] && [[ $TN == $(( SN - 1 )) ]] && CP=$NI && SI=$(( NI - SN + 2 + OFFSET_2 ))
|
||||
[[ $CP == 0 ]] && [[ $SI == 1 ]] && [[ $TN == $NI ]] && CP=$TN
|
||||
[[ $CP == $(( SI - 1 )) ]] && [[ $SI != 1 ]] && SI=$(( SI - 1 ))
|
||||
|
||||
[[ $TN != $(( SN - 1 )) ]] && tput cuu $(( TN + OFFSET_2 ))
|
||||
[[ $TN == $(( SN - 1 )) ]] && tput cuu $(( TN + EXT ))
|
||||
[[ $SI != 1 ]] && tput ed # clear screen
|
||||
;;
|
||||
|
||||
"$ad" | "$ad_1")
|
||||
CP=$(( CP + 1 ))
|
||||
[[ $CP == $(( NI + 1 )) ]] && CP=1 && SI=1
|
||||
[[ $CP == $(( SN + SI - 1 + EXT - OFFSET_2 )) ]] && [[ $TN == $(( SN - 1 )) ]] && SI=$(( SI + 1 ))
|
||||
|
||||
[[ $TN != $(( SN - 1 )) ]] && tput cuu $(( TN + OFFSET_2 ))
|
||||
[[ $TN == $(( SN - 1 )) ]] && tput cuu $(( TN + EXT ))
|
||||
[[ $SI != 1 ]] && tput ed # clear screen
|
||||
[[ $SI = 1 ]] && [[ $CP = 1 ]] && tput ed # clear screen
|
||||
;;
|
||||
|
||||
"$nl" | "$nl_1")
|
||||
[[ $TN == $NI ]] && tput cuu $(( TN + OFFSET_2 ))
|
||||
[[ $TN != $NI ]] && tput cuu $(( TN + EXT ))
|
||||
print_diff
|
||||
;;
|
||||
"$co")
|
||||
si=false
|
||||
END=true
|
||||
do_checkout
|
||||
tput cuu 1 #move cursor up one line. (remove extra line)
|
||||
;;
|
||||
|
||||
"q")
|
||||
si=false
|
||||
END=true
|
||||
tput cuu 1 #move cursor up one line. (remove extra line)
|
||||
;;
|
||||
|
||||
* )
|
||||
tput cuu $(( TN + OFFSET_2 ))
|
||||
esac
|
||||
|
||||
done
|
||||
|
||||
# remove temporary less keybindings
|
||||
[[ $LESSKEY = true ]] && rm $HOME/.lsh_less_keys_tmp
|
||||
|
||||
tput cnorm # unhide cursor
|
||||
echo "$NORMAL" # normal colors
|
||||
|
||||
} >&2 # END capture
|
||||
|
44
bin/.bin/git/git-st
Executable file
44
bin/.bin/git/git-st
Executable file
|
@ -0,0 +1,44 @@
|
|||
#!/bin/sh
|
||||
# Came from here: https://raw.githubusercontent.com/PlatyPew/dotfiles/master/configs/git/git-st
|
||||
IFS=
|
||||
status="$(git -c color.status=always status -sb)"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
diff="$(git diff --color --stat HEAD 2> /dev/null | sed '$d; s/^ //' | cut -d '|' -f 2)"
|
||||
|
||||
IFS=$'\n' status=($status)
|
||||
IFS=$'\n' diff=($diff)
|
||||
|
||||
len=-1
|
||||
for i in $(seq 1 $(( ${#status[@]} - 1)))
|
||||
do
|
||||
if [ ${#status[i]} -gt $len ]
|
||||
then
|
||||
len=${#status[i]}
|
||||
fi
|
||||
done
|
||||
(( len *= -1 ))
|
||||
|
||||
for i in $(seq 0 $(( ${#status[@]} - 1)))
|
||||
do
|
||||
currStatus=${status[i]}
|
||||
if [ $i -eq 0 ]
|
||||
then
|
||||
echo "${status[0]}" | cut -d ' ' -f 2-
|
||||
else
|
||||
if [ ! -z ${diff[i - 1]} ]
|
||||
then
|
||||
currDiff="|${diff[i - 1]}"
|
||||
else
|
||||
currDiff=""
|
||||
fi
|
||||
printf "%*s %s\n" $len "${currStatus}" "${currDiff}"
|
||||
fi
|
||||
done
|
||||
if [ $(( ${#status[@]} - 1)) -eq 0 ]
|
||||
then
|
||||
printf "\033[93mNothing to commit, working tree clean\033[0m\n"
|
||||
fi
|
364
bin/.bin/git/git-wtf
Executable file
364
bin/.bin/git/git-wtf
Executable file
|
@ -0,0 +1,364 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
HELP = <<EOS
|
||||
git-wtf displays the state of your repository in a readable, easy-to-scan
|
||||
format. It's useful for getting a summary of how a branch relates to a remote
|
||||
server, and for wrangling many topic branches.
|
||||
|
||||
git-wtf can show you:
|
||||
- How a branch relates to the remote repo, if it's a tracking branch.
|
||||
- How a branch relates to integration branches, if it's a feature branch.
|
||||
- How a branch relates to the feature branches, if it's an integration
|
||||
branch.
|
||||
|
||||
git-wtf is best used before a git push, or between a git fetch and a git
|
||||
merge. Be sure to set color.ui to auto or yes for maximum viewing pleasure.
|
||||
EOS
|
||||
|
||||
KEY = <<EOS
|
||||
KEY:
|
||||
() branch only exists locally
|
||||
{} branch only exists on a remote repo
|
||||
[] branch exists locally and remotely
|
||||
|
||||
x merge occurs both locally and remotely
|
||||
~ merge occurs only locally
|
||||
(space) branch isn't merged in
|
||||
|
||||
(It's possible for merges to occur remotely and not locally, of course, but
|
||||
that's a less common case and git-wtf currently doesn't display anything
|
||||
special for it.)
|
||||
EOS
|
||||
|
||||
USAGE = <<EOS
|
||||
Usage: git wtf [branch+] [options]
|
||||
|
||||
If [branch] is not specified, git-wtf will use the current branch. The possible
|
||||
[options] are:
|
||||
|
||||
-l, --long include author info and date for each commit
|
||||
-a, --all show all branches across all remote repos, not just
|
||||
those from origin
|
||||
-A, --all-commits show all commits, not just the first 5
|
||||
-s, --short don't show commits
|
||||
-k, --key show key
|
||||
-r, --relations show relation to features / integration branches
|
||||
--dump-config print out current configuration and exit
|
||||
|
||||
git-wtf uses some heuristics to determine which branches are integration
|
||||
branches, and which are feature branches. (Specifically, it assumes the
|
||||
integration branches are named "master", "next" and "edge".) If it guesses
|
||||
incorrectly, you will have to create a .git-wtfrc file.
|
||||
|
||||
To start building a configuration file, run "git-wtf --dump-config >
|
||||
.git-wtfrc" and edit it. The config file is a YAML file that specifies the
|
||||
integration branches, any branches to ignore, and the max number of commits to
|
||||
display when --all-commits isn't used. git-wtf will look for a .git-wtfrc file
|
||||
starting in the current directory, and recursively up to the root.
|
||||
|
||||
IMPORTANT NOTE: all local branches referenced in .git-wtfrc must be prefixed
|
||||
with heads/, e.g. "heads/master". Remote branches must be of the form
|
||||
remotes/<remote>/<branch>.
|
||||
EOS
|
||||
|
||||
COPYRIGHT = <<EOS
|
||||
git-wtf Copyright 2008--2009 William Morgan <wmorgan at the masanjin dot nets>.
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You can find the GNU General Public License at: http://www.gnu.org/licenses/
|
||||
EOS
|
||||
|
||||
require 'yaml'
|
||||
CONFIG_FN = ".git-wtfrc"
|
||||
|
||||
class Numeric; def pluralize s; "#{to_s} #{s}" + (self != 1 ? "s" : "") end end
|
||||
|
||||
if ARGV.delete("--help") || ARGV.delete("-h")
|
||||
puts USAGE
|
||||
exit
|
||||
end
|
||||
|
||||
## poor man's trollop
|
||||
$long = ARGV.delete("--long") || ARGV.delete("-l")
|
||||
$short = ARGV.delete("--short") || ARGV.delete("-s")
|
||||
$all = ARGV.delete("--all") || ARGV.delete("-a")
|
||||
$all_commits = ARGV.delete("--all-commits") || ARGV.delete("-A")
|
||||
$dump_config = ARGV.delete("--dump-config")
|
||||
$key = ARGV.delete("--key") || ARGV.delete("-k")
|
||||
$show_relations = ARGV.delete("--relations") || ARGV.delete("-r")
|
||||
ARGV.each { |a| abort "Error: unknown argument #{a}." if a =~ /^--/ }
|
||||
|
||||
## search up the path for a file
|
||||
def find_file fn
|
||||
while true
|
||||
return fn if File.exist? fn
|
||||
fn2 = File.join("..", fn)
|
||||
return nil if File.expand_path(fn2) == File.expand_path(fn)
|
||||
fn = fn2
|
||||
end
|
||||
end
|
||||
|
||||
want_color = `git config color.wtf`
|
||||
want_color = `git config color.ui` if want_color.empty?
|
||||
$color = case want_color.chomp
|
||||
when "true"; true
|
||||
when "auto"; $stdout.tty?
|
||||
end
|
||||
|
||||
def red s; $color ? "\033[31m#{s}\033[0m" : s end
|
||||
def green s; $color ? "\033[32m#{s}\033[0m" : s end
|
||||
def yellow s; $color ? "\033[33m#{s}\033[0m" : s end
|
||||
def cyan s; $color ? "\033[36m#{s}\033[0m" : s end
|
||||
def grey s; $color ? "\033[1;30m#{s}\033[0m" : s end
|
||||
def purple s; $color ? "\033[35m#{s}\033[0m" : s end
|
||||
|
||||
## the set of commits in 'to' that aren't in 'from'.
|
||||
## if empty, 'to' has been merged into 'from'.
|
||||
def commits_between from, to
|
||||
if $long
|
||||
`git log --pretty=format:"- %s [#{yellow "%h"}] (#{purple "%ae"}; %ar)" #{from}..#{to}`
|
||||
else
|
||||
`git log --pretty=format:"- %s [#{yellow "%h"}]" #{from}..#{to}`
|
||||
end.split(/[\r\n]+/)
|
||||
end
|
||||
|
||||
def show_commits commits, prefix=" "
|
||||
if commits.empty?
|
||||
puts "#{prefix} none"
|
||||
else
|
||||
max = $all_commits ? commits.size : $config["max_commits"]
|
||||
max -= 1 if max == commits.size - 1 # never show "and 1 more"
|
||||
commits[0 ... max].each { |c| puts "#{prefix}#{c}" }
|
||||
puts grey("#{prefix}... and #{commits.size - max} more (use -A to see all).") if commits.size > max
|
||||
end
|
||||
end
|
||||
|
||||
def ahead_behind_string ahead, behind
|
||||
[ahead.empty? ? nil : "#{ahead.size.pluralize 'commit'} ahead",
|
||||
behind.empty? ? nil : "#{behind.size.pluralize 'commit'} behind"].
|
||||
compact.join("; ")
|
||||
end
|
||||
|
||||
def widget merged_in, remote_only=false, local_only=false, local_only_merge=false
|
||||
left, right = case
|
||||
when remote_only; %w({ })
|
||||
when local_only; %w{( )}
|
||||
else %w([ ])
|
||||
end
|
||||
middle = case
|
||||
when merged_in && local_only_merge; green("~")
|
||||
when merged_in; green("x")
|
||||
else " "
|
||||
end
|
||||
print left, middle, right
|
||||
end
|
||||
|
||||
def show b
|
||||
have_both = b[:local_branch] && b[:remote_branch]
|
||||
|
||||
pushc, pullc, oosync = if have_both
|
||||
[x = commits_between(b[:remote_branch], b[:local_branch]),
|
||||
y = commits_between(b[:local_branch], b[:remote_branch]),
|
||||
!x.empty? && !y.empty?]
|
||||
end
|
||||
|
||||
if b[:local_branch]
|
||||
puts "Local branch: " + green(b[:local_branch].sub(/^heads\//, ""))
|
||||
|
||||
if have_both
|
||||
if pushc.empty?
|
||||
puts "#{widget true} in sync with remote"
|
||||
else
|
||||
action = oosync ? "push after rebase / merge" : "push"
|
||||
puts "#{widget false} NOT in sync with remote (you should #{action})"
|
||||
show_commits pushc unless $short
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if b[:remote_branch]
|
||||
puts "Remote branch: #{cyan b[:remote_branch]} (#{b[:remote_url]})"
|
||||
|
||||
if have_both
|
||||
if pullc.empty?
|
||||
puts "#{widget true} in sync with local"
|
||||
else
|
||||
action = pushc.empty? ? "merge" : "rebase / merge"
|
||||
puts "#{widget false} NOT in sync with local (you should #{action})"
|
||||
show_commits pullc unless $short
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
puts "\n#{red "WARNING"}: local and remote branches have diverged. A merge will occur unless you rebase." if oosync
|
||||
end
|
||||
|
||||
def show_relations b, all_branches
|
||||
ibs, fbs = all_branches.partition { |name, br| $config["integration-branches"].include?(br[:local_branch]) || $config["integration-branches"].include?(br[:remote_branch]) }
|
||||
if $config["integration-branches"].include? b[:local_branch]
|
||||
puts "\nFeature branches:" unless fbs.empty?
|
||||
fbs.each do |name, br|
|
||||
next if $config["ignore"].member?(br[:local_branch]) || $config["ignore"].member?(br[:remote_branch])
|
||||
next if br[:ignore]
|
||||
local_only = br[:remote_branch].nil?
|
||||
remote_only = br[:local_branch].nil?
|
||||
name = if local_only
|
||||
purple br[:name]
|
||||
elsif remote_only
|
||||
cyan br[:name]
|
||||
else
|
||||
green br[:name]
|
||||
end
|
||||
|
||||
## for remote_only branches, we'll compute wrt the remote branch head. otherwise, we'll
|
||||
## use the local branch head.
|
||||
head = remote_only ? br[:remote_branch] : br[:local_branch]
|
||||
|
||||
remote_ahead = b[:remote_branch] ? commits_between(b[:remote_branch], head) : []
|
||||
local_ahead = b[:local_branch] ? commits_between(b[:local_branch], head) : []
|
||||
|
||||
if local_ahead.empty? && remote_ahead.empty?
|
||||
puts "#{widget true, remote_only, local_only} #{name} #{local_only ? "(local-only) " : ""}is merged in"
|
||||
elsif local_ahead.empty?
|
||||
puts "#{widget true, remote_only, local_only, true} #{name} merged in (only locally)"
|
||||
else
|
||||
behind = commits_between head, (br[:local_branch] || br[:remote_branch])
|
||||
ahead = remote_only ? remote_ahead : local_ahead
|
||||
puts "#{widget false, remote_only, local_only} #{name} #{local_only ? "(local-only) " : ""}is NOT merged in (#{ahead_behind_string ahead, behind})"
|
||||
show_commits ahead unless $short
|
||||
end
|
||||
end
|
||||
else
|
||||
puts "\nIntegration branches:" unless ibs.empty? # unlikely
|
||||
ibs.sort_by { |v, br| v }.each do |v, br|
|
||||
next if $config["ignore"].member?(br[:local_branch]) || $config["ignore"].member?(br[:remote_branch])
|
||||
next if br[:ignore]
|
||||
local_only = br[:remote_branch].nil?
|
||||
remote_only = br[:local_branch].nil?
|
||||
name = remote_only ? cyan(br[:name]) : green(br[:name])
|
||||
|
||||
ahead = commits_between v, (b[:local_branch] || b[:remote_branch])
|
||||
if ahead.empty?
|
||||
puts "#{widget true, local_only} merged into #{name}"
|
||||
else
|
||||
#behind = commits_between b[:local_branch], v
|
||||
puts "#{widget false, local_only} NOT merged into #{name} (#{ahead.size.pluralize 'commit'} ahead)"
|
||||
show_commits ahead unless $short
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#### EXECUTION STARTS HERE ####
|
||||
|
||||
## find config file and load it
|
||||
$config = { "integration-branches" => %w(heads/master heads/next heads/edge), "ignore" => [], "max_commits" => 5 }.merge begin
|
||||
fn = find_file CONFIG_FN
|
||||
if fn && (h = YAML::load_file(fn)) # yaml turns empty files into false
|
||||
h["integration-branches"] ||= h["versions"] # support old nomenclature
|
||||
h
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
|
||||
if $dump_config
|
||||
puts $config.to_yaml
|
||||
exit
|
||||
end
|
||||
|
||||
## first, index registered remotes
|
||||
remotes = `git config --get-regexp ^remote\.\*\.url`.split(/[\r\n]+/).inject({}) do |hash, l|
|
||||
l =~ /^remote\.(.+?)\.url (.+)$/ or next hash
|
||||
hash[$1] ||= $2
|
||||
hash
|
||||
end
|
||||
|
||||
## next, index followed branches
|
||||
branches = `git config --get-regexp ^branch\.`.split(/[\r\n]+/).inject({}) do |hash, l|
|
||||
case l
|
||||
when /branch\.(.*?)\.remote (.+)/
|
||||
name, remote = $1, $2
|
||||
|
||||
hash[name] ||= {}
|
||||
hash[name].merge! :remote => remote, :remote_url => remotes[remote]
|
||||
when /branch\.(.*?)\.merge ((refs\/)?heads\/)?(.+)/
|
||||
name, remote_branch = $1, $4
|
||||
hash[name] ||= {}
|
||||
hash[name].merge! :remote_mergepoint => remote_branch
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
## finally, index all branches
|
||||
remote_branches = {}
|
||||
`git show-ref`.split(/[\r\n]+/).each do |l|
|
||||
sha1, ref = l.chomp.split " refs/"
|
||||
|
||||
if ref =~ /^heads\/(.+)$/ # local branch
|
||||
name = $1
|
||||
next if name == "HEAD"
|
||||
branches[name] ||= {}
|
||||
branches[name].merge! :name => name, :local_branch => ref
|
||||
elsif ref =~ /^remotes\/(.+?)\/(.+)$/ # remote branch
|
||||
remote, name = $1, $2
|
||||
remote_branches["#{remote}/#{name}"] = true
|
||||
next if name == "HEAD"
|
||||
ignore = !($all || remote == "origin")
|
||||
|
||||
branch = name
|
||||
if branches[name] && branches[name][:remote] == remote
|
||||
# nothing
|
||||
else
|
||||
name = "#{remote}/#{branch}"
|
||||
end
|
||||
|
||||
branches[name] ||= {}
|
||||
branches[name].merge! :name => name, :remote => remote, :remote_branch => "#{remote}/#{branch}", :remote_url => remotes[remote], :ignore => ignore
|
||||
end
|
||||
end
|
||||
|
||||
## assemble remotes
|
||||
branches.each do |k, b|
|
||||
next unless b[:remote] && b[:remote_mergepoint]
|
||||
b[:remote_branch] = if b[:remote] == "."
|
||||
b[:remote_mergepoint]
|
||||
else
|
||||
t = "#{b[:remote]}/#{b[:remote_mergepoint]}"
|
||||
remote_branches[t] && t # only if it's still alive
|
||||
end
|
||||
end
|
||||
|
||||
show_dirty = ARGV.empty?
|
||||
targets = if ARGV.empty?
|
||||
[`git symbolic-ref HEAD`.chomp.sub(/^refs\/heads\//, "")]
|
||||
else
|
||||
ARGV.map { |x| x.sub(/^heads\//, "") }
|
||||
end.map { |t| branches[t] or abort "Error: can't find branch #{t.inspect}." }
|
||||
|
||||
targets.each do |t|
|
||||
show t
|
||||
show_relations t, branches if $show_relations || t[:remote_branch].nil?
|
||||
end
|
||||
|
||||
modified = show_dirty && `git ls-files -m` != ""
|
||||
uncommitted = show_dirty && `git diff-index --cached HEAD` != ""
|
||||
|
||||
if $key
|
||||
puts
|
||||
puts KEY
|
||||
end
|
||||
|
||||
puts if modified || uncommitted
|
||||
puts "#{red "NOTE"}: working directory contains modified files." if modified
|
||||
puts "#{red "NOTE"}: staging area contains staged but uncommitted files." if uncommitted
|
||||
|
||||
# the end!
|
Loading…
Add table
Add a link
Reference in a new issue