diff --git a/autoload/magit/sign.vim b/autoload/magit/sign.vim
index 7a53390921aafefac34b623b5efda53116173d5c..ec02b913b056d2a606b1ea61c4979e1a89cab80b 100644
--- a/autoload/magit/sign.vim
+++ b/autoload/magit/sign.vim
@@ -82,6 +82,27 @@ function! magit#sign#find_signs(pattern, startline, endline)
 	return found_signs
 endfunction
 
+function! magit#sign#get_lines(...)
+	let bufnr = magit#utils#bufnr()
+	let lines = []
+
+	redir => signs
+	silent execute "sign place buffer=" . bufnr
+	redir END
+
+	for sign_line in filter(split(signs, '\n'), 'v:val =~# "="')
+		" Typical sign line:  line=88 id=1234 name=GitGutterLineAdded
+		" We assume splitting is faster than a regexp.
+		let components  = split(sign_line)
+		let id = str2nr(split(components[1], '=')[1])
+		if ( index(a:000, id) != -1 )
+			let line_number = str2nr(split(components[0], '=')[1])
+			call add(lines, line_number)
+		endif
+	endfor
+	return lines
+endfunction
+
 " magit#sign#find_stage_signs: helper function to get marked lines for stage
 " param[in] startline,endline: range of lines
 " return Dict of marked lines
@@ -95,8 +116,8 @@ let s:magit_mark_signs = {'M': 'MagitTBS', 'S': 'MagitBS', 'E': 'MagitBE'}
 " magit#sign#init: initializer function for signs
 function! magit#sign#init()
 	execute "sign define " . s:magit_mark_signs.M . " text=S> linehl=Visual"
-	execute "sign define " . s:magit_mark_signs.S
-	execute "sign define " . s:magit_mark_signs.E
+	execute "sign define " . s:magit_mark_signs.S . " text=S\<Char-0xa0>"
+	execute "sign define " . s:magit_mark_signs.E . " text=\<Char-0xa0>E"
 endfunction
 
 " magit#sign#toggle_signs: toggle marks for range of lines
diff --git a/autoload/magit/state.vim b/autoload/magit/state.vim
index 27df64089b7776909f9516eb01ad9916ff8e96a8..c3495346e9500652fa8af575811de167525a4dae 100644
--- a/autoload/magit/state.vim
+++ b/autoload/magit/state.vim
@@ -96,29 +96,48 @@ function! magit#state#file_set_diff(val) dict
 	endif
 endfunction
 
-function! magit#state#file_put() dict
-	"if ( self.dirty != 0 )
-	if (1)
-		let bufnr = magit#utils#bufnr()
-		let self.sign_start = magit#sign#add_sign(line('.'), 'S', bufnr)
-		put =file.get_filename_header()
-		if ( self.dir != 0 )
-			if ( self.visible == 1 )
-				let self.sign_end = magit#sign#add_sign(line('.'), 'E', bufnr)
-				return 1
-			endif
-		endif
-		if ( self.visible == 0 )
-			let self.sign_end = magit#sign#add_sign(line('.'), 'E', bufnr)
-			return 0
+function! magit#state#file_put(curline) dict
+	try
+		let recursive = 0
+		if ( self.sign_start != 0 && self.sign_end != 0 )
+			let [line_start, line_end] = magit#sign#get_lines(
+						\ self.sign_start, self.sign_end)
+			let curline = line_start
+		else
+			let curline = a:curline
 		endif
-		if ( self.exists == 0 )
-			echoerr "Error, " . self.filename . " should not exists"
+		if ( self.dirty != 0 )
+			silent! execute 'silent! ' . line_start . ',' . line_end . 'delete _'
+			let curline = min( [ curline, line('$') ] )
+			let bufnr = magit#utils#bufnr()
+			let self.sign_start = magit#sign#add_sign(curline, 'S', bufnr)
+			call magit#utils#debug_log(self.filename . '  start ' . curline)
+			call append(file.get_filename_header())
+			if ( self.dir != 0 && self.visible == 1 )
+				let line_end = curline
+				let self.sign_end = magit#sign#add_sign(line_end, 'E', bufnr)
+				let recursive = 1
+				throw 'goto'
+			endif
+
+			if ( self.visible == 0 )
+				let line_end = curline
+				throw 'goto'
+			endif
+			if ( self.exists == 0 )
+				echoerr "Error, " . self.filename . " should not exists"
+			endif
+			let hunk_lines=self.get_flat_hunks()
+			let line_end = curline + len(hunk_lines)
+			call append(curline, hunk_lines)
 		endif
-		let hunk_lines=self.get_flat_hunks()
-		silent put =hunk_lines
-		let self.sign_end = magit#sign#add_sign(line('.'), 'E', bufnr)
-	endif
+	catch /^goto$/
+		"do nothing
+	finally
+		let self.sign_end = magit#sign#add_sign(line_end, 'E', bufnr)
+		call magit#utils#debug_log(self.filename . '  end ' . line_end)
+		return [0, line_end+1]
+	endtry
 endfunction
 
 " s:hunk_template: template for hunk object (nested in s:diff_template)
