git rebase -i -- why is it changing commit hashes?
From the rebase doc:
The commits that were previously saved into the temporary area are then reapplied to the current branch, one by one, in order.
When the commits are "reapplied" it's really creating a brand new commit...it's content may be the same, but it will have a different timestamp which is part of how it's SHA is generated...thus the new commits will have a new SHA's.
You can read more about how SHA's are calculated here.
this will modify the hashes of all 20 commits, even if the only action I take is to squash the last two.
If by "the last two" you mean the most recent two commits in the history, then no, it won't.
Please be concrete, show the actual evidence you're looking at, the todo list you got and the one you executed. Characterizations are far too unreliablevulnerable to unshared context.
Here for instance is what happens when I squash the last two commits, as I understand it:
$ git log --oneline --reverse @{u}..
00f53a2 echo >master6
afcef3e echo >master7
1f55c48 echo >master8
c3197a0 echo >master9
d30bb35 (HEAD -> master) echo >master10
$ GIT_SEQUENCE_EDITOR='sed -i 5s/pick/squash/' git rebase -i
[detached HEAD 16dc80d] echo >master9
Date: Mon Feb 5 09:25:55 2018 -0800
2 files changed, 2 insertions(+)
create mode 100644 master10
create mode 100644 master9
Successfully rebased and updated refs/heads/master.
$ git log --oneline --reverse @{u}..
00f53a2 echo >master6
afcef3e echo >master7
1f55c48 echo >master8
16dc80d (HEAD -> master) echo >master9
$
you can see that the last two commits have been squashed together, the id's of all the commits whose history hasn't changed are left untouched.
You may feel that you didn't change some commits, but you actually changed them in several ways:
Each commit contains the sha1 of its parents. So, changing the sha1 of a parent modifies the commit, hence its sha1. The hashes are chained, changing anything in the past changes the future. Technically, this is called a Merkle tree. This is an important property of Git, because given a sha1 it guarantees not only the integrity of the current commit but also of the whole history leading to it (assuming you can't find a collision in sha1, which is no longer really the case today, but collisions are still very hard to find).
Each commit contains a snapshot of the current state of your project. Hence, even if a commit seems identical because it introduces the same diff, it may not correspond to the same state of the project (to the same tree object).
As already noted, commits contain timestamps (one timestamp for the author, one for the commiter, the second one being changed when you rebase).