@@ -2,6 +2,7 @@ package packp
2
2
3
3
import (
4
4
"fmt"
5
+ "sort"
5
6
"strings"
6
7
7
8
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -68,30 +69,119 @@ func (a *AdvRefs) AddReference(r *plumbing.Reference) error {
68
69
69
70
func (a * AdvRefs ) AllReferences () (memory.ReferenceStorage , error ) {
70
71
s := memory.ReferenceStorage {}
71
- if err := addRefs (s , a ); err != nil {
72
+ if err := a . addRefs (s ); err != nil {
72
73
return s , plumbing .NewUnexpectedError (err )
73
74
}
74
75
75
76
return s , nil
76
77
}
77
78
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 {
80
81
ref := plumbing .NewReferenceFromStrings (name , hash .String ())
81
82
if err := s .SetReference (ref ); err != nil {
82
83
return err
83
84
}
84
85
}
85
86
86
- return addSymbolicRefs (s , ar )
87
+ if a .supportSymrefs () {
88
+ return a .addSymbolicRefs (s )
89
+ }
90
+
91
+ return a .resolveHead (s )
87
92
}
88
93
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 ()))
91
137
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
92
163
}
93
164
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 ) {
95
185
chunks := strings .Split (symref , ":" )
96
186
if len (chunks ) != 2 {
97
187
err := fmt .Errorf ("bad number of `:` in symref value (%q)" , symref )
@@ -108,6 +198,6 @@ func addSymbolicRefs(s storer.ReferenceStorer, ar *AdvRefs) error {
108
198
return nil
109
199
}
110
200
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 )
113
203
}
0 commit comments