@@ -126,7 +145,6 @@ endfunction
 let s:hunk_template = {
 \	'header': '',
 \	'lines': [],
-\	'marks': [],
 \}
 
 " s:diff_template: template for diff object (nested in s:file_template)
@@ -290,6 +308,17 @@ function! magit#state#add_file(mode, status, filename, depth) dict
 	call file.set_diff(diff)
 endfunction
 
+function! magit#state#get_files_lines() dict
+	let lines = {}
+	for diff_dict_mode in values(self.dict)
+		for file in values(diff_dict_mode)
+			let lines[file.filename] = magit#sign#get_lines(
+				\ file.sign_start, file.sign_end)
+		endfor
+	endfor
+	return lines
+endfunction
+
 " magit#state#update: update self.dict
 " if a file does not exists anymore (because all its changes have been
 " committed, deleted, discarded), it is removed from g:mg_diff_dict
@@ -373,6 +402,7 @@ let magit#state#state = {
 			\ 'add_file': function("magit#state#add_file"),
 			\ 'set_files_visible': function("magit#state#set_files_visible"),
 			\ 'update': function("magit#state#update"),
+			\ 'get_files_lines': function("magit#state#get_files_lines"),
 			\ 'dict': { 'staged': {}, 'unstaged': {}},
 			\ }
 
diff --git a/autoload/magit/utils.vim b/autoload/magit/utils.vim
index 6be7df154753667583c371fe83f5179291682185..75c5fdba0b24c685a94738cb26b16170e78e8d18 100644
--- a/autoload/magit/utils.vim
+++ b/autoload/magit/utils.vim
@@ -134,7 +134,12 @@ endfunction
 " return: one dimensional list
 function! magit#utils#flatten(list)
 	let val = []
