diff --git a/.travis.yml b/.travis.yml
index 5df2b12d11f6938cc6a1b8aa04594f4fc03c93ae..660befcb77d8e3608b7da434ad45c5faf381c272 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,28 +1,70 @@
 language: vim
 
-sudo: false
+branches:
+  only:
+    - master
+    - next
 
 os:
   - linux
   - osx
 
 env:
-  matrix:
-    - TEST_SUB_PATH=./
-    - TEST_SUB_PATH=books/templates/
+  - VIM_VERSION=normal
+  - VIM_VERSION=last
+  - VIM_VERSION=neovim
+  - VIM_VERSION=macvim
 
 matrix:
-  allow_failures:
+  exclude:
     - os: osx
+      env: VIM_VERSION=last
+# neovim build fails with homebrew
+# Error: undefined method `desc' for Neovim:Class
+    - os: osx
+      env: VIM_VERSION=neovim
+    - os: linux
+      env: VIM_VERSION=macvim
+
+install:
+  - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then
+      if [ "$VIM_VERSION" = 'neovim' ]; then
+        brew tap neovim/neovim &&
+        brew tap --repair &&
+        brew install --HEAD neovim;
+      elif [ "$VIM_VERSION" = 'macvim' ]; then
+        brew install macvim;
+      elif [ "$VIM_VERSION" = 'normal' ]; then
+        echo "use normal vim";
+      else
+        echo "VIM_VERSION is not set";
+        exit 1;
+      fi
+    elif [ "$TRAVIS_OS_NAME" = 'linux' ]; then
+      if [ "$VIM_VERSION" = 'last' ]; then
+        sudo add-apt-repository -y ppa:fcwu-tw/ppa &&
+        sudo apt-get -qq update &&
+        sudo apt-get -qq -f install &&
+        sudo apt-get -qq install vim;
+      elif [ "$VIM_VERSION" = 'neovim' ]; then
+        sudo add-apt-repository -y ppa:neovim-ppa/unstable &&
+        sudo apt-get -qq update &&
+        sudo apt-get -qq -f install &&
+        sudo apt-get -qq install neovim;
+      elif [ "$VIM_VERSION" = 'normal' ]; then
+        echo "use normal vim";
+      else
+        echo "VIM_VERSION is not set";
+        exit 1;
+      fi
+    fi
 
 before_script:
   - git clone https://github.com/jreybert/djooks
   - git clone https://github.com/junegunn/vader.vim
 
 script:
-  - ./test/run.sh . vader.vim djooks
-
-install: true
+  - ./test/run.sh . vader.vim djooks $VIM_VERSION
 
 after_success:
   - ./test/merge.sh
diff --git a/README.md b/README.md
index 986b807f3949234a15a0048d37cc142847a359b1..9a0fa59d4662ba0e4a27d584c16b8c6759fe49bd 100644
--- a/README.md
+++ b/README.md
@@ -43,10 +43,13 @@ More to come:
 
 ## Usage
 
-IMPORTANT: mappings can have different meanings regarding the cursor position.
+**:Magit**
+The main magical command, showing vimagit buffer.
 
 ### Sections:
 
+IMPORTANT: mappings can have different meanings regarding the cursor position.
+
 There are 3 sections:
 * Commit message: this section appears in commit mode (see below). It
   contains the message to be commited.
@@ -60,38 +63,43 @@ There are 3 sections:
 
 These mappings work in normal mode. They can be redefined.
 
-        S             if cursor is in a hunk, stage/unstage hunk at
-                      cursor position
-                      if cursor is in diff header, stage/unstage whole file
-                      at cursor position
-                      When cursor is in "Unstaged changes" section, it will
-                      stage the hunk/file.
-                      On the other side, when cursor is in "Staged changes"
-                      section, it will unstage hunk/file.
-        F             stage/unstage the whole file at cursor position
-                      When cursor is in "Unstaged changes" section, it will
-                      stage the file.
-                      On the other side, when cursor is in "Staged changes"
-                      section, it will unstage file.
-        DDD           if cursor is in a hunk, discard hunk at cursor position
-                      if cursor is in diff header, discard whole file at
-                      cursor position
-                      When cursor is in "Unstaged changes" section, it will
-                      discard the hunk/file.
-        R             refresh vimagit buffer
-        C,CC,:w<cr>   if not in commit section, set commit mode to "New
-                      commit" and show "Commit message" section with brand new
-                      commit message
-                      if in commit section, commit the all staged changes in
-                      commit mode previously set
-        CA            if not in commit section, set commit mode to "Amend
-                      commit" and show "Commit message" section with previous
-                      commit message
-                      if in commit section, commit the staged changes in
-                      commit mode previously set
-        CF            amend the staged changes into the previous commit,
-                      without modifying previous commit message
-        I             add the file under the cursor in .gitgnore
+**S**
+ * If cursor is in a hunk, stage/unstage hunk at cursor position.
+ * If cursor is in diff header, stage/unstage whole file at cursor position.
+ * When cursor is in "Unstaged changes" section, it will stage the hunk/file.
+ * On the other side, when cursor is in "Staged changes" section, it will unstage hunk/file.
+
+**F**
+ * Stage/unstage the whole file at cursor position.
+ * When cursor is in "Unstaged changes" section, it will stage the file.
+ * On the other side, when cursor is in "Staged changes" section, it will unstage file.
+
+**DDD**
+ * If cursor is in a hunk, discard hunk at cursor position.
+ * If cursor is in diff header, discard whole file at cursor position.
+ * Only works in "Unstaged changes" section.
+
+**C**
+**CC**
+**:w<cr>**
+ * If not in commit section, set commit mode to "New commit" and show "Commit message" section with brand new commit message.
+ * If in commit section, commit the all staged changes in commit mode previously set.
+
+**CA**
+ * If not in commit section, set commit mode to "Amend commit" and show "Commit message" section with previous commit message.
+ * If in commit section, commit the staged changes in commit mode previously set.
+
+**CF**
+ * Amend the staged changes into the previous commit, without modifying previous commit message.
+
+**I**
+ * Add the file under the cursor in .gitgnore
+
+**R**
+ * Refresh vimagit buffer
+
+**h**
+ * Toggle help showing in magit buffer
                 
 ## Installation
 
diff --git a/TODO.md b/TODO.md
index 113a56887213d8f6f734d56b6ff34189cc93ee06..10020b6c096ff4854458d3f4edd2c5b466e01a9c 100644
--- a/TODO.md
+++ b/TODO.md
@@ -4,4 +4,3 @@
 * fix new empty file staging
 * add tests
 * add tutorial
