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

Stacked PRs in lazygit #2527

Open
canadaduane opened this issue Mar 29, 2023 · 15 comments
Open

Stacked PRs in lazygit #2527

canadaduane opened this issue Mar 29, 2023 · 15 comments
Labels
enhancement New feature or request

Comments

@canadaduane
Copy link

Is your feature request related to a problem? Please describe.

I'm interested in incorporating stacked PRs into a lazygit workflow:

https://benjamincongdon.me/blog/2022/07/17/In-Praise-of-Stacked-PRs/
https://timothya.com/blog/git-stack/

I don't yet have a clear vision of how this would work in lazygit, but the overarching goal is to be able to make several related, simultaneous pull requests (each with 1 or more commits) in Github (or similar). Given feedback from the PRs, I'd like a way to edit the commits within PRs, or re-sequence the PRs in lazygit, or omit / introduce new PRs in between existing PRs.

Describe the solution you'd like
This is more of a "call for ideas" than a concrete solution. Has the concept of stacked PRs been discussed? Are there existing solutions that work well with lazygit? Would it make sense to use a command like git-stack, or would a custom implementation specific to lazygit make more sense?

Additional context
I'm exploring command-line tools like gh-stack, git-stack, and git-branchless. There are also possibly-commercial options out there such as graphite (gt).

@canadaduane canadaduane added the enhancement New feature or request label Mar 29, 2023
@stefanhaller
Copy link
Collaborator

stefanhaller commented Apr 3, 2023

I haven't worked with tools like git-stack myself; when I work with stacked branches, I manage them manually. The introduction of git rebase --update-refs in 2.38 made that actually feasible, before it was a pain in the butt.

Before thinking about adding features to manage stacked branches to lazygit, we first need to fix a few basic things that are broken right now:

  1. When typing "e" to start a rebase on the selected commit, lazygit breaks the stack. The reason is that it creates a git-rebase-todo file itself instead of letting git create one, and it doesn't know how to insert update-ref commands.
  2. When initiating a rebase outside of lazygit to work around this, editing rebase todos is broken. The reason is that lazygit assumes it shows as many rebase todos as there are lines in the git-rebase-todo file, which is not true when there are update-ref commands in the file. This means that using ctrl-j/k will move the wrong commits. Because of this, you need to be very careful when using lazygit with stacked branches, and rebase.updateRefs set to true.

I'm working on fixing both of these right now (2nd first).

After that, the next thing I'm missing is to somehow visualize the individual branch heads of the stack in the local commits panel. They are visible when you expand the panel using +, just not when the panel is not expanded. I don't have a good idea how, there's not enough room to draw the branch names, but I'd be ok with somehow visualizing that there is a branch at a given commit, not necessarily which one; maybe just by coloring the commit differently, or putting some icon before the subject, something like that. Ideas welcome, I'm not a good designer.

Once all these are done, I'd be happy and wouldn't need any more support for working with stacked branches. But that's only my personal opinion, others might disagree.

@stefanhaller
Copy link
Collaborator

stefanhaller commented May 3, 2023

The two issues mentioned above are fixed in the 0.38 release, so support for stacked branches is a lot better now.

Visualization of branch heads in the local commits view is not great yet. You have to opt in to it by turning on the gui.experimentalShowBranchHeads config, then it shows branch heads with a (*) annotation. However, it also shows these for remote branches, which is undesirable. We still need to iterate on this some more, but it's a start.

There are a few remaining issues for me:

  • Undoing a rebase operation on a branch stack only resets the top of the stack, not the other branch heads. This is a tricky one to solve, as the undo feature is based entirely on the HEAD reflog.
  • Pushing the individual branches of a stack is tedious; you have to checkout and push each one individually, would be nice if there's an easier way to do that.
  • Visualization of branch heads in the commits list needs to be improved, as mentioned above. This has meanwhile been improved a lot.

If you have other issues with support for stacked branches besides there, I'd be interested to hear about them.

@lettertwo
Copy link

I love that lazygit is working toward support for these types of workflows!

If you have other issues with support for stacked branches besides there, I'd be interested to hear about them.

I think it would be nice if the local branches visualization showed a tree view that reflected the stack of branches. For example, graphite's gt log short visualization looks something like this:

  ◯      feature-c
  │ ◉    feature-b-3
  │ ◯    feature-b-2
  │ ◯    feature-b
  │ │ ◯  feature-a
  ◯─┴─┘  main

Another thing I'd love to have from a stacked branch feature set is integration with worktrees. e.g., instead of operating on the branches in the stack only in the current worktree, move to the existing worktree location for each branch during the operation.

@wederbrand
Copy link

wederbrand commented Sep 1, 2024

I came here to ask for this feature so I'm happy I found it.
I've been trying to use git-town and their stacked changes for this but is has one massive problem; it's not (supported by) lazy git and I rather manage may branches/changes/PRs manually over not using lazy git.

My use case is that I normally do a first PR of typically "cleanup and upgrades" followed by "implement feature A" followed perhaps by "implement feature B". Normally I get all of those done before the first one gets reviewed.

Then, after amending the first PR after review comments, I rebase the other two in order. I have to remember the order (so I try to name them cleverly). I also normally do this rebase interactively and drop commits that originally came from the first (or second) branch to just apply the diff added by this branch/PR.

