aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Gomes <pjbgf@linux.com>2024-05-22 21:09:35 +0000
committerGitHub <noreply@github.com>2024-05-22 21:09:35 +0000
commitc7feada87363f96c224214ba309efd5cf5a886fc (patch)
tree81b33ed60af5532c3e5887888fc853902b8839f0
parent7ff5a5d839262bfee69a47d315a624943f812d6b (diff)
parent746141efcf4c6dcab3063a6e54d6eb20a3004969 (diff)
downloadgo-git-c7feada87363f96c224214ba309efd5cf5a886fc.tar.gz
Merge pull request #1050 from onee-only/fix-empty-commit
git: worktree_commit, Modify checking empty commit. Fixes #723
-rw-r--r--repository_test.go7
-rw-r--r--worktree_commit.go26
-rw-r--r--worktree_commit_test.go121
-rw-r--r--worktree_test.go29
4 files changed, 159 insertions, 24 deletions
diff --git a/repository_test.go b/repository_test.go
index b211f8c..0b77c5a 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -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,
})
c.Assert(err, IsNil)
return h
diff --git a/worktree_commit.go b/worktree_commit.go
index f62054b..2faf6f0 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 {
@@ -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
@@ -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{}
diff --git a/worktree_commit_test.go b/worktree_commit_test.go
index ae8f841..e028fac 100644
--- a/worktree_commit_test.go
+++ b/worktree_commit_test.go
@@ -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")
@@ -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)
@@ -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,
@@ -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")
@@ -258,7 +372,8 @@ 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)
diff --git a/worktree_test.go b/worktree_test.go
index f67cca2..3e151f6 100644
--- a/worktree_test.go
+++ b/worktree_test.go
@@ -32,9 +32,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
@@ -87,8 +89,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)
@@ -124,15 +127,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)
@@ -285,7 +290,8 @@ 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"),
})
@@ -293,8 +299,9 @@ func (s *WorktreeSuite) TestPullAlreadyUptodate(c *C) {
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)
@@ -1001,14 +1008,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)
@@ -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)