Skip to content

Commit aa88b6c

Browse files
committed
push: Resolve from commit
1 parent 9c3a136 commit aa88b6c

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

cmd/push.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ package cmd
1717
import (
1818
"fmt"
1919
"os"
20+
"strings"
2021

2122
"github.com/pfnet-research/git-ghost/pkg/ghost"
23+
"github.com/pfnet-research/git-ghost/pkg/ghost/git"
2224
"github.com/pfnet-research/git-ghost/pkg/ghost/types"
2325
"github.com/pfnet-research/git-ghost/pkg/util/errors"
2426

@@ -43,7 +45,7 @@ func NewPushCommand() *cobra.Command {
4345
Short: "push commits(hash1...hash2), diff(hash...current state) to your ghost repo",
4446
Long: "push commits or diff or all to your ghost repo. If you didn't specify any subcommand, this commands works as an alias for 'push diff' command.",
4547
Args: cobra.RangeArgs(0, 1),
46-
Run: runPushDiffCommand(&flags),
48+
Run: runPushCommitsCommand(&flags),
4749
}
4850
command.AddCommand(&cobra.Command{
4951
Use: "commits [from-hash] [to-hash(default=HEAD)]",
@@ -73,6 +75,32 @@ func NewPushCommand() *cobra.Command {
7375
return command
7476
}
7577

78+
func getFirstRemoteAncestorCommit(commit string) (string, errors.GitGhostError) {
79+
dir := globalOpts.srcDir
80+
for {
81+
branchNames, err := git.GetRemoteBranchesContainingCommit(dir, commit)
82+
if err != nil {
83+
return "", err
84+
}
85+
var originBranchNames []string
86+
for _, branchName := range branchNames {
87+
if strings.HasPrefix(branchName, fmt.Sprintf("refs/remotes/%s/", git.ORIGIN)) {
88+
originBranchNames = append(originBranchNames, branchName)
89+
}
90+
}
91+
if len(originBranchNames) > 0 {
92+
// This commit is the first ancestor commit in the origin remote.
93+
break
94+
}
95+
parentCommit, err := git.GetParentCommit(dir, commit)
96+
if err != nil {
97+
return "", err
98+
}
99+
commit = parentCommit
100+
}
101+
return commit, nil
102+
}
103+
76104
type pushCommitsArg struct {
77105
commitsFrom string
78106
commitsTo string
@@ -111,6 +139,16 @@ func (arg pushCommitsArg) validate() errors.GitGhostError {
111139
func runPushCommitsCommand(flags *pushFlags) func(cmd *cobra.Command, args []string) {
112140
return func(cmd *cobra.Command, args []string) {
113141
pushArg := newPushCommitsArg(args)
142+
143+
// If commitsFrom is not given, find the first ancestor commit that is included in the origin remote.
144+
if pushArg.commitsFrom == "" {
145+
commitsFrom, err := getFirstRemoteAncestorCommit(pushArg.commitsTo)
146+
if err != nil {
147+
errors.LogErrorWithStack(err)
148+
os.Exit(1)
149+
}
150+
pushArg.commitsFrom = commitsFrom
151+
}
114152
if err := pushArg.validate(); err != nil {
115153
errors.LogErrorWithStack(err)
116154
os.Exit(1)

pkg/ghost/git/repo.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package git
1616

1717
import (
18+
"bytes"
1819
"fmt"
1920
"os/exec"
2021
"strings"
@@ -146,3 +147,28 @@ func ResetHardToBranch(dir, branch string) errors.GitGhostError {
146147
exec.Command("git", "-C", dir, "reset", "--hard", branch),
147148
)
148149
}
150+
151+
// GetParentCommit returns the parent commit of the given commit
152+
func GetParentCommit(dir, commit string) (string, errors.GitGhostError) {
153+
resultBytes, err := util.JustOutputCmd(exec.Command("git", "-C", dir, "rev-parse", fmt.Sprintf("%s^", commit)))
154+
if err != nil {
155+
return "", errors.WithStack(gherrors.WithMessage(err, "failed to get the parent commit of a commit"))
156+
}
157+
return strings.TrimSuffix(string(resultBytes), "\n"), nil
158+
}
159+
160+
// GetRemoteBranchesContainingCommit returns a slice of remote branch names each of which contain the given commit
161+
func GetRemoteBranchesContainingCommit(dir, commit string) ([]string, errors.GitGhostError) {
162+
resultBytes, err := util.JustOutputCmd(exec.Command("git", "-C", dir, "branch", "--format", "%(refname)", "--remotes", "--contains", commit))
163+
if err != nil {
164+
return nil, errors.WithStack(gherrors.WithMessage(err, "failed to get remote branches containing a commit"))
165+
}
166+
var branchNames []string
167+
for _, line := range bytes.Split(resultBytes, []byte("\n")) {
168+
branchName := string(line)
169+
if len(branchName) > 0 {
170+
branchNames = append(branchNames, branchName)
171+
}
172+
}
173+
return branchNames, nil
174+
}

0 commit comments

Comments
 (0)