Suppose I have the following text in my vim buffer:

This is a commit msg.

Suppose further I have a git repo located at ~/my_repo.

Goal: Make a vim script so that I can highlight the text above, and have it sent as a git commit message within ~/my_repo. It would look something like

:'<,'>Commit ~/my_repo

It would also have auto-complete on its repo argument.

Attempted Solution:

First, the autocomplete function (AFAIK I think this is OK?):

function! GitLocations()
  return find $HOME -name '.git' -printf '%h\n' "generates a list of all folders which contain a .git dir

Next, the actual git commit function, which is incomplete:

function! CommitTextGitRepo(l1, l2, loc)
  let s:msg = ??? " how do I make this the highlighted text from line l1 to line l2?
  execute '!cd ' . a:loc . '&& git commit --allow-empty -m \"' . s:msg '\"'

Assuming I can figure out how to get CommitTextGitRepo() working above, the final thing I would need is this (I think):

command! -nargs=* -complete=custom,GitLocations -range Commit call CommitToGitRepo(<line1>, <line2>, <q-args>)

I'm so close. How do I finish this up? :)

  • 1
    GitLocations won't work as expected, since you'll be calling Vim's :find, not the find command. Might try something like return system('find $HOME ...') (and add a -type d to it to skip submodules, perhaps?)
    – muru
    Feb 19, 2016 at 16:19
  • Good idea. With that, all I need is a way to bind s:msg to the contents of the line range (within CommitTextGitRepo above). Feb 19, 2016 at 16:27
  • 1
    Maybe you could use getline() and join() like this: let s:msg = join(getline(a:l1,a:l2), "\n")
    – saginaw
    Feb 19, 2016 at 16:36
  • @saginaw: That approach worked to get s:msg. Feb 19, 2016 at 17:09

1 Answer 1


GitLocations won't work as expected, since you'll be calling Vim's :find, not the find command. You might try something like:

return system('find $HOME -name ".git" -printf "%h\n"')

And you could add a -type d to it to skip submodules.

To get visually selected text, you can use getline():

let s:msg = join(getline("'<", "'>"), "\n") . "\n"

However, it will be easier if you took advantage of git commit's ability to read the commit message from standard input. From man git commit:

-F <file>, --file=<file>
   Take the commit message from the given file. Use - to read the
   message from the standard input.

With w !, you can write a set of lines to the standard input of a shell command:

:[range]w[rite] [++opt] !{cmd}
                        Execute {cmd} with [range] lines as standard input
                        (note the space in front of the '!').  {cmd} is
                        executed like with ":!{cmd}", any '!' is replaced with
                        the previous command :!.

You could do something like:

function! CommitToGitRepo(l1, l2, loc) range
    exec a:l1 . ',' . a:l2 'w !cd' shellescape(a:loc) '; git commit --allow-empty -F -'

command! -nargs=1 -range -complete=custom,GitLocations Commit call CommitToGitRepo(<line1>, <line2>, <args>)


  • 2
    -printf isn't available in my OSX version of find but you can get something similar using internal Vim functions anyway: return fnamemodify(finddir('.git', $HOME), ":h"). I always work with my current directory inside the repo though so it's even easier since I don't need to get the git dir, I could just use let l:rootdir = fnamemodify(finddir('.git', getcwd().';/'), ":h") directly in the commit function (this uses upward as opposed to downward searching because of the semicolon). Feb 19, 2016 at 17:28
  • 2
    @dash-tom-bang ah, well, if you're already in the required git repo, you can run git commit directly. :) Even so, the pure Vimscript way might be more efficient than calling system('find ...'), so that's something OP should look into. I assume OP is using GNU find, since they came up with that part themselves.
    – muru
    Feb 19, 2016 at 17:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.