Reputation: 25641
After some years of git commits, we'd like to delete the very old ones.
We have a commit number that we want to consider as the new 'base'.
How can we ask git to remove all(and completely remove) the commits before the specified one?
Upvotes: 0
Views: 97
Reputation: 488183
You can use either git rebase -i
or git filter-branch
. Note first that git rebase
likes to remove merges, so if you are doing this in a complex repository with a lot of branch and merge history that you would like to preserve, this is the wrong tool; use git filter-branch
instead.
As Paŭlo Ebermann noted in a comment, any method that achieves the result you want will give you all new commit IDs. This is because the ID of a commit is, in a very real sense, the contents of that commit and its entire history. See Does a git commit hash equal a repository state? Git cannot change any existing commit(s), so instead, it must copy every commit in the repository—well, every commit you intend to preserve, anyway—to new commits that have different histories, specifically, a history going back to the new root commit (which is a copy of the original commit but with no parent).
The easiest way to do this is with a temporary git replace
or with grafts, followed by git filter-branch
which will make the replacement or graft permanent in the copies. Grafts are conceptually simpler but a bit manky (see meaning 2) in practice; use the cutoff graft only long enough to run the filter-branch operation and you will be fine. For instructions, which date all the way back to Git 1.7.x but still work, see How do I remove the old history from a git repository? After completing the git filter-branch
operation (which you should do on a temporary copy clone for safety; you might put this in an in-memory filesystem or on an SSD for speed as well), you must manually delete any tags or other external references that link to the old history.
Note a small bug in the answer there: rather than just git filter-branch -- --all
you probably want git filter-branch --tag-name-filter cat -- --all
. Also note that filtering strips signatures off signed tags (by design and security: the signature represents the signer's declaration that the tagged item is what it claims to be, and you've just changed it, by copying part but not all of it with your filter-branch
operation, so it's no longer the same as what the signer signed). See the git filter-branch
documentation for additional details and caveats.
Once the history looks the way you intend, and you are OK with the fact that all your commit IDs have changed and your signed tags are now unsigned—you can go make new signed tags whenever you like, redoing the signing of your own and signing others as yourself, or getting those others to sign anew, but for now you must deal with the lack of signatures—the simplest way to get a new, smaller repository is to clone the filtered repository, which will drop all the refs/original/
references that filter-branch
leaves behind.
Since Git's notes
refer to commits by ID, you will lose all your old notes too. As far as I know, there is no tool to copy them across a filter-branch operation. Right at the end of the filter-branch would be the place to do it since filter-branch still has the temporary mapping from old ID to new ID. Probably filter-branch needs a new capability, to call out to a notes copier (or do it on its own).
Upvotes: 3
Reputation: 18825
Create temporary branch from that commit and rebase against it:
git checkout --orphan temp commitId
git commit -m "Truncated history"
git rebase --onto temp commitId master
git branch -D temp
Where commitId
is the new base. Check the article for details.
Upvotes: 2