Vim: Show current git branch in lightline status line without fugitive
Asked Answered
C

4

6

I am using lightline.vim and I would like to show the current git branch. At the moment, I am doing so using vim-fugitive, however, I do not use this plugin at all, except for showing the git branch in the status line.

My question is:

Is there a way to show the git branch in the status line without using fugitive?

I tried to create a custom function that I hooked to lightline. The function fetched the current git branch using the system vimscript function. It (didn't) work well, except that the status line was refreshed on every keystroke, which broke everything else and made vim unusable. Essentially, the git branch was being fetched using the system function on every keystroke...

So that's not a viable solution. What I "could" do, is create a global variable which says whether or not the git branch was fetched, and prevent the custom function from fetching the branch name again if it was already fetched. Then I could fetch the branch name again every time MacVim loses focus (not sure how to do that using terminal vim). That is not ideal though...

Any ideas on how to solve this problem please?

Composition answered 4/6, 2014 at 7:41 Comment(1)
Powerline or lightline?Rayner
R
4

Yes, using a global variable is the way to go.

The non-obvious part is how/when to update the value of that variable. An autocmd seems to be the most obvious choice but hooked to what event? BufEnter seems to be a good start.

Now, since you don't use fugitive, how do you switch branches? Outside of Vim? On Vim's command-line?

If you do it on Vim's command-line, :!git checkout foo, you could write a command that takes a branch name as argument to execute the proper shell command and change the value of g:git_branch in one go, without even using an autocmd.

If you do it outside of Vim (<C-z>, :sh, another terminal window or tmux pane, a GUI app…) you will need to find a solid way to notify Vim of that change or use your system() call with an autocmd.

Rayner answered 4/6, 2014 at 8:0 Comment(3)
I only use git outside of vim (from the command line). As specified in my question, I already considered the autocmd + system() solution. But I was wondering if there was a more "automated" solution. As in, when I change the git branch, it updates lightline automatically. Using fugitive, that's what is happening. I looked at fugitive's source code, but I am struggling to understand how this feature is implemented...Composition
Fugitive doesn't update lightline: fugitive exposes a function that retrieves and caches the branch name and that function is then used in lightline. You can see how it's done in lightline's doc. Parsing the output of system('git branch') to update a global (or better, buffer-local) variable is the most practical solution. Finding the right way to update that variable is what matters, here. A simple autocmd sounds good.Rayner
Fair enough, you convinced me. I am going to implement this solution and refine it over time. Thanks for your answer.Composition
D
26

I have created a plugin which focuses on the function you want.

https://github.com/itchyny/vim-gitbranch

You can get the branch name by gitbranch#name() function.

The code is so small that you can read in a minute.

Deangelo answered 10/6, 2014 at 3:51 Comment(3)
Oh wow! That looks awesome! I am going to check it out! Thanks!Composition
Just used this! Works great along with the vim-airline!Jasper
@aashah7, Can you please show how you did it with vim-airline ?Vagary
R
4

Yes, using a global variable is the way to go.

The non-obvious part is how/when to update the value of that variable. An autocmd seems to be the most obvious choice but hooked to what event? BufEnter seems to be a good start.

Now, since you don't use fugitive, how do you switch branches? Outside of Vim? On Vim's command-line?

If you do it on Vim's command-line, :!git checkout foo, you could write a command that takes a branch name as argument to execute the proper shell command and change the value of g:git_branch in one go, without even using an autocmd.

If you do it outside of Vim (<C-z>, :sh, another terminal window or tmux pane, a GUI app…) you will need to find a solid way to notify Vim of that change or use your system() call with an autocmd.

Rayner answered 4/6, 2014 at 8:0 Comment(3)
I only use git outside of vim (from the command line). As specified in my question, I already considered the autocmd + system() solution. But I was wondering if there was a more "automated" solution. As in, when I change the git branch, it updates lightline automatically. Using fugitive, that's what is happening. I looked at fugitive's source code, but I am struggling to understand how this feature is implemented...Composition
Fugitive doesn't update lightline: fugitive exposes a function that retrieves and caches the branch name and that function is then used in lightline. You can see how it's done in lightline's doc. Parsing the output of system('git branch') to update a global (or better, buffer-local) variable is the most practical solution. Finding the right way to update that variable is what matters, here. A simple autocmd sounds good.Rayner
Fair enough, you convinced me. I am going to implement this solution and refine it over time. Thanks for your answer.Composition
P
2

write the followed code into .vimrc.

    let gitBranch=system("git rev-parse --abbrev-ref HEAD")
    set laststatus=2
    set statusline=%F%m%r%h%w\ [POS=%04l,%04v]\ [%p%%]\ [LEN=%L]
    execute "set statusline +=" . gitBranch

Punish answered 22/2, 2021 at 9:20 Comment(1)
The branch name is only refreshed when vim is closed and opened againReichard
G
0

I had this same question but I just wanted to stick a few lines in my .vimrc instead of installing a plugin. After reading the other answers and some trial and error I ended up with this:

" ~/.vimrc

fun! GitBranch(file)
    let l:dir = fnamemodify(system('readlink -f ' . a:file), ':h')
    let l:cmd = 'git -C ' . l:dir . ' branch --show-current 2>/dev/null'
    let b:git_current_branch = trim(system(l:cmd))
endfun

augroup GitBranch
    autocmd!
    autocmd BufEnter,ShellCmdPost,FileChangedShellPost * call GitBranch(expand('%'))
augroup END

set rulerformat=%32(%=%{b:git_current_branch}%=%8l,%-6(%c%V%)%=%4p%%%)

I put the branch name in the ruler as I don't use lightline or have the statusline on, but rulerformat has exactly the same syntax as statusline, so it should be fairly simple to find where lightline sets statusline and modify it as needed.

The bottom line of my screen looks like this:

".vimrc" 135 lines --39%--                                         master      53,11      39%

The key part is %{b:git_current_branch}, where b:git_current_branch is a variable local to each buffer so you don't get conflicts if you switch buffers.

The GitBranch function will get the current branch name for the file in the current buffer, even if it's in a different directory, following symlinks in the process.

The branch name is updated when you switch buffers, and after a shell command inside vim (e.g. :!git switch or :!git checkout etc.), and also if you change branches outside of vim (after the W11: Warning ... has changed prompt).

If the file in the buffer is not in a git dir, then the variable is empty, and there is no error; the branch name just disappears. If the file is in a git dir but not tracked then you still get the branch name, but you can probably change that with some extra system() calls in GitBranch if that's not what you want.

This works on vim 8 on Linux but I think Mac might have a different readlink command, and I have no idea about Windows.

Grenadine answered 17/8, 2023 at 16:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.