diff --git a/worktree_commit.go b/worktree_commit.go index f62054bcb..07f147f65 100644 --- a/worktree_commit.go +++ b/worktree_commit.go @@ -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 { @@ -66,7 +64,7 @@ func (w *Worktree) Commit(msg string, opts *CommitOptions) (plumbing.Hash, error s: w.r.Storer, } - treeHash, err = h.BuildTree(idx, opts) + treeHash, err := h.BuildTree(idx, opts) if err != nil { return plumbing.ZeroHash, err } @@ -175,7 +173,10 @@ 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) { + allowEmpty := opts != nil && opts.AllowEmptyCommits + + if len(opts.Parents) == 0 && len(idx.Entries) == 0 && !allowEmpty { + // Empty initial commit is filtered first return plumbing.ZeroHash, ErrEmptyCommit } @@ -189,7 +190,21 @@ func (h *buildTreeHelper) BuildTree(idx *index.Index, opts *CommitOptions) (plum } } - return h.copyTreeToStorageRecursive(rootNode, h.trees[rootNode]) + treeHash, err := h.copyTreeToStorageRecursive(rootNode, h.trees[rootNode]) + if err != nil { + return plumbing.ZeroHash, err + } + + parentHash := plumbing.ZeroHash + if len(opts.Parents) > 0 { + parentHash = opts.Parents[0] + } + + if treeHash == parentHash && !allowEmpty { + return plumbing.ZeroHash, ErrEmptyCommit + } + + return treeHash, nil } func (h *buildTreeHelper) commitIndexEntry(e *index.Entry) error { diff --git a/worktree_commit_test.go b/worktree_commit_test.go index fee8b1548..5507cac47 100644 --- a/worktree_commit_test.go +++ b/worktree_commit_test.go @@ -89,6 +89,33 @@ func (s *WorktreeSuite) TestNothingToCommit(c *C) { 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")