@@ -61,7 +61,8 @@ var showFileChanges = function(file, cached) {
6161 Controller . refresh ( ) ;
6262 }
6363
64- if ( file . status == 0 ) // New file?
64+ // Only an untracked file is shown whole; a staged addition has a real diff on both sides
65+ if ( file . status == 0 && ! file . hasStagedChanges ) // Untracked file?
6566 return showNewFile ( file ) ;
6667
6768 setTitle ( ( cached ? "Staged" : "Unstaged" ) + " changes for " + file . path ) ;
@@ -378,12 +379,32 @@ var stageLines = function(reverse) {
378379 patch += l + "\n" ;
379380 }
380381 }
381- patch = diffHeader + '\n' + "@@ -" + start_old . toString ( ) + "," + count [ 0 ] . toString ( ) +
382+ var header = diffHeader ;
383+ if ( start_old == 0 && count [ 0 ] > 0 ) {
384+ // Old side empty (addition, empty file gaining lines, insert at top with
385+ // context 0): git won't partially reverse a creation header, so unstage the
386+ // selection as a modification of the index entry. A full selection keeps
387+ // the header and removes the entry, like the hunk button
388+ header = modificationHeader ( diffHeader ) ;
389+ start_old = 1 ;
390+ }
391+ patch = header + '\n' + "@@ -" + start_old . toString ( ) + "," + count [ 0 ] . toString ( ) +
382392 " +" + start_new . toString ( ) + "," + count [ 1 ] . toString ( ) + " @@\n" + patch ;
383393
384394 addHunkText ( patch , reverse ) ;
385395}
386396
397+ /* Plain modification header for the path of any diff header. Git writes both
398+ * names on the "diff --git A B" line the same length, so splitting at the
399+ * middle is safe for paths with spaces or quotes */
400+ var modificationHeader = function ( header )
401+ {
402+ var names = header . split ( "\n" ) [ 0 ] . replace ( / ^ d i f f - - g i t / , "" ) ;
403+ var half = ( names . length - 1 ) / 2 ;
404+ var a = names . substr ( 0 , half ) , b = names . substr ( half + 1 ) ;
405+ return "diff --git " + a + " " + b + "\n--- " + a + "\n+++ " + b ;
406+ }
407+
387408/* Compute the selection before actually making it. Return as object
388409 * with 2-element array "bounds", and "good", which indicates if the
389410 * selection contains add/del lines. */
0 commit comments