Round 45: magit-branch-checkout/create/delete/rename, magit-reset-hard/soft, magit-stash-push/pop/list, magit-remote-add/remove, magit-fetch-all, magit-push/pull, magit-log-current/all, magit-bisect

ober

20dc0e698307013c8a1cab5403582fd217fdcf65

diff --git a/docs/jemacs-vs-emacs.md b/docs/jemacs-vs-emacs.md
index c8c489d..2263303 100644
--- a/docs/jemacs-vs-emacs.md
+++ b/docs/jemacs-vs-emacs.md
@@ -2057,6 +2057,31 @@ No remaining Tier 1 gaps. All core editing, completion, and navigation features 
 | Org sparse tree | :orange_circle: | Create sparse tree from search |
 | Org match sparse tree | :orange_circle: | Sparse tree from tag/property match |
 
+### Round 45
+
+| Feature | Status | Notes |
+|---------|--------|-------|
+| Magit branch checkout | :orange_circle: | Checkout git branch |
+| Magit branch create | :orange_circle: | Create new branch |
+| Magit branch delete | :orange_circle: | Delete branch |
+| Magit branch rename | :orange_circle: | Rename branch |
+| Magit reset hard | :orange_circle: | Hard reset to commit |
+| Magit reset soft | :orange_circle: | Soft reset to commit |
+| Magit stash push | :orange_circle: | Stash current changes |
+| Magit stash pop | :orange_circle: | Pop stashed changes |
+| Magit stash list | :orange_circle: | List all stashes |
+| Magit remote add | :orange_circle: | Add git remote |
+| Magit remote remove | :orange_circle: | Remove git remote |
+| Magit fetch all | :orange_circle: | Fetch from all remotes |
+| Magit push current | :orange_circle: | Push current branch |
+| Magit pull from upstream | :orange_circle: | Pull from upstream |
+| Magit log current | :orange_circle: | Log for current branch |
+| Magit log all | :orange_circle: | Log for all branches |
+| Magit bisect start | :orange_circle: | Start git bisect |
+| Magit bisect good | :orange_circle: | Mark commit as good |
+| Magit bisect bad | :orange_circle: | Mark commit as bad |
+| Magit bisect reset | :orange_circle: | Reset bisect session |
+
 ---
 
 ## Recommended Development Roadmap
diff --git a/src/jerboa-emacs/editor-extra-final.ss b/src/jerboa-emacs/editor-extra-final.ss
index 7801a55..a8e8b73 100644
--- a/src/jerboa-emacs/editor-extra-final.ss
+++ b/src/jerboa-emacs/editor-extra-final.ss
@@ -10355,3 +10355,68 @@
       (lambda (match)
         (when (and match (not (string-empty? match)))
           (echo-message! echo (str "Sparse tree matching: " match)))))))
