Skip to content

Instantly share code, notes, and snippets.

@evinism
Created January 27, 2023 23:43
Show Gist options
  • Save evinism/6abd2d4940e64aa71d6d110b74667ae8 to your computer and use it in GitHub Desktop.
Save evinism/6abd2d4940e64aa71d6d110b74667ae8 to your computer and use it in GitHub Desktop.
# GitKit
## Experimental git branch management tool
function gk(){
if [ $# -eq 0 ]; then
echo "Usage: gk <command> [args]"
echo "Commands:"
echo " branch <branch> - create a new branch off the current branch"
echo " parent [branch] - get the parent of the current branch or the given branch"
echo " children [branch] - get the children of the current branch or the given branch"
echo " upchain [branch] - list the chain of branches from the current branch or the given branch"
echo " downchain [branch] - list the chain of branches from the current branch or the given branch"
echo " chain [branch] - list both upchain and downchain in order"
echo " evolve - rebase all children on top of the current branch, recursively"
echo " up - move one branch up the chain"
echo " down - move one branch down the chain"
echo " setparent <parent> - set the parent of the current branch"
echo " markmerged - mark the current branch as merged"
return 1
fi
local command=gk_$1
shift
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "ERROR: Not in a git repository"
return 1
fi
$command $@
}
function gk_branch(){
if [ $# -eq 0 ]; then
echo "Usage: gk branch <branch>"
return 1
fi
local dependent=$1
local base=$(git rev-parse --abbrev-ref HEAD)
# If branch has already been created, fail
if git show-ref --verify --quiet refs/heads/$dependent; then
echo "Branch $dependent already exists"
return 1
fi
git checkout -b $dependent
git config branch.$dependent.description "$base"
}
function gk_parent(){
local branch
if [ $# -eq 0 ]; then
branch=$(git rev-parse --abbrev-ref HEAD)
else
branch=$1
fi
git config branch.$branch.description
}
function gk_children(){
local base_branch
if [ $# -eq 0 ]; then
base_branch=$(git rev-parse --abbrev-ref HEAD)
else
base_branch=$1
fi
git for-each-ref --format='%(refname:short)' refs/heads | while read b; do
if [ "$(gk_parent $b)" = "$base_branch" ]; then
echo $b
fi
done
}
function listchain_helper(){
local branch=$1
echo $branch
local parent=$(gk_parent $branch)
if [ -n "$parent" ]; then
listchain_helper $parent
fi
}
function gk_upchain(){
local branch
if [ $# -eq 0 ]; then
branch=$(git rev-parse --abbrev-ref HEAD)
else
branch=$1
fi
listchain_helper $branch
echo "-- end of chain --"
}
function gk_downchain(){
local branch
if [ $# -eq 0 ]; then
branch=$(git rev-parse --abbrev-ref HEAD)
else
branch=$1
fi
local children=$(gk_children $branch)
# if multiple children, print out a special message
echo $branch
if [ $(echo $children | wc -w) -gk 1 ]; then
echo "[multiple children]"
elif [ -n "$children" ]; then
gk_downchain $children
else
echo "-- end of chain --"
fi
}
function gk_chain(){
local branch
if [ $# -eq 0 ]; then
branch=$(git rev-parse --abbrev-ref HEAD)
else
branch=$1
fi
# reverse the order of the upchain, appending a star as the last character on the last line
gk_upchain $branch | tac | sed '$ s/$/*/'
gk_downchain $branch | tail -n +2
}
function gk_evolve(){
# rebase all children on top of the current branch, recursively
local branch=$(git rev-parse --abbrev-ref HEAD)
local children=$(gk_children $branch)
for child in $children; do
echo "Rebasing $child on $branch"
git checkout $child
git rebase $branch
gk_evolve
done
git checkout $branch
}
function gk_up(){
# Move one branch up the chain
local branch=$(git rev-parse --abbrev-ref HEAD)
local parent=$(gk_parent $branch)
if [ -n "$parent" ]; then
git checkout $parent
else
echo "No parent branch"
fi
}
function gk_down(){
# Move one branch down the chain
local branch=$(git rev-parse --abbrev-ref HEAD)
local children=$(gk_children $branch)
# If multiple children, fail
if [ $(echo $children | wc -w) -gt 1 ]; then
echo "Multiple children branches"
return 1
fi
if [ -n "$children" ]; then
git checkout $children
else
echo "No child branch"
fi
}
function gk_setparent(){
# Set the parent of the current branch
local branch=$(git rev-parse --abbrev-ref HEAD)
local parent=$1
if [ -z "$parent" ]; then
echo "Usage: gk setparent <parent>"
return 1
fi
git config branch.$branch.description $parent
}
function gk_markmerged(){
# Mark the current branch as merged
local branch=$(git rev-parse --abbrev-ref HEAD)
# If git disagrees that it's merged, fail
if ! git branch --merged main | grep -q $branch; then
echo "Branch $branch is not merged"
return 1
fi
local children=$(gk_children $branch)
for child in $children; do
git checkout $child
gk_setparent main
done
git checkout $branch
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment