diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a588b9..52d05f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/setup-go@v2 with: - go-version: 1.16 + go-version: 1.17 - run: go mod tidy - run: go build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d46cf6..10c6b82 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/setup-go@v2 with: - go-version: 1.16 + go-version: 1.17 - uses: goreleaser/goreleaser-action@v2 with: diff --git a/git/git.go b/git/git.go index 3f1319c..399715f 100644 --- a/git/git.go +++ b/git/git.go @@ -209,6 +209,40 @@ func SymbolicRef(ref string) (string, error) { return firstLine(output), err } +func TreeRef(ref string) (string, error) { + output, err := execGitQuiet("rev-parse", ref+"^{tree}") + if err != nil { + return "", err + } + return firstLine(output), err +} + +func MergeBase(a, b string) (string, error) { + output, err := execGitQuiet("merge-base", a, b) + if err != nil { + return "", err + } + return firstLine(output), nil +} + +func CommitTree(args ...string) (string, error) { + args = append([]string{"commit-tree"}, args...) + output, err := execGitQuiet(args...) + if err != nil { + return "", err + } + return firstLine(output), nil +} + +func Cherry(args ...string) (string, error) { + args = append([]string{"cherry"}, args...) + output, err := execGitQuiet(args...) + if err != nil { + return "", err + } + return firstLine(output), nil +} + func execGit(args ...string) (string, error) { cmd := exec.Command("git", args...) cmd.Stderr = os.Stderr diff --git a/go.mod b/go.mod index 9900461..fa1d68d 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/jacobwgillespie/git-sync -go 1.16 +go 1.17 diff --git a/main.go b/main.go index 5b25b06..8980d7d 100644 --- a/main.go +++ b/main.go @@ -81,7 +81,23 @@ func main() { diff, err := git.NewRange(fullBranch, fullDefaultBranch) check(err) - if diff.IsAncestor() { + // Determine if branch has been merged with a merge + shouldDelete := diff.IsAncestor() + + // Otherwise, try to determine if branch has been squash-merged + if !shouldDelete { + ancestorHash, err := git.MergeBase(fullDefaultBranch, fullBranch) + check(err) + treeHash, err := git.TreeRef(fullBranch) + check(err) + danglingCommit, err := git.CommitTree(treeHash, "-p", ancestorHash, "-m", fmt.Sprintf("Dangling branch %s", branch)) + check(err) + result, err := git.Cherry(fullDefaultBranch, danglingCommit) + check(err) + shouldDelete = strings.HasPrefix(result, "-") + } + + if shouldDelete { if branch == currentBranch { git.Quiet("checkout", "--quiet", defaultBranch) currentBranch = defaultBranch