-* fix new/renamed file diff: it gives an absolute pathname, which is wrong fir diff
diff --git a/common/magit_common.vim b/common/magit_common.vim
index d183399dc5819b23a98a9930a4932ef6bc2cb04a..88528436a8786a5bac154e1b397834986991da36 100644
--- a/common/magit_common.vim
+++ b/common/magit_common.vim
@@ -2,6 +2,7 @@
 " These are used to beautify the magit buffer and to help for some block
 " selection
 let g:magit_sections = {
+ \ 'info':           'Info',
  \ 'staged':         'Staged changes',
  \ 'unstaged':       'Unstaged changes',
  \ 'commit_start':   'Commit message',
diff --git a/doc/vimagit.txt b/doc/vimagit.txt
index 9c71080ac1b6f54e38e3d7dec6fedaa25a9bb035..14dcbab39ab11678e553ee5f6a8e2486a38a70aa 100644
--- a/doc/vimagit.txt
+++ b/doc/vimagit.txt
@@ -11,19 +11,18 @@ Plugin Homepage:   <https://github.com/jreybert/vimagit>
                                                              ----- ~
 
 ===============================================================================
-CONTENTS                                                      *vimagitContents*
+CONTENTS                                                      *vimagit-contents*
 
-  1.  Introduction ................. |vimagitIntroduction|
-  2.  Installation ................. |vimagitInstallation|
-  3.  Usage ........................ |vimagitUsage|
-  4.  Commands ..................... |vimagitCommands|
-  5.  Customization ................ |vimagitCustomization|
-  6.  FAQ .......................... |vimagitFAQ|
+  1.  Introduction ................. |vimagit-introduction|
+  2.  Installation ................. |vimagit-installation|
+  3.  Usage ........................ |vimagit-usage|
+  4.  Commands ..................... |vimagit-commands|
+  5.  Customization ................ |vimagit-customization|
+  6.  FAQ .......................... |vimagit-FAQ|
 
 
 ===============================================================================
-1. INTRODUCTION                                           *vimagitIntroduction*
-                                                                      *vimagit*
+1. INTRODUCTION                                           *vimagit-introduction*
 
 vimagit is a plugin which try to mimic the fantastic magit emacs plugin. If you
 already know the original plugin, give it a try. If you never have heard about
@@ -31,7 +30,7 @@ magit (or maybe emacs), this is IMO the most efficient way to stage hunks and
 craft nice commits.
 
 ===============================================================================
-2. INSTALLATION                                           *vimagitInstallation*
+2. INSTALLATION                                           *vimagit-installation*
 
 The plugin hierarchy tree respects the vim plugin standard. It is compatible
 with pathogen (and most probably vundle).
@@ -43,18 +42,23 @@ To install:
 <
 
 ===============================================================================
-3. USAGE                                                         *vimagitUsage*
+3. USAGE                                                         *vimagit-usage*
 
 In a git'ed source directory, once you have some unstaged work, simply type
 with :Magit , and here is the magic. A new window appears, with all the diffs
 and new files in your directory.
 
 ===============================================================================
-4. COMMANDS                                                   *vimagitCommands*
+4. COMMANDS                                                   *vimagit-commands*
 
-IMPORTANT: mappings can have different meanings regarding the cursor position.
 
-Sections:
+                                      *:Magit*             *magit#show_magit('v')*
+  :Magit    the main magical command, showing vimagit buffer
+
+Sections:                                                     *vimagit-sections*
+---------
+
+IMPORTANT: mappings can have different meanings regarding the cursor position.
 
 There are 3 sections:
   * Commit message: this section appears in commit mode (see below). It
@@ -65,45 +69,60 @@ There are 3 sections:
     files/hunks.
   * Stash list: this section contains all stahes.
 
-These mappings work in normal mode.
-
-        S             if cursor is in a hunk, stage/unstage hunk at
-                      cursor position
-                      if cursor is in diff header, stage/unstage whole file
-                      at cursor position
-                      When cursor is in "Unstaged changes" section, it will
-                      stage the hunk/file.
-                      On the other side, when cursor is in "Staged changes"
-                      section, it will unstage hunk/file.
-        F             stage/unstage the whole file at cursor position
-                      When cursor is in "Unstaged changes" section, it will
-                      stage the file.
-                      On the other side, when cursor is in "Staged changes"
-                      section, it will unstage file.
-        DDD           if cursor is in a hunk, discard hunk at cursor position
-                      if cursor is in diff header, discard whole file at
-                      cursor position
-                      When cursor is in "Unstaged changes" section, it will
-                      discard the hunk/file.
-        R             refresh vimagit buffer
-        C,CC,:w<cr>   if not in commit section, set commit mode to "New
-                      commit" and show "Commit message" section with brand new
-                      commit message
-                      if in commit section, commit the all staged changes in
-                      commit mode previously set
-        CA            if not in commit section, set commit mode to "Amend
-                      commit" and show "Commit message" section with previous
-                      commit message
-                      if in commit section, commit the staged changes in
-                      commit mode previously set
-        CF            amend the staged changes into the previous commit,
-                      without modifying previous commit message
-        I             add the file under the cursor in .gitgnore
+These mappings work in normal mode.                           *vimagit-mappings*
+
+                                      *vimagit-S*             *magit#stage_hunk()*
+  S         If cursor is in a hunk, stage/unstage hunk at cursor position.
+            If cursor is in diff header, stage/unstage whole file at cursor
+            position.
+            When cursor is in "Unstaged changes" section, it will stage the
+            hunk/file.
+            On the other side, when cursor is in "Staged changes" section, it
+            will unstage hunk/file.
+
+                                      *vimagit-F*             *magit#stage_file()*
+  F         Stage/unstage the whole file at cursor position.
+            When cursor is in "Unstaged changes" section, it will stage the
+            file.
+            On the other side, when cursor is in "Staged changes" section, it
+            will unstage file.
+
+
+                                    *vimagit-DDD*           *magit#discard_hunk()*
+  DDD       If cursor is in a hunk, discard hunk at cursor position.
+            If cursor is in diff header, discard whole file at cursor
+            position.
+            Only works in "Unstaged changes" section.
+
+            *vimagit-C* *vimagit-CC* *vimagit-:w<cr>*     *magit#commit_command('CC')*
+  C,CC,     If not in commit section, set commit mode to "New commit" and show 
+  :w<cr>    "Commit message" section with brand new commit message.
+            If in commit section, commit the all staged changes in commit mode
+            previously set.
+
+                                     *vimagit-CA*     *magit#commit_command('CA')*
+  CA        If not in commit section, set commit mode to "Amend commit" and
+            show "Commit message" section with previous commit message.
+            If in commit section, commit the staged changes in commit mode
+            previously set.
+
+                                     *vimagit-CF*     *magit#commit_command('CF')*
+  CF        Amend the staged changes into the previous commit, without
+            modifying previous commit message
+
+                                      *vimagit-I*            *magit#ignore_file()*
+  I         Add the file under the cursor in .gitgnore
+
+                                      *vimagit-R*          *magit#update_buffer()*
+  R         Refresh vimagit buffer.
+
+                                      *vimagit-h*            *magit#toggle_help()*
+  h         Toggle help showing in magit buffer
 
 
 ===============================================================================
-5. CUSTOMISATION                                         *vimagitCustomization*
+5. CUSTOMISATION                                         *vimagit-customization*
 
 ===============================================================================
-6. FAQ                                                             *vimagitFAQ*
+6. FAQ                                                             *vimagit-FAQ*
 
diff --git a/plugin/magit.vim b/plugin/magit.vim
index 07def374546275d75a4f80beb59c706c31ce4dd5..490d8e262c8d0256382756ffdcfc193a9b2a3c78 100644
--- a/plugin/magit.vim
+++ b/plugin/magit.vim
@@ -4,14 +4,18 @@ if exists('g:loaded_magit') || !executable('git') || &cp
   finish
 endif
 let g:loaded_magit = 1
+
 " Initialisation {{{
 
 " FIXME: find if there is a minimum vim version required
 " if v:version < 703
 " endif
 
+" source common file. variables in common file are shared with plugin and
+" syntax files
 execute 'source ' . resolve(expand('<sfile>:p:h')) . '/../common/magit_common.vim'
 
+" g:magit_unstaged_buffer_name: vim buffer name for vimagit
 let g:magit_unstaged_buffer_name = "magit-playground"
 
 " s:set: helper function to set user definable variable
@@ -53,13 +57,13 @@ call s:set('g:magit_show_help',                 1)
 " FIXME: it won't work when playing with multiple git directories wihtin one
 " vim session
 let s:magit_top_dir=''
-" magit#top_dir: return the absolute path of current git worktree
+" s:mg_top_dir: return the absolute path of current git worktree
 " return top directory
-function! magit#top_dir()
+function! s:mg_top_dir()
 	if ( s:magit_top_dir == '' )
-		let s:magit_top_dir=magit#strip(system("git rev-parse --show-toplevel")) . "/"
+		let s:magit_top_dir=<SID>mg_strip(system("git rev-parse --show-toplevel")) . "/"
 		if ( v:shell_error != 0 )
-			echoerr "Git error: " . top_dir
+			echoerr "Git error: " . s:magit_top_dir
 		endif
 	endif
 	return s:magit_top_dir
@@ -70,13 +74,13 @@ endfunction
 " FIXME: it won't work when playing with multiple git directories wihtin one
 " vim session
 let s:magit_git_dir=''
-" magit#git_dir: return the absolute path of current git worktree
+" s:mg_git_dir: return the absolute path of current git worktree
 " return git directory
-function! magit#git_dir()
+function! s:mg_git_dir()
 	if ( s:magit_git_dir == '' )
-		let s:magit_git_dir=magit#strip(system("git rev-parse --git-dir")) . "/"
+		let s:magit_git_dir=<SID>mg_strip(system("git rev-parse --git-dir")) . "/"
 		if ( v:shell_error != 0 )
-			echoerr "Git error: " . git_dir
+			echoerr "Git error: " . s:magit_git_dir
 		endif
 	endif
 	return s:magit_git_dir
@@ -86,16 +90,16 @@ endfunction
 " 'cd' otherwise
 let s:magit_cd_cmd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
 
-" magit#system: wrapper for system, which only takes String as input in vim,
+" s:mg_system: wrapper for system, which only takes String as input in vim,
 " although it can take String or List input in neovim.
 " INFO: temporarly change pwd to git top directory, then restore to previous
 " pwd at the end of function
 " param[in] ...: command + optional args
 " return: command output as a string
-function! magit#system(...)
+function! s:mg_system(...)
 	let dir = getcwd()
 	try
-		execute s:magit_cd_cmd . magit#top_dir()
+		execute s:magit_cd_cmd . <SID>mg_top_dir()
 		" List as system() input is since v7.4.247, it is safe to check
 		" systemlist, which is sine v7.4.248
 		if exists('*systemlist')
@@ -119,62 +123,71 @@ function! magit#system(...)
 	endtry
 endfunction
 
-" magit#systemlist: wrapper for systemlist, which only exists in neovim for
+" s:mg_systemlist: wrapper for systemlist, which only exists in neovim for
 " the moment.
 " INFO: temporarly change pwd to git top directory, then restore to previous
 " pwd at the end of function
 " param[in] ...: command + optional args to execute, args can be List or String
 " return: command output as a list
-function! magit#systemlist(...)
+function! s:mg_systemlist(...)
 	let dir = getcwd()
 	try
-		execute s:magit_cd_cmd . magit#top_dir()
+		execute s:magit_cd_cmd . <SID>mg_top_dir()
 		" systemlist since v7.4.248
 		if exists('*systemlist')
 			return call('systemlist', a:000)
 		else
-			return split(call('magit#system', a:000), '\n')
+			return split(call('<SID>mg_system', a:000), '\n')
 		endif
 	finally
 		execute s:magit_cd_cmd . dir
 	endtry
 endfunction
 
-" magit#underline: helper function to underline a string
+" s:mg_underline: helper function to underline a string
 " param[in] title: string to underline
 " return a string composed of strlen(title) '='
-function! magit#underline(title)
+function! s:mg_underline(title)
 	return substitute(a:title, ".", "=", "g")
 endfunction
 
-" magit#strip: helper function to strip a string
+" s:mg_strip: helper function to strip a string
 " WARNING: it only works with monoline string
 " param[in] string: string to strip
 " return: stripped string
-function! magit#strip(string)
+function! s:mg_strip(string)
 	return substitute(a:string, '^\s*\(.\{-}\)\s*\n\=$', '\1', '')
 endfunction
 
-" magit#join_list: helper function to concatente a list of strings with newlines
+" s:mg_join_list: helper function to concatente a list of strings with newlines
 " param[in] list: List to to concat
 " return: concatenated list
-function! magit#join_list(list)
+function! s:mg_join_list(list)
 	return join(a:list, "\n") . "\n"
 endfunction
 
-" magit#append_file: helper function to append to a file
+" s:mg_append_file: helper function to append to a file
 " Version working with file *possibly* containing trailing newline
 " param[in] file: filename to append
 " param[in] lines: List of lines to append
-function! magit#append_file(file, lines)
-	let fcontents=readfile(a:file, 'b')
+function! s:mg_append_file(file, lines)
+	let fcontents=[]
+	if ( filereadable(a:file) )
+		let fcontents=readfile(a:file, 'b')
+	endif
 	if !empty(fcontents) && empty(fcontents[-1])
 		call remove(fcontents, -1)
 	endif
 	call writefile(fcontents+a:lines, a:file, 'b')
 endfunction
 
-function! magit#get_diff(mode)
+" s:mg_get_diff: this function write in current buffer all file names and
+" related diffs for a given mode
+" filename are prefixed in git status ('new: ' , 'modified: ', ...)
+" WARNING: this function writes in file, it should only be called through
+" protected functions like magit#update_buffer
+" param[in] mode: can be 'staged' or 'unstaged'
+function! s:mg_get_diff(mode)
 
 	let staged_flag=""
 	if ( a:mode == 'staged' )
@@ -184,7 +197,7 @@ function! magit#get_diff(mode)
 		let status_position=1
 	endif
 
-	let status_list=magit#systemlist("git status --porcelain")
+	let status_list=<SID>mg_systemlist("git status --porcelain")
 	for file_status_line in status_list
 		let file_status=file_status_line[status_position]
 		let file_name=substitute(file_status_line, '.. \(.*\)$', '\1', '')
@@ -204,7 +217,7 @@ function! magit#get_diff(mode)
 			let file_name='"' . file_name . '"'
 		endif
 		let diff_cmd="git diff --no-ext-diff " . staged_flag . "--no-color --patch -- " . dev_null . " " .  file_name
-		let diff_list=magit#systemlist(diff_cmd)
+		let diff_list=<SID>mg_systemlist(diff_cmd)
 		if ( empty(diff_list) )
 			echoerr "diff command \"" . diff_cmd . "\" returned nothing"
 		endif
@@ -214,6 +227,7 @@ function! magit#get_diff(mode)
 	endfor
 endfunction
 
+" s:magit_inline_help: Dict containing inline help for each section
 let s:magit_inline_help = {
 			\ 'staged': [
 \'S      if cursor in diff header, unstage file',
@@ -235,7 +249,9 @@ let s:magit_inline_help = {
 \'       commit message',
 \'R      refresh magit buffer',
 \'h      toggle help showing in magit buffer',
-\'To disable this help by default, add "let g:magit_show_help=0" to .vimrc',
+\'',
+\'To disable inline default appearance, add "let g:magit_show_help=0" to .vimrc',
+\'You will still be able to toggle inline help with h',
 \],
 			\ 'commit': [
 \'C CC   commit all staged changes with commit mode previously set (normal or',
@@ -243,49 +259,73 @@ let s:magit_inline_help = {
 \],
 \}
 
-function! magit#get_inline_help_line_nb(section)
+" 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
+" return number of lines
+function! s:mg_get_inline_help_line_nb(section)
 	return ( g:magit_show_help == 1 ) ?
 		\ len(s:magit_inline_help[a:section]) : 0
 endfunction
 
-function! magit#section_help(section)
+" s:mg_section_help: this function writes in current buffer the inline help
+" for a given section, it does nothing if inline help is disabled.
+" WARNING: this function writes in file, it should only be called through
+" protected functions like magit#update_buffer
+" param[in] section: section identifier
+function! s:mg_section_help(section)
 	if ( g:magit_show_help == 1 )
 		silent put =s:magit_inline_help[a:section]
 	endif
 endfunction
 
-" magit#get_staged: this function writes in current buffer all staged files
+" 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 =<SID>mg_underline(g:magit_sections['info'])
+	silent put =''
+	let branch=<SID>mg_system("git rev-parse --abbrev-ref HEAD")
+	let commit=<SID>mg_system("git show -s --oneline")
+	silent put ='Current branch: ' . branch
+	silent put ='Last commit:    ' . commit
+	silent put =''
+endfunction
+
+" s:mg_get_staged: this function writes in current buffer all staged files
 " WARNING: this function writes in file, it should only be called through
 " protected functions like magit#update_buffer
-function! magit#get_staged()
+function! s:mg_get_staged()
 	silent put =''
 	silent put =g:magit_sections['staged']
-	call magit#section_help('staged')
-	silent put =magit#underline(g:magit_sections['staged'])
+	call <SID>mg_section_help('staged')
+	silent put =<SID>mg_underline(g:magit_sections['staged'])
 	silent put =''
 
-	call magit#get_diff('staged')
+	call <SID>mg_get_diff('staged')
 endfunction
 
-" magit#get_unstaged: this function writes in current buffer all unstaged
+" s:mg_get_unstaged: this function writes in current buffer all unstaged
 " and untracked files
 " WARNING: this function writes in file, it should only be called through
 " protected functions like magit#update_buffer
-function! magit#get_unstaged()
+function! s:mg_get_unstaged()
 	silent put =''
 	silent put =g:magit_sections['unstaged']
-	call magit#section_help('unstaged')
-	silent put =magit#underline(g:magit_sections['unstaged'])
+	call <SID>mg_section_help('unstaged')
+	silent put =<SID>mg_underline(g:magit_sections['unstaged'])
 	silent put =''
 
-	call magit#get_diff('unstaged')
+	call <SID>mg_get_diff('unstaged')
 endfunction
 
-" magit#get_stashes: this function write in current buffer all stashes
+" 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
-function! magit#get_stashes()
-	silent! let stash_list=magit#systemlist("git stash list")
+function! s:mg_get_stashes()
+	silent! let stash_list=<SID>mg_systemlist("git stash list")
 	if ( v:shell_error != 0 )
 		echoerr "Git error: " . stash_list
 	endif
@@ -293,7 +333,7 @@ function! magit#get_stashes()
 	if (!empty(stash_list))
 		silent put =''
 		silent put =g:magit_sections['stash']
-		silent put =magit#underline(g:magit_sections['stash'])
+		silent put =<SID>mg_underline(g:magit_sections['stash'])
 		silent put =''
 
 		for stash in stash_list
@@ -312,14 +352,14 @@ endfunction
 "       'CF': fixup commit mode, it should not be a global state mode
 let s:magit_commit_mode=''
 
-" magit#get_commit_section: this function writes in current buffer the commit
+" s:mg_get_commit_section: this function writes in current buffer the commit
 " section. It is a commit message, depending on s:magit_commit_mode
 " WARNING: this function writes in file, it should only be called through
 " protected functions like magit#update_buffer
 " param[in] s:magit_commit_mode: this function uses global commit mode
 "       'CC': prepare a brand new commit message
 "       'CA': get the last commit message
-function! magit#get_commit_section()
+function! s:mg_get_commit_section()
 	let commit_mode_str=""
 	if ( s:magit_commit_mode == 'CC' )
 		let commit_mode_str="normal"
@@ -329,26 +369,28 @@ function! magit#get_commit_section()
 	silent put =''
 	silent put =g:magit_sections['commit_start']
 	silent put ='Commit mode: '.commit_mode_str
-	call magit#section_help('commit')
-	silent put =magit#underline(g:magit_sections['commit_start'])
+	call <SID>mg_section_help('commit')
+	silent put =<SID>mg_underline(g:magit_sections['commit_start'])
 	silent put =''
 
-	let git_dir=magit#git_dir()
+	let git_dir=<SID>mg_git_dir()
 	" refresh the COMMIT_EDITMSG file
 	if ( s:magit_commit_mode == 'CC' )
-		silent! call magit#system("GIT_EDITOR=/bin/false git commit -e 2> /dev/null")
+		silent! call <SID>mg_system("GIT_EDITOR=/bin/false git commit -e 2> /dev/null")
 	elseif ( s:magit_commit_mode == 'CA' )
-		silent! call magit#system("GIT_EDITOR=/bin/false git commit --amend -e 2> /dev/null")
+		silent! call <SID>mg_system("GIT_EDITOR=/bin/false git commit --amend -e 2> /dev/null")
+	endif
+	if ( filereadable(git_dir . 'COMMIT_EDITMSG') )
+		let comment_char=<SID>mg_comment_char()
+		let commit_msg=<SID>mg_join_list(filter(readfile(git_dir . 'COMMIT_EDITMSG'), 'v:val !~ "^' . comment_char . '"'))
+		put =commit_msg
 	endif
-	let comment_char=magit#comment_char()
-	let commit_msg=magit#join_list(filter(readfile(git_dir . 'COMMIT_EDITMSG'), 'v:val !~ "^' . comment_char . '"'))
-	put =commit_msg
 	put =g:magit_sections['commit_end']
 endfunction
 
-" magit#comment_char: this function gets the commentChar from git config
-function! magit#comment_char()
-	silent! let git_result=magit#strip(magit#system("git config --get core.commentChar"))
+" s:mg_comment_char: this function gets the commentChar from git config
+function! s:mg_comment_char()
+	silent! let git_result=<SID>mg_strip(<SID>mg_system("git config --get core.commentChar"))
 	if ( v:shell_error != 0 )
 		return '#'
 	else
@@ -356,7 +398,7 @@ function! magit#comment_char()
 	endif
 endfunction
 
-" magit#search_block: helper function, to get a block of text, giving a start
+" s:mg_search_block: helper function, to get a block of text, giving a start
 " and multiple end pattern
 " a "pattern parameter" is a List:
 "   @[0]: end pattern regex
@@ -372,17 +414,15 @@ endfunction
 " return: a list.
 "      @[0]: return status
 "      @[1]: List of selected block lines
-function! magit#search_block(start_pattern, end_pattern, upper_limit_pattern)
+function! s:mg_search_block(start_pattern, end_pattern, upper_limit_pattern)
 	let l:winview = winsaveview()
 
 	let upper_limit=0
 	if ( a:upper_limit_pattern != "" )
-		let upper_limit=search(a:upper_limit_pattern, "bnW")
+		let upper_limit=search(a:upper_limit_pattern, "cbnW")
 	endif
 
-	" important if backward regex is at the beginning of the current line
-	call cursor(0, 100)
-	let start=search(a:start_pattern[0], "bW")
+	let start=search(a:start_pattern[0], "cbW")
 	if ( start == 0 )
 		call winrestview(l:winview)
 		return [1, ""]
@@ -413,7 +453,7 @@ function! magit#search_block(start_pattern, end_pattern, upper_limit_pattern)
 	return [0, lines]
 endfunction
 
-" magit#git_commit: commit staged stuff with message prepared in commit section
+" s:mg_git_commit: commit staged stuff with message prepared in commit section
 " param[in] mode: mode to commit
 "       'CF': don't use commit section, just amend previous commit with staged
 "       stuff, without modifying message
@@ -422,39 +462,38 @@ endfunction
 "       'CA': commit staged stuff with message in commit section amending last
 "       commit
 " return no
-function! magit#git_commit(mode)
+function! s:mg_git_commit(mode)
 	if ( a:mode == 'CF' )
-		silent let git_result=magit#system("git commit --amend -C HEAD")
+		silent let git_result=<SID>mg_system("git commit --amend -C HEAD")
 	else
 		let commit_section_pat_start='^'.g:magit_sections['commit_start'].'$'
 		let commit_section_pat_end='^'.g:magit_sections['commit_end'].'$'
-		let commit_jump_line = 3 + magit#get_inline_help_line_nb('commit')
-		let [ret, commit_msg]=magit#search_block(
+		let commit_jump_line = 3 + <SID>mg_get_inline_help_line_nb('commit')
+		let [ret, commit_msg]=<SID>mg_search_block(
 		 \ [commit_section_pat_start, commit_jump_line],
 		 \ [ [commit_section_pat_end, -1] ], "")
 		let amend_flag=""
 		if ( a:mode == 'CA' )
 			let amend_flag=" --amend "
 		endif
-		silent! let git_result=magit#system("git commit " . amend_flag . " --file - ", commit_msg)
+		silent! let git_result=<SID>mg_system("git commit " . amend_flag . " --file - ", commit_msg)
 	endif
 	if ( v:shell_error != 0 )
 		echoerr "Git error: " . git_result
 	endif
 endfunction
 
-" magit#select_file: select the whole diff file, relative to the current
+" s:mg_select_file: select the whole diff file, relative to the current
 " cursor position
 " nota: if the cursor is not in a diff file when the function is called, this
 " function will fail
 " return: a List
 "         @[0]: return value
 "         @[1]: List of lines containing the patch for the whole file
-function! magit#select_file()
-	return magit#search_block(
-				\ [g:magit_diff_re, 0],
-				\ [ [g:magit_diff_re, -1],
-				\   [g:magit_file_re, -1],
+function! s:mg_select_file()
+	return <SID>mg_search_block(
+				\ [g:magit_file_re, 1],
+				\ [ [g:magit_file_re, -1],
 				\   [g:magit_stash_re, -1],
 				\   [g:magit_section_re, -2],
 				\   [g:magit_bin_re, 0],
@@ -463,65 +502,69 @@ function! magit#select_file()
 				\ "")
 endfunction
 
-" magit#select_file_header: select the upper diff header, relative to the current
+" s:mg_select_file_header: select the upper diff header, relative to the current
 " cursor position
 " nota: if the cursor is not in a diff file when the function is called, this
 " function will fail
 " return: a List
 "         @[0]: return value
 "         @[1]: List of lines containing the diff header
-function! magit#select_file_header()
-	return magit#search_block(
-				\ [g:magit_diff_re, 0],
+function! s:mg_select_file_header()
+	return <SID>mg_search_block(
+				\ [g:magit_file_re, 1],
 				\ [ [g:magit_hunk_re, -1] ],
 				\ "")
 endfunction
 
-" magit#select_hunk: select a hunk, from the current cursor position
+" s:mg_select_hunk: select a hunk, from the current cursor position
 " nota: if the cursor is not in a hunk when the function is called, this
 " function will fail
 " return: a List
 "         @[0]: return value
 "         @[1]: List of lines containing the hunk
-function! magit#select_hunk()
-	return magit#search_block(
+function! s:mg_select_hunk()
+	return <SID>mg_search_block(
 				\ [g:magit_hunk_re, 0],
 				\ [ [g:magit_hunk_re, -1],
-				\   [g:magit_diff_re, -1],
 				\   [g:magit_file_re, -1],
 				\   [g:magit_stash_re, -1],
 				\   [g:magit_section_re, -2],
 				\   [g:magit_eof_re, 0 ]
 				\ ],
-				\ g:magit_diff_re)
+				\ g:magit_file_re)
 endfunction
 
-" magit#git_apply: helper function to stage a selection
+" s:mg_git_apply: helper function to stage a selection
 " nota: when git fail (due to misformated patch for example), an error
 " message is raised.
 " param[in] selection: the text to stage. It must be a patch, i.e. a diff 
 " header plus one or more hunks
 " return: no
-function! magit#git_apply(selection)
+function! s:mg_git_apply(selection)
 	let selection = a:selection
 	if ( selection[-1] !~ '^\s*$' )
 		let selection += [ '' ]
 	endif
-	silent let git_result=magit#system("git apply --cached -", selection)
+	" when passing List to system as input, there are some rare and
+	" difficultly reproductable cases failing because of whitespaces
+	let tmp=tempname()
+	call writefile(selection, tmp)
+	silent let git_result=<SID>mg_system("git apply --cached - < " . tmp)
 	if ( v:shell_error != 0 )
 		echoerr "Git error: " . git_result
 		echoerr "Tried to aply this"
 		echoerr string(a:selection)
 	endif
+	call delete(tmp)
 endfunction
 
-" magit#git_unapply: helper function to unstage a selection
+" s:mg_git_unapply: helper function to unstage a selection
 " nota: when git fail (due to misformated patch for example), an error
 " message is raised.
 " param[in] selection: the text to stage. It must be a patch, i.e. a diff 
 " header plus one or more hunks
 " return: no
-function! magit#git_unapply(selection, mode)
+function! s:mg_git_unapply(selection, mode)
 	let cached_flag=''
 	if ( a:mode == 'staged' )
 		let cached_flag=' --cached '
@@ -530,14 +573,26 @@ function! magit#git_unapply(selection, mode)
 	if ( selection[-1] !~ '^\s*$' )
 		let selection += [ '' ]
 	endif
-	silent let git_result=magit#system("git apply " . cached_flag . " --reverse - ", selection)
+	" when passing List to system as input, there are some rare and
+	" difficultly reproductable cases failing because of whitespaces
+	let tmp=tempname()
+	call writefile(selection, tmp)
+	silent let git_result=<SID>mg_system("git apply " . cached_flag . " --reverse - < " . tmp)
 	if ( v:shell_error != 0 )
 		echoerr "Git error: " . git_result
 		echoerr "Tried to unaply this"
 		echoerr string(a:selection)
 	endif
+	call delete(tmp)
 endfunction
 
+" s:mg_get_section: helper function to get the current section, according to
+" cursor position
+" return: string of the current section, without decoration
+function! s:mg_get_section()
+	let section_line=search(g:magit_section_re, "bnW")
+	return getline(section_line)
+endfunction
 " }}}
 
 " {{{ User functions and commands
@@ -561,26 +616,28 @@ function! magit#update_buffer()
 	let l:winview = winsaveview()
 	silent! %d
 	
-	call magit#section_help('global')
+	call <SID>mg_get_info()
+	call <SID>mg_section_help('global')
 	if ( s:magit_commit_mode != '' )
-		call magit#get_commit_section()
+		call <SID>mg_get_commit_section()
 	endif
-	call magit#get_staged()
-	call magit#get_unstaged()
-	call magit#get_stashes()
+	call <SID>mg_get_staged()
+	call <SID>mg_get_unstaged()
+	call <SID>mg_get_stashes()
 
 	call winrestview(l:winview)
 
 	if ( s:magit_commit_mode != '' )
 		let commit_section_pat_start='^'.g:magit_sections['commit_start'].'$'
 		silent! let section_line=search(commit_section_pat_start, "w")
-		silent! call cursor(section_line+3+magit#get_inline_help_line_nb('commit'), 0)
+		silent! call cursor(section_line+3+<SID>mg_get_inline_help_line_nb('commit'), 0)
 	endif
 
 	set filetype=magit
 
 endfunction
 
+" magit#toggle_help: toggle inline help showing in magit buffer
 function! magit#toggle_help()
 	let g:magit_show_help = ( g:magit_show_help == 0 ) ? 1 : 0
 	call magit#update_buffer()
@@ -589,7 +646,7 @@ endfunction
 " magit#show_magit: prepare and show magit buffer
 " it also set local mappings to magit buffer
 function! magit#show_magit(orientation)
-	if ( magit#strip(system("git rev-parse --is-inside-work-tree")) != 'true' )
+	if ( <SID>mg_strip(system("git rev-parse --is-inside-work-tree")) != 'true' )
 		echoerr "Magit must be started from a git repository"
 		return
 	endif
@@ -622,40 +679,32 @@ function! magit#show_magit(orientation)
 	execute "normal! gg"
 endfunction
 
-" magit#get_section: helper function to get the current section, according to
-" cursor position
-" return: string of the current section, without decoration
-function! magit#get_section()
-	let section_line=search(g:magit_section_re, "bnW")
-	return getline(section_line)
-endfunction
-
 " magit#stage_hunk: this function stage a single hunk, from the current
 " cursor position
 " INFO: in unstaged section, it stages the hunk, and in staged section, it
 " unstages the hunk
 " return: no
 function! magit#stage_hunk()
-	let [ret, header] = magit#select_file_header()
+	let [ret, header] = <SID>mg_select_file_header()
 	if ( ret != 0 )
 		echoerr "Can't find diff header"
 		return
 	endif
-	let [ret, hunk] = magit#select_hunk()
+	let [ret, hunk] = <SID>mg_select_hunk()
 	if ( ret == 0 )
 		let selection = header + hunk
 	else
-		let [ret, selection] = magit#select_file()
+		let [ret, selection] = <SID>mg_select_file()
 		if ( ret != 0 )
 			echoerr "Can't find diff header"
 			return
 		endif
 	endif
-	let section=magit#get_section()
+	let section=<SID>mg_get_section()
 	if ( section == g:magit_sections['unstaged'] )
-		call magit#git_apply(selection)
+		call <SID>mg_git_apply(selection)
 	elseif ( section == g:magit_sections['staged'] )
-		call magit#git_unapply(selection, 'staged')
+		call <SID>mg_git_unapply(selection, 'staged')
 	else
 		echoerr "Must be in \"" . 
 		 \ g:magit_sections['staged'] . "\" or \"" . 
@@ -670,16 +719,16 @@ endfunction
 " unstages the file
 " return: no
 function! magit#stage_file()
-	let [ret, selection] = magit#select_file()
+	let [ret, selection] = <SID>mg_select_file()
 	if ( ret != 0 )
 		echoerr "Not in a file region"
 		return
 	endif
-	let section=magit#get_section()
+	let section=<SID>mg_get_section()
 	if ( section == g:magit_sections['unstaged'] )
-		call magit#git_apply(selection)
+		call <SID>mg_git_apply(selection)
 	elseif ( section == g:magit_sections['staged'] )
-		call magit#git_unapply(selection, 'staged')
+		call <SID>mg_git_unapply(selection, 'staged')
 	else
 		echoerr "Must be in \"" . 
 		 \ g:magit_sections['staged'] . "\" or \"" . 
@@ -693,24 +742,24 @@ endfunction
 " INFO: only works in unstaged section
 " return: no
 function! magit#discard_hunk()
-	let [ret, header] = magit#select_file_header()
+	let [ret, header] = <SID>mg_select_file_header()
 	if ( ret != 0 )
 		echoerr "Can't find diff header"
 		return
 	endif
-	let [ret, hunk] = magit#select_hunk()
+	let [ret, hunk] = <SID>mg_select_hunk()
 	if ( ret == 0 )
 		let selection = header + hunk
 	else
-		let [ret, selection] = magit#select_file()
+		let [ret, selection] = <SID>mg_select_file()
 		if ( ret != 0 )
 			echoerr "Can't find diff header"
 			return
 		endif
 	endif
-	let section=magit#get_section()
+	let section=<SID>mg_get_section()
 	if ( section == g:magit_sections['unstaged'] )
-		call magit#git_unapply(selection, 'unstaged')
+		call <SID>mg_git_unapply(selection, 'unstaged')
 	else
 		echoerr "Must be in \"" . 
 		 \ g:magit_sections['unstaged'] . "\" section"
@@ -721,7 +770,7 @@ endfunction
 " magit#ignore_file: this function add the file under cursor to .gitignore
 " FIXME: git diff adds some strange characters to end of line
 function! magit#ignore_file()
-	let [ret, selection] = magit#select_file()
+	let [ret, selection] = <SID>mg_select_file()
 	if ( ret != 0 )
 		echoerr "Not in a file region"
 		return
@@ -729,7 +778,7 @@ function! magit#ignore_file()
 	let ignore_file=""
 	for line in selection
 		if ( match(line, "^+++ ") != -1 )
-			let ignore_file=magit#strip(substitute(line, '^+++ ./\(.*\)$', '\1', ''))
+			let ignore_file=<SID>mg_strip(substitute(line, '^+++ ./\(.*\)$', '\1', ''))
 			break
 		endif
 	endfor
@@ -737,7 +786,7 @@ function! magit#ignore_file()
 		echoerr "Can not find file to ignore"
 		return
 	endif
-	call magit#append_file(magit#top_dir() . ".gitignore", [ ignore_file ] )
+	call <SID>mg_append_file(<SID>mg_top_dir() . ".gitignore", [ ignore_file ] )
 	call magit#update_buffer()
 endfunction
 
@@ -748,9 +797,9 @@ endfunction
 "   'CA'/'CF': if in commit section mode, call magit#git_commit, else just set
 "   global state variable s:magit_commit_mode,
 function! magit#commit_command(mode)
-	let section=magit#get_section()
+	let section=<SID>mg_get_section()
 	if ( a:mode == 'CF' )
-		call magit#git_commit(a:mode)
+		call <SID>mg_git_commit(a:mode)
 	else
 		if ( section == g:magit_sections['commit_start'] )
 			if ( s:magit_commit_mode == '' )
@@ -759,7 +808,7 @@ function! magit#commit_command(mode)
 			endif
 			" when we do commit, it is prefered ot commit the way we prepared it
 			" (.i.e normal or amend), whatever we commit with CC or CA.
-			call magit#git_commit(s:magit_commit_mode)
+			call <SID>mg_git_commit(s:magit_commit_mode)
 			let s:magit_commit_mode=''
 		else
 			let s:magit_commit_mode=a:mode
diff --git a/test/addFile.vader b/test/addFile.vader
index af02e2f47669d24f94147569bffdc01fd6020b03..a26f58c10207635636c207c33e275fef0304f019 100644
--- a/test/addFile.vader
+++ b/test/addFile.vader
@@ -1,14 +1,154 @@
 Include: setup.inc
 
-# add test
-Execute (Add file):
+Execute (Stage untracked file with magit#stage_file at file header):
     call Cd_test_sub()
     Magit
-    /untracked: bootstrap
+    call Search_file('unstaged')
+    call Cursor_position()
+    call magit#stage_file()
+    call Cd_test()
+    let diff=Git_diff('staged', Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_file_diff.expect', diff)
+
+Execute (Unstage file with magit#stage_file at file header):
+    call Cd_test_sub()
+    Magit
+    call Search_file('staged')
+    call Cursor_position()
+    call magit#stage_file()
+    call Cd_test()
+    let diff=Git_status(Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff)
+
+Execute (Stage untracked file with magit#stage_file):
+    call Cd_test_sub()
+    Magit
+    call Search_file('unstaged')
+    call Move_relative(+1)
+    call Cursor_position()
+    call magit#stage_file()
+    call Cd_test()
+    let diff=Git_diff('staged', Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_file_diff.expect', diff)
+
+Execute (Unstage file with magit#stage_file):
+    call Cd_test_sub()
+    Magit
+    call Search_file('staged')
     call Move_relative(+1)
+    call Cursor_position()
     call magit#stage_file()
     call Cd_test()
-    let diff=Git_diff('staged', 'bootstrap')
-    call Expect_diff(g:test_dir . 'addFile_bootstrap.expect', diff)
+    let diff=Git_status(Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff)
+
+Execute (Stage untracked file with magit#stage_hunk at file header):
+    call Cd_test_sub()
+    Magit
+    call Search_file('unstaged')
+    call Cursor_position()
+    call magit#stage_hunk()
+    call Cd_test()
+    let diff=Git_diff('staged', Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_file_diff.expect', diff)
+
+Execute (Unstage file with magit#stage_hunk at file header):
+    call Cd_test_sub()
+    Magit
+    call Search_file('staged')
+    call Cursor_position()
+    call magit#stage_hunk()
+    call Cd_test()
+    let diff=Git_status(Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff)
+
+Execute (Stage untracked file with magit#stage_hunk on diff header):
+    call Cd_test_sub()
+    Magit
+    call Search_file('unstaged')
+    call Move_relative(+1)
+    call Cursor_position()
+    call magit#stage_hunk()
+    call Cd_test()
+    let diff=Git_diff('staged', Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_file_diff.expect', diff)
+
+Execute (Unstage file with magit#stage_hunk on diff header):
+    call Cd_test_sub()
+    Magit
+    call Search_file('staged')
+    call Move_relative(+1)
+    call Cursor_position()
+    call magit#stage_hunk()
+    call Cd_test()
+    let diff=Git_status(Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff)
+
+Execute (Stage untracked file with magit#stage_hunk on start hunk):
+    call Cd_test_sub()
+    Magit
+    call Search_file('unstaged')
+    /^@@ 
+    call Cursor_position()
+    call magit#stage_hunk()
+    call Cd_test()
+    let diff=Git_diff('staged', Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_hunk_diff.expect', diff)
+
+Execute (Unstage file with magit#stage_hunk on diff header):
+    call Cd_test_sub()
+    Magit
+    call Search_file('staged')
+    /^@@ 
+    call Cursor_position()
+    call magit#stage_hunk()
+    call Cd_test()
+    let diff=Git_status(Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff)
+
+Execute (Stage untracked file with magit#stage_hunk on end hunk):
+    call Cd_test_sub()
+    Magit
+    call Search_file('unstaged')
+    /^@@ 
+    call Move_relative(+3)
+    call Cursor_position()
+    call magit#stage_hunk()
+    call Cd_test()
+    let diff=Git_diff('staged', Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_hunk_diff.expect', diff)
+
+Execute (Unstage file with magit#stage_hunk on diff header):
+    call Cd_test_sub()
+    Magit
+    call Search_file('staged')
+    /^@@ 
+    call Move_relative(+3)
+    call Cursor_position()
+    call magit#stage_hunk()
+    call Cd_test()
+    let diff=Git_status(Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff)
+
+Execute (Stage untracked file with magit#stage_file at file header):
+    call Cd_test_sub()
+    Magit
+    call Search_file('unstaged')
+    call Cursor_position()
+    call magit#stage_file()
+    call Cd_test()
+    let diff=Git_diff('staged', Get_filename())
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_file_diff.expect', diff)
+
+Execute (Commit file):
+    call Cd_test_sub()
+    Magit
+    call magit#commit_command('CC')
+    put =['Add bootstrap file', '', 'Some description text', 'On multiple lines', '', 'With blanks']
+    call magit#commit_command('CC')
+    call Cd_test()
+    let commit_msg=Git_commit_msg('HEAD')
+    call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_commit.expect', commit_msg)
+    
 
 Include: cleanup.inc
diff --git a/test/addFile/addFile_books_models_py_commit.expect b/test/addFile/addFile_books_models_py_commit.expect
new file mode 100644
index 0000000000000000000000000000000000000000..7fc69eebb7b482d390025f25c3b1d03ed7c2df75
--- /dev/null
+++ b/test/addFile/addFile_books_models_py_commit.expect
@@ -0,0 +1,62 @@
+Add bootstrap fileAdd bootstrap file
+
+Some description text
+On multiple lines
+
+With blanks
+
+
+diff --git books/models.py books/models.py
+--- books/models.py
++++ books/models.py
+@@ -1,5 +1,9 @@
+ from django.db import models
+ 
++import urllib2 as urllib
++from PIL import Image
++import io
++
+ import isbn_search
+ 
+ class User(models.Model):
+@@ -20,20 +24,26 @@ class BookManager(models.Manager):
+ 				eisbn   = product.eisbn,
+ 				author  = product.author,
+ 				title   = product.title,
+-				edition = product.edition
++				edition = product.edition,
+ 				)
++		if product.cover_url is not '':
++			cover_img_bin = urllib.urlopen(product.cover_url)
++			cover_img_file = Image.open(io.BytesIO(cover_img_bin.read()))
++			book.cover_img.save("cover.jpg", cover_img_file)
+ 		return book
+ 
++def upload_path(book, filename):
++	return 'covers/%s/%s' % (book.isbn, filename)
++
+ class Book(models.Model):
+ 	isbn = models.CharField(max_length=10, unique=True)
+-	eisbn = models.CharField(max_length=13, blank=True)
++	eisbn = models.CharField(max_length=13, blank=True, null=True)
+ 	title = models.CharField(max_length=200)
+ 	author = models.CharField(max_length=200)
+-	edition = models.CharField(max_length=200, blank=True)
+-	cover = models.ImageField(upload_to='covers', blank=True)
++	edition = models.CharField(max_length=200, blank=True, null=True)
++	cover_img = models.ImageField(upload_to=upload_path)
+ 	def __unicode__(self):
+ 		return u'[%s] "%s" by %s' % (self.isbn, self.title, self.author,)
+-
+ 	objects = BookManager()
+ 
+ 
+@@ -47,7 +57,7 @@ class Book_copy(models.Model):
+ class Borrowing(models.Model):
+ 	book_copy = models.ForeignKey(Book_copy)
+ 	borrower = models.ForeignKey(User)
+-	borrow_date = models.DateTimeField('date published')
++	date = models.DateTimeField(auto_now_add=True)
+ 	def __unicode__(self):
+ 		return u'%s loaned by %s since %s' % (self.book_copy.book, self.borrower, self.borrow_date,)
+ 
diff --git a/test/addFile/addFile_books_models_py_file_diff.expect b/test/addFile/addFile_books_models_py_file_diff.expect
new file mode 100644
index 0000000000000000000000000000000000000000..78c9eb694492d1b406b7f891742d69b11d13883b
--- /dev/null
+++ b/test/addFile/addFile_books_models_py_file_diff.expect
@@ -0,0 +1,54 @@
+diff --git books/models.py books/models.py
+--- books/models.py
++++ books/models.py
+@@ -1,5 +1,9 @@
+ from django.db import models
+ 
++import urllib2 as urllib
++from PIL import Image
++import io
++
+ import isbn_search
+ 
+ class User(models.Model):
+@@ -20,20 +24,26 @@ class BookManager(models.Manager):
+ 				eisbn   = product.eisbn,
+ 				author  = product.author,
+ 				title   = product.title,
+-				edition = product.edition
++				edition = product.edition,
+ 				)
++		if product.cover_url is not '':
++			cover_img_bin = urllib.urlopen(product.cover_url)
++			cover_img_file = Image.open(io.BytesIO(cover_img_bin.read()))
++			book.cover_img.save("cover.jpg", cover_img_file)
+ 		return book
+ 
++def upload_path(book, filename):
++	return 'covers/%s/%s' % (book.isbn, filename)
++
+ class Book(models.Model):
+ 	isbn = models.CharField(max_length=10, unique=True)
+-	eisbn = models.CharField(max_length=13, blank=True)
++	eisbn = models.CharField(max_length=13, blank=True, null=True)
+ 	title = models.CharField(max_length=200)
+ 	author = models.CharField(max_length=200)
+-	edition = models.CharField(max_length=200, blank=True)
+-	cover = models.ImageField(upload_to='covers', blank=True)
++	edition = models.CharField(max_length=200, blank=True, null=True)
++	cover_img = models.ImageField(upload_to=upload_path)
+ 	def __unicode__(self):
+ 		return u'[%s] "%s" by %s' % (self.isbn, self.title, self.author,)
+-
+ 	objects = BookManager()
+ 
+ 
+@@ -47,7 +57,7 @@ class Book_copy(models.Model):
+ class Borrowing(models.Model):
+ 	book_copy = models.ForeignKey(Book_copy)
+ 	borrower = models.ForeignKey(User)
+-	borrow_date = models.DateTimeField('date published')
++	date = models.DateTimeField(auto_now_add=True)
+ 	def __unicode__(self):
+ 		return u'%s loaned by %s since %s' % (self.book_copy.book, self.borrower, self.borrow_date,)
+ 
diff --git a/test/addFile/addFile_books_models_py_hunk_diff.expect b/test/addFile/addFile_books_models_py_hunk_diff.expect
new file mode 100644
index 0000000000000000000000000000000000000000..4d9138a938c57a7b32e49aa6e00289063c97ab00
--- /dev/null
+++ b/test/addFile/addFile_books_models_py_hunk_diff.expect
@@ -0,0 +1,13 @@
+diff --git books/models.py books/models.py
+--- books/models.py
++++ books/models.py
+@@ -1,5 +1,9 @@
+ from django.db import models
+ 
++import urllib2 as urllib
++from PIL import Image
++import io
++
+ import isbn_search
+ 
+ class User(models.Model):
diff --git a/test/addFile/addFile_books_models_py_unstaged_status.expect b/test/addFile/addFile_books_models_py_unstaged_status.expect
new file mode 100644
index 0000000000000000000000000000000000000000..419e4688776dc934c2a0b47cbef082044814aae4
--- /dev/null
+++ b/test/addFile/addFile_books_models_py_unstaged_status.expect
@@ -0,0 +1 @@
+ M books/models.py
diff --git a/test/addFile/addFile_bootstrap_commit.expect b/test/addFile/addFile_bootstrap_commit.expect
new file mode 100644
index 0000000000000000000000000000000000000000..7056a6d61aac4a7983514e51ac2c6427e31950e0
--- /dev/null
+++ b/test/addFile/addFile_bootstrap_commit.expect
@@ -0,0 +1,16 @@
+Add bootstrap fileAdd bootstrap file
+
+Some description text
+On multiple lines
+
+With blanks
+
+
+diff --git bootstrap bootstrap
+new file mode 100755
+--- /dev/null
++++ bootstrap
+@@ -0,0 +1,3 @@
++pip install --user python-amazon-simple-product-api django
++python manage.py migrate
++python manage.py makemigrations books
diff --git a/test/addFile_bootstrap.expect b/test/addFile/addFile_bootstrap_file_diff.expect
similarity index 100%
rename from test/addFile_bootstrap.expect
rename to test/addFile/addFile_bootstrap_file_diff.expect
diff --git a/test/addFile/addFile_bootstrap_hunk_diff.expect b/test/addFile/addFile_bootstrap_hunk_diff.expect
new file mode 100644
index 0000000000000000000000000000000000000000..76e066c4387ad7187987eb805fae4a31d177c8e3
--- /dev/null
+++ b/test/addFile/addFile_bootstrap_hunk_diff.expect
@@ -0,0 +1,8 @@
+diff --git bootstrap bootstrap
+new file mode 100755
+--- /dev/null
++++ bootstrap
+@@ -0,0 +1,3 @@
++pip install --user python-amazon-simple-product-api django
++python manage.py migrate
++python manage.py makemigrations books
diff --git a/test/addFile/addFile_bootstrap_unstaged_status.expect b/test/addFile/addFile_bootstrap_unstaged_status.expect
new file mode 100644
index 0000000000000000000000000000000000000000..b4b587b9dec49ff2da0c517e2a5cb1020a090921
--- /dev/null
+++ b/test/addFile/addFile_bootstrap_unstaged_status.expect
@@ -0,0 +1 @@
+?? bootstrap
diff --git a/test/ignoreFile.vader b/test/ignoreFile.vader
new file mode 100644
index 0000000000000000000000000000000000000000..8287d314bfccf3f3accfefefd65790c5e06b21d8
--- /dev/null
+++ b/test/ignoreFile.vader
@@ -0,0 +1,20 @@
+Include: setup.inc
+
+Execute (Ignore untracked file):
+    call Cd_test_sub()
+    Magit
+    call Search_file('unstaged')
+    call Cursor_position()
+    call magit#ignore_file()
+    call Cd_test()
+    let diff=Git_diff('unstaged', '.gitignore')
+    call Expect_diff(g:test_script_dir . 'ignoreFile/ignoreFile_' . Get_safe_filename() . '_ignore_diff.expect', diff)
+    call magit#update_buffer()
+    Assert (Search_file('unstaged') == 0), $VIMAGIT_TEST_FILENAME . 'should be ignored'
+    call search('^modified: .gitignore$')
+    call magit#discard_hunk()
+    call magit#update_buffer()
+    Assert (Search_file('unstaged') != 0), $VIMAGIT_TEST_FILENAME . 'should not be ignored anymore'
+
+
+Include: cleanup.inc
diff --git a/test/ignoreFile/ignoreFile_bootstrap_ignore_diff.expect b/test/ignoreFile/ignoreFile_bootstrap_ignore_diff.expect
new file mode 100644
index 0000000000000000000000000000000000000000..ac7158716e5ea0e44d80c4a6d5a691c89a081258
--- /dev/null
+++ b/test/ignoreFile/ignoreFile_bootstrap_ignore_diff.expect
@@ -0,0 +1,9 @@
+diff --git .gitignore .gitignore
+--- .gitignore
++++ .gitignore
+@@ -1,3 +1,4 @@
+ *.py[co]
+ /db.sqlite3
+ /books.cfg
++bootstrap
+\ No newline at end of file
diff --git a/test/run.sh b/test/run.sh
index 96d7578bd927b89e7dfefc9f9f27aa9dfbb3ae9a..24a2d162fbf7fc0be84192fae681ca2cff52ac6e 100755
--- a/test/run.sh
+++ b/test/run.sh
@@ -1,7 +1,7 @@
 set -xe
 
-if [[ $# -ne 3 ]]; then
-	echo "Usage $0 VIMAGIT_PATH VADER_PATH TEST_PATH"
+if [[ $# -ne 4 ]]; then
+	echo "Usage $0 VIMAGIT_PATH VADER_PATH TEST_PATH VIM_VERSION"
 	exit 1
 fi
 
@@ -12,21 +12,55 @@ python -c "import os,sys; print(os.path.realpath(os.path.expanduser(sys.argv[1])
 export VIMAGIT_PATH=$(prealpath $1)
 export VADER_PATH=$(prealpath $2)
 export TEST_PATH=$(prealpath $3)
-export TEST_SUB_PATH=$(prealpath $TEST_PATH/$TEST_SUB_PATH)
+export VIM_VERSION=$4
 
-if [[ ! ( -d $VIMAGIT_PATH && -d $VADER_PATH && -d $TEST_PATH && -d $TEST_SUB_PATH) ]]; then
-	echo "can't access to one of them '$VIMAGIT_PATH' '$VADER_PATH' '$TEST_PATH' '$TEST_SUB_PATH'"
+if [[ ! ( -d $VIMAGIT_PATH && -d $VADER_PATH && -d $TEST_PATH ) ]]; then
+	echo "can't access to one of them '$VIMAGIT_PATH' '$VADER_PATH' '$TEST_PATH'"
 	exit 1
 fi
 
+pushd $TEST_PATH
+git config --local user.email 'tester@vimagit.org'
+git config --local user.name 'vimagit tester'
 export TEST_HEAD_SHA1='6efcd49'
+popd
 
-vim -Nu <(cat << EOF
-filetype off
-set rtp-=~/.vim
-set rtp-=~/.vim/after
-set rtp+=$VIMAGIT_PATH
-set rtp+=$VADER_PATH
-filetype plugin indent on
-syntax enable
-EOF) -c "Vader! $VIMAGIT_PATH/test/*"
+if [ "$VIM_VERSION" = 'neovim' ]; then
+	VIM=nvim
+elif [ "$VIM_VERSION" = 'macvim' ]; then
+	VIM=mvim
+else
+	VIM=vim
+fi
+
+echo 'Vim version'
+$VIM --version
+
+source $VIMAGIT_PATH/test/test.config
+
+for script in ${!test_scripts[@]}; do
+
+	for filename in ${test_scripts[$script]}; do
+		for test_path in ${test_paths[@]}; do
+			export TEST_SUB_PATH=$(prealpath $TEST_PATH/$test_path)
+			export VIMAGIT_TEST_FILENAME=$filename
+
+			for i in 1 0; do
+				export VIMAGIT_TEST_FROM_EOL=$i
+
+				echo "Test $script with $filename from path $TEST_SUB_PATH and from $([ $i -eq 1 ] && echo "end" || echo "start") of line"
+
+				$VIM -Nu <(cat << EOF
+				filetype off
+				set rtp-=~/.vim
+				set rtp-=~/.vim/after
+				set rtp+=$VIMAGIT_PATH
+				set rtp+=$VADER_PATH
+				filetype plugin indent on
+				syntax enable
+EOF) -c "Vader! $VIMAGIT_PATH/test/$script"
+
+			done
+		done
+	done
+done
diff --git a/test/setup.inc b/test/setup.inc
index b9a8785bd90ba51655af7aa64dc726ba98e97304..fa73d19e98955ada5fb534eb1ac313fa4a6e6d56 100644
--- a/test/setup.inc
+++ b/test/setup.inc
@@ -1,5 +1,5 @@
 Execute (setup):
   source $VIMAGIT_PATH/test/utils.vim
-  cd $TEST_PATH
+  call Cd_test()
   call system("git reset " . $TEST_HEAD_SHA1 . "~1")
-  cd $TEST_SUB_PATH
+  call Cd_test_sub()
diff --git a/test/test.config b/test/test.config
new file mode 100644
index 0000000000000000000000000000000000000000..f6c49aa2bfb1fd80185e7bd7f0c755caaf2032b9
--- /dev/null
+++ b/test/test.config
@@ -0,0 +1,2 @@
+declare -a test_paths=(./ ./books/templates/)
+declare -A test_scripts=( [addFile.vader]='bootstrap books/models.py' [ignoreFile.vader]='bootstrap' )
diff --git a/test/utils.vim b/test/utils.vim
index c8f54f78a05458f31bbed3846b0ca640c0c10cd2..410d7f56c8f80d4e503fc8ec4073c0419e7b0fbb 100644
--- a/test/utils.vim
+++ b/test/utils.vim
@@ -1,42 +1,137 @@
-if ( ! ( exists("$VIMAGIT_PATH") && exists("$VADER_PATH") && exists("$TEST_PATH") ) 
-\ && ( ! ( isdirectory("$VIMAGIT_PATH") && isdirectory("$VADER_PATH") && isdirectory("$TEST_PATH") ) ) )
-	echoerr "can't access to one of them '$VIMAGIT_PATH' '$VADER_PATH' '$TEST_PATH'"
+"This file contains utility functions for tests, and wrapper around
+"environment variables. Env var are the way found to run the same test with
+"different configurations.
+
+" These environment variables must be exported from bash
+" $VIMAGIT_PATH: vimagit plugin root path
+" $VADER_PATH: vader plugin root path
+" $TEST_PATH: git dir used for test root path
+" $TEST_SUB_PATH: git dir used for test subdir path (we want to test vimagit commands from subdirs)
+" $VIMAGIT_TEST_FILENAME: filename we test (stage/unstage/ignore...)
+" $VIMAGIT_TEST_FROM_EOL: change cursor initial position before a command test see Cursor_position()
+" Optionals
+" $VIMAGIT_CRAFT_EXPECT: see Is_crafting() and Expect_diff()
+if ( ! ( exists("$VIMAGIT_PATH") && exists("$VADER_PATH") && exists("$TEST_PATH") && exists("$TEST_SUB_PATH") )  
+\ && ( ! ( isdirectory("$VIMAGIT_PATH") && isdirectory("$VADER_PATH") && isdirectory("$TEST_PATH")  && isdirectory("$TEST_PATH"."/"."$TEST_SUB_PATH")) ) )
+	echoerr "can't access to one of them '$VIMAGIT_PATH' '$VADER_PATH' '$TEST_PATH' '$TEST_SUB_PATH'"
+endif
+
+if ( ! ( exists('$VIMAGIT_TEST_FILENAME') ) )
+	echoerr "env VIMAGIT_TEST_FILENAME is not set"
 endif
 
-let g:test_dir = $VIMAGIT_PATH . '/test/'
 
+" directory containing test scripts and golden files
+let g:test_script_dir = $VIMAGIT_PATH . '/test/'
+" regex to discard sha1 lines in diff, commit, ... git messages
+" we don't want them because they change at each run, we can't put them in
+" golden files
+let g:index_regex = "\"^index [[:xdigit:]]\\{7\\}\\.\\.[[:xdigit:]]\\{7\\}\""
+
+" this method is used to generate gold files
+" when envvar VIMAGIT_CRAFT_EXPECT is set, we don't check diff with gold
+" files, we create them.
+function! Is_crafting()
+	return exists("$VIMAGIT_CRAFT_EXPECT") ? $VIMAGIT_CRAFT_EXPECT : 0
+endfunction
+
+" helper function to move cursor few lines up or down
 function! Move_relative(nb_lines)
 	call cursor(line('.') + a:nb_lines, 0)
 endfunction
 
+" wrapper to execute command, echoerr'ing complete message in case of error
+function! Git_cmd(...)
+	let ret=call('system', a:000)
+	if ( v:shell_error != 0 )
+		echoerr "Error:\ncommand:\n" . join(a:000, "\n") . "\nret:\n" . ret
+	endif
+	return ret
+endfunction
+
+" helper function to get a commit message (without sha1)
+function! Git_commit_msg(sha1)
+	let commit_cmd="git show --src-prefix='' --dst-prefix='' --format='%s%B' " . a:sha1 .
+				\ " | \\grep -v " . g:index_regex
+	return Git_cmd(commit_cmd)
+endfunction
+
+" helper function to get status of a given file
+function! Git_status(file)
+	call Cd_test()
+	let status_cmd="git status --porcelain -- " . a:file
+	let status=Git_cmd(status_cmd)
+	call Cd_test_sub()
+	return status
+endfunction
+
+" helper function to get the diff of a file, in staged or unstaged mode
 function! Git_diff(state, file)
 	let staged_flag = ( a:state == 'staged' ) ? ' --staged ' : ''
 	let diff_cmd="git diff --no-color --no-ext-diff --src-prefix='' --dst-prefix='' " .
 				\ staged_flag . " -- " . a:file .
-				\ " | \\grep -v \"^index [[:xdigit:]]\\{7\\}\\.\\.[[:xdigit:]]\\{7\\}\""
-	let diff=system(diff_cmd)
-	if ( v:shell_error != 0 )
-		echoerr "git diff: " . diff
-	endif
-	return diff
+				\ " | \\grep -v " . g:index_regex
+	return Git_cmd(diff_cmd)
 endfunction
 
+" helper function to:
+" - check if output is conform to gold file if VIMAGIT_CRAFT_EXPECT == 0
+" - generate gold file with output if VIMAGIT_CRAFT_EXPECT == 0
 function! Expect_diff(gold_file, test_diff)
-    let diff=system("diff " . a:gold_file . " - ", a:test_diff)
-	if ( v:shell_error != 0 )
-		echoerr "diff: " . diff
+	if ( Is_crafting() == 0 )
+		let diff_cmd="diff " . a:gold_file . " - "
+		let diff=system(diff_cmd, a:test_diff)
+		if ( v:shell_error != 0 )
+			echoerr "diff: " . diff
+			echoerr "diffcmd: " . diff_cmd
+		endif
+		return v:shell_error
+	else
+		let ret=writefile(split(a:test_diff, '\n'), a:gold_file, "w")
+		if ( ret != 0 )
+			echoerr 'Error while writing ' . a:gold_file
+		endif
+	endif
+endfunction
+
+" we want to test every magit command with cursor at the begenning and at the
+" end of the line before calling the command
+function! Cursor_position()
+	if ( exists("$VIMAGIT_TEST_FROM_EOL") ? $VIMAGIT_TEST_FROM_EOL : 0 )
+		call cursor(0, virtcol('$'))
+	else
+		call cursor(0, 1)
 	endif
-	return v:shell_error
 endfunction
 
+" set cwd to vimagit path
 function! Cd_vimagit()
 	cd $VIMAGIT_PATH
 endfunction
 
+" set cwd to git test directory root
 function! Cd_test()
 	cd $TEST_PATH
 endfunction
 
+" set cwd to git test directory subdir (see $TEST_SUB_PATH)
 function! Cd_test_sub()
 	cd $TEST_SUB_PATH
 endfunction
+
+" search a file header in magit buffer, for example 'added: bootstrap', move
+" the cursor and return the line
+function! Search_file(mode)
+	call search(substitute(a:mode, '.*', '\u\0', '') . ' changes')
+	return search("^.*: " . $VIMAGIT_TEST_FILENAME)
+endfunction
+
+" get the filename we curently test
+function! Get_filename()
+	return $VIMAGIT_TEST_FILENAME
+endfunction
+
+" get a safe to use string of filename we curently test (for golden files)
+function! Get_safe_filename()
+	return substitute($VIMAGIT_TEST_FILENAME, '[/.]', '_', 'g')
+endfunction