Skip to content

Commit

Permalink
Merge branch 'master' into jc-push-atomic
Browse files Browse the repository at this point in the history
  • Loading branch information
mcuadros committed Dec 10, 2021
2 parents 589a41c + 39f97ab commit fe158cd
Show file tree
Hide file tree
Showing 25 changed files with 438 additions and 42 deletions.
2 changes: 1 addition & 1 deletion _examples/remotes/main.go
Expand Up @@ -33,7 +33,7 @@ func main() {
CheckIfError(err)

// List remotes from a repository
Info("git remotes -v")
Info("git remote -v")

list, err := r.Remotes()
CheckIfError(err)
Expand Down
33 changes: 33 additions & 0 deletions config/branch.go
Expand Up @@ -2,6 +2,7 @@ package config

import (
"errors"
"strings"

"github.com/go-git/go-git/v5/plumbing"
format "github.com/go-git/go-git/v5/plumbing/format/config"
Expand All @@ -26,6 +27,12 @@ type Branch struct {
// "true" and "interactive". "false" is undocumented and
// typically represented by the non-existence of this field
Rebase string
// Description explains what the branch is for.
// Multi-line explanations may be used.
//
// Original git command to edit:
// git branch --edit-description
Description string

raw *format.Subsection
}
Expand Down Expand Up @@ -75,16 +82,42 @@ func (b *Branch) marshal() *format.Subsection {
b.raw.SetOption(rebaseKey, b.Rebase)
}

if b.Description == "" {
b.raw.RemoveOption(descriptionKey)
} else {
desc := quoteDescription(b.Description)
b.raw.SetOption(descriptionKey, desc)
}

return b.raw
}

// hack to trigger conditional quoting in the
// plumbing/format/config/Encoder.encodeOptions
//
// Current Encoder implementation uses Go %q format if value contains a backslash character,
// which is not consistent with reference git implementation.
// git just replaces newline characters with \n, while Encoder prints them directly.
// Until value quoting fix, we should escape description value by replacing newline characters with \n.
func quoteDescription(desc string) string {
return strings.ReplaceAll(desc, "\n", `\n`)
}

func (b *Branch) unmarshal(s *format.Subsection) error {
b.raw = s

b.Name = b.raw.Name
b.Remote = b.raw.Options.Get(remoteSection)
b.Merge = plumbing.ReferenceName(b.raw.Options.Get(mergeKey))
b.Rebase = b.raw.Options.Get(rebaseKey)
b.Description = unquoteDescription(b.raw.Options.Get(descriptionKey))

return b.Validate()
}

// hack to enable conditional quoting in the
// plumbing/format/config/Encoder.encodeOptions
// goto quoteDescription for details.
func unquoteDescription(desc string) string {
return strings.ReplaceAll(desc, `\n`, "\n")
}
1 change: 1 addition & 0 deletions config/config.go
Expand Up @@ -247,6 +247,7 @@ const (
rebaseKey = "rebase"
nameKey = "name"
emailKey = "email"
descriptionKey = "description"
defaultBranchKey = "defaultBranch"

// DefaultPackWindow holds the number of previous objects used to
Expand Down
11 changes: 8 additions & 3 deletions config/config_test.go
Expand Up @@ -50,6 +50,7 @@ func (s *ConfigSuite) TestUnmarshal(c *C) {
[branch "master"]
remote = origin
merge = refs/heads/master
description = "Add support for branch description.\\n\\nEdit branch description: git branch --edit-description\\n"
[init]
defaultBranch = main
[url "ssh://git@github.com/"]
Expand Down Expand Up @@ -86,6 +87,7 @@ func (s *ConfigSuite) TestUnmarshal(c *C) {
c.Assert(cfg.Submodules["qux"].Branch, Equals, "bar")
c.Assert(cfg.Branches["master"].Remote, Equals, "origin")
c.Assert(cfg.Branches["master"].Merge, Equals, plumbing.ReferenceName("refs/heads/master"))
c.Assert(cfg.Branches["master"].Description, Equals, "Add support for branch description.\n\nEdit branch description: git branch --edit-description\n")
c.Assert(cfg.Init.DefaultBranch, Equals, "main")
}

Expand All @@ -111,6 +113,7 @@ func (s *ConfigSuite) TestMarshal(c *C) {
[branch "master"]
remote = origin
merge = refs/heads/master
description = "Add support for branch description.\\n\\nEdit branch description: git branch --edit-description\\n"
[url "ssh://git@github.com/"]
insteadOf = https://github.com/
[init]
Expand Down Expand Up @@ -149,9 +152,10 @@ func (s *ConfigSuite) TestMarshal(c *C) {
}

cfg.Branches["master"] = &Branch{
Name: "master",
Remote: "origin",
Merge: "refs/heads/master",
Name: "master",
Remote: "origin",
Merge: "refs/heads/master",
Description: "Add support for branch description.\n\nEdit branch description: git branch --edit-description\n",
}

cfg.URLs["ssh://git@github.com/"] = &URL{
Expand Down Expand Up @@ -364,4 +368,5 @@ func (s *ConfigSuite) TestRemoveUrlOptions(c *C) {
if strings.Contains(string(buf), "url") {
c.Fatal("conifg should not contain any url sections")
}
c.Assert(err, IsNil)
}
17 changes: 17 additions & 0 deletions options.go
Expand Up @@ -228,12 +228,27 @@ type PushOptions struct {
// FollowTags will send any annotated tags with a commit target reachable from
// the refs already being pushed
FollowTags bool
// ForceWithLease allows a force push as long as the remote ref adheres to a "lease"
ForceWithLease *ForceWithLease
// PushOptions sets options to be transferred to the server during push.
Options map[string]string
// Atomic sets option to be an atomic push
Atomic bool
}

// ForceWithLease sets fields on the lease
// If neither RefName nor Hash are set, ForceWithLease protects
// all refs in the refspec by ensuring the ref of the remote in the local repsitory
// matches the one in the ref advertisement.
type ForceWithLease struct {
// RefName, when set will protect the ref by ensuring it matches the
// hash in the ref advertisement.
RefName plumbing.ReferenceName
// Hash is the expected object id of RefName. The push will be rejected unless this
// matches the corresponding object id of RefName in the refs advertisement.
Hash plumbing.Hash
}

// Validate validates the fields and sets the default values.
func (o *PushOptions) Validate() error {
if o.RemoteName == "" {
Expand Down Expand Up @@ -293,6 +308,8 @@ type CheckoutOptions struct {
// target branch. Force and Keep are mutually exclusive, should not be both
// set to true.
Keep bool
// SparseCheckoutDirectories
SparseCheckoutDirectories []string
}

// Validate validates the fields and sets the default values.
Expand Down
34 changes: 25 additions & 9 deletions plumbing/format/index/encoder.go
Expand Up @@ -14,7 +14,7 @@ import (

var (
// EncodeVersionSupported is the range of supported index versions
EncodeVersionSupported uint32 = 2
EncodeVersionSupported uint32 = 3

// ErrInvalidTimestamp is returned by Encode if a Index with a Entry with
// negative timestamp values
Expand All @@ -36,9 +36,9 @@ func NewEncoder(w io.Writer) *Encoder {

// Encode writes the Index to the stream of the encoder.
func (e *Encoder) Encode(idx *Index) error {
// TODO: support versions v3 and v4
// TODO: support v4
// TODO: support extensions
if idx.Version != EncodeVersionSupported {
if idx.Version > EncodeVersionSupported {
return ErrUnsupportedVersion
}

Expand Down Expand Up @@ -68,8 +68,12 @@ func (e *Encoder) encodeEntries(idx *Index) error {
if err := e.encodeEntry(entry); err != nil {
return err
}
entryLength := entryHeaderLength
if entry.IntentToAdd || entry.SkipWorktree {
entryLength += 2
}

wrote := entryHeaderLength + len(entry.Name)
wrote := entryLength + len(entry.Name)
if err := e.padEntry(wrote); err != nil {
return err
}
Expand All @@ -79,10 +83,6 @@ func (e *Encoder) encodeEntries(idx *Index) error {
}

func (e *Encoder) encodeEntry(entry *Entry) error {
if entry.IntentToAdd || entry.SkipWorktree {
return ErrUnsupportedVersion
}

sec, nsec, err := e.timeToUint32(&entry.CreatedAt)
if err != nil {
return err
Expand Down Expand Up @@ -110,9 +110,25 @@ func (e *Encoder) encodeEntry(entry *Entry) error {
entry.GID,
entry.Size,
entry.Hash[:],
flags,
}

flagsFlow := []interface{}{flags}

if entry.IntentToAdd || entry.SkipWorktree {
var extendedFlags uint16

if entry.IntentToAdd {
extendedFlags |= intentToAddMask
}
if entry.SkipWorktree {
extendedFlags |= skipWorkTreeMask
}

flagsFlow = []interface{}{flags | entryExtended, extendedFlags}
}

flow = append(flow, flagsFlow...)

if err := binary.Write(e.w, flow...); err != nil {
return err
}
Expand Down
26 changes: 21 additions & 5 deletions plumbing/format/index/encoder_test.go
Expand Up @@ -57,7 +57,7 @@ func (s *IndexSuite) TestEncode(c *C) {
}

func (s *IndexSuite) TestEncodeUnsupportedVersion(c *C) {
idx := &Index{Version: 3}
idx := &Index{Version: 4}

buf := bytes.NewBuffer(nil)
e := NewEncoder(buf)
Expand All @@ -67,24 +67,40 @@ func (s *IndexSuite) TestEncodeUnsupportedVersion(c *C) {

func (s *IndexSuite) TestEncodeWithIntentToAddUnsupportedVersion(c *C) {
idx := &Index{
Version: 2,
Version: 3,
Entries: []*Entry{{IntentToAdd: true}},
}

buf := bytes.NewBuffer(nil)
e := NewEncoder(buf)
err := e.Encode(idx)
c.Assert(err, Equals, ErrUnsupportedVersion)
c.Assert(err, IsNil)

output := &Index{}
d := NewDecoder(buf)
err = d.Decode(output)
c.Assert(err, IsNil)

c.Assert(cmp.Equal(idx, output), Equals, true)
c.Assert(output.Entries[0].IntentToAdd, Equals, true)
}

func (s *IndexSuite) TestEncodeWithSkipWorktreeUnsupportedVersion(c *C) {
idx := &Index{
Version: 2,
Version: 3,
Entries: []*Entry{{SkipWorktree: true}},
}

buf := bytes.NewBuffer(nil)
e := NewEncoder(buf)
err := e.Encode(idx)
c.Assert(err, Equals, ErrUnsupportedVersion)
c.Assert(err, IsNil)

output := &Index{}
d := NewDecoder(buf)
err = d.Decode(output)
c.Assert(err, IsNil)

c.Assert(cmp.Equal(idx, output), Equals, true)
c.Assert(output.Entries[0].SkipWorktree, Equals, true)
}
18 changes: 18 additions & 0 deletions plumbing/format/index/index.go
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"path/filepath"
"strings"
"time"

"github.com/go-git/go-git/v5/plumbing"
Expand Down Expand Up @@ -211,3 +212,20 @@ type EndOfIndexEntry struct {
// their contents).
Hash plumbing.Hash
}

// SkipUnless applies patterns in the form of A, A/B, A/B/C
// to the index to prevent the files from being checked out
func (i *Index) SkipUnless(patterns []string) {
for _, e := range i.Entries {
var include bool
for _, pattern := range patterns {
if strings.HasPrefix(e.Name, pattern) {
include = true
break
}
}
if !include {
e.SkipWorktree = true
}
}
}
4 changes: 4 additions & 0 deletions plumbing/object/treenoder.go
Expand Up @@ -38,6 +38,10 @@ func NewTreeRootNode(t *Tree) noder.Noder {
}
}

func (t *treeNoder) Skip() bool {
return false
}

func (t *treeNoder) isRoot() bool {
return t.name == ""
}
Expand Down
6 changes: 3 additions & 3 deletions plumbing/protocol/packp/updreq.go
Expand Up @@ -87,9 +87,9 @@ type Action string

const (
Create Action = "create"
Update = "update"
Delete = "delete"
Invalid = "invalid"
Update Action = "update"
Delete Action = "delete"
Invalid Action = "invalid"
)

type Command struct {
Expand Down

0 comments on commit fe158cd

Please sign in to comment.