Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Key bindings for git with fzf (https://junegunn.kr/2016/07/fzf-git/)
# GIT heart FZF
# -------------
is_in_git_repo() {
git rev-parse HEAD > /dev/null 2>&1
}
fzf-down() {
fzf --height 50% "$@" --border
}
gf() {
is_in_git_repo || return
git -c color.status=always status --short |
fzf-down -m --ansi --nth 2..,.. \
--preview '(git diff --color=always -- {-1} | sed 1,4d; cat {-1}) | head -500' |
cut -c4- | sed 's/.* -> //'
}
gb() {
is_in_git_repo || return
git branch -a --color=always | grep -v '/HEAD\s' | sort |
fzf-down --ansi --multi --tac --preview-window right:70% \
--preview 'git log --oneline --graph --date=short --color=always --pretty="format:%C(auto)%cd %h%d %s" $(sed s/^..// <<< {} | cut -d" " -f1) | head -'$LINES |
sed 's/^..//' | cut -d' ' -f1 |
sed 's#^remotes/##'
}
gt() {
is_in_git_repo || return
git tag --sort -version:refname |
fzf-down --multi --preview-window right:70% \
--preview 'git show --color=always {} | head -'$LINES
}
gh() {
is_in_git_repo || return
git log --date=short --format="%C(green)%C(bold)%cd %C(auto)%h%d %s (%an)" --graph --color=always |
fzf-down --ansi --no-sort --reverse --multi --bind 'ctrl-s:toggle-sort' \
--header 'Press CTRL-S to toggle sort' \
--preview 'grep -o "[a-f0-9]\{7,\}" <<< {} | xargs git show --color=always | head -'$LINES |
grep -o "[a-f0-9]\{7,\}"
}
gr() {
is_in_git_repo || return
git remote -v | awk '{print $1 "\t" $2}' | uniq |
fzf-down --tac \
--preview 'git log --oneline --graph --date=short --pretty="format:%C(auto)%cd %h%d %s" {1} | head -200' |
cut -d$'\t' -f1
}
bind '"\er": redraw-current-line'
bind '"\C-g\C-f": "$(gf)\e\C-e\er"'
bind '"\C-g\C-b": "$(gb)\e\C-e\er"'
bind '"\C-g\C-t": "$(gt)\e\C-e\er"'
bind '"\C-g\C-h": "$(gh)\e\C-e\er"'
bind '"\C-g\C-r": "$(gr)\e\C-e\er"'
join-lines() {
local item
while read item; do
echo -n "${(q)item} "
done
}
bind-git-helper() {
local c
for c in $@; do
eval "fzf-g$c-widget() { local result=\$(g$c | join-lines); zle reset-prompt; LBUFFER+=\$result }"
eval "zle -N fzf-g$c-widget"
eval "bindkey '^g^$c' fzf-g$c-widget"
done
}
bind-git-helper f b t r h
unset -f bind-git-helper
@johnor

This comment has been minimized.

Copy link

commented Oct 18, 2016

Thanks, these functions are great! I had to add "zle reset-prompt" though in order to not mess up the prompt when using zsh.
eval "fzf-g$c-widget() { zle reset-prompt; LBUFFER+=$(g$c | join-lines) } "

@faruzzy

This comment has been minimized.

Copy link

commented Nov 4, 2016

@johnor could you please share your .vimrc, I'm having issues setting this up

@mikejakobsen

This comment has been minimized.

Copy link

commented Nov 8, 2016

Any idea how i apply the key-bindings in ZSH?

@johnor

This comment has been minimized.

Copy link

commented Nov 9, 2016

@faruzzy These functions are not for vim, they are for bash or zsh. If you want to browse the git history from vim you should take a look at fzf.vim (https://github.com/junegunn/fzf.vim) and :Commits.
@mikejakobsen I have copied the contents of key-binding.zsh and functions.sh to a new file. You can then just source that file in your .zshrc to get it working. Adding everything to your .zshrc should also work :)

@parkercoates

This comment has been minimized.

Copy link

commented Nov 16, 2016

@johnor, thanks for the hint about zle reset-prompt, but I ended up having to do something a little more complicated to get it working. See my fork.

@junegunn, the gh() function wasn't working for me as the final grep invocation always failed to find the hash. Removing the escapes from the braces fixed it. Perhaps this is due to different versions of grep? I'm on Linux.

@junegunn

This comment has been minimized.

Copy link
Owner Author

commented Nov 21, 2016

@parkercoates Maybe. FYI, the command works for me both on macOS and Linux.

> uname -a
Linux ------- 2.6.32-573.18.1.el6.centos.plus.x86_64 #1 SMP Wed Feb 10 18:09:24 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
> grep --version
GNU grep 2.6.3

Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

> echo 1234567 abcdef0 | grep -o "[a-f0-9]\{7,\}"
1234567
abcdef0

I updated bind-git-helper following your suggestion. Thanks.

https://gist.github.com/junegunn/8b572b8d4b5eddd8b85e5f4d40f17236/revisions

@parkercoates

This comment has been minimized.

Copy link

commented Jan 4, 2017

@junegunn, my bad. I just realised that I had grep aliased to grep --color=auto --perl-regexp, which I see now was a really bad idea. Sorry for the noise.

And thanks for incorporating my bind-git-helper change.

@abarax

This comment has been minimized.

Copy link

commented Apr 6, 2017

Thank you @junegunn, I am a big fan of your work!

Is join-lines really required? I'm unsure about why it is there and it seems to work fine without it.

@janclarin

This comment has been minimized.

Copy link

commented Apr 14, 2017

@parkercoates, I can't seem to be able to get the keybindings to work for the fzf-g$c-widget. Can you try out the key-binding.zsh and let me know if it works for you?

@filipekiss

This comment has been minimized.

Copy link

commented Aug 16, 2017

I'm having trouble making this work when on tmux. :( It works just fine on a normal session, but as soon as I am on TMUX, the bindings don't work (if I call the functions directly from the prompt, it works). Any idea what I must do to solve this?

My tmux has no customization yet.


Just realized what was the problem: Basically, all my bindings worked, except for Control-gControl-b. Turns out Control-gControl-b was invoking my tmux <prefix>, thus, rendering the binding useless.

I've changed my prefix to Control-a and everything is working as expected.

@aluxian

This comment has been minimized.

Copy link

commented Aug 31, 2017

@teto

This comment has been minimized.

Copy link

commented Sep 19, 2017

no one feeling like creating a repository with these gems ?
There seems to be some bugs with it and collaborative work could help polish these. I am no shell expert so not too enthusiastic about hosting it (yet).

@teto

This comment has been minimized.

Copy link

commented Sep 20, 2017

I've started one here https://github.com/teto/fzf-gems . Will try to beef up the readme

@mikeage

This comment has been minimized.

Copy link

commented Dec 31, 2017

Very nice! Any objection to replacing fzf with fzf-tmux in fzf-down?

@ghost

This comment has been minimized.

Copy link

commented Jan 20, 2018

I had an issue getting gh to work, changing grep to command grep fixed the issue

thanks for scripts

@faruzzy

This comment has been minimized.

Copy link

commented Mar 13, 2018

One of the things that I find useful with these helpers is the ability to do a diff of two hash key.
You don't know the hashes by heart so you type: git diff <C-g><C-h> and you can select the hashes you want to diff. But I do have issues if I have the following entry in my inputrc: set editing-mode vi and set keymap vi-command.
The behavior becomes different, instead of copying the hashes right on the line I was on originally such as the result is git diff <hash1> <hash2> it instead pastes the hashes above the line I was on. Does anybody know how to solve this issue?
Thanks for the help

@robinmitra

This comment has been minimized.

Copy link

commented Mar 31, 2018

This is bloody amazing! In my case, the functions weren't working, and as it turns out it was because these conflicted with some existing function somewhere. So, I just prefixed all of your functions with fn- (e.g. fn-gt rather than gt) and now all seem to work beautifully.

@adah1972

This comment has been minimized.

Copy link

commented Aug 18, 2018

I had some problems with gb and gr, due to ambiguity between names of branches, remotes, and paths. Here are the revised functions:

gb() {
  is_in_git_repo || return
  git branch -a --color=always | grep -v '/HEAD\s' | sort |
  fzf-down --ansi --multi --tac --preview-window right:70% \
    --preview 'git log --oneline --graph --date=short --pretty="format:%C(auto)%cd %h%d %s" $(sed s/^..// <<< {} | cut -d" " -f1) -- | head -'$LINES |
  sed 's/^..//' | cut -d' ' -f1 |
  sed 's#^remotes/##'
}

gr() {
  is_in_git_repo || return
  git remote -v | awk '{print $1 "\t" $2}' | uniq |
  fzf-down --tac \
    --preview 'git log --oneline --graph --date=short --pretty="format:%C(auto)%cd %h%d %s" --remotes={1} | head -200' |
  cut -d$'\t' -f1
}
@adah1972

This comment has been minimized.

Copy link

commented Aug 20, 2018

Just solved another problem due to the fact that grep -o "[a-f0-9]\{7,\}" will not only match the Git hashes, but also a string like "feedback". gh is fixed as follows:

gh() {
  is_in_git_repo || return
  git log --date=short --format="%C(green)%C(bold)%cd %C(auto)%h%d %s (%an)" --graph --color=always |
  fzf-down --ansi --no-sort --reverse --multi --bind 'ctrl-s:toggle-sort' \
    --header 'Press CTRL-S to toggle sort' \
    --preview 'grep -o "[a-f0-9]\{7,\}" <<< {} | head -1 | xargs git show --color=always | head -'$LINES |
  grep -o "[a-f0-9]\{7,\}" | head -1
}
@zanza00

This comment has been minimized.

Copy link

commented Sep 20, 2018

for anyone who has oh-my-zsh there are already some alias so the solution is to add a prefix to the functions and modify the helper

fzf_gf() {
...
}

fzf_gb() {
...
}

fzf_gt() {
...
}

fzf_gh() {
...
}

fzf_gr() {
...
}

bind-git-helper() {
  local c
  for c in $@; do
    eval "fzf-g$c-widget() { local result=\$(fzf_g$c | join-lines); zle reset-prompt; LBUFFER+=\$result }"
    eval "zle -N fzf-g$c-widget"
    eval "bindkey '^g^$c' fzf-g$c-widget"
  done
}
@baiwfg2

This comment has been minimized.

Copy link

commented Nov 22, 2018

Thanks for the work. There's a tiny issue that I met. When started with --preview option, it's really slow to scroll the preview pane with mouse. If there're many lines there, it'll take a long time. Any ideas to scroll faster ?

@rawaludin

This comment has been minimized.

Copy link

commented Nov 23, 2018

I can't get this working with pure prompt https://github.com/sindresorhus/pure

Always getting this:

prompt_pure_async_callback:11: bad set of key/value pairs for associative array
@rawaludin

This comment has been minimized.

Copy link

commented Nov 23, 2018

nvm, its conflict with existing gf function. I just prefixed it

@ztou

This comment has been minimized.

Copy link

commented Jan 17, 2019

I am using git bash on Windows and I am getting error like << was unexpected at this time. on those function using <<< {}, any thoughts?

f_gh() {                                                                                                                  
  is_in_git_repo || return                                                                                                
  git log --date=short --format="%C(green)%C(bold)%cd %C(auto)%h%d %s (%an)" --graph --color=always |                     
  fzf-down --ansi --no-sort --reverse --multi --bind 'ctrl-s:toggle-sort' \                                               
    --header 'Press CTRL-S to toggle sort' \                                                                              
    --preview 'grep -o "[a-f0-9]\{7,\}" <<< {} | xargs git show --color=always | head -'$LINES | grep -o "[a-f0-9]\{7,\}" 
}                                                                                                                         

but actually below script works:

huangjoh@SHAPC0N4NVD MINGW64 /m/x-hub/cosv2/flask-app (test-branch-1)
$ grep -o "[a-f0-9]\{7,\}" <<< "* 2019-01-04 2884e18"
2884e18

I've to change the function to use --preview 'echo {} | grep -o "[a-f0-9]\{7,\}" | xargs git show --color=always | head -'$LINES | grep -o "[a-f0-9]\{7,\}" and it works fine.

@albertogalan

This comment has been minimized.

Copy link

commented Apr 2, 2019

Great tool!

@deecewan

This comment has been minimized.

Copy link

commented Jun 19, 2019

hmmm. I can't seem to get bindings of the form ^G^$c to work. if i bind the widget directly to a single keypress (bindkey '^B' fzf-gb-widget) it works as expected, but with multi-key bindings, I get nothing.

ZSH in vi-mode

@jeebak

This comment has been minimized.

Copy link

commented Jun 25, 2019

hmmm. I can't seem to get bindings of the form ^G^$c to work. if i bind the widget directly to a single keypress (bindkey '^B' fzf-gb-widget) it works as expected, but with multi-key bindings, I get nothing.

ZSH in vi-mode

Do you have ^G already bound to something else? I had to remove a binding for my setup (with bindkey -r "^G") before I could use the the ^G prefix.

@deecewan

This comment has been minimized.

Copy link

commented Jun 25, 2019

That was it! Also in this process, I've discovered that bindkey "<binding>" will print the existing functionality of the key. ^G in my case was list-expand

@jeebak

This comment has been minimized.

Copy link

commented Jun 26, 2019

That was it! Also in this process, I've discovered that bindkey "<binding>" will print the existing functionality of the key. ^G in my case was list-expand

Ah, cool. It looks like gists won't let me add a "👍" to comments :). Yep, and bindkey w/out any arguments will list EVERY bindings.

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.