Reputation: 5207
Is there a way to 'remove' all commits prior to a specific commit all the way to the root commit?
I figured git filter-repo
does this kind of stuff?
Although I wasn't sure if it will work when root commit is involved.
My situation is like this:
I got a copy of a repo where I started working in but ended up doing something quite different that the new files have no relation to what I started with.
Unwanted commits Desired commits
+-------------------+ +-----------------------+
| | | |
O1 -> O2 -> ... -> On -> N1 -> N2 -> N3 -> ... -> Nm
where On
commits are the old commits that I wish to get rid of and
Nm
commits are the ones I wish to keep.
This is what I wish to make it:
Desired commits
+-----------------------+
| |
N1 -> N2 -> N3 -> ... -> Nm
where N1
would become root instead of `O1.
I want to keep the git history of only the N
commits.
Is there a way to do this?
Previously, I tried to ask git filter-repo
to keep the commits of only the desired set of files with this:
(Saw that in the example section of the manual. https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html#_path_based_filtering)
git filter-repo --path file1 --path file2 --path dir/
But that removed the files that I wanted and the git log became kind of empty. I guess I misunderstood something.
Upvotes: 1
Views: 410
Reputation: 28869
First off, note that matt's answer solves your ask without using git-filter-repo
. That is a good answer if you don't have many commits to rewrite (simply because rebasing is relatively slow compared to git-filter-repo
), and if your history is linear, or you desire it to become linear, or if you wish to preserve merge commits and you didn't have historical conflicts.
A more general solution is to use a similar strategy as this answer:
git checkout --orphan new-main <commit-ID-of-N1>
# if you want the same commit message as N1:
git commit --reuse-message=<commit-ID-of-N1>
# if you want a different commit message:
git commit -m "New root commit"
N1
with the new commit:git replace <commit-ID-of-N1> @
git-filter-repo
:git filter-repo --replace-refs update-or-add --force
The advantages of this method are that it's extremely fast (even if you have hundreds of thousands of commits), and it isn't possible to have merge conflicts because you aren't changing the graph of the portion of history you're keeping.
Upvotes: 2
Reputation: 534893
Suppose we have this history for my main branch main
:
bf89ae6 (HEAD -> main) f
de493f8 e
87f0019 d
45ddf08 c
e26add9 b
a01bc2c a
And let's say I want to cut off all of the history before "d" (i.e. 87f0019
). Then I say:
git checkout --orphan temp 87f0019
git commit -m 'a fresh start'
git rebase --onto temp 87f0019 main
Result:
5e6216c (HEAD -> main) f
e0c4157 e
cfbac28 (temp) a fresh start
Okay, those are entirely new commits, but when you're changing history, that's inevitable. Also, note that the first commit contains all the work up to that point; it has basically been squashed into a single initial commit. That might or might not be what you want.
Upvotes: 3