Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit f0fb843

Browse files
authored
Merge pull request #489 from mcuadros/shallow-push
repository: allow push from shallow repositories
2 parents 9775f82 + d851b90 commit f0fb843

File tree

6 files changed

+166
-41
lines changed

6 files changed

+166
-41
lines changed

plumbing/object/commit_walker.go

+36-12
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,16 @@ type commitPreIterator struct {
1818
// The given callback will be called for each visited commit. Each commit will
1919
// be visited only once. If the callback returns an error, walking will stop
2020
// and will return the error. Other errors might be returned if the history
21-
// cannot be traversed (e.g. missing objects).
22-
func NewCommitPreorderIter(c *Commit) CommitIter {
21+
// cannot be traversed (e.g. missing objects). Ignore allows to skip some
22+
// commits from being iterated.
23+
func NewCommitPreorderIter(c *Commit, ignore []plumbing.Hash) CommitIter {
24+
seen := make(map[plumbing.Hash]bool)
25+
for _, h := range ignore {
26+
seen[h] = true
27+
}
28+
2329
return &commitPreIterator{
24-
seen: make(map[plumbing.Hash]bool),
30+
seen: seen,
2531
stack: make([]CommitIter, 0),
2632
start: c,
2733
}
@@ -51,20 +57,33 @@ func (w *commitPreIterator) Next() (*Commit, error) {
5157
}
5258
}
5359

54-
// check and update seen
5560
if w.seen[c.Hash] {
5661
continue
5762
}
5863

5964
w.seen[c.Hash] = true
65+
6066
if c.NumParents() > 0 {
61-
w.stack = append(w.stack, c.Parents())
67+
w.stack = append(w.stack, filteredParentIter(c, w.seen))
6268
}
6369

6470
return c, nil
6571
}
6672
}
6773

