Is there any way to hook saving in Vim up to commiting in git?

10

8

I am new to the world of Vim, and I want to make it so that every time I save a file it is commited to version control. Is this possible?

gonzo.floyd

Posted 2011-05-20T15:06:59.527

Reputation: 101

Answers

4

You could use Vim's autocommands:

:autocmd BufWritePost * execute '!git add % && git commit -m %'

That's untested but it should add the file and commit it with the filename as commit message.
You want BufWritePost as this is triggered after the file is written. I'd imagine there are a lot of irksome or unsafe edge cases though.

donothingsuccessfully

Posted 2011-05-20T15:06:59.527

Reputation: 161

4

I use a vim autocommand which I place in my .vimrc. The command first does a crude check that we're working in a git directory (by checking existence of a .git directory, either in the current directory or using git rev-parse), then uses git -a -m % so that only files that have previously been added are staged and committed.

autocmd BufWritePost * execute '! if [ -d .git ] || git rev-parse --git-dir > /dev/null 2>&1 ; then git add % ; git commit -m %; fi'

Nick Edwards

Posted 2011-05-20T15:06:59.527

Reputation: 187

This works for me on linux. Any idea how to make it work on windows? – user334287 – 2018-02-09T07:09:24.807

1There is missing single quote at the end of the cmd, right after fi. – Andrew-Dufresne – 2012-09-25T15:37:41.807

2

This version works only if you are in the root directory of your repo. A better solution is autocmd BufWritePost * execute '! if [ -d .git ] || git rev-parse --git-dir > /dev/null 2>&1 ; then git add % ; git commit -m %; fi', from a SO answer

– Andrew-Dufresne – 2012-09-25T15:39:38.293

2

You may want to look into the fugitive plugin, it's a very powerful git plugin for vim. You can also setup an autocmd as donothingsuccessfully suggests, but have it pop up :Gcommit or :Gstatus (from which you can cherry pick changes to add to the git index)

mkomitee

Posted 2011-05-20T15:06:59.527

Reputation: 596

1

Building on the answers others have provided:

autocmd BufWritePost * execute ':silent ! if git rev-parse --git-dir > /dev/null 2>&1 ; then git add % ; git commit -m "Auto-commit: saved %"; fi > /dev/null 2>&1'

This is completely transparent. You won't get the "Press enter to continue" message (but if the commit didn't work, you won't know it failed).

sargon

Posted 2011-05-20T15:06:59.527

Reputation: 11

0

I want to report my take on this problem.

I have the vimrc.vim in a git repository ($VIMCONF, with a bootstrap .vimrc), and mapped <Leader>ve ("vim edit") to open the vimrc in a new tab. This does not affect the current working directory.

So if I edit vimrc.vim from a vim started in a different directory outside of my vim git repository, the approach which was discussed by Nick Edwards will fail. My hack is the following (for windows and linux)

if has('win32')
    " The git command has to be passed to git. So we need to call bash.exe.
    autocmd BufEnter *vimrc.vim silent! lcd %:p:h
    autocmd BufWritePost *vimrc.vim if expand('<amatch>') =~ substitute(expand('$VIMCONF\vimrc.vim'), '\', '/', "g") | execute '! git add % & git commit -m %' | endif
else " Linux
    autocmd BufWritePost *vimrc.vim
        \ if expand('<amatch>') =~ expand($VIMCONF)."/vimrc.vim" |
        \ let tempdir = getcwd() | execute 'cd' fnameescape(expand('<amatch>:h')) | 
        \ execute '! if git rev-parse --git-dir > /dev/null 2>&1 ; then git add % ; git commit -m % ; fi' |
        \ execute 'cd' fnameescape(tempdir) |
        \ endif
endif

Explanation:

  1. For windows, I change the directory to the vimrc file location. This is not the best, and I might change later to be similar to linux. Don't take this too serious but you might want to use it as a guide. git has to be in the path (i.e. you should be able to type git <ENTER> in cmd.exe)
  2. For Linux, I first check that I am editing the right vimrc.vim
  3. Save the current working directory to tempdir
  4. Change directory to the vimrc.vim file
  5. Do the git commit
  6. Return to the previous working directory
  7. I manually push the git changes

Notes:

  1. Commands can be "chained" in vim with |. The chain will abort if any of the commands fails. To break over several lines start the next line with \.
  2. This can be extended to ftplugin files. Your filters will be *.vim and expand($VIMCONF)."/ftplugin/"

user334287

Posted 2011-05-20T15:06:59.527

Reputation: 101

0

You surely could to this whit a macro or with command remapping.

(Check https://stackoverflow.com/questions/117150/can-i-re-map-commands-in-vim)

I'm not sure it's a good option though. I'm not proficient in git for now and I know it's sometimes different from svn. But I wouldn't do this auto-commit with svn. Commit needs to be meaningful and not some save at regular time.

You normally commit because you added a function, fixed a bug, ... not just because you worked on a file. You won't end up with non compiling project or unfinished function.

M'vy

Posted 2011-05-20T15:06:59.527

Reputation: 3 540

That's true, but I also want to have an overnight script that moves files that successfully compile from the "save-on-commit" repo to a "meaningful change" repo. – gonzo.floyd – 2011-05-20T15:19:46.863

Well, it's not entirely a bad idea with Git. "Commit frequently" is kind of a motto. It works better this way, too, because you can work concurrently on the same file with multiple developers and minimal issues. It would be quite useful to hook into vim's save mechanism. – Metagrapher – 2011-12-09T19:23:10.313

Workflows in Git can be radically different from Subversion. You might never do this in svn because it would be abusive, but it has perfectly valid uses in git. For example a test integration server of some kind could be hooked to a test branch. Auto-commit on save then becomes quite useful. When you get to the point something is working, you would then use git rebase to squash all the activity into a single commit with a meaningful message, then merge into your devel branch. If this sounds scary or complex it's only because you are adapted to the limitations of a non-distributed source vcs. – Caleb – 2014-04-04T12:34:24.370

0

I know this question is old and this is blatant self-promotion, but I wrote a Vim plugin that will trigger certain shell scripts to be run after specific Vim autocmd events. For example, a script named .bufwritepost.vimhook.sh would be run (synchronously) every time the BufWritePost command is fired. You could then easily include whatever logic you want for performing the git commit inside that script. The plugin assumes specific naming conventions of these scripts and also supports "hook" scripts which trigger only on files matching certain names or having certain extensions.

Full details: https://github.com/ahw/vim-hooks

Andrew

Posted 2011-05-20T15:06:59.527

Reputation: 1