In a git repository, I have a single file with a large commit I want to divide into multiple commits. I am trying to follow the instructions at this answer but I have run into a problem. git status
shows that file.js is untracked, but git add -p file.js
responds "No changes."
I made a github reposiotry to illustrate exactly what I mean.
In this specific repository, I want divide commit 92cc4839abe2bfe54981d8227c17acf07c24c84b into several commits, each adding one function to file.js. However, the only helpful instructions I have found fail.
How to reproduce:
git clone https://github.com/jgibbons94/rebase-error.git
cd rebase-error/
git rebase -i HEAD~2
and mark commit 92cc483 to edit. Keep everything else the same.git reset HEAD~
git status
lists file.js is not tracked.git diff file.js
shows no changes.git add -p file.js
responds "No changes."Is this a known issue with a known workaround? Am I misunderstanding something? All help will be appreciated.
The problem is here:
- git reset HEAD~
- git status lists file.js is not tracked.
Commit 92cc483
added the file, so when you did a git reset
to back out the copy of 92cc483
, this removed the file from Git's index.
Reminder: the index or staging area (two terms for the same thing) holds a copy of each file that will go into the next commit. It's initially a copy of the current commit. So git reset HEAD~1
(or anything equivalent) means take everything that's in the index out, and put in, instead, everything that's in HEAD~1
. The file file.js
isn't in that previous commit, so now it is not in the index either.
The git add -p
command needs to have something in the index to patch against. An empty file in the index suffices, and git add -N
creates such an entry, so:
git add -N file.js
will let you run git add -p file.js
.
This isn't really all that useful because the entirety of file.js
will now show up as the patch. You might as well open file.js
in your editor, snip most of it out, write that back, and then—while the editor is still open—run git add file.js
and then undo the snip-away part so that you have the whole thing. You now have, in the index, the copy of file.js
that you'd like to have:
$ vi file.js # open file.js in editor
[snip]
:w
^Z # suspend editor - or, open another window to run git add
$ git add file.js
$ fg # resume editor
[undo snippage]
:x # write and exit
The result of all of this is:
$ git status
interactive rebase in progress; onto 85aa6aa
Last command done (1 command done):
edit 92cc483 A really big commit
Next command to do (1 remaining command):
pick 3891479 Add description.txt
(use "git rebase --edit-todo" to view and edit)
You are currently splitting a commit while rebasing branch 'master' on '85aa6aa'.
(Once your working directory is clean, run "git rebase --continue")
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: file.js
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: file.js
I can now git commit
, resume my editor, snip (less this time), write, suspend, git add
, git commit
, resume editor and undo snippage, etc., until I've made all the commits for each function. There's no need to bother with the clunky git add -p
.