arche / commit

commit 90c6eb90d257c11bb9fa211f9df4af8693e4561f1599583fc5e5d6b89d9505c2
change nshvkagx
author dewn <dewn5228@proton.me>
committer dewn <dewn5228@proton.me>
date 2026-03-12 16:45:38
phase public
parents 20e34e66
signature Unsigned
add snapshot alias for arche snap command
internal/cli/cmd_snap.go [M]
--- a/internal/cli/cmd_snap.go
+++ b/internal/cli/cmd_snap.go
@@ -1,180 +1,180 @@
 package cli
 
 import (
 	"bufio"
 	"fmt"
 	"os"
 	"strings"
 
 	"arche/internal/gitcompat"
 	"arche/internal/tui"
 	"arche/internal/wc"
 
 	"github.com/spf13/cobra"
 )
 
 var (
 	snapInteractive bool
 	snapSign        bool
 	snapSignKey     string
 	snapAmend       bool
 	snapNoAdvance   bool
 )
 
 var snapCmd = &cobra.Command{
 	Use:     "snap [message]",
 	Aliases: []string{"commit"
+, "snapshot"
 },
 	Short:   "Finalise the working copy draft into a named commit",
 	Long: `Snapshot the current working directory into the draft commit (optionally
 setting a message), finalise it, and create a new empty draft as the next
 HEAD. The snapped commit keeps its change ID; only the content hash changes
 if files were modified since the last snap.
 
 With --interactive (-i) you are shown each hunk and asked whether to include
 it in this snap.  Unselected hunks remain as working-copy changes in the new
 draft.`,
 	RunE: func(cmd *cobra.Command, args []string) error {
 		r := openRepo()
 		defer r.Close()
 
 		msg := strings.Join(args, " ")
 		if msg == "" {
 			msg = promptMessage()
 		}
 		if msg == "" {
 			return fmt.Errorf("aborting snap: empty commit message")
 		}
 
 		w := wc.New(r)
 
 		if snapNoAdvance {
 			w.NoAutoAdvance = true
 		}
 
 		if snapSign || r.Cfg.Sign.Auto {
 			w.SignKey = r.Cfg.Sign.KeyFile
 			if snapSignKey != "" {
 				w.SignKey = snapSignKey
 			}
 		}
 
 		if snapAmend {
 			amended, amendedID, err := w.Amend(msg)
 			if err != nil {
 				return err
 			}
 			signedLabel := ""
 			if amended.CommitSig != nil {
 				signedLabel = " [signed]"
 			}
 			fmt.Printf("Amended %s - %s%s\n", "ch:"+amended.ChangeID, amended.Message, signedLabel)
 			fmt.Printf("  %x\n", amendedID[:8])
 			return nil
 		}
 
 		if snapInteractive {
 			diffs, err := w.ComputeWorkingDiffs()
 			if err != nil {
 				return err
 			}
 			if len(diffs) == 0 {
 				return fmt.Errorf("nothing to snap: working copy is clean")
 			}
 
 			var items []tui.HunkItem
 			for _, fhd := range diffs {
 				for hi, h := range fhd.Hunks {
 					items = append(items, tui.HunkItem{
 						FilePath:         fhd.Path,
 						HunkIdx:          hi,
 						TotalHunksInFile: len(fhd.Hunks),
 						Hunk:             h,
 					})
 				}
 			}
 
 			sel, err := tui.RunHunkSelector(items, "include in snap")
 			if err != nil {
 				return err
 			}
 			if sel.Cancelled {
 				fmt.Fprintln(os.Stderr, "Interactive snap cancelled.")
 				return nil
 			}
 
 			perFile := make(map[string][]bool)
 			idx := 0
 			for _, fhd := range diffs {
 				n := len(fhd.Hunks)
 				perFile[fhd.Path] = sel.Selected[idx : idx+n]
 				idx += n
 			}
 
 			snapped, snappedID, err := w.SnapSelectedHunks(msg, diffs, perFile)
 			if err != nil {
 				return err
 			}
 
 			signedLabelI := ""
 			if snapped.CommitSig != nil {
 				signedLabelI = " [signed]"
 			}
 			fmt.Printf("Snapped %s - %s%s\n", "ch:"+snapped.ChangeID, snapped.Message, signedLabelI)
 			fmt.Printf("  %x\n", snappedID[:8])
 
 			if r.Cfg.Git.Enabled {
 				gitHash, err := gitcompat.MirrorCommit(r.Root, r, snappedID)
 				if err != nil {
 					fmt.Fprintf(os.Stderr, "arche: git mirror failed: %v\n", err)
 				} else if gitHash != "" {
 					fmt.Printf("  git: %s\n", gitHash[:8])
 				}
 			}
 
 			head, _ := r.Head()
 			fmt.Printf("Working copy now at %s (draft)\n", head)
 			return nil
 		}
 
 		snapped, snappedID, err := w.Snap(msg)
 		if err != nil {
 			return err
 		}
 
 		signedLabel := ""
 		if snapped.CommitSig != nil {
 			signedLabel = " [signed]"
 		}
 
 		fmt.Printf("Snapped %s - %s%s\n", "ch:"+snapped.ChangeID, snapped.Message, signedLabel)
 		fmt.Printf("  %x\n", snappedID[:8])
 
 		if r.Cfg.Git.Enabled {
 			gitHash, err := gitcompat.MirrorCommit(r.Root, r, snappedID)
 			if err != nil {
 				fmt.Fprintf(os.Stderr, "arche: git mirror failed: %v\n", err)
 			} else if gitHash != "" {
 				fmt.Printf("  git: %s\n", gitHash[:8])
 			}
 		}
 
 		head, _ := r.Head()
 		fmt.Printf("Working copy now at %s (draft, empty)\n", head)
 		return nil
 	},
 }
 
 func promptMessage() string {
 	fmt.Print("Commit message: ")
 	sc := bufio.NewScanner(os.Stdin)
 	sc.Scan()
 	return strings.TrimSpace(sc.Text())
 }
 
 func init() {
 	snapCmd.Flags().BoolVarP(&snapInteractive, "interactive", "i", false, "interactively select hunks to include in this snap")
 	snapCmd.Flags().BoolVar(&snapSign, "sign", false, "sign the commit with your SSH key")
 	snapCmd.Flags().StringVar(&snapSignKey, "key", "", "path to SSH private key to use for signing (default: auto-detect)")
 	snapCmd.Flags().BoolVar(&snapAmend, "amend", false, "amend the current commit in-place and auto-rebase downstream draft dependents")
 	snapCmd.Flags().BoolVar(&snapNoAdvance, "no-advance", false, "disable bookmark auto-advance for this snap (overrides config)")
 }