Modifying an older commit is more complicated than modifying the latest commit. This is because commits are interdependent; changing an ancestor will require changes to its descendants. The simple way to address this is just to create another commit. However, for this demo, an old commit will be modified. To do that, a rebase has to be performed.
The command below shows that we have two commits, and we want to modify the root/old commit 326a18c to add a new file.
$ git log --oneline
a33f5a3 modify notes
326a18c add notes and metadata
$ git log --stat
commit a33f5a327a0abf89b881a600ec7b88d7d48ff187
Author: <redacted>
Date: <redacted>
modify notes
notes | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
commit 326a18ccaf5f20f2bebbb62ccbe11da2a99b9686
Author: <redacted>
Date: <redacted>
add notes and metadata
metadata | 1 +
notes | 1 +
2 files changed, 2 insertions(+)
Since 326a18c is the root commit, git rebase -i HEAD~2 will not work. We need to include the root commit in the interactive rebase.
$ git rebase -i HEAD~2
fatal: invalid upstream 'HEAD~2'
$ git rebase -i --root
The command above should open an editor. Pick the root commit 326a18c and change pick to edit
pick 326a18c add notes and metadata
pick a33f5a3 modify notes
Changed version then exit the editor.
edit 326a18c add notes and metadata
pick a33f5a3 modify notes
The previous command outputs this. Now, you can perform the changes that you need to do.
Stopped at 326a18c... add notes and metadata
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
In this case, extra is added. Once done, do git rebase --continue.
$ git add extra
$ git commit --amend --no-edit
[detached HEAD 1d96512] add notes and metadata
Date: <redacted>
3 files changed, 3 insertions(+)
create mode 100644 extra
create mode 100644 metadata
create mode 100644 notes
$ git rebase --continue
Successfully rebased and updated refs/heads/main.
Not only did the root change from 326a18c to 1d96512, the former recent commit a33f5a3 became c168fa3. This is because since the parent/root commit hash changed, then the rest of the dependencies/descendants must adjust. Git replays the remaining commit, preserves the message and changes, and generates a new commit hash.
a33f5a3 modify notes
326a18c add notes and metadata
$ git log --oneline
c168fa3 modify notes
1d96512 add notes and metadata
$ git log --stat
commit c168fa314073bf654dea0785500b14596fd9be50
Author: <redacted>
Date: <redacted>
modify notes
notes | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
commit 1d96512da874be9b1827c2dccb2d336255667cdf
Author: <redacted>
Date: <redacted>
add notes and metadata
extra | 1 +
metadata | 1 +
notes | 1 +
3 files changed, 3 insertions(+)