Say I have a Git repo set up like this:
$ git init test && cd test
$ touch a && git add . && git commit -m "add a"
$ touch b && git add . && git commit -m "add b"
$ touch c && git add . && git commit -m "add c"
$
$ git --no-pager log --pretty="%h %s" # print short SHA and message subject
176d6d0 add c
495991e add b
1d8444a add a
Now for some reasons, I want to squash the most recent 2 commits (176d6d0 add c
and 495991e add b
) into one [1]:
$ git reset --soft 1d8444a # go back to the first commit ("add a")
$ git add . && git commit -m "bc"
$
$ git --no-pager log --pretty="%h %s"
c01e64a bc
1d8444a add a
Yeah, it looks we are done!
Not quite!
If we look at git reflog show
, the old commits are still around:
$ git --no-pager reflog show
c01e64a (HEAD -> master) HEAD@{0}: commit: bc
1d8444a HEAD@{1}: reset: moving to 1d8444a9747bd5e4176c
176d6d0 HEAD@{2}: commit: add c # old commit
495991e HEAD@{3}: commit: add b # old commit
1d8444a HEAD@{4}: commit (initial): add a
If we checkout an old commit, we can still restore it.
$ git --no-pager show -s 176d6d0 # this is the "add c" commit
commit 176d6d0aa92b230f4dd1e4ed8ae028b7c5fbb2d5
Author: XXX <XXX@XXX.com>
Date: Tue Oct 22 22:19:23 2019 -0400
add c
$ git checkout 176d6d0
Note: checking out '176d6d0'.
You are in 'detached HEAD' state. You can look around
... # omitted
HEAD is now at 176d6d0 add c
I tried to delete these stale old commits, but none of these works, the old commits are still visible in git reflog show
and git checkout
-able:
git gc
git gc --prune=all
git reflog expire --all
git reflog expire --expire=now
git reflog expire --expire-unreachable=now
git reflog expire --expire=now --all # tricky, see update below
Questions:
- How should I really discard the old commits (
176d6d0 add c
and495991e add b
)? - What's the jargon for these old commits (
176d6d0 add c
and495991e add b
), e.g. are they really "unreachable commits", "stale commits"?
What's the jargon of the act that removes them, e.g. is it "prune", "garbage collection"? - People do
git reset
orgit rebase -i
all the time. If they don't somehow remove these stale old commits, will they get a bloating Git repo, especially for LARGE projects with lots of collaborators (like Chromium)? - (nice to have) Please explain why your answer to 1 works.
footnotes:
[1] I could use git rebase -i
but I want to do it programmatically instead of interactively so that it can be automated by a script, but that's beside the point)
[2] this answer does not quite answer my questions
Update:
This removes all entries showed by
git reflog show
, but I don't quite understand why from reading the docs.. and other questions remain (plz see above)git reflog expire --expire=now --all
However, old commits, though not shown in
git reflog show
, are stillgit checkout
-able if you remember the SHA, that means these old commits are not really deleted!!So this is not the answer.