Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

git: worktree_commit, Modify checking empty commit. Fixes #723 #1050

Merged
merged 2 commits into from
May 22, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,10 @@ func createCommit(c *C, r *Repository) plumbing.Hash {
}

h, err := wt.Commit("test commit message", &CommitOptions{
All: true,
Author: &author,
Committer: &author,
All: true,
Author: &author,
Committer: &author,
AllowEmptyCommits: true,
onee-only marked this conversation as resolved.
Show resolved Hide resolved
})
c.Assert(err, IsNil)
return h
Expand Down
26 changes: 19 additions & 7 deletions worktree_commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ func (w *Worktree) Commit(msg string, opts *CommitOptions) (plumbing.Hash, error
}
}

var treeHash plumbing.Hash

if opts.Amend {
head, err := w.r.Head()
if err != nil {
Expand All @@ -61,16 +59,34 @@ func (w *Worktree) Commit(msg string, opts *CommitOptions) (plumbing.Hash, error
return plumbing.ZeroHash, err
}

// First handle the case of the first commit in the repository being empty.
if len(opts.Parents) == 0 && len(idx.Entries) == 0 && !opts.AllowEmptyCommits {
return plumbing.ZeroHash, ErrEmptyCommit
}

h := &buildTreeHelper{
fs: w.Filesystem,
s: w.r.Storer,
}

treeHash, err = h.BuildTree(idx, opts)
treeHash, err := h.BuildTree(idx, opts)
if err != nil {
return plumbing.ZeroHash, err
}

previousTree := plumbing.ZeroHash
if len(opts.Parents) > 0 {
parentCommit, err := w.r.CommitObject(opts.Parents[0])
if err != nil {
return plumbing.ZeroHash, err
}
previousTree = parentCommit.TreeHash
}

if treeHash == previousTree && !opts.AllowEmptyCommits {
return plumbing.ZeroHash, ErrEmptyCommit
}

commit, err := w.buildCommitObject(msg, opts, treeHash)
if err != nil {
return plumbing.ZeroHash, err
Expand Down Expand Up @@ -175,10 +191,6 @@ type buildTreeHelper struct {
// BuildTree builds the tree objects and push its to the storer, the hash
// of the root tree is returned.
func (h *buildTreeHelper) BuildTree(idx *index.Index, opts *CommitOptions) (plumbing.Hash, error) {
if len(idx.Entries) == 0 && (opts == nil || !opts.AllowEmptyCommits) {
return plumbing.ZeroHash, ErrEmptyCommit
}

const rootNode = ""
h.trees = map[string]*object.Tree{rootNode: {}}
h.entries = map[string]*object.TreeEntry{}
Expand Down
125 changes: 122 additions & 3 deletions worktree_commit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,56 @@ func (s *WorktreeSuite) TestNothingToCommit(c *C) {
c.Assert(err, IsNil)
}

func (s *WorktreeSuite) TestNothingToCommitNonEmptyRepo(c *C) {
fs := memfs.New()
r, err := Init(memory.NewStorage(), fs)
c.Assert(err, IsNil)

w, err := r.Worktree()
c.Assert(err, IsNil)

err = util.WriteFile(fs, "foo", []byte("foo"), 0644)
c.Assert(err, IsNil)

w.Add("foo")
_, err = w.Commit("previous commit\n", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)

hash, err := w.Commit("failed empty commit\n", &CommitOptions{Author: defaultSignature()})
c.Assert(hash, Equals, plumbing.ZeroHash)
c.Assert(err, Equals, ErrEmptyCommit)

_, err = w.Commit("enable empty commits\n", &CommitOptions{Author: defaultSignature(), AllowEmptyCommits: true})
c.Assert(err, IsNil)
}

func (s *WorktreeSuite) TestRemoveAndCommitToMakeEmptyRepo(c *C) {
fs := memfs.New()
r, err := Init(memory.NewStorage(), fs)
c.Assert(err, IsNil)

w, err := r.Worktree()
c.Assert(err, IsNil)

err = util.WriteFile(fs, "foo", []byte("foo"), 0644)
c.Assert(err, IsNil)

_, err = w.Add("foo")
c.Assert(err, IsNil)

_, err = w.Commit("Add in Repo\n", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)

err = fs.Remove("foo")
c.Assert(err, IsNil)

_, err = w.Add("foo")
c.Assert(err, IsNil)

_, err = w.Commit("Remove foo\n", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)
}

func (s *WorktreeSuite) TestCommitParent(c *C) {
expected := plumbing.NewHash("ef3ca05477530b37f48564be33ddd48063fc7a22")

Expand All @@ -101,7 +151,8 @@ func (s *WorktreeSuite) TestCommitParent(c *C) {
err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)

util.WriteFile(fs, "foo", []byte("foo"), 0644)
err = util.WriteFile(fs, "foo", []byte("foo"), 0644)
c.Assert(err, IsNil)

_, err = w.Add("foo")
c.Assert(err, IsNil)
Expand All @@ -113,7 +164,42 @@ func (s *WorktreeSuite) TestCommitParent(c *C) {
assertStorageStatus(c, s.Repository, 13, 11, 10, expected)
}

func (s *WorktreeSuite) TestCommitAmend(c *C) {
func (s *WorktreeSuite) TestCommitAmendWithoutChanges(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}

err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)

err = util.WriteFile(fs, "foo", []byte("foo"), 0644)
c.Assert(err, IsNil)

_, err = w.Add("foo")
c.Assert(err, IsNil)

prevHash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)

amendedHash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), Amend: true})
c.Assert(err, IsNil)

headRef, err := w.r.Head()
c.Assert(err, IsNil)

c.Assert(amendedHash, Equals, headRef.Hash())
c.Assert(amendedHash, Equals, prevHash)

commit, err := w.r.CommitObject(headRef.Hash())
c.Assert(err, IsNil)
c.Assert(commit.Message, Equals, "foo\n")

assertStorageStatus(c, s.Repository, 13, 11, 10, amendedHash)
}

func (s *WorktreeSuite) TestCommitAmendWithChanges(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Expand Down Expand Up @@ -164,6 +250,34 @@ func (s *WorktreeSuite) TestCommitAmend(c *C) {
assertStorageStatus(c, s.Repository, 14, 12, 11, amendedHash)
}

func (s *WorktreeSuite) TestCommitAmendNothingToCommit(c *C) {
fs := memfs.New()
w := &Worktree{
r: s.Repository,
Filesystem: fs,
}

err := w.Checkout(&CheckoutOptions{})
c.Assert(err, IsNil)

err = util.WriteFile(fs, "foo", []byte("foo"), 0644)
c.Assert(err, IsNil)

_, err = w.Add("foo")
c.Assert(err, IsNil)

prevHash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)

_, err = w.Commit("bar\n", &CommitOptions{Author: defaultSignature(), AllowEmptyCommits: true})
c.Assert(err, IsNil)

amendedHash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), Amend: true})
c.Log(prevHash, amendedHash)
c.Assert(err, Equals, ErrEmptyCommit)
c.Assert(amendedHash, Equals, plumbing.ZeroHash)
}

