unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Arthur Miller <arthur.miller@live.com>
To: John Yates <john@yates-sheets.org>
Cc: "Óscar Fuentes" <ofv@wanadoo.es>,
	"Emacs developers" <emacs-devel@gnu.org>
Subject: Re: On the adoption of transient.el
Date: Mon, 16 Aug 2021 03:05:37 +0200	[thread overview]
Message-ID: <AM9PR09MB49777BF2243E1FD70098CA7396FD9@AM9PR09MB4977.eurprd09.prod.outlook.com> (raw)
In-Reply-To: <CAJnXXohZ3SPpHPqY0TTMWN9O4=KEroXKcf3aiiis0+Rx97Cp-g@mail.gmail.com> (John Yates's message of "Sun, 15 Aug 2021 17:57:27 -0400")

[-- Attachment #1: Type: text/plain, Size: 3379 bytes --]

John Yates <john@yates-sheets.org> writes:

> On Sat, Aug 14, 2021 at 8:55 AM Óscar Fuentes <ofv@wanadoo.es> wrote:
>> Arthur Miller <arthur.miller@live.com> writes:
>> > The strategy is to stash save all buffers belonging to the project,
>> > stash everything, inclusive untracked files, and than checkout to the
>> > other branch. When checked back, the stash is applied back. I don't know
>> > if you have something like that in magit or if it is something generally
>> > desirable, but I always wanted something simple and dirty to be able to
>> > switch fast when I need it.
>>
>> How would Magit know that when you "return back" to a branch it must
>> apply a certain stash?
>
> Rather than use a stash I would have a script that does two things:
> * Creates an undo script for the next step
> * Saves everything important as a new commit on the current branch.
>   This would include, among other things, all untracked files and the
>   undo script mentioned in the first step.

I had thoughts of implementing commit strategy too :-). I even have
prepared a variable that I have planned to use for this. My motivation
was mostly to see if it is somewhat faster than stashing and reaplying
changes, but I haven't really got to that yet.

After more thoughts I am also not sure if that would be any better than
stash to be honest. Stashes are meant for something like this, and it is
a normal strategy people use. Can you give me some reason why would it
be better to commit changes instead of stashing away them?

When it comes to tracked/untracked files, I do have from the beginning a
variable to switch what is stashed away. I agree with what you wrote in
your last replay, that it is not always desirable to stash untracked
files. I was just not in the mood for explaining in details what I am
doing, so I wrote just very short notice to not use this strategy :).

> Now with the workspace in a clean state you can switch away to some

Isn't that what stashing away also does?

> other branch.  When you return to the original branch you run the undo
> script.  It backs out the last commit.  This would included performing
>
>     git rm --cached <all originally untracked files>

I do delete the stash after applying it. Pop can't be reliably used in
an automated script like this, so I apply the specially named stash and
than throw it away, which si similar to pop.

> * Creates an undo script for the next step

The undo script would be an interesting addition indeed. I am not sure
if we think of same thing, but what I am doing is saving all open and
modified file buffers belonging to git root and subfolders, before I do
stashing. What would be nice, is to undo saved changes in buffers that
were modified, so that they appear as modified after checking out old
branch again. Currently they are just saved, so when they are checked
out again, they don't appear as modified again.

I am not sure where to look to implement something like that, is there
some variable in buffer I can check for modifications sine last save, so
I could use it to save some state somewhere?

Thanks you for the comment, this was constructive.

If you are interested to take a look I have attached the code, and the
poject is here with some additional info in readme:

https://github.com/amno1/helm-git-branch


