@@ -53,6 +53,7 @@ const (
5353 DiffFileChange
5454 DiffFileDel
5555 DiffFileRename
56+ DiffFileCopy
5657)
5758
5859// DiffLineExpandDirection represents the DiffLineSection expand direction
@@ -447,7 +448,46 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
447448 }
448449 line := linebuf .String ()
449450
450- if strings .HasPrefix (line , "+++ " ) || strings .HasPrefix (line , "--- " ) || len (line ) == 0 {
451+ if strings .HasPrefix (line , "--- " ) {
452+ if line [4 ] == '"' {
453+ fmt .Sscanf (line [4 :], "%q" , & curFile .OldName )
454+ } else {
455+ curFile .OldName = line [4 :]
456+ if strings .Contains (curFile .OldName , " " ) {
457+ // Git adds a terminal \t if there is a space in the name
458+ curFile .OldName = curFile .OldName [:len (curFile .OldName )- 1 ]
459+ }
460+ }
461+ if curFile .OldName [0 :2 ] == "a/" {
462+ curFile .OldName = curFile .OldName [2 :]
463+ }
464+ continue
465+ } else if strings .HasPrefix (line , "+++ " ) {
466+ if line [4 ] == '"' {
467+ fmt .Sscanf (line [4 :], "%q" , & curFile .Name )
468+ } else {
469+ curFile .Name = line [4 :]
470+ if strings .Contains (curFile .Name , " " ) {
471+ // Git adds a terminal \t if there is a space in the name
472+ curFile .Name = curFile .Name [:len (curFile .Name )- 1 ]
473+ }
474+ }
475+ if curFile .Name [0 :2 ] == "b/" {
476+ curFile .Name = curFile .Name [2 :]
477+ }
478+ curFile .IsRenamed = (curFile .Name != curFile .OldName ) && ! (curFile .IsCreated || curFile .IsDeleted )
479+ if curFile .IsDeleted {
480+ curFile .Name = curFile .OldName
481+ curFile .OldName = ""
482+ } else if curFile .IsCreated {
483+ curFile .OldName = ""
484+ }
485+ continue
486+ } else if len (line ) == 0 {
487+ continue
488+ }
489+
490+ if strings .HasPrefix (line , "+++" ) || strings .HasPrefix (line , "---" ) || len (line ) == 0 {
451491 continue
452492 }
453493
@@ -531,36 +571,10 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
531571 break
532572 }
533573
534- // Note: In case file name is surrounded by double quotes (it happens only in git-shell).
535- // e.g. diff --git "a/xxx" "b/xxx"
536- var a string
537- var b string
538-
539- rd := strings .NewReader (line [len (cmdDiffHead ):])
540- char , _ := rd .ReadByte ()
541- _ = rd .UnreadByte ()
542- if char == '"' {
543- fmt .Fscanf (rd , "%q " , & a )
544- } else {
545- fmt .Fscanf (rd , "%s " , & a )
546- }
547- char , _ = rd .ReadByte ()
548- _ = rd .UnreadByte ()
549- if char == '"' {
550- fmt .Fscanf (rd , "%q" , & b )
551- } else {
552- fmt .Fscanf (rd , "%s" , & b )
553- }
554- a = a [2 :]
555- b = b [2 :]
556-
557574 curFile = & DiffFile {
558- Name : b ,
559- OldName : a ,
560- Index : len (diff .Files ) + 1 ,
561- Type : DiffFileChange ,
562- Sections : make ([]* DiffSection , 0 , 10 ),
563- IsRenamed : a != b ,
575+ Index : len (diff .Files ) + 1 ,
576+ Type : DiffFileChange ,
577+ Sections : make ([]* DiffSection , 0 , 10 ),
564578 }
565579 diff .Files = append (diff .Files , curFile )
566580 curFileLinesCount = 0
@@ -569,6 +583,7 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
569583 curFileLFSPrefix = false
570584
571585 // Check file diff type and is submodule.
586+ loop:
572587 for {
573588 line , err := input .ReadString ('\n' )
574589 if err != nil {
@@ -579,23 +594,67 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
579594 }
580595 }
581596
582- switch {
583- case strings .HasPrefix (line , "new file" ):
584- curFile .Type = DiffFileAdd
585- curFile .IsCreated = true
586- case strings .HasPrefix (line , "deleted" ):
587- curFile .Type = DiffFileDel
588- curFile .IsDeleted = true
589- case strings .HasPrefix (line , "index" ):
590- curFile .Type = DiffFileChange
591- case strings .HasPrefix (line , "similarity index 100%" ):
592- curFile .Type = DiffFileRename
593- }
594- if curFile .Type > 0 {
595- if strings .HasSuffix (line , " 160000\n " ) {
596- curFile .IsSubmodule = true
597+ if curFile .Type != DiffFileRename {
598+ switch {
599+ case strings .HasPrefix (line , "new file" ):
600+ curFile .Type = DiffFileAdd
601+ curFile .IsCreated = true
602+ case strings .HasPrefix (line , "deleted" ):
603+ curFile .Type = DiffFileDel
604+ curFile .IsDeleted = true
605+ case strings .HasPrefix (line , "index" ):
606+ curFile .Type = DiffFileChange
607+ case strings .HasPrefix (line , "similarity index 100%" ):
608+ curFile .Type = DiffFileRename
609+ }
610+ if curFile .Type > 0 && curFile .Type != DiffFileRename {
611+ if strings .HasSuffix (line , " 160000\n " ) {
612+ curFile .IsSubmodule = true
613+ }
614+ break
615+ }
616+ } else {
617+ switch {
618+ case strings .HasPrefix (line , "rename from " ):
619+ if line [12 ] == '"' {
620+ fmt .Sscanf (line [12 :], "%q" , & curFile .OldName )
621+ } else {
622+ curFile .OldName = line [12 :]
623+ curFile .OldName = curFile .OldName [:len (curFile .OldName )- 1 ]
624+ }
625+ case strings .HasPrefix (line , "rename to " ):
626+ if line [10 ] == '"' {
627+ fmt .Sscanf (line [10 :], "%q" , & curFile .Name )
628+ } else {
629+ curFile .Name = line [10 :]
630+ curFile .Name = curFile .Name [:len (curFile .Name )- 1 ]
631+ }
632+ curFile .IsRenamed = true
633+ break loop
634+ case strings .HasPrefix (line , "copy from " ):
635+ if line [10 ] == '"' {
636+ fmt .Sscanf (line [10 :], "%q" , & curFile .OldName )
637+ } else {
638+ curFile .OldName = line [10 :]
639+ curFile .OldName = curFile .OldName [:len (curFile .OldName )- 1 ]
640+ }
641+ case strings .HasPrefix (line , "copy to " ):
642+ if line [8 ] == '"' {
643+ fmt .Sscanf (line [8 :], "%q" , & curFile .Name )
644+ } else {
645+ curFile .Name = line [8 :]
646+ curFile .Name = curFile .Name [:len (curFile .Name )- 1 ]
647+ }
648+ curFile .IsRenamed = true
649+ curFile .Type = DiffFileCopy
650+ break loop
651+ default :
652+ if strings .HasSuffix (line , " 160000\n " ) {
653+ curFile .IsSubmodule = true
654+ } else {
655+ break loop
656+ }
597657 }
598- break
599658 }
600659 }
601660 }
0 commit comments