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:
335336 return 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
386443 def _iter_from_process_or_stream (cls , repo : "Repo" , proc_or_stream : Union [Popen , IO ]) -> Iterator ["Commit" ]:
0 commit comments