Skip to content

Commit 607378b

Browse files
committed
pkg/vcs: be more strict in BaseForDiff
Do not tolerate unknown blob hashes - it means that we are unable to find the correct base commit given the repository. Explicitly ignore newly added files - we definitely won't find their hashes. Explicitly skip malformed patches that won't have any blob hashes - otherwise we could end up with too many candidates and waste too much time.
1 parent 5757a3d commit 607378b

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

pkg/vcs/git.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -776,17 +776,22 @@ func (git Git) BaseForDiff(diff []byte, tracer debugtracer.DebugTracer) ([]*Base
776776
}
777777
var fileNames []string
778778
nameToHash := map[string]string{}
779+
ignoreFiles := map[string]struct{}{}
779780
for _, file := range ParseGitDiff(diff) {
780781
if strings.Trim(file.LeftHash, "0") == "" {
781-
// Newly created file are not of any help here.
782+
// Newly created files are not of any help here.
783+
ignoreFiles[file.Name] = struct{}{}
784+
continue
785+
}
786+
if _, ignore := ignoreFiles[file.Name]; ignore {
782787
continue
783788
}
784789
if ok, err := git.verifyHash(file.LeftHash); err != nil {
785790
return nil, fmt.Errorf("hash verification failed: %w", err)
786791
} else if !ok {
787-
// The object is not known in this repository.
788-
// Ignore it, or otherwise the command will fail.
789-
continue
792+
// The object is not known in this repository, so we won't find the exact base commit.
793+
tracer.Log("unknown object %s, stopping base commit search", file.LeftHash)
794+
return nil, nil
790795
}
791796
if _, ok := nameToHash[file.Name]; !ok {
792797
// If the diff is actually a concatenation of several diffs, we only
@@ -797,6 +802,9 @@ func (git Git) BaseForDiff(diff []byte, tracer debugtracer.DebugTracer) ([]*Base
797802
args = append(args, "--find-object="+file.LeftHash)
798803
}
799804
tracer.Log("extracted %d left blob hashes", len(nameToHash))
805+
if len(nameToHash) == 0 {
806+
return nil, nil
807+
}
800808
output, err := git.Run(args...)
801809
if err != nil {
802810
return nil, err

pkg/vcs/git_test.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -551,8 +551,8 @@ func TestBaseForDiff(t *testing.T) {
551551
assert.Equal(t, commit4.Hash, base[0].Hash)
552552
assert.Equal(t, commit2.Hash, base[1].Hash)
553553
})
554-
t.Run("ignore unknown objects", func(t *testing.T) {
555-
// It's okay if the diff contains unknown hashes.
554+
t.Run("unknown objects", func(t *testing.T) {
555+
// It's not okay if the diff contains unknown hashes.
556556
diff2 := `
557557
diff --git a/b.txt b/b.txt
558558
deleted file mode 100644
@@ -561,9 +561,36 @@ index f70f10e..0000000
561561
+++ /dev/null
562562
@@ -1 +0,0 @@
563563
-A`
564+
twoDiffs := append(append([]byte{}, diff...), diff2...)
565+
base, err := repo.repo.BaseForDiff(twoDiffs, &debugtracer.TestTracer{T: t})
566+
require.NoError(t, err)
567+
require.Nil(t, base)
568+
})
569+
t.Run("ignore new files", func(t *testing.T) {
570+
diff2 := `
571+
diff --git a/a.txt b/a.txt
572+
new file mode 100644
573+
index 0000000..fa49b07
574+
--- /dev/null
575+
+++ b/a.txt
576+
@@ -0,0 +1 @@
577+
+new file
578+
diff --git a/a.txt b/a.txt
579+
index fa49b07..01c887f 100644
580+
--- a/a.txt
581+
+++ b/a.txt
582+
@@ -1 +1 @@
583+
-new file
584+
+edit file
585+
`
564586
twoDiffs := append(append([]byte{}, diff...), diff2...)
565587
base, err := repo.repo.BaseForDiff(twoDiffs, &debugtracer.TestTracer{T: t})
566588
require.NoError(t, err)
567589
require.Len(t, base, 2)
568590
})
591+
t.Run("empty patch", func(t *testing.T) {
592+
base, err := repo.repo.BaseForDiff([]byte{}, &debugtracer.TestTracer{T: t})
593+
require.NoError(t, err)
594+
require.Nil(t, base)
595+
})
569596
}

0 commit comments

Comments
 (0)