diff --git a/autoload/magit/state.vim b/autoload/magit/state.vim
index 1163014d2d69bf0eb6deb45a9b326e6fda63ce93..170fd2d78bdc6e144dfcb3630dbd154258f5b857 100644
--- a/autoload/magit/state.vim
+++ b/autoload/magit/state.vim
@@ -3,6 +3,11 @@ function! magit#state#is_file_visible(section, filename) dict
 		 \ ( self.dict[a:section][a:filename].visible == 1 ) )
 endfunction
 
+function! magit#state#is_dir(section, filename) dict
+	return ( has_key(self.dict[a:section], a:filename) &&
+		 \ ( self.dict[a:section][a:filename].dir != 0 ) )
+endfunction
+
 function! magit#state#get_files(mode) dict
 	return self.dict[a:mode]
 endfunction
@@ -28,6 +33,7 @@ let s:file_template = {
 \	'exists': 0,
 \	'status': '',
 \	'empty': 0,
+\	'dir': 0,
 \	'binary': 0,
 \	'symlink': '',
 \	'diff': s:diff_template,
@@ -87,60 +93,60 @@ endfunction
 " param[in] mode: can be staged or unstaged
 " param[in] status: one character status code of the file (AMDRCU?)
 " param[in] filename: filename
-function! magit#state#add_file(mode, status, filename) dict
-	let dir = getcwd()
-	try
-		call magit#utils#lcd(magit#utils#top_dir())
-		let dev_null = ( a:status == '?' ) ? " /dev/null " : " "
-		let staged_flag = ( a:mode == 'staged' ) ? " --staged " : " "
-		let diff_cmd="git diff --no-ext-diff " . staged_flag .
-					\ "--no-color --patch -- " . dev_null . " "
-					\ .  magit#utils#add_quotes(a:filename)
-		let diff_list=magit#utils#systemlist(diff_cmd)
-		if ( empty(diff_list) )
-			echoerr "diff command \"" . diff_cmd . "\" returned nothing"
-		endif
-		let diff_dict_file = self.get_file(a:mode, a:filename, 1)
-		let diff_dict_file.exists = 1
-		let diff_dict_file.status = a:status
-		if ( a:status == '?' && getftype(a:filename) == 'link' )
-			let diff_dict_file.symlink = resolve(a:filename)
-			call add(diff_dict_file.diff.header, 'no header')
-			let diff_dict_file.diff.hunks[0].header = 'New symbolic link file'
-		elseif ( a:status == '?' && getfsize(a:filename) == 0 )
-			let diff_dict_file.empty = 1
-			call add(diff_dict_file.diff.header, 'no header')
-			let diff_dict_file.diff.hunks[0].header = 'New empty file'
-		elseif ( match(system("file --mime " .
-					\ magit#utils#add_quotes(a:filename)),
-					\ a:filename . ".*charset=binary") != -1 )
-			let diff_dict_file.binary = 1
-			call add(diff_dict_file.diff.header, 'no header')
-			let diff_dict_file.diff.hunks[0].header = 'Binary file'
-		else
-			let line = 0
-			" match(
-			while ( line < len(diff_list) && diff_list[line] !~ "^@.*" )
-				call add(diff_dict_file.diff.header, diff_list[line])
-				let line += 1
-			endwhile
-
-			let hunk = diff_dict_file.diff.hunks[0]
-			let hunk.header = diff_list[line]
-
-			for diff_line in diff_list[line+1 : -1]
-				if ( diff_line =~ "^@.*" )
-					let hunk = deepcopy(s:hunk_template)
-					call add(diff_dict_file.diff.hunks, hunk)
-					let hunk.header = diff_line
-					continue
-				endif
-				call add(hunk.lines, diff_line)
-			endfor
-		endif
-	finally
-		call magit#utils#lcd(dir)
-	endtry
+function! magit#state#add_file(mode, status, filename, depth) dict
+	let dev_null = ( a:status == '?' ) ? " /dev/null " : " "
+	let staged_flag = ( a:mode == 'staged' ) ? " --staged " : " "
+	let diff_cmd="git diff --no-ext-diff " . staged_flag .
+				\ "--no-color --patch -- " . dev_null . " "
+				\ .  magit#utils#add_quotes(a:filename)
+	let diff_list=magit#utils#systemlist(diff_cmd)
+	if ( empty(diff_list) )
+		echoerr "diff command \"" . diff_cmd . "\" returned nothing"
+	endif
+	let diff_dict_file = self.get_file(a:mode, a:filename, 1)
+	let diff_dict_file.exists = 1
+	let diff_dict_file.status = a:status
+	let diff_dict_file.depth = a:depth
+	if ( a:status == '?' && getftype(a:filename) == 'link' )
+		let diff_dict_file.symlink = resolve(a:filename)
+		call add(diff_dict_file.diff.header, 'no header')
+		let diff_dict_file.diff.hunks[0].header = 'New symbolic link file'
+	elseif ( a:status == '?' && isdirectory(a:filename) == 1 )
+		let diff_dict_file.dir = 1
+		for subfile in split(globpath(a:filename, '\(.[^.]*\|*\)'), '\n')
+			call self.add_file(a:mode, a:status, subfile, a:depth + 1)
+		endfor
+	elseif ( a:status == '?' && getfsize(a:filename) == 0 )
+		let diff_dict_file.empty = 1
+		call add(diff_dict_file.diff.header, 'no header')
+		let diff_dict_file.diff.hunks[0].header = 'New empty file'
+	elseif ( match(system("file --mime " .
+				\ magit#utils#add_quotes(a:filename)),
+				\ a:filename . ".*charset=binary") != -1 )
+		let diff_dict_file.binary = 1
+		call add(diff_dict_file.diff.header, 'no header')
+		let diff_dict_file.diff.hunks[0].header = 'Binary file'
+	else
+		let line = 0
+		" match(
+		while ( line < len(diff_list) && diff_list[line] !~ "^@.*" )
+			call add(diff_dict_file.diff.header, diff_list[line])
+			let line += 1
+		endwhile
+
+		let hunk = diff_dict_file.diff.hunks[0]
+		let hunk.header = diff_list[line]
+
+		for diff_line in diff_list[line+1 : -1]
+			if ( diff_line =~ "^@.*" )
+				let hunk = deepcopy(s:hunk_template)
+				call add(diff_dict_file.diff.hunks, hunk)
+				let hunk.header = diff_line
+				continue
+			endif
+			call add(hunk.lines, diff_line)
+		endfor
+	endif
 endfunction
 
 " magit#state#update: update self.dict
@@ -157,19 +163,24 @@ function! magit#state#update() dict
 		endfor
 	endfor
 
-	for [mode, diff_dict_mode] in items(self.dict)
-
-		let status_list = magit#git#get_status()
-		for file_status in status_list
-			let status=file_status[mode]
+	let dir = getcwd()
+	try
+		call magit#utils#lcd(magit#utils#top_dir())
+		for [mode, diff_dict_mode] in items(self.dict)
+			let status_list = magit#git#get_status()
+			for file_status in status_list
+				let status=file_status[mode]
 
-			" untracked code apperas in staged column, we skip it
-			if ( status == ' ' || ( ( mode == 'staged' ) && status == '?' ) )
-				continue
-			endif
-			call self.add_file(mode, status, file_status.filename)
+				" untracked code apperas in staged column, we skip it
+				if ( status == ' ' || ( ( mode == 'staged' ) && status == '?' ) )
+					continue
+				endif
+				call self.add_file(mode, status, file_status.filename, 0)
+			endfor
 		endfor
-	endfor
+	finally
+		call magit#utils#lcd(dir)
+	endtry
 
 	" remove files that have changed their mode or been committed/deleted/discarded...
 	for diff_dict_mode in values(self.dict)
@@ -202,6 +213,7 @@ let magit#state#state = {
 			\ 'get_hunks': function("magit#state#get_hunks"),
 			\ 'get_flat_hunks': function("magit#state#get_flat_hunks"),
 			\ 'add_file': function("magit#state#add_file"),
+			\ 'is_dir': function("magit#state#is_dir"),
 			\ 'is_file_visible': function("magit#state#is_file_visible"),
 			\ 'update': function("magit#state#update"),
 			\ 'dict': { 'staged': {}, 'unstaged': {}},
diff --git a/common/magit_common.vim b/common/magit_common.vim
index c14c3be02f3ab50c7a97240a5415bb983ab46111..9a18e9133e83cde4aa6f6474c5c5952f6f2df3ce 100644
--- a/common/magit_common.vim
+++ b/common/magit_common.vim
@@ -21,6 +21,7 @@ let g:magit_git_status_code = {
  \ '!': 'ignored',
  \ 'E': 'empty',
  \ 'L': 'symlink',
+ \ 'N': 'new dir',
  \ }
 
 " Regular expressions used to select blocks
diff --git a/plugin/magit.vim b/plugin/magit.vim
index 8402ed53cb7493c06428d08ed3e4a3f1b02c2326..aa81dbb776b0c27fe821e49d26d1651e85d8457b 100644
--- a/plugin/magit.vim
+++ b/plugin/magit.vim
@@ -140,24 +140,23 @@ function! s:mg_get_info()
 	silent put =''
 endfunction
 
+function! s:mg_display_files(mode, curdir, depth)
 
-" s:mg_get_staged_section: this function writes in current buffer all staged
-" or unstaged files, using s:state.dict information
-" WARNING: this function writes in file, it should only be called through
-" protected functions like magit#update_buffer
-" param[in] mode: 'staged' or 'unstaged'
-function! s:mg_get_staged_section(mode)
-	put =''
-	put =g:magit_sections[a:mode]
-	call <SID>mg_section_help(a:mode)
-	put =magit#utils#underline(g:magit_sections[a:mode])
-	put =''
-
+	" FIXME: ouch, must store subdirs in more efficient way
 	for [ filename, file_props ] in items(s:state.get_files(a:mode))
+		if ( file_props.depth != a:depth || filename !~ a:curdir . '.*' )
+			continue
+		endif
 		if ( file_props.empty == 1 )
 			put =g:magit_git_status_code.E . ': ' . filename
 		elseif ( file_props.symlink != '' )
 			put =g:magit_git_status_code.L . ': ' . filename . ' -> ' . file_props.symlink
+		elseif ( file_props.dir != 0 )
+			put =g:magit_git_status_code.N . ': ' . filename
+			if ( file_props.visible == 1 )
+				call s:mg_display_files(a:mode, filename, a:depth + 1)
+				continue
+			endif
 		else
 			put =g:magit_git_status_code[file_props.status] . ': ' . filename
 		endif
@@ -177,6 +176,20 @@ function! s:mg_get_staged_section(mode)
 	endfor
 endfunction
 
+" s:mg_get_staged_section: this function writes in current buffer all staged
+" or unstaged files, using s:state.dict information
+" WARNING: this function writes in file, it should only be called through
+" protected functions like magit#update_buffer
+" param[in] mode: 'staged' or 'unstaged'
+function! s:mg_get_staged_section(mode)
+	put =''
+	put =g:magit_sections[a:mode]
+	call <SID>mg_section_help(a:mode)
+	put =magit#utils#underline(g:magit_sections[a:mode])
+	put =''
+	call s:mg_display_files(a:mode, '', 0)
+endfunction
+
 " s:mg_get_stashes: this function write in current buffer all stashes
 " WARNING: this function writes in file, it should only be called through
 " protected functions like magit#update_buffer
@@ -663,7 +676,8 @@ function! s:mg_select_closed_file()
 		let list = matchlist(getline("."), g:magit_file_re)
 		let filename = list[2]
 		let section=<SID>mg_get_section()
-		if ( s:state.is_file_visible(section, filename) == 0 )
+		if ( s:state.is_file_visible(section, filename) == 0 ||
+			\ s:state.is_dir(section, filename) == 1 )
 			let selection = s:state.get_flat_hunks(section, filename)
 			return selection
 		endif
@@ -687,6 +701,7 @@ function! magit#stage_block(selection, discard) abort
 		if ( section == 'unstaged' )
 			if ( file.empty == 1 ||
 			\    file.symlink != '' ||
+			\    file.dir != 0 ||
 			\    file.binary == 1 )
 				call magit#utils#system('git add ' .
 					\ magit#utils#add_quotes(filename))
@@ -696,6 +711,7 @@ function! magit#stage_block(selection, discard) abort
 		elseif ( section == 'staged' )
 			if ( file.empty == 1 ||
 			\    file.symlink != '' ||
+			\    file.dir != 0 ||
 			\    file.binary == 1 )
 				call magit#utils#system('git reset ' .
 					\ magit#utils#add_quotes(filename))
@@ -711,6 +727,7 @@ function! magit#stage_block(selection, discard) abort
 		if ( section == 'unstaged' )
 			if ( file.empty == 1 ||
 			\    file.symlink != '' ||
+			\    file.dir != 0 ||
 			\    file.binary == 1 )
 				call delete(filename)
 			else