Skip to content

Commit f68a84b

Browse files
authored
Use Git instead of go-git (#7)
This switches out dependence on the go-git module with just using the installed git executable. This drastically reduces the number of dependencies, and hopefully improves compatibility (if git changes their plumbing, go-git might break, breaking this executable). This also fixes renames getting marked as add+delete, and adds support for type change statuses.
1 parent bae878c commit f68a84b

13 files changed

+338
-485
lines changed

cmd/git-lzc/main.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ package main
33
import (
44
"fmt"
55
"os"
6-
"strings"
76

87
lazycommit "github.com/spenserblack/git-lazy-commit"
98
)
109

1110
func main() {
12-
repo, err := lazycommit.OpenRepo(".")
13-
onError(err)
11+
repo := lazycommit.Repo(".")
1412

1513
noStaged, err := repo.NoStaged()
1614
onError(err)
@@ -19,12 +17,10 @@ func main() {
1917
onError(repo.StageAll())
2018
}
2119

22-
hash, msg, err := repo.Commit()
20+
out, err := repo.Commit()
2321
onError(err)
2422

25-
msgLines := strings.Split(msg, "\n")
26-
27-
fmt.Printf("[%s] %s\n", hash, msgLines[0])
23+
fmt.Printf("%s", out)
2824
}
2925

3026
func onError(err error) {

commit.go

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,74 +5,57 @@ import (
55
"fmt"
66
"strings"
77

8-
"github.com/go-git/go-git/v5"
9-
"github.com/go-git/go-git/v5/plumbing"
10-
118
"github.com/spenserblack/git-lazy-commit/pkg/fileutils"
129
)
1310

1411
// Commit commits all changes in the repository.
1512
//
16-
// It returns the commit hash and the commit message.
17-
func (r *LazyRepo) Commit() (hash plumbing.Hash, msg string, err error) {
18-
msg, err = r.CommitMsg()
13+
// It returns the output of the commit command.
14+
func (repo Repo) Commit() ([]byte, error) {
15+
msg, err := repo.CommitMsg()
1916
if err != nil {
20-
return
17+
return nil, err
2118
}
22-
23-
hash, err = r.wt.Commit(msg, &git.CommitOptions{})
24-
return
19+
cmd, err := repo.cmd("commit", "-m", msg)
20+
if err != nil {
21+
return nil, err
22+
}
23+
return cmd.Output()
2524
}
2625

2726
// CommitMsg builds a commit message using the tracked files in the repository.
28-
func (r *LazyRepo) CommitMsg() (string, error) {
29-
status, err := r.status()
27+
func (repo Repo) CommitMsg() (string, error) {
28+
statuses, err := repo.Status()
3029
if err != nil {
3130
return "", err
3231
}
33-
for filename, fileStatus := range status {
34-
if fileStatus.Staging == git.Unmodified || fileStatus.Staging == git.Untracked {
35-
delete(status, filename)
32+
33+
// NOTE: Filtering to only statuses that are staged and can be used for the commit message.
34+
commitableStatuses := make([]StatusRecord, 0, len(statuses))
35+
for _, status := range statuses {
36+
if _, ok := statusMap[status.Staged]; ok {
37+
commitableStatuses = append(commitableStatuses, status)
3638
}
3739
}
3840

39-
if len(status) == 0 {
41+
if len(commitableStatuses) == 0 {
4042
return "", errors.New("no tracked files")
4143
}
42-
if len(status) == 1 {
43-
for filename, fileStatus := range status {
44-
return singleFileMsg(filename, fileStatus), nil
45-
}
46-
}
47-
return multiFileMsg(status), nil
48-
}
4944

50-
func singleFileMsg(filename string, fileStatus *git.FileStatus) string {
51-
statusString := ""
52-
switch fileStatus.Staging {
53-
case git.Added:
54-
statusString = "Create"
55-
case git.Deleted:
56-
statusString = "Delete"
57-
case git.Modified:
58-
statusString = "Update"
59-
case git.Renamed:
60-
statusString = "Rename to"
61-
case git.Copied:
62-
statusString = "Copy to"
63-
default:
64-
statusString = "Do something to"
45+
if len(commitableStatuses) == 1 {
46+
status := commitableStatuses[0]
47+
return status.Message(), nil
6548
}
6649

67-
return fmt.Sprintf("%s %s", statusString, filename)
50+
return multiFileMsg(commitableStatuses), nil
6851
}
6952

70-
func multiFileMsg(status git.Status) string {
53+
// MultiFileMsg builds a commit message from multiple files.
54+
func multiFileMsg(statuses []StatusRecord) string {
7155
var builder strings.Builder
72-
73-
filenames := make([]string, 0, len(status))
74-
for name := range status {
75-
filenames = append(filenames, name)
56+
filenames := make([]string, 0, len(statuses))
57+
for _, status := range statuses {
58+
filenames = append(filenames, status.Path)
7659
}
7760

7861
sharedDir := fileutils.SharedDirectory(filenames)
@@ -84,9 +67,8 @@ func multiFileMsg(status git.Status) string {
8467
}
8568
builder.WriteRune('\n')
8669

87-
for filename, fileStatus := range status {
88-
msgItem := singleFileMsg(filename, fileStatus)
89-
builder.WriteString(fmt.Sprintf("- %s\n", msgItem))
70+
for _, status := range statuses {
71+
builder.WriteString(fmt.Sprintf("- %s\n", status.Message()))
9072
}
9173

9274
return builder.String()

commit_test.go

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,73 @@ package lazycommit
33
import (
44
"strings"
55
"testing"
6-
7-
gitconfig "github.com/go-git/go-git/v5/config"
86
)
97

108
// Tests that a commit message can't be built when there are no staged changes.
11-
func TestBuildCommitMessageNoStaged(t *testing.T) {
9+
func TestBuildCommitMessage(t *testing.T) {
10+
t.Log("Creating a new repo.")
1211
dir := tempRepo(t)
13-
repo, err := OpenRepo(dir)
12+
repo := Repo(dir)
13+
14+
_, err := repo.CommitMsg()
15+
if err == nil && err.Error() != "no tracked files" {
16+
t.Errorf(`Expected "no tracked files", got %v`, err)
17+
}
18+
19+
f := commitFile(t, dir, "test.txt", "test")
20+
defer f.Close()
21+
22+
t.Log(`Modifying test.txt`)
23+
commitFile(t, dir, "test.txt", "")
24+
addFile(t, dir, "test.txt", "different text")
25+
26+
msg, err := repo.CommitMsg()
1427
if err != nil {
1528
t.Fatal(err)
1629
}
17-
_, err = repo.CommitMsg()
18-
if err == nil {
19-
t.Fatal("expected error")
30+
if msg != "Update test.txt" {
31+
t.Errorf(`Expected "Update test.txt", got %v`, msg)
2032
}
21-
}
2233

23-
// Tests that commit commits all files in the worktree.
24-
func TestCommit(t *testing.T) {
25-
dir := tempRepo(t)
26-
updateConfig(t, dir, func(config *gitconfig.Config) {
27-
config.User.Name = "Test User"
28-
config.User.Email = "[email protected]"
29-
})
30-
addFile(t, dir, "test.txt", "test")
34+
t.Log(`Adding a new file`)
3135
addFile(t, dir, "test2.txt", "test")
3236

33-
repo, err := OpenRepo(dir)
37+
msg, err = repo.CommitMsg()
3438
if err != nil {
3539
t.Fatal(err)
3640
}
37-
38-
_, msg, err := repo.Commit()
39-
if err != nil {
40-
t.Fatal(err)
41+
lines := strings.Split(msg, "\n")
42+
if lines[0] != "Update files" {
43+
t.Errorf(`Expected "Update files" in the header, got %v`, lines[0])
4144
}
45+
if lines[1] != "" {
46+
t.Errorf(`Expected an empty line after the header, got %v`, lines[1])
47+
}
48+
body := strings.Join(lines[2:], "\n")
49+
t.Logf("Body:\n %v", body)
50+
for _, want := range []string{"- Update test.txt", "- Create test2.txt"} {
51+
if !strings.Contains(body, want) {
52+
t.Errorf(`Expected %v in the body`, want)
53+
}
54+
}
55+
}
4256

43-
wantHeader := "Update files"
44-
wantBodyLines := []string{"- Create test.txt", "- Create test2.txt"}
57+
// TestBuildCommitMessageWithRename tests that a commit message can be built when a file is renamed.
58+
func TestBuildCommitMessageWithRename(t *testing.T) {
59+
dir := tempRepo(t)
60+
repo := Repo(dir)
4561

46-
if !strings.HasPrefix(msg, wantHeader) {
47-
t.Errorf("expected commit message to start with %q, got %q", wantHeader, msg)
48-
}
62+
f := commitFile(t, dir, "foo.txt", "test")
63+
defer f.Close()
4964

50-
for _, line := range wantBodyLines {
51-
if !strings.Contains(msg, line) {
52-
t.Errorf("expected commit message to contain %q, got %q", line, msg)
53-
}
65+
t.Log(`Renaming test.txt to test2.txt`)
66+
moveFile(t, dir, "foo.txt", "bar.txt")
67+
68+
msg, err := repo.CommitMsg()
69+
if err != nil {
70+
t.Fatal(err)
71+
}
72+
if msg != "Rename foo.txt to bar.txt" {
73+
t.Errorf(`Expected "Rename foo.txt to bar.txt", got %v`, msg)
5474
}
5575
}

go.mod

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,4 @@ module github.com/spenserblack/git-lazy-commit
22

33
go 1.20
44

5-
require (
6-
github.com/go-git/go-billy/v5 v5.4.1
7-
github.com/go-git/go-git/v5 v5.5.2
8-
)
9-
10-
require (
11-
github.com/Microsoft/go-winio v0.5.2 // indirect
12-
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect
13-
github.com/acomagu/bufpipe v1.0.3 // indirect
14-
github.com/cloudflare/circl v1.1.0 // indirect
15-
github.com/emirpasic/gods v1.18.1 // indirect
16-
github.com/go-git/gcfg v1.5.0 // indirect
17-
github.com/imdario/mergo v0.3.13 // indirect
18-
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
19-
github.com/kevinburke/ssh_config v1.2.0 // indirect
20-
github.com/pjbgf/sha1cd v0.2.3 // indirect
21-
github.com/sergi/go-diff v1.1.0 // indirect
22-
github.com/skeema/knownhosts v1.1.0 // indirect
23-
github.com/xanzy/ssh-agent v0.3.3 // indirect
24-
golang.org/x/crypto v0.3.0 // indirect
25-
golang.org/x/net v0.2.0 // indirect
26-
golang.org/x/sys v0.3.0 // indirect
27-
gopkg.in/warnings.v0 v0.1.2 // indirect
28-
)
5+
require github.com/cli/safeexec v1.0.1

0 commit comments

Comments
 (0)