jesseduffield / lazygit

simple terminal UI for git commands
MIT License
51.51k stars 1.8k forks source link

Branch-sensitive commits traversal #3575

Open liontiger23 opened 4 months ago

liontiger23 commented 4 months ago

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

When viewing repository with a lot of merges to the main branch (e.g. when all feature PRs are merged without fast-forwarding), it is annoying to have to try to visually find previous/next merge commit (or next normal commit) in this particular branch, especially if there are long running feature branches with many commits being merged. Iterating with <down>/<up> keybindings does not help much, because there is no control over which commit will go next -- it will jump from one sub-branch to the other, when I might want to go through commits of one particular branch without checking it out.

Describe the solution you'd like

Ideally, there would be keybindings like <a-down>/<a-up> (<a-j>/<a-k>) to traverse graph view in commits window, which will select previous/next commit in given branch and "skipping" merge commits by following only the first parent (like git log --first-parent) when going back in history. When going forward in history the behavior should be similar -- as if we were going upwards in git log --first-parent.

These keybindings are supported in Sublime Merge, and you can use them starting from any commit on any branch, although I am not sure how they resolve going forwards in history -- which commit to choose if there are many choices. But if we traversed backwards in history, the traversal upwards from that point seems to follow the same path as it took to get there.

So in the following example, starting from commit h we should be able to traverse h -> g -> e -> c -> a using <a-down> and the other way starting from a -- a -> c -> e -> g -> h using <a-up>.

%%{init: { 'theme': 'base', 'gitGraph': {'rotateCommitLabel': false}} }%%
gitGraph
   commit id: "a"
   branch bar
   checkout bar
   commit id: "b"
   checkout main
   commit id: "c"
   branch foo
   checkout foo
   commit id: "d"
   checkout main
   merge bar id: "e"
   checkout foo
   commit id: "f"
   checkout main
   commit id: "g"
   merge foo id: "h"

Note that in Sublime Merge if we start from commit f and go backwards, the path will be f -> d -> c -> a, and if the we go forwards, it will do the same path in reverse -- a -> c -> d -> f. However, if starting from f we go forward to merge commit h, from there going backwards will follow main branch according to --first-parent rule -- h -> g -> e -> ....

Describe alternatives you've considered

  1. Filtering the whole displayed graph with --first-parent:
    git log --graph --first-parent

    However, I would still prefer to see all the intermediate commits in branches that I am skipping this way. Also it does not work with --all, so I won't be able to see other unrelated branches in the same view while filtering my branch with --first-parent.

  2. Supporting collapsing/expanding of merge commits, like in https://github.com/jesseduffield/lazygit/issues/2843#issuecomment-1837629329 This will mostly suffice when viewing single branch history, but with --all it still will be possible to traverse other branches' commits by going backwards/forwards in history. However, these to suggestions are not mutually exclusive, since Sublime Merge supports both better history traversal and collapsible merge commits.

Additional context

If some mechanism of such branch-sensitive traversal is implemented, it might be a good idea to support also "selection history" traversal (again like it is implemented in Sublime Merge), where <a-left>/<a-right> traverse through previously selected commits -- something like undo history for commit selection.

Kahitar commented 4 weeks ago

I would really love this feature... Would help a lot in huge monorepos with many devs working on it.