Skip to content

Commit 1060946

Browse files
authored
feat: speed up finding changed files in commits (#2645)
We don't need the actual diffs between commits - only the names of the changed files. This massively improves performance of "release init". While there *may* be other things we want to do in the future, this makes enough of a difference that we can probably hold off on larger changes (at least for the sake of performance). Fixes #2634
1 parent 867264d commit 1060946

File tree

2 files changed

+75
-10
lines changed

2 files changed

+75
-10
lines changed

internal/gitrepo/gitrepo.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -477,18 +477,21 @@ func (r *LocalRepository) ChangedFilesInCommit(commitHash string) ([]string, err
477477
}
478478
}
479479

480-
patch, err := fromTree.Patch(toTree)
480+
changes, err := fromTree.Diff(toTree)
481481
if err != nil {
482-
return nil, fmt.Errorf("failed to get patch for commit %s: %w", commitHash, err)
482+
return nil, fmt.Errorf("failed to get diff for commit %s: %w", commitHash, err)
483483
}
484484
var files []string
485-
for _, filePatch := range patch.FilePatches() {
486-
from, to := filePatch.Files()
487-
if from != nil {
488-
files = append(files, from.Path())
485+
for _, change := range changes {
486+
from := change.From.Name
487+
to := change.To.Name
488+
// Deletion or modification
489+
if from != "" {
490+
files = append(files, from)
489491
}
490-
if to != nil && (from == nil || from.Path() != to.Path()) {
491-
files = append(files, to.Path())
492+
// Insertion or rename
493+
if to != "" && from != to {
494+
files = append(files, to)
492495
}
493496
}
494497
return files, nil

internal/gitrepo/gitrepo_test.go

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,16 @@ func TestChangedFilesInCommit(t *testing.T) {
11021102
commitHash: commitHashes["commit 3"],
11031103
wantFiles: []string{"file2.txt"},
11041104
},
1105+
{
1106+
name: "commit 4",
1107+
commitHash: commitHashes["commit 4"],
1108+
wantFiles: []string{"file2.txt"},
1109+
},
1110+
{
1111+
name: "commit 5",
1112+
commitHash: commitHashes["commit 5"],
1113+
wantFiles: []string{"file1.txt", "file3.txt"},
1114+
},
11051115
{
11061116
name: "invalid commit hash",
11071117
commitHash: "invalid",
@@ -1552,9 +1562,53 @@ func createAndCommit(t *testing.T, repo *git.Repository, path string, content []
15521562
t.Fatalf("os.MkdirAll failed: %v", err)
15531563
}
15541564
}
1565+
return commitChanges(t, repo, commitMsg, path)
1566+
1567+
}
1568+
1569+
// deleteAndCommit deletes a file in a repository and commits the change.
1570+
func deleteAndCommit(t *testing.T, repo *git.Repository, path string, commitMsg string) *object.Commit {
1571+
t.Helper()
1572+
w, err := repo.Worktree()
1573+
if err != nil {
1574+
t.Fatalf("Worktree() failed: %v", err)
1575+
}
15551576

1556-
if _, err := w.Add(path); err != nil {
1557-
t.Fatalf("w.Add failed: %v", err)
1577+
fullPath := filepath.Join(w.Filesystem.Root(), path)
1578+
if err := os.Remove(fullPath); err != nil {
1579+
t.Fatalf("Remove() failed: %v", err)
1580+
}
1581+
return commitChanges(t, repo, commitMsg, path)
1582+
}
1583+
1584+
// renameAndCommit renames a file in a repository and commits the change.
1585+
func renameAndCommit(t *testing.T, repo *git.Repository, fromPath, toPath string, commitMsg string) *object.Commit {
1586+
t.Helper()
1587+
w, err := repo.Worktree()
1588+
if err != nil {
1589+
t.Fatalf("Worktree() failed: %v", err)
1590+
}
1591+
1592+
fullFromPath := filepath.Join(w.Filesystem.Root(), fromPath)
1593+
fullToPath := filepath.Join(w.Filesystem.Root(), toPath)
1594+
if err := os.Rename(fullFromPath, fullToPath); err != nil {
1595+
t.Fatalf("Rename() failed: %v", err)
1596+
}
1597+
return commitChanges(t, repo, commitMsg, fromPath, toPath)
1598+
}
1599+
1600+
// commitChanges adds the specified paths to the repository and commits the change.
1601+
func commitChanges(t *testing.T, repo *git.Repository, commitMsg string, paths ...string) *object.Commit {
1602+
t.Helper()
1603+
w, err := repo.Worktree()
1604+
if err != nil {
1605+
t.Fatalf("Worktree() failed: %v", err)
1606+
}
1607+
1608+
for _, path := range paths {
1609+
if _, err := w.Add(path); err != nil {
1610+
t.Fatalf("w.Add failed: %v", err)
1611+
}
15581612
}
15591613
hash, err := w.Commit(commitMsg, &git.CommitOptions{
15601614
Author: &object.Signature{Name: "Test", Email: "[email protected]"},
@@ -1589,6 +1643,14 @@ func setupRepoForChangedFilesTest(t *testing.T) (*LocalRepository, map[string]st
15891643
commit3 := createAndCommit(t, repo, "file2.txt", []byte("content3"), "commit 3")
15901644
commitHashes["commit 3"] = commit3.Hash.String()
15911645

1646+
// Commit 4 (delete file2.txt)
1647+
commit4 := deleteAndCommit(t, repo, "file2.txt", "commit 4")
1648+
commitHashes["commit 4"] = commit4.Hash.String()
1649+
1650+
// Commit 5 (rename file1.txt to file3.txt)
1651+
commit5 := renameAndCommit(t, repo, "file1.txt", "file3.txt", "commit 5")
1652+
commitHashes["commit 5"] = commit5.Hash.String()
1653+
15921654
return &LocalRepository{Dir: dir, repo: repo}, commitHashes
15931655
}
15941656

0 commit comments

Comments
 (0)