-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(stack reorder): Delete branches removed from reorder plan (#174)
# Example Have a branch structure: ``` * 2023-06-08-two-b ce20b00 (HEAD -> 2023-06-08-two) | * 2023-06-08-two-a 1f8f16b | * 2023-06-08-one-b 061ed6e (2023-06-08-one) | * 2023-06-08-one-a a4db90d | * 2023-05-30-one-a (#957) 87232f0 (origin/main, origin/HEAD, main) ``` Run `av stack reorder` and delete the `stack-branch 2023-06-08-two` line (effectively merging all commits into `2023-06-08-one`): <img width="817" alt="image" src="https://github.com/aviator-co/av/assets/773453/3887bbce-d805-4910-a84b-2c52b8e766e6"> Choose `e` to edit the plan: <img width="817" alt="image" src="https://github.com/aviator-co/av/assets/773453/b72f207e-10e3-472a-b14a-01197a4bb725"> (looks like unfortunately we lose the comment information, but this can be fixed in a future change) Save the same plan, choose `o` to orphan the branches: <img width="817" alt="image" src="https://github.com/aviator-co/av/assets/773453/18ecec96-3e2e-412d-bb9c-e99841dc832d"> Confirmed that `2023-06-08-two` still exists and hasn't had it's HEAD modified. Reset to the state above, but this time choose `d` to delete the branches: <img width="817" alt="image" src="https://github.com/aviator-co/av/assets/773453/b74a5511-726c-48be-adee-c557b0e8d5c3">
- Loading branch information
Showing
9 changed files
with
310 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package reorder | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
|
||
"github.com/spf13/pflag" | ||
|
||
"github.com/aviator-co/av/internal/git" | ||
"github.com/aviator-co/av/internal/utils/colors" | ||
"github.com/aviator-co/av/internal/utils/errutils" | ||
) | ||
|
||
// DeleteBranchCmd is a command that deletes a branch. | ||
// This is for internal use only to clean up branches that were removed from a | ||
// re-order operation. | ||
type DeleteBranchCmd struct { | ||
Name string | ||
// If true, delete the branch from Git as well as from the internal database. | ||
// If false, only delete the branch metadata from the internal database. | ||
DeleteGitRef bool | ||
} | ||
|
||
func (d DeleteBranchCmd) Execute(ctx *Context) error { | ||
tx := ctx.DB.WriteTx() | ||
tx.DeleteBranch(d.Name) | ||
if err := tx.Commit(); err != nil { | ||
return err | ||
} | ||
|
||
if !d.DeleteGitRef { | ||
_, _ = fmt.Fprint(os.Stderr, | ||
"Orphaned branch ", colors.UserInput(d.Name), ".\n", | ||
" - Run ", colors.CliCmd("git branch --delete ", d.Name), | ||
" to delete the branch from your repository.\n", | ||
) | ||
return nil | ||
} | ||
|
||
_, err := ctx.Repo.Run(&git.RunOpts{ | ||
Args: []string{"branch", "--delete", "--force", d.Name}, | ||
ExitError: true, | ||
}) | ||
if exiterr, ok := errutils.As[*exec.ExitError](err); ok && | ||
strings.Contains(string(exiterr.Stderr), "not found") { | ||
_, _ = fmt.Fprint(os.Stderr, | ||
colors.Warning("Branch "), colors.UserInput(d.Name), | ||
colors.Warning(" was already deleted.\n"), | ||
) | ||
return nil | ||
} else if err != nil { | ||
return err | ||
} | ||
|
||
_, _ = fmt.Fprint(os.Stderr, | ||
"Deleted branch ", colors.UserInput(d.Name), ".\n", | ||
) | ||
return nil | ||
} | ||
|
||
func (d DeleteBranchCmd) String() string { | ||
sb := strings.Builder{} | ||
sb.WriteString("delete-branch ") | ||
sb.WriteString(d.Name) | ||
if d.DeleteGitRef { | ||
sb.WriteString(" --delete-git-ref") | ||
} | ||
return sb.String() | ||
} | ||
|
||
var _ Cmd = DeleteBranchCmd{} | ||
|
||
func parseDeleteBranchCmd(args []string) (Cmd, error) { | ||
cmd := DeleteBranchCmd{} | ||
flags := pflag.NewFlagSet("delete-branch", pflag.ContinueOnError) | ||
flags.BoolVar( | ||
&cmd.DeleteGitRef, | ||
"delete-git-ref", | ||
false, | ||
"delete the branch from Git as well as from the internal database", | ||
) | ||
if err := flags.Parse(args); err != nil { | ||
return nil, err | ||
} | ||
if flags.NArg() != 1 { | ||
return nil, ErrInvalidCmd{ | ||
"delete-branch", | ||
"exactly one argument is required (the name of the branch to delete)", | ||
} | ||
} | ||
cmd.Name = flags.Arg(0) | ||
return cmd, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package reorder | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
|
||
"github.com/aviator-co/av/internal/git" | ||
"github.com/aviator-co/av/internal/git/gittest" | ||
"github.com/aviator-co/av/internal/meta/jsonfiledb" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestDeleteBranchCmd_String(t *testing.T) { | ||
assert.Equal(t, "delete-branch my-branch", DeleteBranchCmd{Name: "my-branch"}.String()) | ||
assert.Equal( | ||
t, | ||
"delete-branch my-branch --delete-git-ref", | ||
DeleteBranchCmd{Name: "my-branch", DeleteGitRef: true}.String(), | ||
) | ||
} | ||
|
||
func TestDeleteBranchCmd_Execute(t *testing.T) { | ||
repo := gittest.NewTempRepo(t) | ||
db, err := jsonfiledb.OpenRepo(repo) | ||
require.NoError(t, err) | ||
out := &bytes.Buffer{} | ||
ctx := &Context{repo, db, &State{Branch: "main"}, out} | ||
|
||
start, err := repo.RevParse(&git.RevParse{Rev: "HEAD"}) | ||
require.NoError(t, err) | ||
|
||
_, err = repo.Git("switch", "-c", "my-branch") | ||
require.NoError(t, err) | ||
gittest.CommitFile(t, repo, "file", []byte("hello\n")) | ||
|
||
// Need to switch back to main so that the branch ref can be deleted. | ||
// This shouldn't be an issue in the actual reorder because we'll never be | ||
// checked out on branches that we're about to delete (unless the user does | ||
// weird things™). | ||
_, err = repo.Git("switch", "main") | ||
require.NoError(t, err) | ||
|
||
// delete-branch without --delete-git-ref should preserve the branch ref in Git | ||
err = DeleteBranchCmd{Name: "my-branch"}.Execute(ctx) | ||
require.NoError(t, err) | ||
_, err = repo.RevParse(&git.RevParse{Rev: "my-branch"}) | ||
require.NoError(t, err, "DeleteBranchCmd.Execute should preserve the branch ref in Git") | ||
|
||
// delete-branch with --delete-git-ref should delete the branch ref in Git | ||
err = DeleteBranchCmd{Name: "my-branch", DeleteGitRef: true}.Execute(ctx) | ||
require.NoError(t, err) | ||
_, err = repo.RevParse(&git.RevParse{Rev: "my-branch"}) | ||
require.Error(t, err, "DeleteBranchCmd.Execute should delete the branch ref in Git") | ||
|
||
// subsequent delete-branch should be a no-op | ||
err = DeleteBranchCmd{Name: "my-branch", DeleteGitRef: true}.Execute(ctx) | ||
require.NoError( | ||
t, | ||
err, | ||
"DeleteBranchCmd.Execute should be a no-op if the branch ref is already deleted", | ||
) | ||
|
||
// HEAD of original branch should be preserved | ||
head, err := repo.RevParse(&git.RevParse{Rev: "HEAD"}) | ||
require.NoError(t, err) | ||
require.Equal( | ||
t, | ||
start, | ||
head, | ||
"DeleteBranchCmd.Execute should preserve the HEAD of the original branch", | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.