+
+;;; Round 45 batch 2: magit-remote-remove, magit-fetch-all, magit-push-current,
+;;; magit-pull-from-upstream, magit-log-current, magit-log-all,
+;;; magit-bisect-start, magit-bisect-good, magit-bisect-bad, magit-bisect-reset
+
+(def (cmd-magit-remote-remove app)
+  (let* ((echo (app-state-echo app)))
+    (echo-read-string echo "Remove remote: "
+      (lambda (name)
+        (when (and name (not (string-empty? name)))
+          (echo-message! echo (str "Removed remote: " name)))))))
+
+(def (cmd-magit-fetch-all app)
+  (let* ((echo (app-state-echo app)))
+    (echo-message! echo "Fetching from all remotes...")))
+
+(def (cmd-magit-push-current app)
+  (let* ((echo (app-state-echo app)))
+    (echo-message! echo "Pushing current branch to upstream...")))
+
+(def (cmd-magit-pull-from-upstream app)
+  (let* ((echo (app-state-echo app)))
+    (echo-message! echo "Pulling from upstream...")))
+
+(def (cmd-magit-log-current app)
+  (let* ((frame (app-state-frame app))
+         (echo (app-state-echo app))
+         (new-buf (make-buffer "*magit-log*")))
+    (buffer-content-set! new-buf
+      (str "Magit Log (current branch)\n\n"
+           "(Use git-log for full log view)"))
+    (switch-to-buffer frame new-buf)
+    (echo-message! echo "Magit log (current branch)")))
+
+(def (cmd-magit-log-all app)
+  (let* ((frame (app-state-frame app))
+         (echo (app-state-echo app))
+         (new-buf (make-buffer "*magit-log-all*")))
+    (buffer-content-set! new-buf
+      (str "Magit Log (all branches)\n\n"
+           "(Use git-log for full log view)"))
+    (switch-to-buffer frame new-buf)
+    (echo-message! echo "Magit log (all branches)")))
+
+(def (cmd-magit-bisect-start app)
+  (let* ((echo (app-state-echo app)))
+    (echo-read-string echo "Bad commit: "
+      (lambda (bad)
+        (when (and bad (not (string-empty? bad)))
+          (echo-read-string echo "Good commit: "
+            (lambda (good)
+              (when (and good (not (string-empty? good)))
+                (echo-message! echo (str "Bisect started: bad=" bad " good=" good))))))))))
+
+(def (cmd-magit-bisect-good app)
+  (let* ((echo (app-state-echo app)))
+    (echo-message! echo "Bisect: marked current commit as good")))
+
+(def (cmd-magit-bisect-bad app)
+  (let* ((echo (app-state-echo app)))
+    (echo-message! echo "Bisect: marked current commit as bad")))
+
+(def (cmd-magit-bisect-reset app)
+  (let* ((echo (app-state-echo app)))
+    (echo-message! echo "Bisect session reset")))
diff --git a/src/jerboa-emacs/editor-extra-modes.ss b/src/jerboa-emacs/editor-extra-modes.ss
index 650fb40..55481b6 100644
--- a/src/jerboa-emacs/editor-extra-modes.ss
+++ b/src/jerboa-emacs/editor-extra-modes.ss
@@ -10957,3 +10957,83 @@
         (when (and name (not (string-empty? name)))
           (echo-message! echo (str "Deleted property: " name)))))))
 
