Skip to content

Commit 8d163ca

Browse files
committed
Add option RefToShowDivergenceFrom to GetCommitsOptions
Not used yet.
1 parent 504f0e6 commit 8d163ca

File tree

3 files changed

+61
-14
lines changed

3 files changed

+61
-14
lines changed

pkg/commands/git_commands/commit_loader.go

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"path/filepath"
88
"regexp"
9+
"sort"
910
"strconv"
1011
"strings"
1112
"sync"
@@ -68,6 +69,8 @@ type GetCommitsOptions struct {
6869
RefForPushedStatus string // the ref to use for determining pushed/unpushed status
6970
// determines if we show the whole git graph i.e. pass the '--all' flag
7071
All bool
72+
// If non-empty, show divergence from this ref (left-right log)
73+
RefToShowDivergenceFrom string
7174
}
7275

7376
// GetCommits obtains the commits of the current branch
@@ -93,17 +96,21 @@ func (self *CommitLoader) GetCommits(opts GetCommitsOptions) ([]*models.Commit,
9396
defer wg.Done()
9497

9598
logErr = self.getLogCmd(opts).RunAndProcessLines(func(line string) (bool, error) {
96-
commit := self.extractCommitFromLine(line)
99+
commit := self.extractCommitFromLine(line, opts.RefToShowDivergenceFrom != "")
97100
commits = append(commits, commit)
98101
return false, nil
99102
})
100103
})
101104

102105
var ancestor string
106+
var remoteAncestor string
103107
go utils.Safe(func() {
104108
defer wg.Done()
105109

106110
ancestor = self.getMergeBase(opts.RefName)
111+
if opts.RefToShowDivergenceFrom != "" {
112+
remoteAncestor = self.getMergeBase(opts.RefToShowDivergenceFrom)
113+
}
107114
})
108115

109116
passedFirstPushedCommit := false
@@ -137,7 +144,24 @@ func (self *CommitLoader) GetCommits(opts GetCommitsOptions) ([]*models.Commit,
137144
return commits, nil
138145
}
139146

140-
setCommitMergedStatuses(ancestor, commits)
147+
if opts.RefToShowDivergenceFrom != "" {
148+
sort.SliceStable(commits, func(i, j int) bool {
149+
// In the divergence view we want incoming commits to come first
150+
return commits[i].Divergence > commits[j].Divergence
151+
})
152+
153+
_, localSectionStart, found := lo.FindIndexOf(commits, func(commit *models.Commit) bool {
154+
return commit.Divergence == models.DivergenceLeft
155+
})
156+
if !found {
157+
localSectionStart = len(commits)
158+
}
159+
160+
setCommitMergedStatuses(remoteAncestor, commits[:localSectionStart])
161+
setCommitMergedStatuses(ancestor, commits[localSectionStart:])
162+
} else {
163+
setCommitMergedStatuses(ancestor, commits)
164+
}
141165

