Skip to content

Commit

Permalink
feat: add file with using .gitignore, fixed src-d/go-git#1219
Browse files Browse the repository at this point in the history
  • Loading branch information
jk2K committed Jun 10, 2020
1 parent 96a108e commit e4a5532
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 36 deletions.
6 changes: 6 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,12 @@ var (
ErrMissingAuthor = errors.New("author field is required")
)

// AddOptions describes how a add operation should be performed
type AddOptions struct {
All bool
Path string
}

// CommitOptions describes how a commit operation should be performed.
type CommitOptions struct {
// All automatically stage files that have been modified and deleted, but
Expand Down
101 changes: 65 additions & 36 deletions worktree_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path"
"path/filepath"
"strings"

"github.com/go-git/go-billy/v5/util"
"github.com/go-git/go-git/v5/plumbing"
Expand Down Expand Up @@ -264,43 +265,22 @@ func diffTreeIsEquals(a, b noder.Hasher) bool {
// the worktree to the index. If any of the files is already staged in the index
// no error is returned. When path is a file, the blob.Hash is returned.
func (w *Worktree) Add(path string) (plumbing.Hash, error) {
// TODO(mcuadros): remove plumbing.Hash from signature at v5.
s, err := w.Status()
if err != nil {
return plumbing.ZeroHash, err
}

idx, err := w.r.Storer.Index()
if err != nil {
return plumbing.ZeroHash, err
}

var h plumbing.Hash
var added bool

fi, err := w.Filesystem.Lstat(path)
if err != nil || !fi.IsDir() {
added, h, err = w.doAddFile(idx, s, path)
} else {
added, err = w.doAddDirectory(idx, s, path)
}

if err != nil {
return h, err
}

if !added {
return h, nil
}

return h, w.r.Storer.SetIndex(idx)
return w.doAdd(path, make([]gitignore.Pattern, 0))
}

func (w *Worktree) doAddDirectory(idx *index.Index, s Status, directory string) (added bool, err error) {
func (w *Worktree) doAddDirectory(idx *index.Index, s Status, directory string, ignorePattern []gitignore.Pattern) (added bool, err error) {
files, err := w.Filesystem.ReadDir(directory)
if err != nil {
return false, err
}
if len(ignorePattern) > 0 {
m := gitignore.NewMatcher(ignorePattern)
matchPath := strings.Split(directory, string(os.PathSeparator))
if m.Match(matchPath, true) {
// ignore
return false, nil
}
}

for _, file := range files {
name := path.Join(directory, file.Name())
Expand All @@ -311,9 +291,9 @@ func (w *Worktree) doAddDirectory(idx *index.Index, s Status, directory string)
// ignore special git directory
continue
}
a, err = w.doAddDirectory(idx, s, name)
a, err = w.doAddDirectory(idx, s, name, ignorePattern)
} else {
a, _, err = w.doAddFile(idx, s, name)
a, _, err = w.doAddFile(idx, s, name, ignorePattern)
}

if err != nil {
Expand All @@ -328,6 +308,47 @@ func (w *Worktree) doAddDirectory(idx *index.Index, s Status, directory string)
return
}

// add changes from all tracked and untracked files
func (w *Worktree) AddWithOptions(opts *AddOptions) (plumbing.Hash, error) {
if opts.All {
return w.doAdd(".", w.Excludes)
}
return w.Add(opts.Path)
}

func (w *Worktree) doAdd(path string, ignorePattern []gitignore.Pattern) (plumbing.Hash, error) {
// TODO(mcuadros): remove plumbing.Hash from signature at v5.
s, err := w.Status()
if err != nil {
return plumbing.ZeroHash, err
}

idx, err := w.r.Storer.Index()
if err != nil {
return plumbing.ZeroHash, err
}

var h plumbing.Hash
var added bool

fi, err := w.Filesystem.Lstat(path)
if err != nil || !fi.IsDir() {
added, h, err = w.doAddFile(idx, s, path, ignorePattern)
} else {
added, err = w.doAddDirectory(idx, s, path, ignorePattern)
}

if err != nil {
return h, err
}

if !added {
return h, nil
}

return h, w.r.Storer.SetIndex(idx)
}

// AddGlob adds all paths, matching pattern, to the index. If pattern matches a
// directory path, all directory contents are added to the index recursively. No
// error is returned if all matching paths are already staged in index.
Expand Down Expand Up @@ -360,9 +381,9 @@ func (w *Worktree) AddGlob(pattern string) error {

var added bool
if fi.IsDir() {
added, err = w.doAddDirectory(idx, s, file)
added, err = w.doAddDirectory(idx, s, file, make([]gitignore.Pattern, 0))
} else {
added, _, err = w.doAddFile(idx, s, file)
added, _, err = w.doAddFile(idx, s, file, make([]gitignore.Pattern, 0))
}

if err != nil {
Expand All @@ -383,10 +404,18 @@ func (w *Worktree) AddGlob(pattern string) error {

// doAddFile create a new blob from path and update the index, added is true if
// the file added is different from the index.
func (w *Worktree) doAddFile(idx *index.Index, s Status, path string) (added bool, h plumbing.Hash, err error) {
func (w *Worktree) doAddFile(idx *index.Index, s Status, path string, ignorePattern []gitignore.Pattern) (added bool, h plumbing.Hash, err error) {
if s.File(path).Worktree == Unmodified {
return false, h, nil
}
if len(ignorePattern) > 0 {
m := gitignore.NewMatcher(ignorePattern)
matchPath := strings.Split(path, string(os.PathSeparator))
if m.Match(matchPath, true) {
// ignore
return false, h, nil
}
}

h, err = w.copyFileToStorage(path)
if err != nil {
Expand Down
46 changes: 46 additions & 0 deletions worktree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1370,6 +1370,52 @@ func (s *WorktreeSuite) TestAddDirectoryErrorNotFound(c *C) {
c.Assert(h.IsZero(), Equals, true)
}

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

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

idx, err := w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 9)

err = util.WriteFile(w.Filesystem, "file1", []byte("file1"), 0644)
c.Assert(err, IsNil)

err = util.WriteFile(w.Filesystem, "file2", []byte("file2"), 0644)
c.Assert(err, IsNil)

err = util.WriteFile(w.Filesystem, "file3", []byte("ignore me"), 0644)
c.Assert(err, IsNil)

w.Excludes = make([]gitignore.Pattern, 0)
w.Excludes = append(w.Excludes, gitignore.ParsePattern("file3", nil))

_, err = w.AddWithOptions(&AddOptions{All: true})
c.Assert(err, IsNil)

idx, err = w.r.Storer.Index()
c.Assert(err, IsNil)
c.Assert(idx.Entries, HasLen, 11)

status, err := w.Status()
c.Assert(err, IsNil)
c.Assert(status, HasLen, 2)

file1 := status.File("file1")
c.Assert(file1.Staging, Equals, Added)
file2 := status.File("file2")
c.Assert(file2.Staging, Equals, Added)
file3 := status.File("file3")
c.Assert(file3.Staging, Equals, Untracked)
c.Assert(file3.Worktree, Equals, Untracked)
}

func (s *WorktreeSuite) TestAddGlob(c *C) {
fs := memfs.New()
w := &Worktree{
Expand Down

0 comments on commit e4a5532

Please sign in to comment.