feat: 新增 git.undo 撤销提交命令
This commit is contained in:
@@ -0,0 +1,94 @@
|
|||||||
|
package executor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// gitUndoOptions are the parsed arguments of `kopsc git undo`.
|
||||||
|
type gitUndoOptions struct {
|
||||||
|
Hard bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// runGitUndo undoes the last commit.
|
||||||
|
func runGitUndo(ctx context.Context, req BuiltinRequest) error {
|
||||||
|
return runGitUndoWith(ctx, req, execGitRunner{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGitUndoWith(ctx context.Context, req BuiltinRequest, runner gitRunner) error {
|
||||||
|
opts, confirmed, err := parseGitUndoArgs(req.Args)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
confirmed = confirmed || req.Confirmed
|
||||||
|
|
||||||
|
// Get the last commit info
|
||||||
|
out, _, err := runner.Run(ctx, "log", "-1", "--format=%h %s")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("获取提交信息失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCommit := strings.TrimSpace(out)
|
||||||
|
if lastCommit == "" {
|
||||||
|
return errors.New("没有提交可以撤销")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show preview
|
||||||
|
fmt.Fprintf(req.Stdout, "撤销最后一次提交\n\n")
|
||||||
|
fmt.Fprintf(req.Stdout, "提交: %s\n", lastCommit)
|
||||||
|
|
||||||
|
if opts.Hard {
|
||||||
|
fmt.Fprintf(req.Stdout, "模式: 完全丢弃改动(--hard)\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(req.Stdout, "模式: 保留改动到暂存区(--soft)\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !confirmed {
|
||||||
|
fmt.Fprintf(req.Stdout, "\n")
|
||||||
|
if opts.Hard {
|
||||||
|
fmt.Fprintf(req.Stdout, "⚠️ 这将永久丢弃最后一次提交的改动!加 --yes 确认执行。\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(req.Stdout, "撤销后改动会保留在暂存区,加 --yes 执行。\n")
|
||||||
|
}
|
||||||
|
return &ExitError{Code: 2, Err: errors.New("需要确认")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute undo
|
||||||
|
resetArg := "--soft"
|
||||||
|
if opts.Hard {
|
||||||
|
resetArg = "--hard"
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, stderr, err := runner.Run(ctx, "reset", resetArg, "HEAD~1"); err != nil {
|
||||||
|
return fmt.Errorf("撤销失败: %w\n%s", err, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Hard {
|
||||||
|
fmt.Fprintf(req.Stdout, "\n✓ 已撤销提交并丢弃改动\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(req.Stdout, "\n✓ 已撤销提交,改动保留在暂存区\n")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGitUndoArgs(args []string) (gitUndoOptions, bool, error) {
|
||||||
|
var opts gitUndoOptions
|
||||||
|
var confirmed bool
|
||||||
|
|
||||||
|
for _, arg := range args {
|
||||||
|
switch arg {
|
||||||
|
case "--yes", "-y":
|
||||||
|
confirmed = true
|
||||||
|
case "--hard":
|
||||||
|
opts.Hard = true
|
||||||
|
default:
|
||||||
|
if strings.HasPrefix(arg, "-") {
|
||||||
|
return opts, false, fmt.Errorf("未知选项 %q", arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts, confirmed, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user