Last active
September 26, 2024 06:12
-
-
Save junegunn/f4fca918e937e6bf5bad to your computer and use it in GitHub Desktop.
Browsing git commit history with fzf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# fshow - git commit browser (enter for show, ctrl-d for diff, ` toggles sort) | |
fshow() { | |
local out shas sha q k | |
while out=$( | |
git log --graph --color=always \ | |
--format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" | | |
fzf --ansi --multi --no-sort --reverse --query="$q" \ | |
--print-query --expect=ctrl-d --toggle-sort=\`); do | |
q=$(head -1 <<< "$out") | |
k=$(head -2 <<< "$out" | tail -1) | |
shas=$(sed '1,2d;s/^[^a-z0-9]*//;/^$/d' <<< "$out" | awk '{print $1}') | |
[ -z "$shas" ] && continue | |
if [ "$k" = ctrl-d ]; then | |
git diff --color=always $shas | less -R | |
else | |
for sha in $shas; do | |
git show --color=always $sha | less -R | |
done | |
fi | |
done | |
} |
Thanks for this... and another modification. This shows preview of the file, while allowing you to still go into it.
Key binds:
- q = quit
- j = down
- k = up
- alt-k = preview up
- alt-j = preview down
- ctrl-f = preview page down
- ctrl-b = preview page up
git-commit-show () { git log --graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" | \ fzf --ansi --no-sort --reverse --tiebreak=index --preview \ 'f() { set -- $(echo -- "$@" | grep -o "[a-f0-9]\{7\}"); [ $# -eq 0 ] || git show --color=always $1 ; }; f {}' \ --bind "j:down,k:up,alt-j:preview-down,alt-k:preview-up,ctrl-f:preview-page-down,ctrl-b:preview-page-up,q:abort,ctrl-m:execute: (grep -o '[a-f0-9]\{7\}' | head -1 | xargs -I % sh -c 'git show --color=always % | less -R') << 'FZF-EOF' {} FZF-EOF" --preview-window=right:60% }
Add open commit link
version:
#!/usr/bin/env python3
import subprocess
import re
from typing import Optional
import argparse
import os
GITLOG_PATH = os.path.abspath(__file__)
USAGE_DOC = """
Usage:
gitlog [--opencommitlink <shorthash>] [<git-log-options>...]
Examples:
gitlog --all
gitlog --since="2 weeks ago" --author="John Doe"
gitlog --opencommitlink abc1234
"""
def gitlog(*args: str) -> None:
git_cmd = [
'git', 'log', '--graph', '--color=always', '--format=%C(auto)%h%d %s %C(bold green)%ar %C(dim white)%an'
] + list(args or [])
# Usage:
# - ctrl-m: page the commit
# - ctrl-l: open the commit link
# See [ref](https://gist.github.com/junegunn/f4fca918e937e6bf5bad?permalink_comment_id=2731105#gistcomment-2731105)
fzf_cmd = [
'fzf', '--ansi', '--no-sort', '--reverse', '--tiebreak=index', '--no-multi',
'--preview', 'f() { set -- $(echo -- "$@" | grep -o "[a-f0-9]\\{7\\}"); [ $# -eq 0 ] || git show --color=always $1 ; }; f {}',
'--preview-window=right:60%:hidden',
'--bind', 'ctrl-j:down,ctrl-k:up',
'--bind', 'ctrl-f:page-down,ctrl-b:page-up',
'--bind', 'alt-j:preview-down,alt-k:preview-up',
'--bind', 'alt-f:preview-page-down,alt-b:preview-page-up',
'--bind', 'ctrl-/:toggle-preview',
'--bind', 'ctrl-u:track+clear-query',
'--bind', 'q:abort',
'--bind', 'ctrl-m:execute:(echo {} | grep -o "[a-f0-9]\\{7\\}" | head -1 | xargs -I @ sh -c \'git show --color=always @ | command bat --number\')',
'--bind', 'ctrl-l:execute:(echo {} | grep -o "[a-f0-9]\\{7\\}" | head -1 | xargs -I @ ' + GITLOG_PATH + ' --opencommitlink @)'
]
# Run git log command and pipe to fzf
process = subprocess.Popen(git_cmd, stdout=subprocess.PIPE)
subprocess.run(fzf_cmd, stdin=process.stdout)
process.wait()
def commit_link(shorthash: str) -> Optional[str]:
# get fullhash
fullhash = subprocess.run(['git', 'rev-parse', shorthash], stdout=subprocess.PIPE).stdout.decode().strip()
if not fullhash:
print(f"Invalid commit hash: {shorthash}")
return None
# get the remote URL
remote_url = subprocess.run(['git', 'config', '--get', 'remote.origin.url'], stdout=subprocess.PIPE).stdout.decode().strip()
if not remote_url:
print("Could not determine remote URL")
return None
# parse the remote URL
match = re.search(r'(?:://|@)([^/:]+)[:/](.+)\.git', remote_url)
if not match:
print("Could not determine repository or host")
return None
host = match.group(1)
repo = match.group(2)
return f"https://{host}/{repo}/commit/{fullhash}"
def open_commit_link(shorthash: str) -> None:
link = commit_link(shorthash)
if link:
subprocess.run(['xdg-open', link], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def main() -> None:
parser = argparse.ArgumentParser(
description="A script to display git logs and open commit links.",
formatter_class=argparse.RawTextHelpFormatter,
epilog=USAGE_DOC
)
parser.add_argument('--opencommitlink', type=str, help="Open the commit link for the given short hash.")
known_args, other_args = parser.parse_known_args()
if known_args.opencommitlink:
open_commit_link(known_args.opencommitlink)
else:
gitlog(*other_args)
if __name__ == "__main__":
main()
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@ultrox @slerer
This article gives you a git alias that is exactly what you are after