Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend commit panel with branch operations (switch/rename/delete) #4115

Open
seflue opened this issue Dec 14, 2024 · 11 comments
Open

Extend commit panel with branch operations (switch/rename/delete) #4115

seflue opened this issue Dec 14, 2024 · 11 comments
Labels
enhancement New feature or request

Comments

@seflue
Copy link
Contributor

seflue commented Dec 14, 2024

Is your feature request related to a problem? Please describe.
Lazygit's commit panel provides a clear visualization of the git graph, which is particularly helpful when working with complex branch structures.
During intensive branch cleanup sessions (involving rebasing and cherry-picking), I frequently need to switch between the commit panel and branch view to manage branches. This interrupts the workflow as I lose sight of the graph structure momentarily and need to keep branch names in mind while navigating between views. This becomes particularly challenging when working with multiple branches that need reorganizing.

Describe the solution you'd like
Since Lazygit already supports creating new branches from the commit panel, it would be helpful to have other branch operations available there as well. Specifically, being able to:

  • Switch between branches
  • Rename branches
  • Delete branches
  • Perform merges and rebases

Having these operations available directly where we can see the full branch structure would streamline complex git workflows.

Describe alternatives you've considered
Currently, I work with the standard approach of noting the branch name from the commit panel, switching to the branch view, finding the branch again, and performing the operation there. While this works, it interrupts the natural flow of working with the git graph, especially during intensive cleanup sessions.

Additional context
This enhancement would complement Lazygit's existing visualization capabilities. By bringing branch management directly to where the branches are visualized, it would make complex git workflows more efficient.

@seflue seflue added the enhancement New feature or request label Dec 14, 2024
@stefanhaller
Copy link
Collaborator

I'm not sure what you mean by "log view", that's not standard lazygit terminology as far as I can tell. Are you talking about the Commits panel (panel 4), or about the commits view that you get by pressing enter on a branch in the Branches panel (panel 3), or something else?

Either way, I don't quite see how the UX would work for what you are suggesting. The standard paradigm for lazygit to operate on things (in order to rename or delete them) is to have a list of these things (e.g. in the Branches panel), select one, and then invoke the command that operates on the selected thing. I don't see how you would do that if the list of these things is not visible because you are in some other panel. Do you have more concrete suggestions for how exactly your proposed operations would work?

Finally, it might help if you describe some of your complex workflows more concretely (maybe with screenshots), I don't really think I understand what it is that you are missing.

@seflue seflue changed the title Extend log view with branch operations (switch/rename/delete) Extend commit panel with branch operations (switch/rename/delete) Dec 14, 2024
@seflue
Copy link
Contributor Author

seflue commented Dec 14, 2024

First I updated the issue to align with Lazygit terminology. For me it is the standard view on the git log, that's why I reached for the term "log view". But your right, we should stick to the established terms of the project.

There are two options to implement this, one, which needs more keybindings, the other would be a bit more cumbersome to work with, but I would be fine with both of them.

Option 1:
Have dedicated key bindings to:

  • rename the branch of a selected commit
  • delete the branch on a selected commit
  • switch to the branch of a selected commit
  • rebase the checked-out branch to a selected commit
  • merge the branch of a selected commit in the checked-out branch

When there is only one branch on the selected commit, the command is applied immediately, otherwise we could have a select box for the available branches to resolve (similar to what we have with e.g. setting upstream branches). If no branch is available, we could show an error. I always liked the metaphor of post-its attached to commits for branches and tags in git and I would like to move my post-its around looking at the commit graph. This kind of workflow I usually do when experimenting locally with code. Then I use my Git like a tree of local snapshots of my work. Before I merge something into long time history, I need to consolidate and clean up and while I like squashes and fixups, sometimes it get's a bit more complicated.

Option 2:
The other, more cumbersome approach would be a keybinding for "branch operations" and then I can select, what I actually want to do. This could then also be stripped down to the available options. If no branch is available on the commit, rename, switch and merge would not be available. After selecting a command, it could continue like option 1.

I was formerly a poweruser of SmartGit, where they have this feature - and I used it a lot. But I love my command line, my TUIs and my vim motions, so when I discovered lazygit I almost abandoned SmartGit.

I am also teaching Git to colleagues and it helps newcomers a lot in understanding what actually happens when doing branch operations visually on the commit graph.

@stefanhaller
Copy link
Collaborator

Oh wait, you are talking about the Commits panel when the "git.log.showWholeGraph" option is on, is that true? It always makes me nervous when people use this option, because it is so broken. We have tons of code all over the lazygit codebase that assumes all entries in the Commits panel belong to the current branch; #3608 has some examples, but there are probably many more. I wish we didn't have that option, at least as long as we didn't fix all those issues.

(But then, even without the showWholeGraph option, the commands you are proposing to add can still be useful in a stacked branches workflow.)

Anyway, thanks for the detailed explanation, it makes a lot more sense to me now. My initial reaction was that I don't like adding more keybindings to the Commits panel because it has so many already, but actually some of them could be folded into the existing ones, so it wouldn't be so bad. Let's see in detail:

  • rename the branch of a selected commit -> this would have to be a new command
  • delete the branch on a selected commit -> this can be folded into the existing d keybinding. Currently you get a confirmation panel when you hit d, so we could turn this into a menu with two entries (delete selected commit, and delete branch pointing to selected commit).
  • switch to the branch of a selected commit -> can be folded into space. Currently you get a confirmation to check out a detached head on the selected commit; again, this could become a menu, similar to the one that you get when pressing space on a remote branch.
  • rebase the checked-out branch to a selected commit -> we have an issue for that already -> Allow rebasing onto any ref #2850. It's a bit tricky because of conflicting keybindings.
  • merge the branch of a selected commit in the checked-out branch -> I don't have an opinion about that one, since I never merge anything locally. Maybe it's easiest to add a new command for this, like for rename, but I wonder if it's really absolutely needed.

