Skip to content

Commit f3fc175

Browse files
supitsdumrexox
andauthored
fix: use pre-push stdin for push file detection (#1368)
Co-authored-by: Valentin Kiselev <mrexox@evilmartians.com>
1 parent 236a5bd commit f3fc175

3 files changed

Lines changed: 85 additions & 4 deletions

File tree

internal/git/repository.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ const (
2323
stashMessage = "lefthook auto backup"
2424
unstagedPatchName = "lefthook-unstaged.patch"
2525
infoDirMode = 0o775
26-
27-
// The result of `git hash-object -t tree /dev/null`.
28-
emptyTreeSHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
2926
)
3027

3128
var (
@@ -35,6 +32,7 @@ var (
3532
reStashMessage = regexp.MustCompile(`^(?P<stash>[^ ]+):\s*` + stashMessage)
3633
cmdPushFilesBase = []string{"git", "diff", "--name-only", "HEAD", "@{push}"}
3734
cmdPushFilesHead = []string{"git", "diff", "--name-only", "HEAD"}
35+
cmdPushFilesTreeBase = []string{"git", "ls-tree", "-r", "--name-only"}
3836
cmdStagedFiles = []string{"git", "diff", "--name-only", "--cached", "--diff-filter=ACMR"}
3937
cmdStagedFilesWithDeleted = []string{"git", "diff", "--name-only", "--cached", "--diff-filter=ACMRD"}
4038
cmdStatusShort = []string{"git", "status", "--short", "--porcelain", "-z"}
@@ -212,7 +210,12 @@ func (r *Repository) resolveHeadBranch() string {
212210
}
213211
}
214212

215-
return emptyTreeSHA
213+
// Nothing has been pushed yet or upstream is not set
214+
if len(r.headBranch) == 0 {
215+
return r.FindExistingFiles(append(cmdPushFilesTreeBase, "HEAD"), "")
216+
}
217+
218+
return r.FindExistingFiles(append(cmdPushFilesHead, r.headBranch), "")
216219
}
217220

218221
// PartiallyStagedFiles returns the list of files that have both staged and

internal/git/repository_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
package git
22

33
import (
4+
"errors"
45
"fmt"
6+
"io"
7+
"path/filepath"
58
"sync"
69
"testing"
710

11+
"github.com/spf13/afero"
12+
813
"github.com/evilmartians/lefthook/v2/tests/helpers/cmdtest"
914
)
1015

@@ -170,3 +175,52 @@ func TestChangeset(t *testing.T) {
170175
})
171176
}
172177
}
178+
179+
func TestPushFiles(t *testing.T) {
180+
t.Run("falls back to ls-tree for initial push without upstream", func(t *testing.T) {
181+
fs := afero.NewMemMapFs()
182+
root := "/repo"
183+
readme := filepath.Join(root, "README.md")
184+
185+
if err := fs.MkdirAll(root, 0o755); err != nil {
186+
t.Fatalf("unexpected error: %s", err)
187+
}
188+
if err := afero.WriteFile(fs, readme, []byte("readme"), 0o644); err != nil {
189+
t.Fatalf("unexpected error: %s", err)
190+
}
191+
192+
cmd := cmdtest.NewTracking(func(command string, _ string, out io.Writer) error {
193+
switch command {
194+
case "git diff --name-only HEAD @{push}":
195+
return errors.New("no upstream configured")
196+
case "git branch --remotes":
197+
return nil
198+
case "git ls-tree -r --name-only HEAD":
199+
_, err := out.Write([]byte("README.md\nmissing.txt\n"))
200+
return err
201+
default:
202+
t.Fatalf("unexpected command: %s", command)
203+
return nil
204+
}
205+
})
206+
207+
repository := &Repository{
208+
Fs: fs,
209+
RootPath: root,
210+
Git: &CommandExecutor{
211+
mu: new(sync.Mutex),
212+
cmd: cmd,
213+
},
214+
}
215+
repository.Setup()
216+
217+
files, err := repository.PushFiles()
218+
if err != nil {
219+
t.Fatalf("unexpected error: %s", err)
220+
}
221+
222+
if want := []string{"README.md"}; len(files) != len(want) || files[0] != want[0] {
223+
t.Fatalf("expected %v, got %v", want, files)
224+
}
225+
})
226+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[windows] skip
2+
3+
exec git init --object-format=sha256
4+
exec git config user.email "you@example.com"
5+
exec git config user.name "Your Name"
6+
exec git branch -m main
7+
exec git add -A
8+
exec git commit -m "initial"
9+
exec git init --bare --object-format=sha256 ../remote.git
10+
exec git remote add origin ../remote.git
11+
exec lefthook install
12+
exec git push -u origin main
13+
stdout 'PUSH README.md lefthook.yml'
14+
! stderr 'no upstream configured'
15+
! stderr 'ambiguous argument'
16+
exec git --git-dir ../remote.git rev-parse refs/heads/main
17+
18+
-- lefthook.yml --
19+
pre-push:
20+
jobs:
21+
- run: echo PUSH {push_files}
22+
23+
-- README.md --
24+
hello

0 commit comments

Comments
 (0)