@@ -108,7 +108,9 @@ func (d *Diff) finalize() error { return d.contentWriter.CloseForWriting() }
108
108
109
109
// Commit contains commit header info and diffs.
110
110
type Commit struct {
111
- Hash string
111
+ Hash string
112
+ // The source of a commit, if it doesn't exist in the repository's history.
113
+ Source string
112
114
Author string
113
115
Committer string
114
116
Date time.Time
@@ -231,19 +233,23 @@ func (c *Parser) RepoPath(
231
233
) (chan * Diff , error ) {
232
234
args := []string {
233
235
"-C" , source ,
236
+ "--no-replace-objects" ,
234
237
"log" ,
235
238
"--patch" , // https://git-scm.com/docs/git-log#Documentation/git-log.txt---patch
236
239
"--full-history" ,
237
240
"--date=format:%a %b %d %H:%M:%S %Y %z" ,
238
241
"--pretty=fuller" , // https://git-scm.com/docs/git-log#_pretty_formats
239
242
"--notes" , // https://git-scm.com/docs/git-log#Documentation/git-log.txt---notesltrefgt
243
+ "--source" , // https://git-scm.com/docs/git-log#Documentation/git-log.txt---source
240
244
}
241
245
if abbreviatedLog {
246
+ // https://git-scm.com/docs/git-log#Documentation/git-log.txt---diff-filterACDMRTUXB82308203
242
247
args = append (args , "--diff-filter=AM" )
243
248
}
244
249
if head != "" {
245
250
args = append (args , head )
246
251
} else {
252
+ // https://git-scm.com/docs/git-log#Documentation/git-log.txt---all
247
253
args = append (args , "--all" )
248
254
}
249
255
for _ , glob := range excludedGlobs {
@@ -332,10 +338,9 @@ func (c *Parser) FromReader(ctx context.Context, stdOut io.Reader, diffChan chan
332
338
outReader := bufio .NewReader (stdOut )
333
339
var (
334
340
currentCommit * Commit
335
-
336
- totalLogSize int
341
+ totalLogSize int
342
+ latestState = Initial
337
343
)
338
- var latestState = Initial
339
344
340
345
diff := func (c * Commit , opts ... diffOption ) * Diff {
341
346
opts = append (opts , withCustomContentWriter (bufferwriter .New ()))
@@ -395,10 +400,18 @@ func (c *Parser) FromReader(ctx context.Context, stdOut io.Reader, diffChan chan
395
400
// Create a new currentDiff and currentCommit
396
401
currentCommit = & Commit {Message : strings.Builder {}}
397
402
currentDiff = diff (currentCommit )
398
- // Check that the commit line contains a hash and set it.
399
- if len (line ) >= 47 {
400
- currentCommit .Hash = string (line [7 :47 ])
403
+
404
+ hash , ref := parseCommitLine (line )
405
+ if hash == nil || ref == nil {
406
+ ctx .Logger ().Error (
407
+ fmt .Errorf (`expected line to match 'commit <hash> <ref>', got "%s"` , line ),
408
+ "Failed to parse CommitLine" )
409
+ latestState = ParseFailure
410
+ continue
401
411
}
412
+
413
+ currentCommit .Hash = string (hash )
414
+ currentCommit .Source = parseSourceRef (ref )
402
415
case isMergeLine (isStaged , latestState , line ):
403
416
latestState = MergeLine
404
417
case isAuthorLine (isStaged , latestState , line ):
@@ -614,6 +627,47 @@ func isCommitLine(isStaged bool, latestState ParseState, line []byte) bool {
614
627
return false
615
628
}
616
629
630
+ func parseCommitLine (line []byte ) (hash []byte , ref []byte ) {
631
+ // Check that the commit line contains a 40-character hash and set it.
632
+ // `commit e5575cd6f2d21d3a1a604287c7bf4a7eab2266e0\n`
633
+ if len (line ) >= 47 {
634
+ hash = line [7 :47 ]
635
+ }
636
+
637
+ // Check if the commit line includes branch references.
638
+ // `commit 2dbbb28727c7c2954438666dafba57bb8c714d3b refs/heads/fix/github-enterprise-gist\n`
639
+ if len (line ) > 48 {
640
+ ref = line [48 : len (line )- 1 ]
641
+ }
642
+
643
+ return
644
+ }
645
+
646
+ // ParseCommitSource s
647
+ // https://git-scm.com/docs/git-log#Documentation/git-log.txt---source
648
+ func parseSourceRef (ref []byte ) string {
649
+ // We don't care about 'normal' refs.
650
+ if bytes .HasPrefix (ref , []byte ("refs/heads/" )) || bytes .HasPrefix (ref , []byte ("refs/tags/" )) {
651
+ return ""
652
+ }
653
+
654
+ // Handle GitHub pull requests.
655
+ // e.g., `refs/pull/238/head` or `refs/pull/1234/merge`
656
+ if after , ok := bytes .CutPrefix (ref , []byte ("refs/pull/" )); ok {
657
+ prNumber := after [:bytes .Index (after , []byte ("/" ))]
658
+ return "Pull request #" + string (prNumber )
659
+ }
660
+
661
+ // Handle GitLab merge requests
662
+ // e.g., `refs/merge-requests/238/head` or `refs/merge-requests/1234/merge`
663
+ if after , ok := bytes .CutPrefix (ref , []byte ("refs/merge-requests/" )); ok {
664
+ mrNumber := after [:bytes .Index (after , []byte ("/" ))]
665
+ return "Merge request #" + string (mrNumber )
666
+ }
667
+
668
+ return fmt .Sprintf ("%s (hidden ref)" , string (ref ))
669
+ }
670
+
617
671
// Author: Bill Rich <[email protected] >
618
672
func isAuthorLine (isStaged bool , latestState ParseState , line []byte ) bool {
619
673
if isStaged || ! (latestState == CommitLine || latestState == MergeLine ) {
0 commit comments