jesseduffield / lazygit

simple terminal UI for git commands
MIT License
52.65k stars 1.84k forks source link

Stacked PRs in lazygit #2527

Open canadaduane opened 1 year ago

canadaduane commented 1 year ago

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).

stefanhaller commented 1 year ago

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 think 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 commented 1 year ago

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:

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

lettertwo commented 1 year ago

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 commented 2 months ago

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 commented 2 months ago

@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:

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

wederbrand commented 2 months ago

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 commented 2 months ago

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 commented 2 months ago

Excellent!

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