74+
func filteredParentIter(c *Commit, seen map[plumbing.Hash]bool) CommitIter {
75+
var hashes []plumbing.Hash
76+
for _, h := range c.ParentHashes {
77+
if !seen[h] {
78+
hashes = append(hashes, h)
79+
}
80+
}
81+
82+
return NewCommitIter(c.s,
83+
storer.NewEncodedObjectLookupIter(c.s, plumbing.CommitObject, hashes),
84+
)
85+
}
86+
6887
func (w *commitPreIterator) ForEach(cb func(*Commit) error) error {
6988
for {
7089
c, err := w.Next()
@@ -98,11 +117,16 @@ type commitPostIterator struct {
98117
// history like WalkCommitHistory but in post-order. This means that after
99118
// walking a merge commit, the merged commit will be walked before the base
100119
// it was merged on. This can be useful if you wish to see the history in
101-
// chronological order.
102-
func NewCommitPostorderIter(c *Commit) CommitIter {
120+
// chronological order. Ignore allows to skip some commits from being iterated.
121+
func NewCommitPostorderIter(c *Commit, ignore []plumbing.Hash) CommitIter {
122+
seen := make(map[plumbing.Hash]bool)
123+
for _, h := range ignore {
124+
seen[h] = true
125+
}
126+
103127
return &commitPostIterator{
104128
stack: []*Commit{c},
105-
seen: make(map[plumbing.Hash]bool),
129+
seen: seen,
106130
}
107131
}
108132

@@ -114,17 +138,17 @@ func (w *commitPostIterator) Next() (*Commit, error) {
114138

115139
c := w.stack[len(w.stack)-1]
116140
w.stack = w.stack[:len(w.stack)-1]
141+
117142
if w.seen[c.Hash] {
118143
continue
119144
}
145+
120146
w.seen[c.Hash] = true
121147

122-
err := c.Parents().ForEach(func(pcm *Commit) error {
123-
w.stack = append(w.stack, pcm)
148+
return c, c.Parents().ForEach(func(p *Commit) error {
149+
w.stack = append(w.stack, p)
124150
return nil
125151
})
126-
127-
return c, err
128152
}
129153
}
130154

plumbing/object/commit_walker_test.go

+52-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package object
22

3-
import . "gopkg.in/check.v1"
3+
import (
4+
"gopkg.in/src-d/go-git.v4/plumbing"
5+
6+
. "gopkg.in/check.v1"
7+
)
48

59
type CommitWalkerSuite struct {
610
BaseObjectsSuite
@@ -12,8 +16,7 @@ func (s *CommitWalkerSuite) TestCommitPreIterator(c *C) {
1216
commit := s.commit(c, s.Fixture.Head)
1317

1418
var commits []*Commit
15-
wIter := NewCommitPreorderIter(commit)
16-
wIter.ForEach(func(c *Commit) error {
19+
NewCommitPreorderIter(commit, nil).ForEach(func(c *Commit) error {
1720
commits = append(commits, c)
1821
return nil
1922
})
@@ -35,12 +38,33 @@ func (s *CommitWalkerSuite) TestCommitPreIterator(c *C) {
3538
}
3639
}
3740

41+
func (s *CommitWalkerSuite) TestCommitPreIteratorWithIgnore(c *C) {
42+
commit := s.commit(c, s.Fixture.Head)
43+
44+
var commits []*Commit
45+
NewCommitPreorderIter(commit, []plumbing.Hash{
46+
plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
47+
}).ForEach(func(c *Commit) error {
48+
commits = append(commits, c)
49+
return nil
50+
})
51+
52+
c.Assert(commits, HasLen, 2)
53+
54+
expected := []string{
55+
"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
56+
"918c48b83bd081e863dbe1b80f8998f058cd8294",
57+
}
58+
for i, commit := range commits {
59+
c.Assert(commit.Hash.String(), Equals, expected[i])
60+
}
61+
}
62+
3863
func (s *CommitWalkerSuite) TestCommitPostIterator(c *C) {
3964
commit := s.commit(c, s.Fixture.Head)
4065

4166
var commits []*Commit
42-
wIter := NewCommitPostorderIter(commit)
43-
wIter.ForEach(func(c *Commit) error {
67+
NewCommitPostorderIter(commit, nil).ForEach(func(c *Commit) error {
4468
commits = append(commits, c)
4569
return nil
4670
})
@@ -57,6 +81,29 @@ func (s *CommitWalkerSuite) TestCommitPostIterator(c *C) {
5781
"b029517f6300c2da0f4b651b8642506cd6aaf45d",
5882
"35e85108805c84807bc66a02d91535e1e24b38b9",
5983
}
84+
85+
for i, commit := range commits {
86+
c.Assert(commit.Hash.String(), Equals, expected[i])
87+
}
88+
}
89+
90+
func (s *CommitWalkerSuite) TestCommitPostIteratorWithIgnore(c *C) {
91+
commit := s.commit(c, s.Fixture.Head)
92+
93+
var commits []*Commit
94+
NewCommitPostorderIter(commit, []plumbing.Hash{
95+
plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
96+
}).ForEach(func(c *Commit) error {
97+
commits = append(commits, c)
98+
return nil
99+
})
100+
101+
c.Assert(commits, HasLen, 2)
102+
103+
expected := []string{
104+
"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
105+
"918c48b83bd081e863dbe1b80f8998f058cd8294",
106+
}
60107
for i, commit := range commits {
61108
c.Assert(commit.Hash.String(), Equals, expected[i])
62109
}

plumbing/revlist/revlist.go

+19-20
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@ import (
1616
// the reachable objects from the given objects. Ignore param are object hashes
1717
// that we want to ignore on the result. All that objects must be accessible
1818
// from the object storer.
19-
func Objects(
20-
s storer.EncodedObjectStorer,
21-
objects []plumbing.Hash,
22-
ignore []plumbing.Hash) ([]plumbing.Hash, error) {
23-
19+
func Objects(s storer.EncodedObjectStorer, objects, ignore []plumbing.Hash) ([]plumbing.Hash, error) {
2420
seen := hashListToSet(ignore)
2521
result := make(map[plumbing.Hash]bool)
2622

@@ -32,7 +28,7 @@ func Objects(
3228
}
3329

3430
for _, h := range objects {
35-
if err := processObject(s, h, seen, walkerFunc); err != nil {
31+
if err := processObject(s, h, seen, ignore, walkerFunc); err != nil {
3632
return nil, err
3733
}
3834
}
@@ -45,6 +41,7 @@ func processObject(
4541
s storer.EncodedObjectStorer,
4642
h plumbing.Hash,
4743
seen map[plumbing.Hash]bool,
44+
ignore []plumbing.Hash,
4845
walkerFunc func(h plumbing.Hash),
4946
) error {
5047
o, err := s.EncodedObject(plumbing.AnyObject, h)
@@ -59,12 +56,12 @@ func processObject(
5956

6057
switch do := do.(type) {
6158
case *object.Commit:
62-
return reachableObjects(do, seen, walkerFunc)
59+
return reachableObjects(do, seen, ignore, walkerFunc)
6360
case *object.Tree:
6461
return iterateCommitTrees(seen, do, walkerFunc)
6562
case *object.Tag:
6663
walkerFunc(do.Hash)
67-
return processObject(s, do.Target, seen, walkerFunc)
64+
return processObject(s, do.Target, seen, ignore, walkerFunc)
6865
case *object.Blob:
6966
walkerFunc(do.Hash)
7067
default:
@@ -82,22 +79,24 @@ func processObject(
8279
func reachableObjects(
8380
commit *object.Commit,
8481
seen map[plumbing.Hash]bool,
82+
ignore []plumbing.Hash,
8583
cb func(h plumbing.Hash)) error {
86-
return object.NewCommitPreorderIter(commit).
87-
ForEach(func(commit *object.Commit) error {
88-
if seen[commit.Hash] {
89-
return nil
90-
}
9184

92-
cb(commit.Hash)
85+
i := object.NewCommitPreorderIter(commit, ignore)
86+
return i.ForEach(func(commit *object.Commit) error {
87+
if seen[commit.Hash] {
88+
return nil
89+
}
90+
91+
cb(commit.Hash)
9392

94-
tree, err := commit.Tree()
95-
if err != nil {
96-
return err
97-
}
93+
tree, err := commit.Tree()
94+
if err != nil {
95+
return err
96+
}
9897

99-
return iterateCommitTrees(seen, tree, cb)
100-
})
98+
return iterateCommitTrees(seen, tree, cb)
99+
})
101100
}
102101

103102
// iterateCommitTrees iterate all reachable trees from the given commit

remote.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ func (r *Remote) Push(o *PushOptions) (err error) {
104104

105105
req := packp.NewReferenceUpdateRequestFromCapabilities(ar.Capabilities)
106106
if err := r.addReferencesToUpdate(o.RefSpecs, remoteRefs, req); err != nil {
107+
107108
return err
108109
}
109110

@@ -121,6 +122,15 @@ func (r *Remote) Push(o *PushOptions) (err error) {
121122
return err
122123
}
123124

125+
stop, err := r.s.Shallow()
126+
if err != nil {
127+
return err
128+
}
129+
130+
// if we have shallow we should include this as part of the objects that
131+
// we are aware.
132+
haves = append(haves, stop...)
133+
124134
hashesToPush, err := revlist.Objects(r.s, objects, haves)
125135
if err != nil {
126136
return err
@@ -486,7 +496,7 @@ func isFastForward(s storer.EncodedObjectStorer, old, new plumbing.Hash) (bool,
486496
}
487497

488498
found := false
489-
iter := object.NewCommitPreorderIter(c)
499+
iter := object.NewCommitPreorderIter(c, nil)
490500
return found, iter.ForEach(func(c *object.Commit) error {
491501
if c.Hash != old {
492502
return nil

repository.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ func (r *Repository) Log(o *LogOptions) (object.CommitIter, error) {
689689
return nil, err
690690
}
691691

692-
return object.NewCommitPreorderIter(commit), nil
692+
return object.NewCommitPreorderIter(commit, nil), nil
693693
}
694694

695695
// Tags returns all the References from Tags. This method returns all the tag
@@ -918,7 +918,7 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
918918
commit = c
919919
}
920920
case revision.CaretReg:
921-
history := object.NewCommitPreorderIter(commit)
921+
history := object.NewCommitPreorderIter(commit, nil)
922922

923923
re := item.(revision.CaretReg).Regexp
924924
negate := item.(revision.CaretReg).Negate
@@ -948,7 +948,7 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
948948

949949
commit = c
950950
case revision.AtDate:
951-
history := object.NewCommitPreorderIter(commit)
951+
history := object.NewCommitPreorderIter(commit, nil)
952952

953953
date := item.(revision.AtDate).Date
954954

repository_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
. "gopkg.in/check.v1"
2121
"gopkg.in/src-d/go-billy.v3/memfs"
2222
"gopkg.in/src-d/go-billy.v3/osfs"
23+
"gopkg.in/src-d/go-billy.v3/util"
2324
)
2425

2526
type RepositorySuite struct {
@@ -767,6 +768,50 @@ func (s *RepositorySuite) TestPushToEmptyRepository(c *C) {
767768
c.Assert(err, IsNil)
768769
}
769770

771+
func (s *RepositorySuite) TestPushDepth(c *C) {
772+
dir, err := ioutil.TempDir("", "push-depth")
773+
defer os.RemoveAll(dir)
774+
775+
origin, err := PlainClone(c.MkDir(), true, &CloneOptions{
776+
URL: fixtures.Basic().One().DotGit().Root(),
777+
})
778+
779+
c.Assert(err, IsNil)
780+
fs := origin.Storer.(*filesystem.Storage).Filesystem()
781+
782+
r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{
783+
URL: fs.Root(),
784+
Depth: 1,
785+
})
786+
c.Assert(err, IsNil)
787+
788+
err = util.WriteFile(r.wt, "foo", nil, 0755)
789+
c.Assert(err, IsNil)
790+
791+
w, err := r.Worktree()
792+
c.Assert(err, IsNil)
793+
794+
_, err = w.Add("foo")
795+
c.Assert(err, IsNil)
796+
797+
hash, err := w.Commit("foo", &CommitOptions{
798+
Author: defaultSignature(),
799+
Committer: defaultSignature(),
800+
})
801+
c.Assert(err, IsNil)
802+
803+
err = r.Push(&PushOptions{})
804+
c.Assert(err, IsNil)
805+
806+
remote, err := origin.Head()
807+
c.Assert(err, IsNil)
808+
c.Assert(remote.Hash(), Equals, hash)
809+
810+
local, err := r.Head()
811+
c.Assert(err, IsNil)
812+
c.Assert(local.Hash(), Equals, remote.Hash())
813+
}
814+
770815
func (s *RepositorySuite) TestPushNonExistentRemote(c *C) {
771816
srcFs := fixtures.Basic().One().DotGit()
772817
sto, err := filesystem.NewStorage(srcFs)

0 commit comments

Comments
 (0)