Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Browsing git commit history with fzf
# 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
}
@junegunn

This comment has been minimized.

Copy link
Owner Author

commented Oct 23, 2015

Simpler version using execute action:

# fshow - git commit browser
fshow() {
  git log --graph --color=always \
      --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" |
  fzf --ansi --no-sort --reverse --tiebreak=index --toggle-sort=\` \
      --bind "ctrl-m:execute:
                echo '{}' | grep -o '[a-f0-9]\{7\}' | head -1 |
                xargs -I % sh -c 'git show --color=always % | less -R'"
}
@junegunn

This comment has been minimized.

Copy link
Owner Author

commented Jan 9, 2016

A new version fixed escaping issues:

# fshow - git commit browser
fshow() {
  git log --graph --color=always \
      --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" |
  fzf --ansi --no-sort --reverse --tiebreak=index --bind=ctrl-s:toggle-sort \
      --bind "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"
}
@tobiisdesired

This comment has been minimized.

Copy link

commented Jan 26, 2016

Inspired by your git browser I implemented a log browser based on fzf. The connection is done via the line number. Don't know if xargs is really necessary.

logshow() {
    cat -n $1 | fzf --reverse --no-sort --tiebreak=index \
                    --bind "ctrl-m:execute:echo {} | grep -Eo "[0-9]+" | head -n 1 | xargs -Ireplace less -N +replaceg $1"
}
@akatrevorjay

This comment has been minimized.

Copy link

commented Jan 31, 2017

I simplified this: https://gist.github.com/akatrevorjay/9fc061e8371529c4007689a696d33c62

All those heredocs made my brain hurt a little. lulz.

@victorbrca

This comment has been minimized.

Copy link

commented Oct 12, 2018

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%
}
@avshyz

This comment has been minimized.

Copy link

commented Jun 22, 2019

Cool stuff!
Is it possible to make it work with git log -S (git pickaxe)?

@tamphh

This comment has been minimized.

Copy link

commented Jul 18, 2019

Thanks you guys. Here my modification which support both git log branch & a particular file.
Gist: https://gist.github.com/tamphh/3c9a4aa07ef21232624bacb4b3f3c580
Screen record: https://asciinema.org/a/257939

# git log show with fzf
gli() {

  # param validation
  if [[ ! `git log -n 1 $@ | head -n 1` ]] ;then
    return
  fi

  # filter by file string
  local filter
  # param existed, git log for file if existed
  if [ -n $@ ] && [ -f $@ ]; then
    filter="-- $@"
  fi

  # git command
  local gitlog=(
    git log
    --graph --color=always
    --abbrev=7
    --format='%C(auto)%h %an %C(blue)%s %C(yellow)%cr'
    $@
  )

  # fzf command
  local fzf=(
    fzf
    --ansi --no-sort --reverse --tiebreak=index
    --preview "f() { set -- \$(echo -- \$@ | grep -o '[a-f0-9]\{7\}'); [ \$# -eq 0 ] || git show --color=always \$1 $filter; }; f {}"
    --bind "ctrl-q:abort,ctrl-m:execute:
                (grep -o '[a-f0-9]\{7\}' | head -1 |
                xargs -I % sh -c 'git show --color=always % $filter | less -R') << 'FZF-EOF'
                {}
                FZF-EOF"
   --preview-window=right:60%
  )

  # piping them
  $gitlog | $fzf
}
@jasonmendes

This comment has been minimized.

Copy link

commented Jul 26, 2019

@tamphh - yours is really neat, but I couldn't get it to work. It would only output git help. I'm not pro enough at bash to see the issue, so I just squashed it together a bit (and added the key bindings from @victorbrca above, and made the fzf window larger) to this:

gli() {
  local filter
  if [ -n $@ ] && [ -f $@ ]; then
    filter="-- $@"
  fi

  git log \
    --graph --color=always --abbrev=7 --format='%C(auto)%h %an %C(blue)%s %C(yellow)%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 $filter; }; 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% \
      --height 80%
}
@gabesoft

This comment has been minimized.

Copy link

commented Aug 31, 2019

A version for the fish shell

Gist https://gist.github.com/gabesoft/b6e5e959c4cb11ed257d41edb07d47cb

function gbr --description "Git browse commits"
    set -l log_line_to_hash "echo {} | grep -o '[a-f0-9]\{7\}' | head -1"
    set -l view_commit "$log_line_to_hash | xargs -I % sh -c 'git show --color=always % | diff-so-fancy | less -R'"
    set -l copy_commit_hash "$log_line_to_hash | xclip"
    set -l git_checkout "$log_line_to_hash | xargs -I % sh -c 'git checkout %'"
    set -l open_cmd "open"

    if test (uname) = Linux
        set open_cmd "xdg-open"
    end

    set github_open "$log_line_to_hash | xargs -I % sh -c '$open_cmd https://github.\$(git config remote.origin.url | cut -f2 -d. | tr \':\' /)/commit/%'"

    git log --color=always --format='%C(auto)%h%d %s %C(green)%C(bold)%cr% C(blue)%an' | \
        fzf --no-sort --reverse --tiebreak=index --no-multi --ansi \
            --preview="$view_commit" \
            --header="ENTER to view, CTRL-Y to copy hash, CTRL-O to open on GitHub, CTRL-X to checkout, CTRL-C to exit" \
            --bind "enter:execute:$view_commit" \
            --bind "ctrl-y:execute:$copy_commit_hash" \
            --bind "ctrl-x:execute:$git_checkout" \
            --bind "ctrl-o:execute:$github_open"
end
@victorkristof

This comment has been minimized.

Copy link

commented Oct 21, 2019

@jasonmendes I also couldn't run the function (showing git help instead).
I solved it by replacing the final "piping" line by "${gitlog[@]}" | "${fzf[@]}".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.