With the Commit tool window in IntelliJ, you can do partial git commits, meaning you can commit only some files with changes, or even certain certain chunks of changes within changed files. I'm familiar with git's interactive adding and patching abilities, but those commands add changes to the index, after which issuing a commit will commit the whole index, not just the result of the patch. IntelliJ, however, seems like it can somehow do the patch but also only commit just the selected changes, ignoring other changes that may be in the git index, and I'd love to know what set of git CL commands can produce an equivalent behavior. Maybe something like stashing the index, unstashing the selected file(s), doing the patch, commit, and then unstashing the rest of the stash? Is there an easier way to accomplish this?
CodePudding user response:
Every Git commit is a full snapshot of all files (plus metadata). That means that for IntelliJ to make a Git commit, it must make a full snapshot—so it must do the same thing that git add -p
does.
You can, however, create a temporary index, in addition to the standard index that Git assigns to your working tree. Note that git worktree add
actually adds both a working tree and a new index for that working tree. There is also a private HEAD
for the added working tree, and some per-worktree refs for bisection and so on; the details get a bit complicated. But overall each working tree has one distinguished index–"the" index—and that's the one that git commit
will use by default.
To make a temporary index, you would:
Create a temporary index file (well, file-name in most cases, but you can copy "the" index for the working tree to this file; you just can't have an empty file as Git rejects that, so if you use
mktemp
from a shell script, you have to either remove the file, or copy the regular index to it).Populate that temporary index as desired: set the environment variable
GIT_INDEX_FILE
to hold that file's name while usinggit reset
and/orgit restore
and/orgit add
and so on, to adjust this temporary index's content. (Note that you must not dilly-dally too much here: changes made in this temporary index might be wrecked by agit gc
if you do not complete everything within 14 days. That's generally true for all tricky Git hackery, such as usinggit write-tree
andgit commit-tree
.)Use
git commit
with this sameGIT_INDEX_FILE
setting, to make a new commit from the temporary index, rather than from the real index.Do something about the real index: it's now badly out of sync with the current commit.
The real hard part here is step 4. You must figure out what to do, how to do it, and how to roll it back in case of a disaster such as the disk drive running out of disk space.
The git commit
command itself has --only
and --include
options that do steps 1 through 4 internally during the git commit
action. For instance, you can run:
git add file1.ext file2.ext
# edit file3, realize you want to commit *just* the file3 changes
git commit --only file3
# go back to working with files 1, 2, adn 3
This sometimes involves just the two index files—the real one and a temporary one—and sometimes, to handle the complications mentioned above for step 4, involves making three index files. Once the git commit
action is finished (with or without error), one of the two or three index files becomes the "real" index file for this work-tree.
What IntelliJ does internally, I have no idea, but the above covers the visible-to-Git parts of what must be done.