2626import os
2727from io import BytesIO
2828import logging
29+ from collections import defaultdict
2930
3031
3132# typing ------------------------------------------------------------------
@@ -335,8 +336,70 @@ def stats(self) -> Stats:
335336return Stats ._list_from_string (self .repo ,text )
336337
337338@property
338- def trailers (self )-> Dict :
339- """Get the trailers of the message as dictionary
339+ def trailers (self )-> Dict [str ,str ]:
340+ """Get the trailers of the message as a dictionary
341+
342+ Git messages can contain trailer information that are similar to RFC 822
343+ e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers).
344+
345+ WARNING: This function only returns the latest instance of each trailer key
346+ and will be deprecated soon. Please see either ``Commit.trailers_list`` or ``Commit.trailers_dict``.
347+
348+ :return:
349+ Dictionary containing whitespace stripped trailer information.
350+ Only the latest instance of each trailer key.
351+ """
352+ return {
353+ k :v [0 ]for k ,v in self .trailers_dict .items ()
354+ }
355+
356+ @property
357+ def trailers_list (self )-> List [str ]:
358+ """Get the trailers of the message as a list
359+
360+ Git messages can contain trailer information that are similar to RFC 822
361+ e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers).
362+
363+ This functions calls ``git interpret-trailers --parse`` onto the message
364+ to extract the trailer information, returns the raw trailer data as a list.
365+
366+ Valid message with trailer::
367+
368+ Subject line
369+
370+ some body information
371+
372+ another information
373+
374+ key1: value1.1
375+ key1: value1.2
376+ key2 : value 2 with inner spaces
377+
378+
379+ Returned list will look like this::
380+
381+ [
382+ "key1: value1.1",
383+ "key1: value1.2",
384+ "key2 : value 2 with inner spaces",
385+ ]
386+
387+
388+ :return:
389+ List containing whitespace stripped trailer information.
390+ """
391+ cmd = ["git" ,"interpret-trailers" ,"--parse" ]
392+ proc :Git .AutoInterrupt = self .repo .git .execute (cmd ,as_process = True ,istream = PIPE )# type: ignore
393+ trailer :str = proc .communicate (str (self .message ).encode ())[0 ].decode ()
394+ trailer = trailer .strip ()
395+ if trailer :
396+ return [t .strip ()for t in trailer .split ("\n " )]
397+
398+ return []
399+
400+ @property
401+ def trailers_dict (self )-> Dict [str ,List [str ]]:
402+ """Get the trailers of the message as a dictionary
340403
341404 Git messages can contain trailer information that are similar to RFC 822
342405 e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers).
@@ -345,42 +408,36 @@ def trailers(self) -> Dict:
345408 to extract the trailer information. The key value pairs are stripped of
346409 leading and trailing whitespaces before they get saved into a dictionary.
347410
348- Valid message with trailer:
349-
350- .. code-block::
411+ Valid message with trailer::
351412
352413 Subject line
353414
354415 some body information
355416
356417 another information
357418
358- key1: value1
419+ key1: value1.1
420+ key1: value1.2
359421 key2 : value 2 with inner spaces
360422
361- dictionary will look like this:
362423
363- .. code-block ::
424+ Returned dictionary will look like this ::
364425
365426 {
366- "key1": "value1" ,
367- "key2": "value 2 with inner spaces"
427+ "key1":[ "value1.1", "value1.2"] ,
428+ "key2":[ "value 2 with inner spaces"],
368429 }
369430
370- :return: Dictionary containing whitespace stripped trailer information
371431
432+ :return:
433+ Dictionary containing whitespace stripped trailer information.
434+ Mapping trailer keys to a list of their corresponding values.
372435 """
373- d = {}
374- cmd = ["git" ,"interpret-trailers" ,"--parse" ]
375- proc :Git .AutoInterrupt = self .repo .git .execute (cmd ,as_process = True ,istream = PIPE )# type: ignore
376- trailer :str = proc .communicate (str (self .message ).encode ())[0 ].decode ()
377- if trailer .endswith ("\n " ):
378- trailer = trailer [0 :- 1 ]
379- if trailer != "" :
380- for line in trailer .split ("\n " ):
381- key ,value = line .split (":" ,1 )
382- d [key .strip ()]= value .strip ()
383- return d
436+ d = defaultdict (list )
437+ for trailer in self .trailers_list :
438+ key ,value = trailer .split (":" ,1 )
439+ d [key .strip ()].append (value .strip ())
440+ return dict (d )
384441
385442@classmethod
386443def _iter_from_process_or_stream (cls ,repo :"Repo" ,proc_or_stream :Union [Popen ,IO ])-> Iterator ["Commit" ]: