lazygit icon indicating copy to clipboard operation
lazygit copied to clipboard

Does lazygit have features similar to IDEA changeList?

Open awaken233 opened this issue 2 years ago • 20 comments

Topic A clear and concise description of what you want to discuss image

Your thoughts What you have to say about the topic I hope I can only commit all the files in the specified changeList when I commit it.

awaken233 avatar Aug 09 '23 08:08 awaken233

+1 on this feature!

Primarily, I use this feature in IntelliJ to separate things that I want to commit and things that I need to keep on local.

https://www.jetbrains.com/help/idea/managing-changelists.html

I'm open to other people's workflow as well if they solve this in some way with lazygit's current featureset. I tried to replicate this functionality with stashes (apply stash and apply reverse stash, details here), but it is not good ux.

@stefanhaller, any thoughts on this?

I'm open to contributing as well.

njkevlani avatar Oct 10 '25 06:10 njkevlani

My feeling is that lazygit doesn't need this feature because it makes it so easy to amend commits. It seems to me that IntelliJ is adding a feature on top of git that allows you to group uncommitted changes into change sets; but really, that's what commits are for. Instead of doing the work of assigning your changes to changeLists, simply commit them (yes, even if unfinished), as multiple commits; treat those as your changeLists. Then, when you want to add more changes to one of your "changeLists", select the corresponding commit and hit shift-A.

What's missing?

stefanhaller avatar Oct 11 '25 07:10 stefanhaller

@stefanhaller Let me explain my scenario, I have some local changes (personal configurations) that I don't want to commit directly to git, I create an IDEA changelist called ignore, IDEA includes a change list called Changes by default, so that I can commit all the changes in the change list in IDEA by default.

But with lazygit I can't do that, I need to manually Stage, and find out which files don't need to be committed, and then commit them together.

awaken233 avatar Oct 11 '25 07:10 awaken233

Can you explain more what those "personal configurations" are? It sounds to me that those shouldn't be under version control in the first place?

stefanhaller avatar Oct 11 '25 07:10 stefanhaller

e.g.: bootstrap.yml register-enabled: false

Image

I don't want to register it with the development environment for local debugging, so I'll add it manually.

awaken233 avatar Oct 11 '25 08:10 awaken233

I see. You might look into git update-index --skip-worktree for solving this, independent of whether your git client is lazygit or the command line or some other client.

See https://www.brandonpugh.com/til/git/skip-worktree-ignore-modified-files/ for a good summary.

stefanhaller avatar Oct 11 '25 08:10 stefanhaller

In a non-IDEA environment, this is exactly the solution I use, but it requires manually typing commands, which is not as convenient as the shortcut commands integrated with lazygit, and manually viewing or managing which files need to be ignored locally is cumbersome.

I don't know what other people's usage scenarios are, for me it would be better with this feature, but I'm fine without it.

awaken233 avatar Oct 11 '25 08:10 awaken233

but it requires manually typing commands, which is not as convenient as the shortcut commands integrated with lazygit,

Have you tried using custom commands for that?

mark2185 avatar Oct 11 '25 08:10 mark2185

Sounds good , I can use a custom command in [2]Files to ignore specific files, but awkwardly I don't seem to have a place to use a custom command to un-ignore them

awaken233 avatar Oct 11 '25 08:10 awaken233

I don't seem to have a place to use a custom command to un-ignore them

This can help:

customCommands:
  - key: i
    context: files
    description: "Ignore file from worktree"
    prompts:
      - type: 'confirm'
        title: 'Confirmation'
        body: 'Do you want to ignore {{ .SelectedFile.Name }} from worktree?'
    command: git update-index --skip-worktree {{ .SelectedFile.Name }}

  - key: I
    context: files
    description: "Reconsider file for worktree"
    prompts:
      - type: 'menuFromCommand'
        title: 'Choose File to reconsider'
        key: 'FileToReconsider'
        command: bash -c "git ls-files -v | grep ^S"
        filter: S (?P<fileToReconsider>.*)
        valueFormat: '{{ .fileToReconsider }}'
    command: 'git update-index --no-skip-worktree {{ .Form.FileToReconsider }}'

Will use it for sometime and see how it works out for me.

Thanks folks for suggesting git update-index --skip-worktree!

njkevlani avatar Oct 11 '25 09:10 njkevlani

@njkevlani Thank you so much for sharing this configuration! It works perfectly for my workflow and solves exactly what I needed.

However, I noticed that the i key conflicts with lazygit's built-in keybinding in the Files view (used for "Ignore or exclude file" - adding to .gitignore). To avoid this conflict, I modified the keybindings to use t and T instead:

customCommands:
  - key: t
    context: files
    description: "Skip worktree - untrack file temporarily"
    prompts:
      - type: 'confirm'
        title: 'Confirmation'
        body: 'Do you want to skip worktree (untrack) {{ .SelectedFile.Name }}?'
    command: git update-index --skip-worktree {{ .SelectedFile.Name }}

  - key: T
    context: files
    description: "No-skip worktree - restore file tracking"
    prompts:
      - type: 'menuFromCommand'
        title: 'Choose File to restore tracking'
        key: 'FileToReconsider'
        command: bash -c "git ls-files -v | grep ^S"
        filter: S (?P<fileToReconsider>.*)
        valueFormat: '{{ .fileToReconsider }}'
    command: 'git update-index --no-skip-worktree {{ .Form.FileToReconsider }}'