[-- Attachment #2: helm-git-branch.el --]
[-- Type: text/plain, Size: 8357 bytes --]

;;; helm-git-branch.el --- Switch git branch with Helm interface.  -*- lexical-binding: t; -*-

;; Copyright (C) 2021  Arthur Miller

;; Author: Arthur Miller <arthur.miller@live.com>
;; Keywords:

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;;

;;; Code:

(require 'helm-ls-git)

(defvar helm-source-git-local-branches nil
  "This source will built at runtime.
It can be build explicitly with function
`helm-git-build-local-branches-source'.")

(defface helm-git-branch-current-clean-face
    '((t :foreground "#2aa198"))
  "Files which contain rebase/merge conflicts."
  :group 'helm-ls-git)

(defface helm-git-branch-current-dirty-face
    '((t :foreground "#dc322f"))
  "Files which contain rebase/merge conflicts."
  :group 'helm-ls-git)

;;; Custom
\f
(defgroup helm-git-branch nil
  "Fast git branch switching with Helm."
  :group 'helm)

(defcustom helm-git-branch-changes-action 'stash
  "The default action upon changing a branch with uncommited changes.

If this option is set to 'stash the changes will be automatically stashed.

If this option is set to 'commit the changes will automatically commited."
  :type 'symbol
  :group 'helm)

(defgroup helm-git-branch nil
  "Fast git branch switching with Helm."
  :group 'helm)

(defcustom helm-git-branch-stash-prefix "helm-git-branch--"
  "The prefix to prepend to stash names when autostashing a branch."
  :type 'string
  :group 'helm)

(defcustom helm-git-branch-auto-save-on-change t
  ""
  :type 'boolean
  :group 'helm)

(defcustom helm-git-branch-auto-stash-unstaged t
  ""
  :type 'boolean
  :group 'helm)

(defcustom helm-git-branch-fuzzy-match nil
  "Enable fuzzy matching in `helm-git-*-branch'."
  :group 'helm-branch-git
  :set (lambda (var val)
         (set var val)
         (setq helm-source-git-local-branches nil))
  :type 'boolean)
\f
(defmacro replace-all (from to &optional buffer)
  `(with-current-buffer (or ,buffer (current-buffer))
     (goto-char (point-min))
     (while (search-forward ,from nil t)
       (replace-match ,to))))

(defun git-make-cmd (git-args &rest cmd-args)
  (let ((cmd
         (seq-concatenate
          'list
          '(call-process "git" nil t nil) (split-string git-args) cmd-args)))
    `(lambda () ,cmd)))

(defun git-call (git-args)
  (funcall (git-make-cmd git-args)))

(defmacro with-helm-git (git-cmd &rest body)
  `(nbutlast
     (split-string
      (helm-aif (helm-ls-git-root-dir)
          (with-helm-default-directory it
            (with-output-to-string
              (with-current-buffer standard-output
                (insert (format "%s" (git-call ,git-cmd)))
                ,@body
                (buffer-string))))) "\n" t "[\s\t]*")))

(defvar helm-git-branch-map
  (let ((map (make-sparse-keymap)))
    (set-keymap-parent map helm-generic-files-map)
    map))

(defvar helm-git-branch-buffer-map
  (let ((map (make-sparse-keymap)))
    (set-keymap-parent map helm-buffer-map)
    map))
\f
;;; Sources
(defun helm-git--local-branches ()
  (with-helm-git "branch"))

(defun helm-git-branch-local-transformer (candidates _source)
  (cl-loop with root = (helm-ls-git-root-dir)
        for i in candidates
        collect
        (cond ((string-match "^\\(*\\)\\(.*\\)" i) ; current branch
               (if (helm-git-branch--dirty-p)
                   (cons (propertize i 'face 'helm-git-branch-current-dirty-face)
                         (expand-file-name (match-string 2 i) root))
                 (cons (propertize i 'face 'helm-git-branch-current-clean-face)
                       (expand-file-name (match-string 2 i) root))))
              (t i))))

(defun helm-git-branch-local-action-transformer (actions _candidate)
  (when (= 1 (length (helm-marked-candidates)))
    (helm-make-actions "Checkout branch"
                       (lambda (_candidate)
                         (let ((marked (helm-marked-candidates)))
                           (dolist (f marked)
                             (vc-git-revert f)
                             (helm-aif (get-file-buffer f)
                                 (with-current-buffer it
                                   (revert-buffer t t)))))))
    actions))
\f
(defclass helm-git-local-source (helm-source-in-buffer)
  ((header-name :initform 'helm-ls-git-header-name)
   (init :initform
         (lambda ()
           (helm-init-candidates-in-buffer 'global
             (helm-git--local-branches))))
   (keymap :initform 'helm-git-branch-map)
   (action :initform (helm-make-actions "Git checkout"
                                        (lambda (_candidate)
                                          (helm-git-branch--checkout _candidate))))
   (filtered-candidate-transformer :initform 'helm-git-branch-local-transformer)
   (action-transformer :initform 'helm-git-branch-local-action-transformer)))

(defun helm-git-build-local-branches-source ()
  ;;(and (memq 'helm-source-ls-git-branches helm-ls-git-default-sources)
  (helm-make-source "Local branches" 'helm-git-local-source
    :fuzzy-match helm-git-branch-fuzzy-match
    :group 'helm
    :keymap helm-git-branch-map))
\f
(defun helm-git-branch--dirty-p ()
  (not (string-blank-p (helm-ls-git-status))))

(defun helm-git-branch--stash ()
  (helm-aif (helm-ls-git-root-dir)
      (with-helm-default-directory it
        (with-output-to-string
          (with-current-buffer standard-output
            (insert
             (call-process "git" nil t nil "stash" "save"
                           (when helm-git-branch-auto-stash-unstaged "-u")
                           (concat helm-git-branch-stash-prefix
                                   (helm-ls-git--branch)))))))))

(defun helm-git-branch--unstash ()
  (helm-aif (helm-ls-git-root-dir)
      (with-helm-default-directory it
        (with-output-to-string
          (with-current-buffer standard-output
            (insert (call-process "git" nil t nil "stash" "list"))
            (goto-char (point-min))
            (when (search-forward (concat helm-git-branch-stash-prefix
                                          (helm-ls-git--branch)) nil t)
              (goto-char (line-beginning-position))
              (search-forward "}" (line-end-position))
              (let ((stash (buffer-substring-no-properties
                            (line-beginning-position) (point))))
                (call-process "git" nil t nil "stash" "apply" stash)
                (call-process "git" nil t nil "stash" "drop" stash))))))))

(defun helm-git-branch--checkout (branch)
  (helm-aif (helm-ls-git-root-dir)
      (with-helm-default-directory it
        (with-output-to-string
          (with-current-buffer standard-output
            (when helm-git-branch-auto-save-on-change
              (save-some-buffers
               t
               (lambda () (file-in-directory-p default-directory (helm-ls-git-root-dir)))))
            (when (helm-git-branch--dirty-p)
              (helm-git-branch--stash))
            (insert (call-process "git" nil t nil "checkout" branch))
            (helm-git-branch--unstash))))))
\f
;;; Commands
;;;###autoload
(defun helm-git-local-branches (&optional arg)
  (interactive "p")
  (let ((helm-ff-default-directory
         (or helm-ff-default-directory
             default-directory)))
    (when (and arg (not (helm-ls-git-root-dir)))
      (error "Not inside a Git repository"))
    (setq helm-source-git-local-branches
          (helm-git-build-local-branches-source))
    (helm-set-local-variable
     'helm-ls-git--current-branch (helm-ls-git--branch))
    (helm :sources helm-source-git-local-branches
          :ff-transformer-show-only-basename nil
          :truncate-lines helm-buffers-truncate-lines
          :buffer "*helm branches*")))

(provide 'helm-git-branch)
;;; helm-git-branch.el ends here

  reply	other threads:[~2021-08-16  1:05 UTC|newest]

Thread overview: 69+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-03 21:13 On the adoption of transient.el Gabriel
2021-07-05 14:24 ` Philip Kaludercic
2021-07-05 16:09   ` Gabriel
2021-07-05 17:00     ` Stefan Monnier
2021-07-05 19:16       ` Lars Ingebrigtsen
2021-07-05 16:50   ` Yuri Khan
2021-07-05 17:06     ` Eli Zaretskii
2021-07-05 17:29       ` Yuri Khan
2021-07-05 17:49         ` Stefan Monnier
2021-07-05 18:09     ` Philip Kaludercic
2021-08-01 20:19       ` Rudolf Adamkovič
2021-08-01 21:08         ` T.V Raman
2021-08-01 21:24         ` Arthur Miller
2021-08-03 13:07           ` Jonas Bernoulli
2021-08-03 20:00             ` Arthur Miller
2021-08-14  3:17             ` Arthur Miller
2021-08-14 12:54               ` Óscar Fuentes
2021-08-14 20:45                 ` Arthur Miller
2021-08-15 21:57                 ` John Yates
2021-08-16  1:05                   ` Arthur Miller [this message]
2021-08-16  1:35                   ` Stefan Monnier
2021-08-16  2:36                     ` Arthur Miller
2021-08-01 21:25         ` Arthur Miller
2021-08-04 11:22         ` Philip Kaludercic
2021-08-04 15:56           ` Óscar Fuentes
2021-08-04 18:56           ` T.V Raman
2021-08-04 19:57             ` Jesse Millwood
2021-08-04 21:45               ` T.V Raman
2021-08-05  7:01                 ` Arthur Miller
2021-08-05  8:59                   ` Eric S Fraga
2021-08-05  9:23                     ` Tim Cross
2021-08-05 10:37                       ` Eric S Fraga
2021-08-05 11:01                         ` Eli Zaretskii
2021-08-05 14:45                           ` Óscar Fuentes
2021-08-05 16:17                             ` Eli Zaretskii
2021-08-05 23:17                               ` Juri Linkov
2021-08-06  6:11                                 ` Eli Zaretskii
2021-08-06  2:13                               ` Phil Sainty
2021-08-05 23:20                             ` Juri Linkov
2021-08-06 12:39                               ` John Yates
2021-08-06 14:42                                 ` Stefan Monnier
2021-08-06 17:20                                   ` Omar Polo
2021-08-10  7:22                                 ` Juri Linkov
2021-08-10 10:32                                   ` John Yates
2021-08-08  1:21                               ` Dmitry Gutov
2021-08-10  7:15                                 ` Juri Linkov
2021-08-10 12:40                                   ` Dmitry Gutov
2021-08-11  6:58                                     ` Juri Linkov
2021-08-13  3:06                                       ` Dmitry Gutov
2021-08-08  1:42                               ` Alfred M. Szmidt
2021-08-10  7:18                                 ` Juri Linkov
2021-08-10  8:16                                   ` Alfred M. Szmidt
2021-08-11  6:56                                     ` Juri Linkov
2021-08-05  9:38                     ` Arthur Miller
2021-08-05  9:51                       ` Jean-Christophe Helary
2021-08-05 14:33                     ` T.V Raman
2021-08-05 14:55                       ` Eric S Fraga
2021-08-05 15:05                       ` Arthur Miller
2021-08-06 23:02             ` Rudolf Adamkovič
2021-08-07  2:03               ` T.V Raman
2021-08-07  3:15               ` Phil Sainty
2021-08-07 10:19               ` Jonas Bernoulli
2021-08-07 15:42               ` T.V Raman
2021-07-05 19:51     ` Jim Porter
  -- strict thread matches above, loose matches on Subject: below --
2022-07-31  9:08 Manuel Uberti
2022-07-31 13:25 ` T.V Raman
2022-07-31 20:03 ` Juri Linkov
2022-08-21 16:04   ` Juri Linkov
2022-08-01  3:32 ` Richard Stallman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=AM9PR09MB49777BF2243E1FD70098CA7396FD9@AM9PR09MB4977.eurprd09.prod.outlook.com \
    --to=arthur.miller@live.com \
    --cc=emacs-devel@gnu.org \
    --cc=john@yates-sheets.org \
    --cc=ofv@wanadoo.es \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).