The nice thing about this is that these don't have to be done all at once; they could be added one by one, the most important ones first. Are you interested in working on (some of) this?

@seflue
Copy link
Contributor Author

seflue commented Dec 14, 2024

Thanks for the detailed answer. And yes, I am speaking about the showWholeGraph feature.

If I would have to put priorities onto the listed operations, the list would look like this:

  1. Switch: This is by far the command I miss the most. I can only checkout a commit as detached head, more often I just want to switch the branch.
  2. Delete: When I look at the graph to see, what I still need and what is obsolete, I directly want to prune the graph, where I can see it.
  3. Rebase: It's a lot easier, when you see, where you want to rebase to. For me it would be sufficient, if it allows only for rebasing onto actual branches, if this is easier to implement in the current codebase.
  4. Rename: It's just convenient, when you do cleanup work
  5. Merge: I also don't merge so often locally, so I have no priority on this. I just listed it because of completeness.

@stefanhaller
Copy link
Collaborator

Makes sense to me, and we could easily start by making PRs for the first two, they are the easiest probably.

You didn't answer my last question though. :)

@seflue
Copy link
Contributor Author

seflue commented Dec 14, 2024

To answer your last question: Another rabbit hole I can dive into and an opportunity to learn Go ... actually, if you can give me some entry points into the code base and also some advice, what I have to consider in terms of code style and pattern, I would be happy to contribute. I cannot make promises, but having another project over the Christmas holidays which makes me more productive in the new year sounds tempting. 🤓

Edit: I just forked the repo and started to look into the contribution guidelines. But if you already can give me more direct hints where I need to look into the codebase to implement one of the listed operations, I would appreciate that. 👍

@stefanhaller
Copy link
Collaborator

Cool. I recommend to start by reading Contributing.md, and docs/dev/Codebase_Guide.md to get a general rough idea of what code is where.

Then, the code to checkout a commit is here. Note that BasicCommitsController is not only for the Commits panel; it is also used for the subCommits view (e.g. when you press enter on a branch or tag) and for the reflog view, but there's no reason not to offer the same functionality there, so why not.

To find the branches that point to the selected commit, loop over the branches in the model (no need to make a git call). Let me know if you get stuck on anything.

@seflue
Copy link
Contributor Author

seflue commented Dec 14, 2024

To find the branches that point to the selected commit, loop over the branches in the model (no need to make a git call). Let me know if you get stuck on anything.

Currently I struggle to understand how to access the branches from the BasicCommitsController. The commit model passed as method argument (commit *.models.Commit) has no obvious collection of branches. Would you mind to point me to an example in the code base, where the branches are accessed and the branch model is not passed as argument (like in the BranchesController)?

@stefanhaller
Copy link
Collaborator

Controllers have a c field that contains references to all sorts of useful stuff including the model. Branches are available as self.c.Model().Branches.

Development tip: the go language server is very good at auto-completing incomplete call chains, so if you suspect the model is available somehow, you can start typing self.mod and it will suggest self.c.Model.

@seflue
Copy link
Contributor Author

seflue commented Dec 15, 2024

Ok, I have a first basic version of the switch-branch-feature working.

I want to polish it a bit though. Particularly I want to add the possibility to checkout also remote branches. But I don't know, how to correlate a remote branch to it's current commit hash, because it doesn't have a Hash field like *model.Branch, so I am stuck, filtering the relevant ones (my tries grepping for an example in the code base weren't successful). Do you have a hint for me?

And in general, would you prefer to continue the discussion in a draft PR?

Edit: I decided to create a first PR #4117 and leave the remote branches for later improvement.

@stefanhaller
Copy link
Collaborator

I want to polish it a bit though. Particularly I want to add the possibility to checkout also remote branches. But I don't know, how to correlate a remote branch to it's current commit hash, because it doesn't have a Hash field like *model.Branch, so I am stuck, filtering the relevant ones (my tries grepping for an example in the code base weren't successful). Do you have a hint for me?

I was wondering about remote branches as well, but wasn't sure how important that is. Thinking about it, it could actually be quite useful, for example if a coworker pushes a stack of branches, and I check out the top branch of the stack and want to easily check out the other ones as well from there.

It's funny that remote branches don't have a Hash field, it seems we never needed it so far. It should be quite easy to add though. We simply add %00%(objectname) to the --format argument of the git for-each-ref call in RemoteLoader.getRemoteBranchesByRemoteName and then split on "\x00" to get branch name and hash.

Note, however, that adding remote branches to the feature is not trivial. You need to check whether there is already a local branch that has this remote branch as an upstream; however, the local branch needn't necessarily have the same name as the remote branch, and of course it needn't point at the same commit. I think this is complex enough that it would be best done in a separate PR.

stefanhaller added a commit that referenced this issue Jan 1, 2025
- **PR Description**

When the user checks out a commit which has a local branch ref attached
to it, they can select between checking out the branch or checking out
the commit as detached head. If no local branch is attached to the
commit, the behavior is like before: They are asked to confirm, if they
want to checkout the commit as detached head.

Requested in #4115.

Note: I tried also to consider remote branches, but because I wasn't
able to correlate remote branches to their commits, I deferred it and
leave it open for later improvement.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants