helm-ls-git icon indicating copy to clipboard operation
helm-ls-git copied to clipboard

Feature proposal/question: basic git branches management with Helm?

Open amno1 opened this issue 3 years ago • 8 comments

I would like to be able to do at least some very basic branch manipulation with Helm. What I think of is a command like 'helm-ls-git-branches'. When run, this command will in usual style display all available branches in a git repo. Default (persistent) action would be to switch to a branch. This can't be a tad bit more involved if there are unstaged changes, so some flags and strategies would have to be customized by user how to deal with those (stash auto or similar). It would be nice if the command also offered an option to delete a branch, and to merge/squash marked branches and to push a marked branch or branches upstream. I was looking around on the webb, but I couldn't find any helm interface for managing branches, and I really miss the option to at least checkout branch from within the Helm interface, and to see a list of branches.

I am not sure if this should be tucked in the same app as helm-ls-git or if it should be a separate app.

amno1 avatar Jul 26 '21 16:07 amno1

Arthur Miller @.***> writes:

[[PGP Encrypted Part:OK]] I would like to be able to do at least some very basic branch manipulation with Helm.

Why don't you hit bb from magit, it allows quick branch switching with helm completion (when helm-mode is enabled). Otherwise for quick basic branch switching from current-buffer I use my mode-line and the mouse to select a branch, see the code at https://github.com/thierryvolpiatto/emacs-config/blob/main/init.el#L542.

-- Thierry

thierryvolpiatto avatar Jul 26 '21 18:07 thierryvolpiatto

Why don't you hit bb from magit, it allows quick branch switching with

I am not so much of the mouse guy :). Helm is just cool, and I am sure magit is also very cool, but to be honest, I didn't used that part from magit, actually I used magit very little, I do stuff from cmd line mostly. Can that helm-completion in magit be snitched out of magit? :-) Or is it too tightly coupled with magit?

It would be cool to be ablte to do this from Helm interface. Like C-z b to show branches and then complete the one I wish to checkout, or delete it or push it to remote. Compare to helm vs. dired, magit is kind of similar to dired in this regard. I don't know, maybe I am wrong, just idea. I was coding a bit last night and was trying to adapt the code in hlem-ls-git, but I have never written a helm addon som I am not really at home with how everything hangs together, with all those transformer funcitons and sources and what not :).

I hacked this to list branches, was not a big deal:

(defun helm-ls-git-branches (&optional arg)
  "List branches on local or remote repository.

If `arg' is nil it will show only local branches (i.e. the command 
\"git branch\").

If `arg' has value 'all then it will fetch all remote branches,
  tracked and untracked (\"git ls-remote --heads\").

If `arg' has value 't it will show all tracked branches as of
\"git branch -r\"."
  (message "K: %s" arg)
  (helm-aif (helm-ls-git-root-dir)
      (with-helm-default-directory it
        (split-string
         (with-output-to-string
           (with-current-buffer standard-output
             (cond ((null arg)
                    (insert (call-process "git" nil t nil "branch")))
                   ((equal arg 'all)
                    (insert (call-process "git" nil t nil "ls-remote"
                                          "--heads"))
                    (goto-char (point-min))
                    (when (search-forward "From" (line-end-position) t 1)
                      (replace-match "Branches for remote repository:"))
                    (goto-char (point-min))
                    (while (search-forward "refs/heads/" nil t)
                      (replace-match ""))
                    (when (search-backward "?^@" nil t)
                      (replace-match "")))
                   (arg
                    (insert (call-process "git" nil t nil "branch" "-r"))))
             (buffer-substring-no-properties (goto-char (point-min))
                                             (line-end-position)))) "\n" t))))

But I am not sure how to hook it up into the helm interface. I would like to reuse some code from helm-ls-git, but branches can't share same screen with files, they need their own screen, so I was not sure if to build a separate app, or to hack on ls-git. At least while I am playing, I'll play with it in ls-git. The code above is not final, lists need cleanup. I am currently reading J.K blog: https://kitchingroup.cheme.cmu.edu/blog/2015/01/24/Anatomy-of-a-helm-source/ to see if I can hook-up things together.

amno1 avatar Jul 26 '21 19:07 amno1

Arthur Miller @.***> writes:

[[PGP Encrypted Part:OK]] Why don't you hit bb from magit, it allows quick branch switching with

I am not so much of the mouse guy :). Helm is just cool, and I am sure magit is also very cool, but to be honest, I didn't used that part from magit, actually I used magit very little, I do stuff from cmd line mostly. Can that helm-completion in magit be snitched out of magit? :-) Or is it too tightly coupled with magit?

Magit use a completing-read and once you enable helm-mode, all completing-read's (among other things) are turned into an helm interface.

It would be cool to be ablte to do this from Helm interface.

Yes but it is already implemented by helm-mode, why reinvent the wheel while Magit is already providing this?

  1. Switch to magit-status
  2. hit bb
  3. choose your branch

Like C-z b to show branches and then complete the one I wish to checkout, or delete it or push it to remote. Compare to helm vs. dired, magit is kind of similar to dired in this regard. I don't know, maybe I am wrong, just idea. I was coding a bit last night and was trying to adapt the code in hlem-ls-git, but I have never written a helm addon som I am not really at home with how everything hangs together, with all those transformer funcitons and sources and what not :).

I hacked this to list branches, was not a big deal:

(defun helm-ls-git-branches (&optional arg) "List branches on local or remote repository.

If `arg' is nil it will show only local branches (i.e. the command "git branch").

If `arg' has value 'all then it will fetch all remote branches, tracked and untracked ("git ls-remote --heads").

If `arg' has value 't it will show all tracked branches as of "git branch -r"." (message "K: %s" arg) (helm-aif (helm-ls-git-root-dir) (with-helm-default-directory it (split-string (with-output-to-string (with-current-buffer standard-output (cond ((null arg) (insert (call-process "git" nil t nil "branch"))) ((equal arg 'all) (insert (call-process "git" nil t nil "ls-remote" "--heads")) (goto-char (point-min)) (when (search-forward "From" (line-end-position) t 1) (replace-match "Branches for remote repository:")) (goto-char (point-min)) (while (search-forward "refs/heads/" nil t) (replace-match "")) (when (search-backward "?^@" nil t) (replace-match ""))) (arg (insert (call-process "git" nil t nil "branch" "-r")))) (buffer-substring-no-properties (goto-char (point-min)) (line-end-position)))) "\n" t))))

But I am not sure how to hook it up into the helm interface.

Will show you soon, it should not be that hard, not the time right now ;-)

-- Thierry

thierryvolpiatto avatar Jul 27 '21 05:07 thierryvolpiatto

Will show you soon, it should not be that hard, not the time right now ;-)