Using t/T (as in "track"/"untrack") feels intuitive and avoids any conflicts. I'll be using this setup for a while to see how it works in practice.

Hope this helps others who might face the same issue! Again, thanks for the excellent solution! 🙌

awaken233 avatar Oct 11 '25 14:10 awaken233

This is really nice, great work coming up with this!

Now that I see this working so well, I do wonder if it should be a builtin feature. 😄 This would allow us to handle some of the awkward edge cases a little better (e.g. the ugly error message that you get when invoking t with a directory selected, or the error you get when invoking T when no files are hidden).

I'd probably call it Hide/Unhide (with tooltips explaining what this means exactly), and use h/H as keybindings. I find "untrack" to be a bit misleading here.

stefanhaller avatar Oct 11 '25 16:10 stefanhaller

@stefanhaller Thank you for the thoughtful feedback! I'm glad you found this useful.

You're absolutely right about the edge cases. I just tested both scenarios:

  • Invoking t on a directory does show an ugly error message
  • Invoking T when no files are hidden also produces an error

These are indeed awkward, and having this as a built-in feature with proper error handling would be much better! 👍

Regarding the keybindings, I agree that Hide/Unhide is more intuitive than track/untrack. However, I noticed that h is already used as a global keybinding for "navigate panel" (moving focus left between panels). Perhaps H/Shift+H could work, or maybe a different key combination altogether?

What do you think would be a good alternative keybinding that doesn't conflict with existing ones?

awaken233 avatar Oct 11 '25 16:10 awaken233

However, I noticed that h is already used as a global keybinding for "navigate panel"

Ah, I missed that, never use it myself. And it doesn't show up in the keybindings menu, I wonder if that's intentional.

Perhaps H/Shift+H could work,

Erm, H and Shift+H are the same. 😄

I don't know, maybe we go with t/T then after all. It wouldn't be the first time that the keybinding has nothing to do with the command name (like g for "reset").

Another option we could consider is to not waste two keybindings, but only one. We could have a "Hide/unhide" command, bound to shift-H, and it would show a menu with two entries, "Hide" and "Unhide". Maybe not the greatest UX, just a measure to not pollute the global command space with too many fine-grained commands.

Anyone got a better suggestion?

stefanhaller avatar Oct 11 '25 16:10 stefanhaller

Will shift+h work as a keybinding? I think it has the same "issue" as shift+l, i.e. it's scrolling the current panel horizontally.

mark2185 avatar Oct 11 '25 16:10 mark2185

Oh right, I forgot about that, too. :-/

stefanhaller avatar Oct 11 '25 17:10 stefanhaller

Another option we could consider is to not waste two keybindings, but only one. We could have a "Hide/unhide" command, bound to shift-H, and it would show a menu with two entries, "Hide" and "Unhide". Maybe not the greatest UX, just a measure to not pollute the global command space with too many fine-grained commands.

I think the single-key menu approach makes sense! Since this is a relatively low-frequency operation, the extra menu step is totally acceptable, especially considering the benefit of not cluttering the global command space.

awaken233 avatar Oct 11 '25 17:10 awaken233

This would allow us to handle some of the awkward edge cases a little better (e.g. the ugly error message that you get when invoking t with a directory selected, or the error you get when invoking T when no files are hidden).

There are a couple of UX ideas that I could think of.

Having these commands behind conditions

We can put these commands behind conditions and handle failure cases.

It will look something like this:

Image

In this solution, I have put the prompt message and command behind condition based on SelectedFile's availability.

Con that I could think of: a bit hacky.

Baking this as a built in feature

As a operation in files area, a natural expectation for skipping files from worktree would be that all the file under current path should be skipped from worktree (same way in which space stages all the files under current path).

That solves the issue that we faced when skipping files.


Now coming to no-skipping/reconsidering (for lake of better words) files for worktree, I see a good option is to have another subarea in Files area (next to Worktree, Submodule, etc) named Skipped Files. That section can have the files which currently skipped from worktree.

Cherry on the cake can be - we can use the same key for performing both the actions for skipping and no-skipping depending on the section we are in (files or Skipped Files)

Con that I could think of: It will confuse users when they skip files by mistake.

njkevlani avatar Oct 11 '25 17:10 njkevlani

I see a good option is to have another subarea in Files area (next to Worktree, Submodule, etc) named Skipped Files.

I'm reluctant to add this, since it would then take a pretty prominent place in the UI for something that (I would assume) only very few users need.

However, I could imagine an entry in the Filtering dialog (ctrl-b) for hidden files.

stefanhaller avatar Oct 11 '25 18:10 stefanhaller

I would also really like this feature native in lazygit since I too often use the "ignore some changes to that otherwise tracked file" with IDEA. And not having a "clean" staging area where I can just stage all the changes with a single keypress but have to watch out to not commit those things gets annoying quick and increases the risk of accidentally committing something I did not want.

The t/T bindings from @njkevlani and @awaken233 (thanks you two!) do help with that (although I had do wrap the file name in the cmd with " otherwise it sometimes errors out), but a more robust solution would be welcome!

As was stated before this could hopefully lead to better error handling and maybe even support to ignore entire folders or even new (i.e. untracked by git) files like local scratch files without needing to extend the .gitignore with entries noone else cares about.

Just wanted to throw my hat in the ring as another user that likes this niche workflow :D

OliverWich avatar Dec 10 '25 12:12 OliverWich