@@ -62,10 +62,55 @@ type Commit struct {
6262 ParentHashes []plumbing.Hash
6363 // Encoding is the encoding of the commit.
6464 Encoding MessageEncoding
65+ // List of extra headers of the commit
66+ ExtraHeaders []ExtraHeader
6567
6668 s storer.EncodedObjectStorer
6769}
6870
71+ // ExtraHeader holds any non-standard header
72+ type ExtraHeader struct {
73+ // Header name
74+ Key string
75+ // Value of the header
76+ Value string
77+ }
78+
79+ // Implement fmt.Formatter for ExtraHeader
80+ func (h ExtraHeader ) Format (f fmt.State , verb rune ) {
81+ switch verb {
82+ case 'v' :
83+ fmt .Fprintf (f , "ExtraHeader{Key: %v, Value: %v}" , h .Key , h .Value )
84+ default :
85+ fmt .Fprintf (f , "%s" , h .Key )
86+ if len (h .Value ) > 0 {
87+ fmt .Fprint (f , " " )
88+ // Content may be spread on multiple lines, if so we need to
89+ // prepend each of them with a space for "continuation".
90+ value := strings .TrimSuffix (h .Value , "\n " )
91+ lines := strings .Split (value , "\n " )
92+ fmt .Fprint (f , strings .Join (lines , "\n " ))
93+ }
94+ }
95+ }
96+
97+ // Parse an extra header and indicate whether it may be continue on the next line
98+ func parseExtraHeader (line []byte ) (ExtraHeader , bool ) {
99+ split := bytes .SplitN (line , []byte {' ' }, 2 )
100+
101+ out := ExtraHeader {
102+ Key : string (bytes .TrimRight (split [0 ], "\n " )),
103+ Value : "" ,
104+ }
105+
106+ if len (split ) == 2 {
107+ out .Value += string (split [1 ])
108+ return out , true
109+ } else {
110+ return out , false
111+ }
112+ }
113+
69114// GetCommit gets a commit from an object storer and decodes it.
70115func GetCommit (s storer.EncodedObjectStorer , h plumbing.Hash ) (* Commit , error ) {
71116 o , err := s .EncodedObject (plumbing .CommitObject , h )
@@ -204,6 +249,7 @@ func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
204249 var mergetag bool
205250 var pgpsig bool
206251 var msgbuf bytes.Buffer
252+ var extraheader * ExtraHeader = nil
207253 for {
208254 line , err := r .ReadBytes ('\n' )
209255 if err != nil && err != io .EOF {
@@ -230,7 +276,19 @@ func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
230276 }
231277 }
232278
279+ if extraheader != nil {
280+ if len (line ) > 0 && line [0 ] == ' ' {
281+ extraheader .Value += string (line [1 :])
282+ continue
283+ } else {
284+ extraheader .Value = strings .TrimRight (extraheader .Value , "\n " )
285+ c .ExtraHeaders = append (c .ExtraHeaders , * extraheader )
286+ extraheader = nil
287+ }
288+ }
289+
233290 if ! message {
291+ original_line := line
234292 line = bytes .TrimSpace (line )
235293 if len (line ) == 0 {
236294 message = true
@@ -261,6 +319,13 @@ func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
261319 case headerpgp :
262320 c .PGPSignature += string (data ) + "\n "
263321 pgpsig = true
322+ default :
323+ h , maybecontinued := parseExtraHeader (original_line )
324+ if maybecontinued {
325+ extraheader = & h
326+ } else {
327+ c .ExtraHeaders = append (c .ExtraHeaders , h )
328+ }
264329 }
265330 } else {
266331 msgbuf .Write (line )
@@ -341,6 +406,13 @@ func (c *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
341406 }
342407 }
343408
409+ for _ , header := range c .ExtraHeaders {
410+
411+ if _ , err = fmt .Fprintf (w , "\n %s" , header ); err != nil {
412+ return err
413+ }
414+ }
415+
344416 if c .PGPSignature != "" && includeSig {
345417 if _ , err = fmt .Fprint (w , "\n " + headerpgp + " " ); err != nil {
346418 return err
0 commit comments