-	for elem in a:list
+	if ( type(a:list) == type([]) )
+		let list = a:list
+	elseif ( type(a:list) == type({}) )
+		let list = items(a:list)
+	endif
+	for elem in list
 		if type(elem) == type([])
 			call extend(val, magit#utils#flatten(elem))
 		else
@@ -173,3 +178,30 @@ endfunction
 function! magit#utils#bufnr()
 	return s:bufnr
 endfunction
+
+function! magit#utils#set_debug()
+	echom "Log into " . g:magit_log_file
+	execute "edit " . g:magit_log_file
+	execute '%delete _'
+	write!
+	let g:magit_debug = 1
+endfunction
+
+function! magit#utils#debug_cmd(cmd)
+	if ( g:magit_debug != 0 )
+		execute "a:cmd"
+	endif
+endfunc
+
+function! magit#utils#debug_log(message)
+	if ( g:magit_debug != 0 )
+		if ( type(a:message) == type("") )
+			let msg = split(a:message, '\n')
+		elseif ( type(a:message) == type({}) )
+			let msg = split(string(a:message), '\n')
+		else
+			let msg = a:message
+		endif
+		call magit#utils#append_file(g:magit_log_file, msg)
+	endif
+endfunction
diff --git a/plugin/magit.vim b/plugin/magit.vim
index 317667b02e0d88d7ac720d8c4ce7aa45986d746a..66179923f247fb677cf577498b8a77b002b119a2 100644
--- a/plugin/magit.vim
+++ b/plugin/magit.vim
@@ -50,6 +50,10 @@ let g:magit_default_fold_level     = get(g:, 'magit_default_fold_level',
 
 let g:magit_warning_max_lines      = get(g:, 'magit_warning_max_lines',         10000)
 
+
+let g:magit_debug                  = get(g:, 'magit_debug',                     1)
+let g:magit_log_file               = get(g:, 'magit_log_file',                  '/tmp/vimagit.log')
+
 execute "nnoremap <silent> " . g:magit_show_magit_mapping . " :call magit#show_magit('v')<cr>"
 " }}}
 
@@ -95,6 +99,8 @@ let s:magit_inline_help = {
 \],
 \}
 
+let s:current_line = 1
+
 " s:mg_get_inline_help_line_nb: this function returns the number of lines of
 " a given section, or 0 if help is disabled.
 " param[in] section: section identifier
@@ -115,19 +121,33 @@ function! s:mg_section_help(section)
 	endif
 endfunction
 
+let s:info_sign_start = 0
+let s:info_sign_end = 0
 " s:mg_get_info: this function writes in current buffer current git state
 " WARNING: this function writes in file, it should only be called through
 " protected functions like magit#update_buffer
-function! s:mg_get_info()
-	silent put =''
-	silent put =g:magit_sections.info
-	silent put =magit#utils#underline(g:magit_sections.info)
-	silent put =''
-	let branch=magit#utils#system("git rev-parse --abbrev-ref HEAD")
-	let commit=magit#utils#system("git show -s --oneline")
-	silent put ='Current branch: ' . branch
-	silent put ='Last commit:    ' . commit
-	silent put =''
+function! s:mg_get_info(curline)
+	if ( s:info_sign_start == 0 )
+		let bufnr = magit#utils#bufnr()
+		let s:info_sign_start = magit#sign#add_sign(a:curline, 'S', bufnr)
+		let branch = magit#utils#system("git rev-parse --abbrev-ref HEAD")
+		let commit = magit#utils#system("git show -s --oneline")
+		let info_msg = [
+		\'',
+		\g:magit_sections.info,
+		\magit#utils#underline(g:magit_sections.info),
+		\'',
+		\'Current branch: ' . branch,
+		\'Last commit:    ' . commit,
+		\'',
+		\]
+		call append(a:curline, info_msg)
+		let endline = a:curline + len(info_msg)
+		let s:info_sign_end = magit#sign#add_sign(endline, 'E', bufnr)
+	else
+		let endline = magit#sign#get_lines(s:info_sign_end)
+	endif
+	return endline
 endfunction
 
 " s:mg_display_files: display in current buffer files, filtered by some
@@ -137,33 +157,54 @@ endfunction
 " directory)
 " param[in] depth: current directory depth (only needed for untracked
 " directory)
-function! s:mg_display_files(mode, curdir, depth)
+function! s:mg_display_files(mode, curdir, depth, curline)
 
+	let nextline = a:curline + 1
+	call magit#utils#debug_log(">> display nextline " . nextline)
 	" FIXME: ouch, must store subdirs in more efficient way
 	for filename in sort(keys(s:state.get_files(a:mode)))
 		let file = s:state.get_file(a:mode, filename)
+		call magit#utils#debug_log("filename " . filename)
 		if ( file.depth != a:depth || filename !~ a:curdir . '.*' )
+			call magit#utils#debug_log("!! skip")
 			continue
 		endif
-		if ( file.put() != 0 )
-			call s:mg_display_files(a:mode, filename, a:depth + 1)
+		call magit#utils#debug_log('before put nextline ' . nextline)
+		let [recursive, nextline] = file.put(nextline)
+		call magit#utils#debug_log('after put nextline ' . nextline)
+		if ( recursive != 0 )
+			call magit#utils#debug_log('before recursive nextline ' . nextline)
+			let nextline = s:mg_display_files(a:mode, filename, a:depth + 1, nextline)
+			call magit#utils#debug_log('before recursive nextline ' . nextline)
 		endif
-		put =''
 	endfor
+	call magit#utils#debug_log('return nextline ' . nextline)
+	return nextline
 endfunction
 
+let s:stage_sign_start = { 'stage': 0, 'unstaged': 0}
+let s:stage_sign_end =   { 'stage': 0, 'unstaged': 0}
 " 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)
+function! s:mg_get_staged_section(mode, curline)
+
+	if ( s:stage_sign_start[a:mode] == 0 )
+		let bufnr = magit#utils#bufnr()
+		let s:stage_sign_start[a:mode] = magit#sign#add_sign(a:curline, 'S', bufnr)
+		let stage_msg = [
+		\ g:magit_sections[a:mode],
+		\ magit#utils#underline(g:magit_sections[a:mode]),
+		\]
+		call append(a:curline, stage_msg)
+		let endline = a:curline + len(stage_msg)
+		let s:stage_sign_end[a:mode] = magit#sign#add_sign(endline, 'E', bufnr)
+	else
+		let endline = magit#sign#get_lines(s:stage_sign_end[a:mode])
+	endif
+	return s:mg_display_files(a:mode, '', 0, endline)
 endfunction
 
 " s:mg_get_stashes: this function write in current buffer all stashes
@@ -505,7 +546,8 @@ function! magit#update_buffer()
 	" delete buffer
 	silent! execute "silent :%delete _"
 	
-	call <SID>mg_get_info()
+	let current_line = 1
+	let current_line = <SID>mg_get_info(current_line)
 	call <SID>mg_section_help('global')
 	if ( s:magit_commit_mode != '' )
 		call <SID>mg_get_commit_section()
@@ -522,8 +564,9 @@ function! magit#update_buffer()
 		endif
 	endif
 
-	call <SID>mg_get_staged_section('staged')
-	call <SID>mg_get_staged_section('unstaged')
+	let current_line = <SID>mg_get_staged_section('staged', current_line)
+	let current_line = <SID>mg_get_staged_section('unstaged', current_line)
+
 	call <SID>mg_get_stashes()
 
 	call winrestview(l:winview)
@@ -812,4 +855,8 @@ endfunction
 
 command! Magit call magit#show_magit('v')
 
+command! MagitDebugFilesLines call magit#utils#append_file(g:magit_log_file, magit#utils#flatten(items(s:state.get_files_lines())))
+
+command! MagitDebug call magit#utils#set_debug()
+
 " }}}