142166
return commits, nil
143167
}
@@ -177,8 +201,8 @@ func (self *CommitLoader) MergeRebasingCommits(commits []*models.Commit) ([]*mod
177201
// then puts them into a commit object
178202
// example input:
179203
// 8ad01fe32fcc20f07bc6693f87aa4977c327f1e1|10 hours ago|Jesse Duffield| (HEAD -> master, tag: v0.15.2)|refresh commits when adding a tag
180-
func (self *CommitLoader) extractCommitFromLine(line string) *models.Commit {
181-
split := strings.SplitN(line, "\x00", 7)
204+
func (self *CommitLoader) extractCommitFromLine(line string, showDivergence bool) *models.Commit {
205+
split := strings.SplitN(line, "\x00", 8)
182206

183207
sha := split[0]
184208
unixTimestamp := split[1]
@@ -187,6 +211,10 @@ func (self *CommitLoader) extractCommitFromLine(line string) *models.Commit {
187211
extraInfo := strings.TrimSpace(split[4])
188212
parentHashes := split[5]
189213
message := split[6]
214+
divergence := models.DivergenceNone
215+
if showDivergence {
216+
divergence = lo.Ternary(split[7] == "<", models.DivergenceLeft, models.DivergenceRight)
217+
}
190218

191219
tags := []string{}
192220

@@ -220,6 +248,7 @@ func (self *CommitLoader) extractCommitFromLine(line string) *models.Commit {
220248
AuthorName: authorName,
221249
AuthorEmail: authorEmail,
222250
Parents: parents,
251+
Divergence: divergence,
223252
}
224253
}
225254

@@ -249,7 +278,7 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode
249278

250279
fullCommits := map[string]*models.Commit{}
251280
err = cmdObj.RunAndProcessLines(func(line string) (bool, error) {
252-
commit := self.extractCommitFromLine(line)
281+
commit := self.extractCommitFromLine(line, false)
253282
fullCommits[commit.Sha] = commit
254283
return false, nil
255284
})
@@ -623,8 +652,13 @@ func (self *CommitLoader) getFirstPushedCommit(refName string) (string, error) {
623652
func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj {
624653
config := self.UserConfig.Git.Log
625654

655+
refSpec := opts.RefName
656+
if opts.RefToShowDivergenceFrom != "" {
657+
refSpec += "..." + opts.RefToShowDivergenceFrom
658+
}
659+
626660
cmdArgs := NewGitCmd("log").
627-
Arg(opts.RefName).
661+
Arg(refSpec).
628662
ArgIf(config.Order != "default", "--"+config.Order).
629663
ArgIf(opts.All, "--all").
630664
Arg("--oneline").
@@ -633,11 +667,12 @@ func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj {
633667
ArgIf(opts.Limit, "-300").
634668
ArgIf(opts.FilterPath != "", "--follow").
635669
Arg("--no-show-signature").
670+
ArgIf(opts.RefToShowDivergenceFrom != "", "--left-right").
636671
Arg("--").
637672
ArgIf(opts.FilterPath != "", opts.FilterPath).
638673
ToArgv()
639674

640675
return self.cmd.New(cmdArgs).DontLog()
641676
}
642677

643-
const prettyFormat = `--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s`
678+
const prettyFormat = `--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s%x00%m`

pkg/commands/git_commands/commit_loader_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestGetCommits(t *testing.T) {
4545
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
4646
runner: oscommands.NewFakeRunner(t).
4747
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
48-
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
48+
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s%x00%m", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
4949

5050
expectedCommits: []*models.Commit{},
5151
expectedError: nil,
@@ -57,7 +57,7 @@ func TestGetCommits(t *testing.T) {
5757
opts: GetCommitsOptions{RefName: "refs/heads/mybranch", RefForPushedStatus: "refs/heads/mybranch", IncludeRebaseCommits: false},
5858
runner: oscommands.NewFakeRunner(t).
5959
ExpectGitArgs([]string{"merge-base", "refs/heads/mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
60-
ExpectGitArgs([]string{"log", "refs/heads/mybranch", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
60+
ExpectGitArgs([]string{"log", "refs/heads/mybranch", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s%x00%m", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
6161

6262
expectedCommits: []*models.Commit{},
6363
expectedError: nil,
@@ -72,7 +72,7 @@ func TestGetCommits(t *testing.T) {
7272
// here it's seeing which commits are yet to be pushed
7373
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
7474
// here it's actually getting all the commits in a formatted form, one per line
75-
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, commitsOutput, nil).
75+
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s%x00%m", "--abbrev=40", "--no-show-signature", "--"}, commitsOutput, nil).
7676
// here it's testing which of the configured main branches have an upstream
7777
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "master@{u}"}, "refs/remotes/origin/master", nil). // this one does
7878
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "main@{u}"}, "", errors.New("error")). // this one doesn't, so it checks origin instead
@@ -209,7 +209,7 @@ func TestGetCommits(t *testing.T) {
209209
// here it's seeing which commits are yet to be pushed
210210
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
211211
// here it's actually getting all the commits in a formatted form, one per line
212-
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
212+
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s%x00%m", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
213213
// here it's testing which of the configured main branches exist; neither does
214214
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "master@{u}"}, "", errors.New("error")).
215215
ExpectGitArgs([]string{"rev-parse", "--verify", "--quiet", "refs/remotes/origin/master"}, "", errors.New("error")).
@@ -246,7 +246,7 @@ func TestGetCommits(t *testing.T) {
246246
// here it's seeing which commits are yet to be pushed
247247
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
248248
// here it's actually getting all the commits in a formatted form, one per line
249-
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
249+
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s%x00%m", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
250250
// here it's testing which of the configured main branches exist
251251
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "master@{u}"}, "refs/remotes/origin/master", nil).
252252
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "main@{u}"}, "", errors.New("error")).
@@ -282,7 +282,7 @@ func TestGetCommits(t *testing.T) {
282282
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
283283
runner: oscommands.NewFakeRunner(t).
284284
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
285-
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
285+
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s%x00%m", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
286286

287287
expectedCommits: []*models.Commit{},
288288
expectedError: nil,
@@ -294,7 +294,7 @@ func TestGetCommits(t *testing.T) {
294294
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", FilterPath: "src"},
295295
runner: oscommands.NewFakeRunner(t).
296296
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
297-
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--follow", "--no-show-signature", "--", "src"}, "", nil),
297+
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s%x00%m", "--abbrev=40", "--follow", "--no-show-signature", "--", "src"}, "", nil),
298298

299299
expectedCommits: []*models.Commit{},
300300
expectedError: nil,

pkg/commands/models/commit.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ const (
3030
ActionConflict = todo.Comment + 1
3131
)
3232

33+
type Divergence int
34+
35+
// For a divergence log (left/right comparison of two refs) this is set to
36+
// either DivergenceLeft or DivergenceRight for each commit; for normal
37+
// commit views it is always DivergenceNone.
38+
const (
39+
DivergenceNone Divergence = iota
40+
DivergenceLeft
41+
DivergenceRight
42+
)
43+
3344
// Commit : A git commit
3445
type Commit struct {
3546
Sha string
@@ -41,6 +52,7 @@ type Commit struct {
4152
AuthorName string // something like 'Jesse Duffield'
4253
AuthorEmail string // something like 'jessedduffield@gmail.com'
4354
UnixTimestamp int64
55+
Divergence Divergence // set to DivergenceNone unless we are showing the divergence view
4456

4557
// SHAs of parent commits (will be multiple if it's a merge commit)
4658
Parents []string

0 commit comments

Comments
 (0)