Multiple indices / staging areas

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,
I am thinking about extending the current index mechanism, and I wish
to ask for feedback if this would be something that you would be
interested in. Please note, I have no prior git development
experience.

The main idea is to mirror the "changelist" functionality found in
IntelliJ IDE's (https://www.jetbrains.com/help/idea/managing-changelists.html).
Namely, at each given moment you can create a "changelist"/separate
index to which you can move hunks to. Such changelists are named, and
optionally have a (default) commit message.
This allows for an easy way to split current changes into separate
commits, to have clean and atomic work units committed; while seeing
the combined changes in the worktree; as well as having a
conceptual/logical separation for changes

Scenario: I am introducing a new functionality. Changes are
conceptually separate, but work together. i.e. new version of package
& using the new functionality from the package.
Scenario 2: I am not yet sure about what needs to be done, so I am
sketching in code. Some changes will be of linting nature, some will
introduce code, some will be an "ad-hoc fix".

What we can do with the current flow:
* Commit/amend/fixup. This works best when one has prior knowledge of
what needs to be done, i.e. bumping versions then using the
functionality. Problems arise when the code is "living", as such you
need to fixup commits in the local branch, which can lead to
conflicts. Another issue is that if you wish to commit small change
(i.e. a fix for a linter) you need to juggle the staging area. (This
is my current flow in the vanilla git. It can become clunky if you,
like me, sketch the solution in the code)
* git worktree. While this functionality is the closest to what I am
proposing, it does not allow for easy transfer of hunks, nor it allows
for working with all the changes in the same worktree at the same
time.
* branches. This again does not allow us to see all the changes at the
same time.

The idea for the implementation would be as follows, and should
hopefully introduce no change to the existing flow.

1) Design

1.1) New indices file
We add a new file in the $GIT_DIR, called `indices`. This is a map
file that will MUST have at least one entry. Index entry MUST have a
name. Index entries COULD have default commit message
Example:
```.git/indices
selected=1 # maps to .git/index.1
#  translates to .git/index.0
index[0].name=Default
#  translates to .git/index.1
index[1].name=Add named index
#  translates to .git/index.2
index[2].name=Wip
index[2].message=Add named index\n\nThis is a longer description
```
The "selected" index is in two places - one is `index` and the other
is based on the selected entry; so following example, `index.1`. The
best way to keep them synced would be to symlink them, though this
would introduce FS dependency. Synchronized copy would work as well.
Renames could work, but there would be IMO high risk of losing changes
from the index due to a mistake.

This way, the existing index file format remains unchanged; and all
new functionality can be handled via the new `indices` file; due to
that all existing code should work without an issue.
I see a potential problem of two indices overlapping (i.e. index
changed via older git, or other tool) - in this case I would
transparently correct other indices, treating selected index as the
source of truth. This would imply that software not aware of the
indices would see the changes in the not-selected index as unstaged.
The second issue is the split index, as I know nothing about it, yet
it might require changes.

1.2) Commands
A git index create <name> [-m|--message <message>]
A git index delete <name>
A git index switch <name>
A git index update <name> [-m|--message <message>] [-n|--name <new name>]
M git add [-I|--index <index name>]
M git diff [-I|--index <index name>]

2) Example workflows
2.1) Working with indices/non interactive add
git index create "wip" --message="This is a default commit message" #
We have a new index, but the default one is selected
touch {example|example2|example3}
git add example # Added to the "current"/"default" index, by default 0
git index switch "wip"
git add example2 # Added to the "wip"/ index, with id of 1
git add example3 --index=default # Added to the "current"/"default" index,
git commit # commit message="This is a default commit message"
# At this point, index.1 (wip) is empty, but selected. We can commit
another index
git commit --index=default -m "This is a commit message for the default index"

2.2) Status
> git status
On branch main
Selected index: wip
Changes to be committed (wip):
  (use "git restore --staged <file>..." to unstage)
        modified:   example

Changes staged for commit (default)
  (use "git restore --index=default --staged <file>..." to unstage)
        modified:   example

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   example

2.3) Git add (interactive)
> git add --interactive # details omitted for brevity
-Example change
+Example change 2
(1/1) Stage this hunk to wip [y,n,q,a,d,e,i,?]?
> ?
i - change the current index

2.4) Remove index
> git index remove # removes current, all staged goes to the "default" branch/index 0
> git index remove wip # removes wip, all staged goes to the default branch/index 0
> git index switch default
> git index remove # Does nothing...
> git index rename default "WIP" # index[0].name=WIP
> git index remove # renames default -> index[0].name=Default
...

I am open for the feedback/questions, or early go/nogo.

Jacek Lipiec




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux