aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2020-05-24 14:34:30 +0200
committerMáximo Cuadros <mcuadros@gmail.com>2020-05-24 14:34:30 +0200
commitd13825550a301d8e087122bbec87a2698424af27 (patch)
treefb9d3fdcde4981d89b32e2a3c98deddfc31d0527
parenta107e18b9327e9a5da7a44b3a872b2f43598dfb4 (diff)
parent6d8103df45ce09ffd5323b4ef46d26440400a54f (diff)
downloadgo-git-d13825550a301d8e087122bbec87a2698424af27.tar.gz
Merge branch 'master' of github.com:go-git/go-git into scope-config
-rw-r--r--_examples/README.md1
-rw-r--r--_examples/submodule/main.go55
-rw-r--r--options.go3
-rw-r--r--plumbing/format/diff/unified_encoder.go79
-rw-r--r--plumbing/format/diff/unified_encoder_test.go22
-rw-r--r--plumbing/object/commit.go9
-rw-r--r--plumbing/object/commit_test.go11
-rw-r--r--plumbing/object/tree_test.go11
-rw-r--r--remote.go9
-rw-r--r--remote_test.go28
10 files changed, 187 insertions, 41 deletions
diff --git a/_examples/README.md b/_examples/README.md
index cf9c2d3..6c17941 100644
--- a/_examples/README.md
+++ b/_examples/README.md
@@ -20,6 +20,7 @@ Here you can find a list of annotated _go-git_ examples:
- [remotes](remotes/main.go) - Working with remotes: adding, removing, etc
- [progress](progress/main.go) - Printing the progress information from the sideband
- [revision](revision/main.go) - Solve a revision into a commit
+- [submodule](submodule/main.go) - Submodule update remote
### Advanced
- [custom_http](custom_http/main.go) - Replacing the HTTP client using a custom one
diff --git a/_examples/submodule/main.go b/_examples/submodule/main.go
new file mode 100644
index 0000000..1a76193
--- /dev/null
+++ b/_examples/submodule/main.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "os"
+
+ "github.com/go-git/go-git/v5"
+ . "github.com/go-git/go-git/v5/_examples"
+)
+
+// Basic example of how to clone a repository including a submodule and
+// updating submodule ref
+func main() {
+ CheckArgs("<url>", "<directory>", "<submodule>")
+ url := os.Args[1]
+ directory := os.Args[2]
+ submodule := os.Args[3]
+
+ // Clone the given repository to the given directory
+ Info("git clone %s %s --recursive", url, directory)
+
+ r, err := git.PlainClone(directory, false, &git.CloneOptions{
+ URL: url,
+ RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
+ })
+
+ CheckIfError(err)
+
+ w, err := r.Worktree()
+ if err != nil {
+ CheckIfError(err)
+ }
+
+ sub, err := w.Submodule(submodule)
+ if err != nil {
+ CheckIfError(err)
+ }
+
+ sr, err := sub.Repository()
+ if err != nil {
+ CheckIfError(err)
+ }
+
+ sw, err := sr.Worktree()
+ if err != nil {
+ CheckIfError(err)
+ }
+
+ Info("git submodule update --remote")
+ err = sw.Pull(&git.PullOptions{
+ RemoteName: "origin",
+ })
+ if err != nil {
+ CheckIfError(err)
+ }
+}
diff --git a/options.go b/options.go
index 93fe684..5367031 100644
--- a/options.go
+++ b/options.go
@@ -190,6 +190,9 @@ type PushOptions struct {
// Prune specify that remote refs that match given RefSpecs and that do
// not exist locally will be removed.
Prune bool
+ // Force allows the push to update a remote branch even when the local
+ // branch does not descend from it.
+ Force bool
}
// Validate validates the fields and sets the default values.
diff --git a/plumbing/format/diff/unified_encoder.go b/plumbing/format/diff/unified_encoder.go
index 19c3f0b..413984a 100644
--- a/plumbing/format/diff/unified_encoder.go
+++ b/plumbing/format/diff/unified_encoder.go
@@ -86,48 +86,73 @@ func (e *UnifiedEncoder) writeFilePatchHeader(sb *strings.Builder, filePatch Fil
}
isBinary := filePatch.IsBinary()
- sb.WriteString(e.color[Meta])
+ var lines []string
switch {
case from != nil && to != nil:
hashEquals := from.Hash() == to.Hash()
- fmt.Fprintf(sb, "diff --git a/%s b/%s\n", from.Path(), to.Path())
+ lines = append(lines,
+ fmt.Sprintf("diff --git a/%s b/%s", from.Path(), to.Path()),
+ )
if from.Mode() != to.Mode() {
- fmt.Fprintf(sb, "old mode %o\n", from.Mode())
- fmt.Fprintf(sb, "new mode %o\n", to.Mode())
+ lines = append(lines,
+ fmt.Sprintf("old mode %o", from.Mode()),
+ fmt.Sprintf("new mode %o", to.Mode()),
+ )
}
if from.Path() != to.Path() {
- fmt.Fprintf(sb, "rename from %s\n", from.Path())
- fmt.Fprintf(sb, "rename to %s\n", to.Path())
+ lines = append(lines,
+ fmt.Sprintf("rename from %s", from.Path()),
+ fmt.Sprintf("rename to %s", to.Path()),
+ )
}
if from.Mode() != to.Mode() && !hashEquals {
- fmt.Fprintf(sb, "index %s..%s\n", from.Hash(), to.Hash())
+ lines = append(lines,
+ fmt.Sprintf("index %s..%s", from.Hash(), to.Hash()),
+ )
} else if !hashEquals {
- fmt.Fprintf(sb, "index %s..%s %o\n", from.Hash(), to.Hash(), from.Mode())
+ lines = append(lines,
+ fmt.Sprintf("index %s..%s %o", from.Hash(), to.Hash(), from.Mode()),
+ )
}
if !hashEquals {
- e.writePathLines(sb, "a/"+from.Path(), "b/"+to.Path(), isBinary)
+ lines = e.appendPathLines(lines, "a/"+from.Path(), "b/"+to.Path(), isBinary)
}
case from == nil:
- fmt.Fprintf(sb, "diff --git a/%s b/%s\n", to.Path(), to.Path())
- fmt.Fprintf(sb, "new file mode %o\n", to.Mode())
- fmt.Fprintf(sb, "index %s..%s\n", plumbing.ZeroHash, to.Hash())
- e.writePathLines(sb, "/dev/null", "b/"+to.Path(), isBinary)
+ lines = append(lines,
+ fmt.Sprintf("diff --git a/%s b/%s", to.Path(), to.Path()),
+ fmt.Sprintf("new file mode %o", to.Mode()),
+ fmt.Sprintf("index %s..%s", plumbing.ZeroHash, to.Hash()),
+ )
+ lines = e.appendPathLines(lines, "/dev/null", "b/"+to.Path(), isBinary)
case to == nil:
- fmt.Fprintf(sb, "diff --git a/%s b/%s\n", from.Path(), from.Path())
- fmt.Fprintf(sb, "deleted file mode %o\n", from.Mode())
- fmt.Fprintf(sb, "index %s..%s\n", from.Hash(), plumbing.ZeroHash)
- e.writePathLines(sb, "a/"+from.Path(), "/dev/null", isBinary)
+ lines = append(lines,
+ fmt.Sprintf("diff --git a/%s b/%s", from.Path(), from.Path()),
+ fmt.Sprintf("deleted file mode %o", from.Mode()),
+ fmt.Sprintf("index %s..%s", from.Hash(), plumbing.ZeroHash),
+ )
+ lines = e.appendPathLines(lines, "a/"+from.Path(), "/dev/null", isBinary)
+ }
+
+ sb.WriteString(e.color[Meta])
+ sb.WriteString(lines[0])
+ for _, line := range lines[1:] {
+ sb.WriteByte('\n')
+ sb.WriteString(line)
}
sb.WriteString(e.color.Reset(Meta))
+ sb.WriteByte('\n')
}
-func (e *UnifiedEncoder) writePathLines(sb *strings.Builder, fromPath, toPath string, isBinary bool) {
+func (e *UnifiedEncoder) appendPathLines(lines []string, fromPath, toPath string, isBinary bool) []string {
if isBinary {
- fmt.Fprintf(sb, "Binary files %s and %s differ\n", fromPath, toPath)
- } else {
- fmt.Fprintf(sb, "--- %s\n", fromPath)
- fmt.Fprintf(sb, "+++ %s\n", toPath)
+ return append(lines,
+ fmt.Sprintf("Binary files %s and %s differ", fromPath, toPath),
+ )
}
+ return append(lines,
+ fmt.Sprintf("--- %s", fromPath),
+ fmt.Sprintf("+++ %s", toPath),
+ )
}
type hunksGenerator struct {
@@ -341,9 +366,11 @@ func (o *op) writeTo(sb *strings.Builder, color ColorConfig) {
colorKey := operationColorKey[o.t]
sb.WriteString(color[colorKey])
sb.WriteByte(operationChar[o.t])
- sb.WriteString(o.text)
- sb.WriteString(color.Reset(colorKey))
- if !strings.HasSuffix(o.text, "\n") {
- sb.WriteString("\n\\ No newline at end of file\n")
+ if strings.HasSuffix(o.text, "\n") {
+ sb.WriteString(strings.TrimSuffix(o.text, "\n"))
+ } else {
+ sb.WriteString(o.text + "\n\\ No newline at end of file")
}
+ sb.WriteString(color.Reset(colorKey))
+ sb.WriteByte('\n')
}
diff --git a/plumbing/format/diff/unified_encoder_test.go b/plumbing/format/diff/unified_encoder_test.go
index 1e44572..22dc4f1 100644
--- a/plumbing/format/diff/unified_encoder_test.go
+++ b/plumbing/format/diff/unified_encoder_test.go
@@ -894,11 +894,11 @@ index 0adddcde4fd38042c354518351820eb06c417c82..d39ae38aad7ba9447b5e7998b2e4714f
color.Bold + "diff --git a/README.md b/README.md\n" +
"index 94954abda49de8615a048f8d2e64b5de848e27a1..f3dad9514629b9ff9136283ae331ad1fc95748a8 100644\n" +
"--- a/README.md\n" +
- "+++ b/README.md\n" + color.Reset +
+ "+++ b/README.md" + color.Reset + "\n" +
color.Cyan + "@@ -1,2 +1,2 @@" + color.Reset + "\n" +
" hello\n" +
- color.Red + "-world\n" + color.Reset +
- color.Green + "+bug\n" + color.Reset,
+ color.Red + "-world" + color.Reset + "\n" +
+ color.Green + "+bug" + color.Reset + "\n",
}, {
patch: testPatch{
message: "",
@@ -933,10 +933,10 @@ index 0adddcde4fd38042c354518351820eb06c417c82..d39ae38aad7ba9447b5e7998b2e4714f
color.Bold + "diff --git a/test.txt b/test.txt\n" +
"index 9daeafb9864cf43055ae93beb0afd6c7d144bfa4..180cf8328022becee9aaa2577a8f84ea2b9f3827 100644\n" +
"--- a/test.txt\n" +
- "+++ b/test.txt\n" + color.Reset +
+ "+++ b/test.txt" + color.Reset + "\n" +
color.Cyan + "@@ -1 +1 @@" + color.Reset + "\n" +
- color.Red + "-test\n" + color.Reset +
- color.Green + "+test2\n" + color.Reset,
+ color.Red + "-test" + color.Reset + "\n" +
+ color.Green + "+test2" + color.Reset + "\n",
}, {
patch: oneChunkPatch,
desc: "modified deleting lines file with context to 1 with color",
@@ -948,21 +948,21 @@ index 0adddcde4fd38042c354518351820eb06c417c82..d39ae38aad7ba9447b5e7998b2e4714f
color.Bold + "diff --git a/onechunk.txt b/onechunk.txt\n" +
"index ab5eed5d4a2c33aeef67e0188ee79bed666bde6f..0adddcde4fd38042c354518351820eb06c417c82 100644\n" +
"--- a/onechunk.txt\n" +
- "+++ b/onechunk.txt\n" + color.Reset +
+ "+++ b/onechunk.txt" + color.Reset + "\n" +
color.Cyan + "@@ -1,2 +1 @@" + color.Reset + "\n" +
- color.Red + "-A\n" + color.Reset +
+ color.Red + "-A" + color.Reset + "\n" +
" B\n" +
color.Cyan + "@@ -7,3 +6,2 @@" + color.Reset + " " + color.Reverse + "F" + color.Reset + "\n" +
" G\n" +
- color.Red + "-H\n" + color.Reset +
+ color.Red + "-H" + color.Reset + "\n" +
" I\n" +
color.Cyan + "@@ -14,3 +12,2 @@" + color.Reset + " " + color.Reverse + "M" + color.Reset + "\n" +
" N\n" +
- color.Red + "-Ñ\n" + color.Reset +
+ color.Red + "-Ñ" + color.Reset + "\n" +
" O\n" +
color.Cyan + "@@ -21,3 +18,2 @@" + color.Reset + " " + color.Reverse + "S" + color.Reset + "\n" +
" T\n" +
- color.Red + "-U\n" + color.Reset +
+ color.Red + "-U" + color.Reset + "\n" +
" V\n",
}}
diff --git a/plumbing/object/commit.go b/plumbing/object/commit.go
index b27f20b..113cb29 100644
--- a/plumbing/object/commit.go
+++ b/plumbing/object/commit.go
@@ -87,9 +87,12 @@ func (c *Commit) PatchContext(ctx context.Context, to *Commit) (*Patch, error) {
return nil, err
}
- toTree, err := to.Tree()
- if err != nil {
- return nil, err
+ var toTree *Tree
+ if to != nil {
+ toTree, err = to.Tree()
+ if err != nil {
+ return nil, err
+ }
}
return fromTree.PatchContext(ctx, toTree)
diff --git a/plumbing/object/commit_test.go b/plumbing/object/commit_test.go
index 28a7a81..e260a7f 100644
--- a/plumbing/object/commit_test.go
+++ b/plumbing/object/commit_test.go
@@ -12,8 +12,8 @@ import (
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/cache"
- . "gopkg.in/check.v1"
"github.com/go-git/go-git/v5/storage/filesystem"
+ . "gopkg.in/check.v1"
)
type SuiteCommit struct {
@@ -188,6 +188,15 @@ Binary files /dev/null and b/binary.jpg differ
c.Assert(buf.String(), Equals, patch.String())
}
+func (s *SuiteCommit) TestPatchContext_ToNil(c *C) {
+ from := s.commit(c, plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"))
+
+ patch, err := from.PatchContext(context.Background(), nil)
+ c.Assert(err, IsNil)
+
+ c.Assert(len(patch.String()), Equals, 242679)
+}
+
func (s *SuiteCommit) TestCommitEncodeDecodeIdempotent(c *C) {
ts, err := time.Parse(time.RFC3339, "2006-01-02T15:04:05-07:00")
c.Assert(err, IsNil)
diff --git a/plumbing/object/tree_test.go b/plumbing/object/tree_test.go
index 474bb6a..d9dad47 100644
--- a/plumbing/object/tree_test.go
+++ b/plumbing/object/tree_test.go
@@ -377,6 +377,17 @@ func (s *TreeSuite) TestTreeWalkerNextNonRecursive(c *C) {
c.Assert(count, Equals, 8)
}
+func (s *TreeSuite) TestPatchContext_ToNil(c *C) {
+ commit := s.commit(c, plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"))
+ tree, err := commit.Tree()
+ c.Assert(err, IsNil)
+
+ patch, err := tree.PatchContext(context.Background(), nil)
+ c.Assert(err, IsNil)
+
+ c.Assert(len(patch.String()), Equals, 242971)
+}
+
func (s *TreeSuite) TestTreeWalkerNextSubmodule(c *C) {
dotgit := fixtures.ByURL("https://github.com/git-fixtures/submodule.git").One().DotGit()
st := filesystem.NewStorage(dotgit, cache.NewObjectLRUDefault())
diff --git a/remote.go b/remote.go
index 98c4acf..e642c57 100644
--- a/remote.go
+++ b/remote.go
@@ -123,6 +123,15 @@ func (r *Remote) PushContext(ctx context.Context, o *PushOptions) (err error) {
return ErrDeleteRefNotSupported
}
+ if o.Force {
+ for i := 0; i < len(o.RefSpecs); i++ {
+ rs := &o.RefSpecs[i]
+ if !rs.IsForceUpdate() {
+ o.RefSpecs[i] = config.RefSpec("+" + rs.String())
+ }
+ }
+ }
+
localRefs, err := r.references()
if err != nil {
return err
diff --git a/remote_test.go b/remote_test.go
index 0fc3449..ce46390 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -612,6 +612,34 @@ func (s *RemoteSuite) TestPushForce(c *C) {
c.Assert(newRef, Not(DeepEquals), oldRef)
}
+func (s *RemoteSuite) TestPushForceWithOption(c *C) {
+ f := fixtures.Basic().One()
+ sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault())
+
+ dstFs := f.DotGit()
+ dstSto := filesystem.NewStorage(dstFs, cache.NewObjectLRUDefault())
+
+ url := dstFs.Root()
+ r := NewRemote(sto, &config.RemoteConfig{
+ Name: DefaultRemoteName,
+ URLs: []string{url},
+ })
+
+ oldRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
+ c.Assert(err, IsNil)
+ c.Assert(oldRef, NotNil)
+
+ err = r.Push(&PushOptions{
+ RefSpecs: []config.RefSpec{"refs/heads/master:refs/heads/branch"},
+ Force: true,
+ })
+ c.Assert(err, IsNil)
+
+ newRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
+ c.Assert(err, IsNil)
+ c.Assert(newRef, Not(DeepEquals), oldRef)
+}
+
func (s *RemoteSuite) TestPushPrune(c *C) {
fs := fixtures.Basic().One().DotGit()
url := c.MkDir()