hehe ... I have figured it out, took me about two hours, but includes reading all J.K helm articles and feeding 3 months old baby at same time :). I can now list branches and do the selection, have yet to see how to implement actions. I should have looked into less convoluted app, ls-git is a slightly bit complex to start learning helm apps, but it wasn't that bad.

Yes but it is already implemented by helm-mode, why reinvent the wheel while Magit is already providing this?

Just a convenience, why opening magit just to switch a branch? Can as well do from M-!. But it is just slightly more convenient to hit say C-z b and complete a branch to check out. Just my personal preference. Also, not much of reinventing the wheel, you have already done it in helm-ls-git, I have just copied and slightly modified stuff to add 3 extra shell commands, nothing spectacular :). I am just not familiar with Helm framework.

I have added 3 new iterative commands, rest is mostly just modified and reused code from helm-ls-git:


;;;###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-git-root-dir)))
      (error "Not inside a Git repository"))
    (helm :sources (helm-git--build-local-source)
          :ff-transformer-show-only-basename nil
          :truncate-lines helm-buffers-truncate-lines
          :buffer "*helm branches*")))

;;;###autoload
(defun helm-git-remote-branches (&optional arg)
  (interactive "p")
  (let ((helm-ff-default-directory
         (or helm-ff-default-directory
             default-directory)))
    (when (and arg (not (helm-git-root-dir)))
      (error "Not inside a Git repository"))
    (helm :sources (helm-git--build-remote-source)
          :ff-transformer-show-only-basename nil
          :truncate-lines helm-buffers-truncate-lines
          :buffer "*helm branches*")))


;;;###autoload
(defun helm-git-tracked-branches (&optional arg)  <-- horrible name, need better name for this
  (interactive "p")
  (let ((helm-ff-default-directory
         (or helm-ff-default-directory
             default-directory)))
    (when (and arg (not (helm-git-root-dir)))
      (error "Not inside a Git repository"))
    (helm :sources (helm-git--build-tracked-source)
          :ff-transformer-show-only-basename nil
          :truncate-lines helm-buffers-truncate-lines
          :buffer "*helm branches*")))

I am not done yet as said, I have removed checks and fluff while I am testing it.

If you think helm-ls-git can do some branches too, I'll rename stuff to helm-ls-git prefix. If you don't think it is something to have, I'll make a small standalone helm app. I would prefer it to be part of helm-ls-git, but I am ok if you don't want it. I understand if you don't see this as something for helm-ls-git.

amno1 avatar Jul 27 '21 11:07 amno1

Arthur Miller @.***> writes:

[[PGP Encrypted Part:OK]] Will show you soon, it should not be that hard, not the time right now ;-)

hehe ... I have figured it out, took me about two hours, but includes reading all J.K helm articles and feeding 3 months old baby at same time :).

Glad you find out how to do!

Just a convenience, why opening magit just to switch a branch?

You don't need necessarily to open magit-status, you can just M-x magit-branch-checkout.

If you think helm-ls-git can do some branches too, I'll rename stuff to helm-ls-git prefix. If you don't think it is something to have, I'll make a small standalone helm app. I would prefer it to be part of helm-ls-git, but I am ok if you don't want it. I understand if you don't see this as something for helm-ls-git.

I don't think it is something to have in helm-ls-git as it is already provided by magit and IMO it is doing a better job than us in this sector (see all magit-branch-* commands).

-- Thierry

thierryvolpiatto avatar Jul 27 '21 13:07 thierryvolpiatto

Sure.

amno1 avatar Jul 27 '21 16:07 amno1

Rethinking at it, it is indeed cool to have some git branch management for non Magit users, I discover Vc provides nothing for this (or I missed something?) so I started writing some basic stuff for branches.

thierryvolpiatto avatar Aug 28 '21 14:08 thierryvolpiatto

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

It is not finished yet because of lack of time so I haven't published it in Melpa, but switching local branches is operational. My plan is to add functionality to create new branch, similar as to what helm does with new files (it is just to git checkout -b branch-name) and to add functionality to pull/fetch remote branches. I meant to publish in Melpa after I add those, but if you want to include it in Helm, it's ok too.

This isn't just for non-magit users. What I did is automation. This works very well with magit or without magit. It just saves some time with a common case which we probably all do from time to time.

Magit is cool, but it is 1:1 with git. It does not do any automation for switching branches. I mentioned that it would be nice to have it on emacs-devel but Jonas never answered on that one.

amno1 avatar Aug 28 '21 14:08 amno1