func (s *WorktreeSuite) TestAddAndCommitWithSkipStatus(c *C) {
expected := plumbing.NewHash("375a3808ffde7f129cdd3c8c252fd0fe37cfd13b")

Expand Down Expand Up @@ -233,7 +347,9 @@ func (s *WorktreeSuite) TestAddAndCommitWithSkipStatusPathNotModified(c *C) {
})
c.Assert(hash, Equals, expected)
c.Assert(err, IsNil)

commit1, err := w.r.CommitObject(hash)
c.Assert(err, IsNil)

status, err = w.Status()
c.Assert(err, IsNil)
Expand All @@ -256,11 +372,14 @@ func (s *WorktreeSuite) TestAddAndCommitWithSkipStatusPathNotModified(c *C) {
c.Assert(foo.Worktree, Equals, Untracked)

hash, err = w.Commit("commit with no changes\n", &CommitOptions{
Author: defaultSignature(),
Author: defaultSignature(),
AllowEmptyCommits: true,
})
c.Assert(hash, Equals, expected2)
c.Assert(err, IsNil)

commit2, err := w.r.CommitObject(hash)
c.Assert(err, IsNil)

status, err = w.Status()
c.Assert(err, IsNil)
Expand Down
29 changes: 18 additions & 11 deletions worktree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ import (
. "gopkg.in/check.v1"
)

var (
defaultTestCommitOptions = &CommitOptions{Author: &object.Signature{Name: "testuser", Email: "testemail"}}
)
func defaultTestCommitOptions() *CommitOptions {
return &CommitOptions{
Author: &object.Signature{Name: "testuser", Email: "testemail"},
}
}

type WorktreeSuite struct {
BaseSuite
Expand Down Expand Up @@ -88,8 +90,9 @@ func (s *WorktreeSuite) TestPullFastForward(c *C) {

w, err := server.Worktree()
c.Assert(err, IsNil)
err = os.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755)
err = os.WriteFile(filepath.Join(url, "foo"), []byte("foo"), 0755)
c.Assert(err, IsNil)
w.Add("foo")
hash, err := w.Commit("foo", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)

Expand Down Expand Up @@ -125,15 +128,17 @@ func (s *WorktreeSuite) TestPullNonFastForward(c *C) {

w, err := server.Worktree()
c.Assert(err, IsNil)
err = os.WriteFile(filepath.Join(path, "foo"), []byte("foo"), 0755)
err = os.WriteFile(filepath.Join(url, "foo"), []byte("foo"), 0755)
c.Assert(err, IsNil)
w.Add("foo")
_, err = w.Commit("foo", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)

w, err = r.Worktree()
c.Assert(err, IsNil)
err = os.WriteFile(filepath.Join(path, "bar"), []byte("bar"), 0755)
err = os.WriteFile(filepath.Join(dir, "bar"), []byte("bar"), 0755)
c.Assert(err, IsNil)
w.Add("bar")
_, err = w.Commit("bar", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)

Expand Down Expand Up @@ -286,16 +291,18 @@ func (s *RepositorySuite) TestPullAdd(c *C) {
func (s *WorktreeSuite) TestPullAlreadyUptodate(c *C) {
path := fixtures.Basic().ByTag("worktree").One().Worktree().Root()

r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{
fs := memfs.New()
r, err := Clone(memory.NewStorage(), fs, &CloneOptions{
URL: filepath.Join(path, ".git"),
})

c.Assert(err, IsNil)

w, err := r.Worktree()
c.Assert(err, IsNil)
err = os.WriteFile(filepath.Join(path, "bar"), []byte("bar"), 0755)
err = util.WriteFile(fs, "bar", []byte("bar"), 0755)
c.Assert(err, IsNil)
w.Add("bar")
_, err = w.Commit("bar", &CommitOptions{Author: defaultSignature()})
c.Assert(err, IsNil)

Expand Down Expand Up @@ -1002,14 +1009,14 @@ func (s *WorktreeSuite) TestStatusCheckedInBeforeIgnored(c *C) {
_, err = w.Add("fileToIgnore")
c.Assert(err, IsNil)

_, err = w.Commit("Added file that will be ignored later", defaultTestCommitOptions)
_, err = w.Commit("Added file that will be ignored later", defaultTestCommitOptions())
c.Assert(err, IsNil)

err = util.WriteFile(fs, ".gitignore", []byte("fileToIgnore\nsecondIgnoredFile"), 0755)
c.Assert(err, IsNil)
_, err = w.Add(".gitignore")
c.Assert(err, IsNil)
_, err = w.Commit("Added .gitignore", defaultTestCommitOptions)
_, err = w.Commit("Added .gitignore", defaultTestCommitOptions())
c.Assert(err, IsNil)
status, err := w.Status()
c.Assert(err, IsNil)
Expand Down Expand Up @@ -2056,7 +2063,7 @@ func (s *WorktreeSuite) TestAddSkipStatusWithIgnoredPath(c *C) {
c.Assert(err, IsNil)
_, err = w.Add(".gitignore")
c.Assert(err, IsNil)
_, err = w.Commit("Added .gitignore", defaultTestCommitOptions)
_, err = w.Commit("Added .gitignore", defaultTestCommitOptions())
c.Assert(err, IsNil)

err = util.WriteFile(fs, "fileToIgnore", []byte("file to ignore"), 0644)
Expand Down