diff --git a/autoload/magit/state.vim b/autoload/magit/state.vim
index 032416eacd461d1ef8b82abd57206c605157e2a8..cebbe232f0e319dcbf11653fe9e90d82f128cb63 100644
--- a/autoload/magit/state.vim
+++ b/autoload/magit/state.vim
@@ -52,6 +52,50 @@ function! magit#state#file_get_flat_hunks() dict
 	return lines
 endfunction
 
+function! magit#state#file_set_status(val) dict
+	if ( self.status != a:val )
+		let self.dirty = 1
+		let self.status = a:val
+	endif
+endfunction
+function! magit#state#file_set_empty(val) dict
+	if ( self.empty != a:val )
+		let self.dirty = 1
+		let self.empty = a:val
+	endif
+endfunction
+function! magit#state#file_set_dir(val) dict
+	if ( self.dir != a:val )
+		let self.dirty = 1
+		let self.dir = a:val
+	endif
+endfunction
+function! magit#state#file_set_binary(val) dict
+	if ( self.binary != a:val )
+		let self.dirty = 1
+		let self.binary = a:val
+	endif
+endfunction
+function! magit#state#file_set_symlink(val) dict
+	if ( self.symlink != a:val )
+		let self.dirty = 1
+		let self.symlink = a:val
+	endif
+endfunction
+function! magit#state#file_set_depth(val) dict
+	if ( self.depth != a:val )
+		let self.dirty = 1
+		let self.depth = a:val
+	endif
+endfunction
+
+function! magit#state#file_set_diff(val) dict
+	if ( self.diff != a:val )
+		let self.dirty = 1
+		let self.diff = a:val
+	endif
+endfunction
+
 " s:hunk_template: template for hunk object (nested in s:diff_template)
 " WARNING: this variable must be deepcopy()'ied
 let s:hunk_template = {
@@ -70,24 +114,36 @@ let s:diff_template = {
 " s:file_template: template for file object
 " WARNING: this variable must be deepcopy()'ied
 let s:file_template = {
-\	'exists': 0,
-\	'filename': '',
-\	'status': '',
-\	'empty': 0,
-\	'dir': 0,
-\	'binary': 0,
-\	'submodule': 0,
-\	'symlink': '',
-\	'diff': s:diff_template,
-\	'is_dir': function("magit#state#is_file_dir"),
-\	'is_visible': function("magit#state#is_file_visible"),
-\	'set_visible': function("magit#state#set_file_visible"),
-\	'toggle_visible': function("magit#state#toggle_file_visible"),
-\	'must_be_added': function("magit#state#must_be_added"),
-\	'get_header': function("magit#state#file_get_header"),
+\	'filename'       : '',
+\	'exists'         : 0,
+\	'status'         : '',
+\	'mode'           : '',
+\	'empty'          : 0,
+\	'dir'            : 0,
+\	'binary'         : 0,
+\	'submodule'      : 0,
+\	'symlink'        : '',
+\	'depth'          : 0,
+\	'dirty'          : 0,
+\	'sign_start'     : 0,
+\	'sign_end'       : 0,
+\	'diff'           : deepcopy(s:diff_template),
+\	'set_status'     : function("magit#state#file_set_status"),
+\	'set_empty'      : function("magit#state#file_set_empty"),
+\	'set_dir'        : function("magit#state#file_set_dir"),
+\	'set_binary'     : function("magit#state#file_set_binary"),
+\	'set_symlink'    : function("magit#state#file_set_symlink"),
+\	'set_depth'      : function("magit#state#file_set_depth"),
+\	'set_diff'       : function("magit#state#file_set_diff"),
+\	'is_dir'         : function("magit#state#is_file_dir"),
+\	'is_visible'     : function("magit#state#is_file_visible"),
+\	'set_visible'    : function("magit#state#set_file_visible"),
+\	'get_header'     : function("magit#state#file_get_header"),
+\	'get_filename_header' : function("magit#state#file_get_filename_header"),
 \	'get_hunks'      : function("magit#state#file_get_hunks"),
 \	'get_flat_hunks' : function("magit#state#file_get_flat_hunks"),
-\	'get_filename_header' : function("magit#state#file_get_filename_header"),
+\	'toggle_visible' : function("magit#state#toggle_file_visible"),
+\	'must_be_added'  : function("magit#state#must_be_added"),
 \}
 
 " magit#state#get_file: function accessor for file
@@ -103,6 +159,7 @@ function! magit#state#get_file(mode, filename, ...) dict
 		let self.dict[a:mode][a:filename] = deepcopy(s:file_template)
 		let self.dict[a:mode][a:filename].visible = b:magit_default_show_all_files
 		let self.dict[a:mode][a:filename].filename = a:filename
+		let self.dict[a:mode][a:filename].mode = a:mode
 	elseif ( file_exists == 0 && create == 0 )
 		throw 'file_doesnt_exists'
 	endif
@@ -142,45 +199,51 @@ function! magit#state#add_file(mode, status, filename, depth) dict
 	endif
 	let file = self.get_file(a:mode, a:filename, 1)
 	let file.exists = 1
+	let file.dirty = 0
 
-	let file.status = a:status
-	let file.depth = a:depth
+	call file.set_status(a:status)
+	call file.set_depth(a:depth)
+
+	let diff = deepcopy(s:diff_template)
 
 	if ( a:status == '?' && getftype(a:filename) == 'link' )
 		let file.status = 'L'
-		let file.symlink = resolve(a:filename)
-		let file.diff.hunks[0].header = 'New symbolic link file'
+		call file.set_symlink(resolve(a:filename))
+		let diff.header = 'no header'
+		let diff.hunks[0].header = 'New symbolic link file'
 	elseif ( magit#utils#is_submodule(a:filename))
 		let file.status = 'S'
 		let file.submodule = 1
-		let file.diff.hunks[0].header = ''
-		let file.diff.hunks[0].lines = diff_list
+		let diff.hunks[0].header = ''
+		let diff.hunks[0].lines = diff_list
 		if ( file.is_visible() )
 			let self.nb_diff_lines += len(diff_list)
 		endif
 	elseif ( a:status == '?' && isdirectory(a:filename) == 1 )
 		let file.status = 'N'
 		let file.dir = 1
-		for subfile in magit#utils#ls_all(a:filename)
+		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 file.status = 'E'
-		let file.empty = 1
-		let file.diff.hunks[0].header = 'New empty file'
+		call file.set_empty(1)
+		let diff.header = 'no header'
+		let diff.hunks[0].header = 'New empty file'
 	elseif ( magit#utils#is_binary(magit#utils#add_quotes(a:filename)))
-		let file.binary = 1
-		let file.diff.hunks[0].header = 'Binary file'
+		call file.set_binary(1)
+		let diff.header = 'no header'
+		let diff.hunks[0].header = 'Binary file'
 	else
 		let line = 0
 		" match(
 		while ( line < len(diff_list) && diff_list[line] !~ "^@.*" )
-			call add(file.diff.header, diff_list[line])
+			call add(diff.header, diff_list[line])
 			let line += 1
 		endwhile
 
 		if ( line < len(diff_list) )
-			let hunk = file.diff.hunks[0]
+			let hunk = diff.hunks[0]
 			let hunk.header = diff_list[line]
 
 			for diff_line in diff_list[line+1 : -1]
@@ -197,6 +260,8 @@ function! magit#state#add_file(mode, status, filename, depth) dict
 			let self.nb_diff_lines += len(diff_list)
 		endif
 	endif
+
+	call file.set_diff(diff)
 endfunction
 
 " magit#state#update: update self.dict
@@ -209,8 +274,6 @@ function! magit#state#update() dict
 	for diff_dict_mode in values(self.dict)
 		for file in values(diff_dict_mode)
 			let file.exists = 0
-			" always discard previous diff
-			let file.diff = deepcopy(s:diff_template)
 		endfor
 	endfor