So, I (thumbup) and (vote) for this one and I'm happy to test it out on a beta.

@stefanhaller
Copy link
Collaborator

@wederbrand What you describe is a workflow I use very frequently. I often stack two, three, or sometimes four branches onto each other, and work with them using lazygit. I find that lazygit does a decent job of supporting this workflow, if you pay attention to a few basic rules.

I only had a brief look at git-town's stacked branches documentation that you linked to above, and it doesn't strike me as superior; it seems that you have to do a bit of manual maintenance (e.g. call sync or ship at the right times), and I don't want to have to do that.

With lazygit (or stock cli git for that matter), what you have to keep in mind is to always work on the topmost branch of the stack. Keep that branch checked out at all times, even when working on the lower branches. This way, whenever you do any kind of history rewriting (amending commits, moving commits up/down, etc), you stack stays intact. The only time you have to manually fix your stack is when a coworker "helpfully" pushes a fixup commit to one of the lower branches.

This workflow has a few consequences:

  • when creating a fixup commit for one of the lower branches using shift-F, it ends up at the top of the last branch, which is not what you want, so you need to move it down to the end of the branch that it belongs to. This works best if you do it in interactive rebase mode, because then you see the update-ref todos and can move it right before that one. I'm actually wondering if we should change lazygit to put the fixup commit at the end of the right branch automatically; I can't think of a scenario where that's not what you want. I'll look into that.
  • Since the lower branches are never checked out, you can't be sure (after very heavy history rewriting) whether they still compile, so it's worth hitting e on them once in a while to verify that. Of course, this is no different from the individual commits of a longer, non-stacked branch.

Let me know if anything is unclear, or if you are missing other functionality (besides the ones that were already mentioned above).

@wederbrand
Copy link

I'm sure I follow, or I do it wrong.

If have stacked branches A (bottom of stack), B and C (top of stack) and I'm working on C but the change I'm doing is for one of the commits in A.

I would do the change, stage it and then select a commit from A and do shift+A to amend it to that one.
From C this looks fine but branches A and B now points to historical versions of all commits.
I have at times copied the sha and then a force reset on each branch (A and B) to their new versions but this too is tedious.

What git-town does (and I'm not saying it does it well) is to allow me to switch to A, do the amend, and then switch back to C and sync it. All of A, B and C are now correctly pointing to each other and the remots have been updated.

@stefanhaller
Copy link
Collaborator

Sounds like you don't have the rebase.updateRefs config turned on. Do this once: git config --global rebase.updateRefs true, and everything will work transparently from then on.

What git-town does (and I'm not saying it does it well) is to allow me to switch to A, do the amend, and then switch back to C and sync it.

That's the thing, I don't want to have to switch to A and back to C, or do some manual syncing.

@wederbrand
Copy link

Excellent!

My work flow predates 2.38 and apparently I haven't been paying attention ;)

@slieschke
Copy link

slieschke commented Nov 22, 2024

If you have other issues with support for stacked branches besides there, I'd be interested to hear about them.

When using stacked commits after moving a commit across branch boundaries with <c-j> or <c-k> the commit selection doesn't get maintained as expected as I logged at #4040 (edit: now fixed 🙂️).

@dlvhdr
Copy link

dlvhdr commented Jan 8, 2025

I have no idea why, but when I press e on a lower branch in the stack, I don't get a update ref commit. When I do the same thing on a commit that's not the HEAD of the lower branch, I do see a update-ref commit...

When on the HEAD of add-fruits:
image

When on the HEAD^1 of add-fruits:
image

@stefanhaller
Copy link
Collaborator

@dlvhdr This is already fixed on master (see #4090), just not released yet.

I hope we'll have a release sometime soon.

@massarom
Copy link

massarom commented Feb 17, 2025

I find lazygit's support for stacked branches already quite good (in 2025), even if some QoL things could be added. What really I would love seeing (not a Go dev unfortunately...) is the option to also push all branches in the stack. I already can see them since I get the little "branch icon" when I'm at the top of the stack, and lazygit correctly implements update-refs, but having to then push multiple branches manually is a bit of a chore.

Lazygit has all the information it needs already to do this automatically, right? Since it's able to place the branch icons in the commit list, it should also be able to get the same branches and push them one by one. Is this feature already there, and I'm just not aware of it?

@stefanhaller
Copy link
Collaborator

@massarom This is still missing. There's a long discussion about it in #2755; the discussion is a bit hard to follow because it also includes the topic of pulling the branches without checking them out.

@PeterCardenas
Copy link
Contributor

Have a couple of suggestions that I believe aren't covered in this thread:

  • Oftentimes I just want to amend a commit and have it propagate to other branches in the stack, but just using the A keybinding removes the update-ref, which is undesirable. I have to create a fixup commit with F and then apply the fixups in the branch. It would be much easier if we checked whether rebase.updateRefs is enabled and then change the behavior of amend to do the fixup and apply it.
  • I have a similar sentiment for remapping the rename commit keybind r to create the amend! fixup and squash it when rebase.updateRefs is enabled.

@stefanhaller
Copy link
Collaborator

@PeterCardenas I'm confused; I do both of these things all the time, and they work great with stacked branches. I can think of no reason why they don't work for you, but squashing fixups does. And I don't even know what clarifying questions I can ask to get to the bottom of this. Still, can you describe a specific scenario in more detail?

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

8 participants