@@ -2,6 +2,7 @@ package packp
22
33import (
44 "fmt"
5+ "sort"
56 "strings"
67
78 "gopkg.in/src-d/go-git.v4/plumbing"
@@ -68,30 +69,119 @@ func (a *AdvRefs) AddReference(r *plumbing.Reference) error {
6869
6970func (a * AdvRefs ) AllReferences () (memory.ReferenceStorage , error ) {
7071 s := memory.ReferenceStorage {}
71- if err := addRefs (s , a ); err != nil {
72+ if err := a . addRefs (s ); err != nil {
7273 return s , plumbing .NewUnexpectedError (err )
7374 }
7475
7576 return s , nil
7677}
7778
78- func addRefs (s storer.ReferenceStorer , ar * AdvRefs ) error {
79- for name , hash := range ar .References {
79+ func ( a * AdvRefs ) addRefs (s storer.ReferenceStorer ) error {
80+ for name , hash := range a .References {
8081 ref := plumbing .NewReferenceFromStrings (name , hash .String ())
8182 if err := s .SetReference (ref ); err != nil {
8283 return err
8384 }
8485 }
8586
86- return addSymbolicRefs (s , ar )
87+ if a .supportSymrefs () {
88+ return a .addSymbolicRefs (s )
89+ }
90+
91+ return a .resolveHead (s )
8792}
8893
89- func addSymbolicRefs (s storer.ReferenceStorer , ar * AdvRefs ) error {
90- if ! hasSymrefs (ar ) {
94+ // If the server does not support symrefs capability,
95+ // we need to guess the reference where HEAD is pointing to.
96+ //
97+ // Git versions prior to 1.8.4.3 has an special procedure to get
98+ // the reference where is pointing to HEAD:
99+ // - Check if a reference called master exists. If exists and it
100+ // has the same hash as HEAD hash, we can say that HEAD is pointing to master
101+ // - If master does not exists or does not have the same hash as HEAD,
102+ // order references and check in that order if that reference has the same
103+ // hash than HEAD. If yes, set HEAD pointing to that branch hash
104+ // - If no reference is found, throw an error
105+ func (a * AdvRefs ) resolveHead (s storer.ReferenceStorer ) error {
106+ if a .Head == nil {
107+ return nil
108+ }
109+
110+ ref , err := s .Reference (plumbing .ReferenceName (plumbing .Master ))
111+
112+ // check first if HEAD is pointing to master
113+ if err == nil {
114+ ok , err := a .createHeadIfCorrectReference (ref , s )
115+ if err != nil {
116+ return err
117+ }
118+
119+ if ok {
120+ return nil
121+ }
122+ }
123+
124+ if err != nil && err != plumbing .ErrReferenceNotFound {
125+ return err
126+ }
127+
128+ // From here we are trying to guess the branch that HEAD is pointing
129+ refIter , err := s .IterReferences ()
130+ if err != nil {
131+ return err
132+ }
133+
134+ var refNames []string
135+ err = refIter .ForEach (func (r * plumbing.Reference ) error {
136+ refNames = append (refNames , string (r .Name ()))
91137 return nil
138+ })
139+ if err != nil {
140+ return err
141+ }
142+
143+ sort .Strings (refNames )
144+
145+ var headSet bool
146+ for _ , refName := range refNames {
147+ ref , err := s .Reference (plumbing .ReferenceName (refName ))
148+ if err != nil {
149+ return err
150+ }
151+ ok , err := a .createHeadIfCorrectReference (ref , s )
152+ if err != nil {
153+ return err
154+ }
155+ if ok {
156+ headSet = true
157+ break
158+ }
159+ }
160+
161+ if ! headSet {
162+ return plumbing .ErrReferenceNotFound
92163 }
93164
94- for _ , symref := range ar .Capabilities .Get (capability .SymRef ) {
165+ return nil
166+ }
167+
168+ func (a * AdvRefs ) createHeadIfCorrectReference (
169+ reference * plumbing.Reference ,
170+ s storer.ReferenceStorer ) (bool , error ) {
171+ if reference .Hash () == * a .Head {
172+ headRef := plumbing .NewSymbolicReference (plumbing .HEAD , reference .Name ())
173+ if err := s .SetReference (headRef ); err != nil {
174+ return false , err
175+ }
176+
177+ return true , nil
178+ }
179+
180+ return false , nil
181+ }
182+
183+ func (a * AdvRefs ) addSymbolicRefs (s storer.ReferenceStorer ) error {
184+ for _ , symref := range a .Capabilities .Get (capability .SymRef ) {
95185 chunks := strings .Split (symref , ":" )
96186 if len (chunks ) != 2 {
97187 err := fmt .Errorf ("bad number of `:` in symref value (%q)" , symref )
@@ -108,6 +198,6 @@ func addSymbolicRefs(s storer.ReferenceStorer, ar *AdvRefs) error {
108198 return nil
109199}
110200
111- func hasSymrefs ( ar * AdvRefs ) bool {
112- return ar .Capabilities .Supports (capability .SymRef )
201+ func ( a * AdvRefs ) supportSymrefs ( ) bool {
202+ return a .Capabilities .Supports (capability .SymRef )
113203}
0 commit comments