Skip to content

Add support for nested git submodules #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion autoload/projectroot.vim
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ let autoloaded_projectroot = 1
if !exists('g:rootmarkers')
let g:rootmarkers = ['.projectroot', '.git', '.hg', '.svn', '.bzr', '_darcs', 'build.xml']
endif
if !exists('g:projectroot_nested_git_submodule')
let g:projectroot_nested_git_submodule = 0
endif

" projectroot#get([file]): get the project root (if any) {{{1
function! projectroot#get(...)
Expand All @@ -28,7 +31,19 @@ function! projectroot#get(...)
let prev=pivot
let pivot=fnamemodify(pivot, ':h')
let fn = pivot.(pivot == '/' ? '' : '/').marker
if filereadable(fn) || isdirectory(fn)

if marker == '.git'
let result=s:examinedotgit(fn)
if result == 3
" if the .git file indicates this git repo is actually a submodule
" contained inside a parent repo, then keep recursing up the
" directory structure
continue
elseif result > 0
" if .git is a file or directory, it is our project root marker
return pivot
endif
elseif filereadable(fn) || isdirectory(fn)
return pivot
endif
if pivot==prev
Expand Down Expand Up @@ -136,3 +151,38 @@ function! s:getmarkfile(mark)
return ''
endtry
endfunction

function! s:examinedotgit(fn)
" returns one of:
" 0: The .git file at a:fn doesn't exist.
" 1: The .git file at a:fn is a directory.
" 2: The .git file at a:fn is a regular file.
" 3: The .git file at a:fn is a nested git submodule (Only when
" g:projectroot_nested_git_submodule is set).
if isdirectory(a:fn)
return 1 " a directory
endif

if g:projectroot_nested_git_submodule && exists('*readfile')
" check to see if we're in a .git submodule
try
let lines=readfile(a:fn, 0, 1)
catch /E484/
return 0 " doesn't exist
endtry
if len(lines) && lines[0] =~ '^gitdir: \%(\.\./\)\+\.git/modules/'
return 3 " the .git is a nested git submodule
endif

return 2 " the .git is some other type of .git file (probably a worktree)
endif

" g:projectroot_nested_git_submodule wasn't set - just check to see if the
" .git entry is a plain file
if filereadable(a:fn)
return 2 " the .git is some other type of .git file (probably a worktree)
endif

return 0 " doesn't exist
endfun

16 changes: 16 additions & 0 deletions doc/projectroot.txt
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@ used as the project root. >
let b:projectroot = '~/foo/bar'
<

*'g:projectroot_nested_git_submodule'*
Default: 0
If you are nesting git repos inside other git repos using git's submodule
feature, then you might actually want the parent repo to be the project root
not just for itself but also for nested repos. In this case, you can use: >

let g:projectroot_nested_git_submodule = 1
<
This setting will cause projectroot to read the contents of '.git' marker
files and check if they are indicate a git submodule inside another git repo.
If this is the case, then projectroot will continue searching up the tree for
another '.git' marker file. (This option only works when `g:rootmarkers`
contains '.git'.)


*'g:projectroot_noskipbufs'*
Default: 0
The default behavior of ProjectBufNext and ProjectBufPrev is to skip buffers
Expand All @@ -213,6 +228,7 @@ thing to do because, well, who needs 2 windows of the same thing?
If you prefer not to have this behavior use: >

let g:projectroot_noskipbufs = 1
<

=============================================================================
EXTENDING *projectroot-extending*
Expand Down