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