You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.0 KiB
158 lines
4.0 KiB
#!/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
|
|
|