Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 25 additions & 47 deletions gitcmds/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func SetLocalPreCommitHook(wd string) error {
_ = f.Close()

if !largeFileHookExist(PreCommitFilePath) {
return fillPreCommitFile(wd, PreCommitFilePath)
return fillPreCommitFile(dir, PreCommitFilePath)
}

return nil
Expand All @@ -84,7 +84,7 @@ func createOrOpenFile(filepath string) (*os.File, error) {
return f, nil
}

func fillPreCommitFile(wd, myFilePath string) error {
func fillPreCommitFile(rootDir, myFilePath string) error {
fPreCommit, err := createOrOpenFile(myFilePath)
if err != nil {
return err
Expand All @@ -93,12 +93,7 @@ func fillPreCommitFile(wd, myFilePath string) error {
_ = fPreCommit.Close()
}()

dir, err := GetRootFolder(wd)
if err != nil {
return err
}
fName := "/.git/hooks/" + LargeFileHookFilename
lfPath := dir + fName
lfPath := rootDir + "/.git/hooks/" + LargeFileHookFilename

lf, err := os.Create(lfPath)
if err != nil {
Expand All @@ -123,14 +118,8 @@ func fillPreCommitFile(wd, myFilePath string) error {
return new(exec.PipedExec).Command("chmod", "+x", myFilePath).Run(os.Stdout, os.Stdout)
}

// isLargeFileHookContentUpToDate checks if the current large-file-hook.sh content matches the expected content
func isLargeFileHookContentUpToDate(wd string) (bool, error) {
dir, err := GetRootFolder(wd)
if err != nil {
return false, err
}

hookPath := filepath.Join(dir, ".git", "hooks", LargeFileHookFilename)
func isLargeFileHookContentUpToDate(rootDir string) (bool, error) {
hookPath := filepath.Join(rootDir, ".git", "hooks", LargeFileHookFilename)

// Check if the file exists
if _, err := os.Stat(hookPath); os.IsNotExist(err) {
Expand All @@ -147,14 +136,8 @@ func isLargeFileHookContentUpToDate(wd string) (bool, error) {
return string(currentContent) == largeFileHookContent, nil
}

// updateLargeFileHookContent updates the large-file-hook.sh file with the current content
func updateLargeFileHookContent(wd string) error {
dir, err := GetRootFolder(wd)
if err != nil {
return err
}

hookPath := filepath.Join(dir, ".git", "hooks", LargeFileHookFilename)
func updateLargeFileHookContent(rootDir string) error {
hookPath := filepath.Join(rootDir, ".git", "hooks", LargeFileHookFilename)

// Create or overwrite the hook file
lf, err := os.Create(hookPath)
Expand All @@ -172,17 +155,18 @@ func updateLargeFileHookContent(wd string) error {
return nil
}

// EnsureLargeFileHookUpToDate checks and updates the large file hook if needed
func EnsureLargeFileHookUpToDate(wd string) error {
upToDate, err := isLargeFileHookContentUpToDate(wd)
rootDir, err := GetRootFolder(wd)
if err != nil {
return err
}
upToDate, err := isLargeFileHookContentUpToDate(rootDir)
if err != nil {
return err
}

if !upToDate {
return updateLargeFileHookContent(wd)
return updateLargeFileHookContent(rootDir)
}

return nil
}

Expand All @@ -196,29 +180,20 @@ func getGlobalHookFolder() string {
return strings.TrimSpace(stdout)
}

func getLocalHookFolder(wd string) (string, error) {
dir, err := GetRootFolder(wd)
if err != nil {
return "", err
}
filename := "/.git/hooks/pre-commit"
filepath := dir + filename

return strings.TrimSpace(filepath), nil
func getLocalHookFolder(rootDir string) string {
return rootDir + "/.git/hooks/pre-commit"
}

// LocalPreCommitHookExist - s.e.
func LocalPreCommitHookExist(wd string) (bool, error) {
filepath, err := getLocalHookFolder(wd)
rootDir, err := GetRootFolder(wd)
if err != nil {
return false, err
}
// Check if the file already exists
if _, err := os.Stat(filepath); os.IsNotExist(err) {
fp := getLocalHookFolder(rootDir)
if _, err := os.Stat(fp); os.IsNotExist(err) {
return false, nil
}

return largeFileHookExist(filepath), nil
return largeFileHookExist(fp), nil
}

func largeFileHookExist(filepath string) bool {
Expand Down Expand Up @@ -262,13 +237,16 @@ func SetGlobalPreCommitHook(wd string) error {

_ = f.Close()
if !largeFileHookExist(filepath) {
return fillPreCommitFile(wd, filepath)
rootDir, err := GetRootFolder(wd)
if err != nil {
return err
}
return fillPreCommitFile(rootDir, filepath)
}

return nil
}


func GetRootFolder(wd string) (string, error) {
stdout, _, err := new(exec.PipedExec).
Command(git, "rev-parse", "--show-toplevel").
Expand All @@ -279,4 +257,4 @@ func GetRootFolder(wd string) (string, error) {
}

return strings.TrimSpace(stdout), nil
}
}
2 changes: 1 addition & 1 deletion gitcmds/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func getListOfChangedFiles(wd, statusOutput string) ([]fileInfo, error) {
case `M`, `MM`, `RM`:
newFileSize, err1 = getFileSize(wd, name)
oldSize, err2 = getFileSizeFromHEAD(wd, gitDir, oldName)
case `D`:
case `D`, `MD`:
oldSize, err2 = getFileSizeFromHEAD(wd, gitDir, oldName)
case `R`:
newFileSize, err1 = getFileSize(wd, name)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
registered_at: 2026-02-22T20:44:12Z
change_id: 2602222044-reduce-getrootfolder-calls
baseline: 54f427c0ff88495738c2b33ea386f73b080bde9d
archived_at: 2026-02-23T02:41:38Z
---

# Change request: Reduce redundant GetRootFolder calls in hook.go

## Why

`GetRootFolder()` spawns a `git rev-parse --show-toplevel` subprocess each time it is called. In `gitcmds/hook.go` it is called 5 times, but several calls are redundant within the same call chain — the result is already available from a caller up the stack.

## What

Eliminate redundant `GetRootFolder()` calls in `gitcmds/hook.go` by passing the already-resolved root dir down the call chain:

- `fillPreCommitFile`: accept `rootDir` parameter instead of calling `GetRootFolder` (caller `SetLocalPreCommitHook` and `SetGlobalPreCommitHook` already have it or can obtain it once)
- `isLargeFileHookContentUpToDate` and `updateLargeFileHookContent`: accept `rootDir` parameter instead of calling `GetRootFolder`; `EnsureLargeFileHookUpToDate` calls `GetRootFolder` once and passes it to both
- `getLocalHookFolder`: accept `rootDir` parameter instead of calling `GetRootFolder` (caller `LocalPreCommitHookExist` obtains it)
- Net result: 5 calls reduced to 3 (one each in `SetLocalPreCommitHook`, `EnsureLargeFileHookUpToDate`, `LocalPreCommitHookExist`)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Implementation plan: Reduce redundant GetRootFolder calls in hook.go

## Construction

- [x] update: [gitcmds/hook.go](../../../../../gitcmds/hook.go)
- refactor: `fillPreCommitFile` — replace `wd` param with `rootDir`, remove internal `GetRootFolder` call
- refactor: `isLargeFileHookContentUpToDate` — replace `wd` param with `rootDir`, remove internal `GetRootFolder` call
- refactor: `updateLargeFileHookContent` — replace `wd` param with `rootDir`, remove internal `GetRootFolder` call
- refactor: `getLocalHookFolder` — replace `wd` param with `rootDir`, remove internal `GetRootFolder` call
- refactor: `EnsureLargeFileHookUpToDate` — call `GetRootFolder` once, pass result to `isLargeFileHookContentUpToDate` and `updateLargeFileHookContent`
- refactor: `SetLocalPreCommitHook` — pass existing `dir` to `fillPreCommitFile`
- refactor: `SetGlobalPreCommitHook` — call `GetRootFolder` once, pass result to `fillPreCommitFile`
- refactor: `LocalPreCommitHookExist` — call `GetRootFolder` once, pass result to `getLocalHookFolder`

### Tests

- [x] review: `go build ./...` compiles without errors
- [x] review: `go vet ./...` passes without errors

Loading