Following further testing it has become apparent that the diff line cannot be used to determine filenames for diffs with any sort of predictability the answer therefore is to use the other lines that are provided with a diff Fix #12768
Showing the changes to services/gitdiff/gitdiff.go (1 of 3 files). Show all
Unified · Split
| @@ -53,6 +53,7 @@ const ( · 52 unmodified lines | ||
| 53 | 53 | DiffFileChange |
| 54 | 54 | DiffFileDel |
| 55 | 55 | DiffFileRename |
| 56 | + DiffFileCopy | |
| 56 | 57 | ) |
| 57 | 58 | |
| 58 | 59 | // DiffLineExpandDirection represents the DiffLineSection expand direction |
| @@ -481,7 +482,46 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D · 422 unmodified lines | ||
| 481 | 482 | } |
| 482 | 483 | line := linebuf.String() |
| 483 | 484 | |
| 484 | − if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") || len(line) == 0 { | |
| 485 | + if strings.HasPrefix(line, "--- ") { | |
| 486 | + if line[4] == '"' { | |
| 487 | + fmt.Sscanf(line[4:], "%q", &curFile.OldName) | |
| 488 | + } else { | |
| 489 | + curFile.OldName = line[4:] | |
| 490 | + if strings.Contains(curFile.OldName, " ") { | |
| 491 | + // Git adds a terminal \t if there is a space in the name | |
| 492 | + curFile.OldName = curFile.OldName[:len(curFile.OldName)-1] | |
| 493 | + } | |
| 494 | + } | |
| 495 | + if curFile.OldName[0:2] == "a/" { | |
| 496 | + curFile.OldName = curFile.OldName[2:] | |
| 497 | + } | |
| 498 | + continue | |
| 499 | + } else if strings.HasPrefix(line, "+++ ") { | |
| 500 | + if line[4] == '"' { | |
| 501 | + fmt.Sscanf(line[4:], "%q", &curFile.Name) | |
| 502 | + } else { | |
| 503 | + curFile.Name = line[4:] | |
| 504 | + if strings.Contains(curFile.Name, " ") { | |
| 505 | + // Git adds a terminal \t if there is a space in the name | |
| 506 | + curFile.Name = curFile.Name[:len(curFile.Name)-1] | |
| 507 | + } | |
| 508 | + } | |
| 509 | + if curFile.Name[0:2] == "b/" { | |
| 510 | + curFile.Name = curFile.Name[2:] | |
| 511 | + } | |
| 512 | + curFile.IsRenamed = (curFile.Name != curFile.OldName) && !(curFile.IsCreated || curFile.IsDeleted) | |
| 513 | + if curFile.IsDeleted { | |
| 514 | + curFile.Name = curFile.OldName | |
| 515 | + curFile.OldName = "" | |
| 516 | + } else if curFile.IsCreated { | |
| 517 | + curFile.OldName = "" | |
| 518 | + } | |
| 519 | + continue | |
| 520 | + } else if len(line) == 0 { | |
| 521 | + continue | |
| 522 | + } | |
| 523 | + | |
| 524 | + if strings.HasPrefix(line, "+++") || strings.HasPrefix(line, "---") || len(line) == 0 { | |
| 485 | 525 | continue |
| 486 | 526 | } |
| 487 | 527 | |
| @@ -569,36 +609,10 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D · 81 unmodified lines | ||
| 569 | 609 | break |
| 570 | 610 | } |
| 571 | 611 | |
| 572 | − // Note: In case file name is surrounded by double quotes (it happens only in git-shell). | |
| 573 | − // e.g. diff --git "a/xxx" "b/xxx" | |
| 574 | − var a string | |
| 575 | − var b string | |
| 576 | − | |
| 577 | − rd := strings.NewReader(line[len(cmdDiffHead):]) | |
| 578 | − char, _ := rd.ReadByte() | |
| 579 | − _ = rd.UnreadByte() | |
| 580 | − if char == '"' { | |
| 581 | − fmt.Fscanf(rd, "%q ", &a) | |
| 582 | − } else { | |
| 583 | − fmt.Fscanf(rd, "%s ", &a) | |
| 584 | − } | |
| 585 | − char, _ = rd.ReadByte() | |
| 586 | − _ = rd.UnreadByte() | |
| 587 | − if char == '"' { | |
| 588 | − fmt.Fscanf(rd, "%q", &b) | |
| 589 | − } else { | |
| 590 | − fmt.Fscanf(rd, "%s", &b) | |
| 591 | − } | |
| 592 | − a = a[2:] | |
| 593 | − b = b[2:] | |
| 594 | − | |
| 595 | 612 | curFile = &DiffFile{ |
| 596 | − Name: b, | |
| 597 | − OldName: a, | |
| 598 | − Index: len(diff.Files) + 1, | |
| 599 | − Type: DiffFileChange, | |
| 600 | − Sections: make([]*DiffSection, 0, 10), | |
| 601 | − IsRenamed: a != b, | |
| 613 | + Index: len(diff.Files) + 1, | |
| 614 | + Type: DiffFileChange, | |
| 615 | + Sections: make([]*DiffSection, 0, 10), | |
| 602 | 616 | } |
| 603 | 617 | diff.Files = append(diff.Files, curFile) |
| 604 | 618 | curFileLinesCount = 0 |
| @@ -607,6 +621,7 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D · 2 unmodified lines | ||
| 607 | 621 | curFileLFSPrefix = false |
| 608 | 622 | |
| 609 | 623 | // Check file diff type and is submodule. |
| 624 | + loop: | |
| 610 | 625 | for { |
| 611 | 626 | line, err := input.ReadString('\n') |
| 612 | 627 | if err != nil { |
| @@ -617,23 +632,67 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D · 4 unmodified lines | ||
| 617 | 632 | } |
| 618 | 633 | } |
| 619 | 634 | |
| 620 | − switch { | |
| 621 | − case strings.HasPrefix(line, "new file"): | |
| 622 | − curFile.Type = DiffFileAdd | |
| 623 | − curFile.IsCreated = true | |
| 624 | − case strings.HasPrefix(line, "deleted"): | |
| 625 | − curFile.Type = DiffFileDel | |
| 626 | − curFile.IsDeleted = true | |
| 627 | − case strings.HasPrefix(line, "index"): | |
| 628 | − curFile.Type = DiffFileChange | |
| 629 | − case strings.HasPrefix(line, "similarity index 100%"): | |
| 630 | − curFile.Type = DiffFileRename | |
| 631 | − } | |
| 632 | − if curFile.Type > 0 { | |
| 633 | − if strings.HasSuffix(line, " 160000\n") { | |
| 634 | − curFile.IsSubmodule = true | |
| 635 | + if curFile.Type != DiffFileRename { | |
| 636 | + switch { | |
| 637 | + case strings.HasPrefix(line, "new file"): | |
| 638 | + curFile.Type = DiffFileAdd | |
| 639 | + curFile.IsCreated = true | |
| 640 | + case strings.HasPrefix(line, "deleted"): | |
| 641 | + curFile.Type = DiffFileDel | |
| 642 | + curFile.IsDeleted = true | |
| 643 | + case strings.HasPrefix(line, "index"): | |
| 644 | + curFile.Type = DiffFileChange | |
| 645 | + case strings.HasPrefix(line, "similarity index 100%"): | |
| 646 | + curFile.Type = DiffFileRename | |
| 647 | + } | |
| 648 | + if curFile.Type > 0 && curFile.Type != DiffFileRename { | |
| 649 | + if strings.HasSuffix(line, " 160000\n") { | |
| 650 | + curFile.IsSubmodule = true | |
| 651 | + } | |
| 652 | + break | |
| 653 | + } | |
| 654 | + } else { | |
| 655 | + switch { | |
| 656 | + case strings.HasPrefix(line, "rename from "): | |
| 657 | + if line[12] == '"' { | |
| 658 | + fmt.Sscanf(line[12:], "%q", &curFile.OldName) | |
| 659 | + } else { | |
| 660 | + curFile.OldName = line[12:] | |
| 661 | + curFile.OldName = curFile.OldName[:len(curFile.OldName)-1] | |
| 662 | + } | |
| 663 | + case strings.HasPrefix(line, "rename to "): | |
| 664 | + if line[10] == '"' { | |
| 665 | + fmt.Sscanf(line[10:], "%q", &curFile.Name) | |
| 666 | + } else { | |
| 667 | + curFile.Name = line[10:] | |
| 668 | + curFile.Name = curFile.Name[:len(curFile.Name)-1] | |
| 669 | + } | |
| 670 | + curFile.IsRenamed = true | |
| 671 | + break loop | |
| 672 | + case strings.HasPrefix(line, "copy from "): | |
| 673 | + if line[10] == '"' { | |
| 674 | + fmt.Sscanf(line[10:], "%q", &curFile.OldName) | |
| 675 | + } else { | |
| 676 | + curFile.OldName = line[10:] | |
| 677 | + curFile.OldName = curFile.OldName[:len(curFile.OldName)-1] | |
| 678 | + } | |
| 679 | + case strings.HasPrefix(line, "copy to "): | |
| 680 | + if line[8] == '"' { | |
| 681 | + fmt.Sscanf(line[8:], "%q", &curFile.Name) | |
| 682 | + } else { | |
| 683 | + curFile.Name = line[8:] | |
| 684 | + curFile.Name = curFile.Name[:len(curFile.Name)-1] | |
| 685 | + } | |
| 686 | + curFile.IsRenamed = true | |
| 687 | + curFile.Type = DiffFileCopy | |
| 688 | + break loop | |
| 689 | + default: | |
| 690 | + if strings.HasSuffix(line, " 160000\n") { | |
| 691 | + curFile.IsSubmodule = true | |
| 692 | + } else { | |
| 693 | + break loop | |
| 694 | + } | |
| 635 | 695 | } |
| 636 | − break | |
| 637 | 696 | } |
| 638 | 697 | } |
| 639 | 698 | } |