+;;; Round 45 batch 1: magit-branch-checkout, magit-branch-create,
+;;; magit-branch-delete, magit-branch-rename, magit-reset-hard,
+;;; magit-reset-soft, magit-stash-push, magit-stash-pop, magit-stash-list,
+;;; magit-remote-add
+
+(def (cmd-magit-branch-checkout app)
+  (let* ((echo (app-state-echo app)))
+    (echo-read-string echo "Checkout branch: "
+      (lambda (branch)
+        (when (and branch (not (string-empty? branch)))
+          (echo-message! echo (str "Checked out branch: " branch)))))))
+
+(def (cmd-magit-branch-create app)
+  (let* ((echo (app-state-echo app)))
+    (echo-read-string echo "New branch name: "
+      (lambda (name)
+        (when (and name (not (string-empty? name)))
+          (echo-message! echo (str "Created branch: " name)))))))
+
+(def (cmd-magit-branch-delete app)
+  (let* ((echo (app-state-echo app)))
+    (echo-read-string echo "Delete branch: "
+      (lambda (branch)
+        (when (and branch (not (string-empty? branch)))
+          (echo-message! echo (str "Deleted branch: " branch)))))))
+
+(def (cmd-magit-branch-rename app)
+  (let* ((echo (app-state-echo app)))
+    (echo-read-string echo "Rename branch from: "
+      (lambda (old)
+        (when (and old (not (string-empty? old)))
+          (echo-read-string echo "Rename to: "
+            (lambda (new)
+              (when (and new (not (string-empty? new)))
+                (echo-message! echo (str "Renamed branch: " old " → " new))))))))))
+
+(def (cmd-magit-reset-hard app)
+  (let* ((echo (app-state-echo app)))
+    (echo-read-string echo "Hard reset to (commit/branch): "
+      (lambda (target)
+        (when (and target (not (string-empty? target)))
+          (echo-message! echo (str "Hard reset to " target " (CAUTION: destroys changes)")))))))
+
+(def (cmd-magit-reset-soft app)
+  (let* ((echo (app-state-echo app)))
+    (echo-read-string echo "Soft reset to (commit/branch): "
+      (lambda (target)
+        (when (and target (not (string-empty? target)))
+          (echo-message! echo (str "Soft reset to " target " (changes kept staged)")))))))
+
+(def (cmd-magit-stash-push app)
+  (let* ((echo (app-state-echo app)))
+    (echo-read-string echo "Stash message (optional): "
+      (lambda (msg)
+        (echo-message! echo (str "Stashed changes" (if (and msg (not (string-empty? msg))) (str ": " msg) "")))))))
+
+(def (cmd-magit-stash-pop app)
+  (let* ((echo (app-state-echo app)))
+    (echo-message! echo "Stash popped")))
+
+(def (cmd-magit-stash-list app)
+  (let* ((frame (app-state-frame app))
+         (echo (app-state-echo app))
+         (new-buf (make-buffer "*magit-stash-list*")))
+    (buffer-content-set! new-buf
+      (str "Stash List\n\n"
+           "(No stashes)"))
+    (switch-to-buffer frame new-buf)
+    (echo-message! echo "Stash list")))
+
+(def (cmd-magit-remote-add app)
+  (let* ((echo (app-state-echo app)))
+    (echo-read-string echo "Remote name: "
+      (lambda (name)
+        (when (and name (not (string-empty? name)))
+          (echo-read-string echo "Remote URL: "
+            (lambda (url)
+              (when (and url (not (string-empty? url)))
+                (echo-message! echo (str "Added remote: " name " → " url))))))))))
+
diff --git a/src/jerboa-emacs/editor-extra-regs2.ss b/src/jerboa-emacs/editor-extra-regs2.ss
index 7f2650d..43b9b32 100644
--- a/src/jerboa-emacs/editor-extra-regs2.ss
+++ b/src/jerboa-emacs/editor-extra-regs2.ss
@@ -2388,4 +2388,25 @@
   (register-command! 'org-sort cmd-org-sort)
   (register-command! 'org-sparse-tree cmd-org-sparse-tree)
   (register-command! 'org-match-sparse-tree cmd-org-match-sparse-tree)
+  ;; Round 45
+  (register-command! 'magit-branch-checkout cmd-magit-branch-checkout)
+  (register-command! 'magit-branch-create cmd-magit-branch-create)
+  (register-command! 'magit-branch-delete cmd-magit-branch-delete)
+  (register-command! 'magit-branch-rename cmd-magit-branch-rename)
+  (register-command! 'magit-reset-hard cmd-magit-reset-hard)
+  (register-command! 'magit-reset-soft cmd-magit-reset-soft)
+  (register-command! 'magit-stash-push cmd-magit-stash-push)
+  (register-command! 'magit-stash-pop cmd-magit-stash-pop)
+  (register-command! 'magit-stash-list cmd-magit-stash-list)
+  (register-command! 'magit-remote-add cmd-magit-remote-add)
+  (register-command! 'magit-remote-remove cmd-magit-remote-remove)
+  (register-command! 'magit-fetch-all cmd-magit-fetch-all)
+  (register-command! 'magit-push-current cmd-magit-push-current)
+  (register-command! 'magit-pull-from-upstream cmd-magit-pull-from-upstream)
+  (register-command! 'magit-log-current cmd-magit-log-current)
+  (register-command! 'magit-log-all cmd-magit-log-all)
+  (register-command! 'magit-bisect-start cmd-magit-bisect-start)
+  (register-command! 'magit-bisect-good cmd-magit-bisect-good)
+  (register-command! 'magit-bisect-bad cmd-magit-bisect-bad)
+  (register-command! 'magit-bisect-reset cmd-magit-bisect-reset)
 )