Skip to content

Instantly share code, notes, and snippets.

@cvrajeesh
Created September 20, 2024 01:15
Show Gist options
  • Save cvrajeesh/569985d53d36f2d07dd9b8660b13b771 to your computer and use it in GitHub Desktop.
Save cvrajeesh/569985d53d36f2d07dd9b8660b13b771 to your computer and use it in GitHub Desktop.
Bash script to navigate between commits in git repo
#!/bin/bash
GIT_NAV_DIR="${HOME}/.git-nav"
# Generate a file path to store commit history
# It use the MD5 hash of the Git root directory as the file name
generate_commit_file_path() {
if git rev-parse --show-toplevel > /dev/null 2>&1; then
git_root=$(git rev-parse --show-toplevel)
file_name=$(echo -n "$git_root" | md5 | awk '{print $1}')
mkdir -p ${GIT_NAV_DIR}
echo "${GIT_NAV_DIR}/${file_name}"
return 0
else
echo "Not inside a Git repository" >&2
return 1
fi
}
COMMITS_FILE="$(generate_commit_file_path)"
if [ $? -ne 0 ]; then
exit 1
fi
# Function to initialize commit history
initialize_commits() {
DEFAULT_BRANCH=$(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5)
BRANCH=$(git rev-parse --abbrev-ref HEAD)
# check if default branch is the same as the current branch
if [ "$DEFAULT_BRANCH" != "$BRANCH" ]; then
MERGE_BASE=$(git merge-base "$DEFAULT_BRANCH" "$BRANCH")
git log --reverse --pretty=format:"%H" "$MERGE_BASE..HEAD" > "$COMMITS_FILE"
else
git log --reverse --pretty=format:"%H" > "$COMMITS_FILE"
fi
}
# Function to get the current commit index
get_current_commit_index() {
current_commit=$(git rev-parse HEAD)
grep -n "$current_commit" "$COMMITS_FILE" | cut -d: -f1
}
# Function to checkout the commit at a specific index
checkout_commit() {
commit=$(sed -n "${1}p" "$COMMITS_FILE")
if [ -n "$commit" ]; then
git checkout "$commit"
else
echo "No commit found at index $1"
fi
}
# Navigate to the next commit
next_commit() {
current_index=$(get_current_commit_index)
if [ -z "$current_index" ]; then
echo "No commits found, or not on a commit."
exit 1
fi
next_index=$((current_index + 1))
checkout_commit $next_index
}
# Navigate to the previous commit
prev_commit() {
current_index=$(get_current_commit_index)
if [ -z "$current_index" ]; then
echo "No commits found, or not on a commit."
exit 1
fi
prev_index=$((current_index - 1))
checkout_commit $prev_index
}
reset_commits() {
BRANCH=$(git branch --contains HEAD | grep -v HEAD | awk '{print $1}')
git checkout $BRANCH
}
# Handle arguments to the script
case "$1" in
next)
next_commit
;;
prev)
prev_commit
;;
first)
checkout_commit 1
;;
reset)
reset_commits
;;
init)
initialize_commits
;;
*)
echo "Usage: git-nav {init|next|prev|first|reset}"
exit 1
;;
esac
@cvrajeesh
Copy link
Author

Git Nav script

A helper script for navigating between commits in a Git branch.

While this may not be useful for everyday tasks, it can be helpful for demonstrating the progress of your feature or implementation. I use this during training sessions, where each commit contains the code implementation of the topic I want to discuss.

Usage

  1. Run git-nav.sh init from the repository to initialize the script.
  2. Use git-nav.sh prev to navigate to the previous commit.
  3. Use git-nav.sh next to navigate to the next commit.

Alias

alias git-nav="bash <path-to-git-nav.sh>"
alias git-next="git-nav next"
alias git-prev="git-nav prev"
alias git-nav-init="git-nav init"
alias git-first="git-nav first"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment