Reputation: 900
Though there are several topics covering similar question, I can't seem to get this solved with what should possibly be solved with Git rebase
.
I have a pretty big Git repo, and I want to cut off a major part of commit history. Current state of commit graph is like this:
(huge tree of various branching and merging) -> commit_I_want_to_squash_to -> branching off into master and couple of feature branches
My desired result would be:
commit_I_want_to_squash_to_is_first_in_tree -> branching off into master and couple of feature branches
I imagine this should be possible somehow as all current branches use single commit as point of origin. I tried playing with git rebase --squash
, but seems it's a pretty big task to squash 300+ branched history. There should somehow be an option to just "slice" the commit tree just before the commit I want to make as first..
Upvotes: 2
Views: 247
Reputation: 31437
So essentially what you want to do is to cut off the history earlier than a certain commit. In Git terms, this means that you want to rewrite that commit from having a parent to having no parent (being the start commit of a new history).
This can be done using git filter-branch, something like this:
git filter-branch \
--parent-filter 'test $GIT_COMMIT = <initial-commit-id> && echo "" || cat' \
--tag-name-filter cat -- --all
Another option is to use the grafts functionality as follows. Note that you can inspect the resulting history after the first command using git log
or a graphical viewer to verify that the desired result is correct:
echo "<initial-commit-id> " >> info/grafts # .git/info/grafts in non-bare repo
git filter-branch --tag-name-filter cat -- --all
Be sure to execute the above commands in a new bare repo cloned with --mirror
. That makes it easier to push all the updated branches and tags.
Old tags/branches that did not include the above initial-commit-id
will still point to the old history. You will have to delete them to really get rid of the old history. You should be able to find them using git branch --contains <previous-initial-commit-id>
and git tag --contains <previous-initial-commit-id>
. <previous-initial-commit-id>
is the ID of the previous "initial commit", which the rewritten history no longer references.
After doing all the above, see Checklist for Shrinking a Repository for how to completely get rid of the old history.
Upvotes: 4
Reputation: 6854
depending on your repo it might be feasible to start a new repo, copy the files from the "new initial commit" there and make it a new commit. then add the existing repo as a remote and cherrypick all the later commits into your new repo. if you have linear history after the "new initial commit" this should work rather smoothly.
maybe rebasing the commits (instead of cherrypicking) would work alright with more complicated layouts, but i don't do it a lot, so i don't want to make a recommendation here.
Upvotes: 0
Reputation: 7484
If I had to do it, I would just write:
git rebase -i <initialCommitOfTheTree>
Squash all commits as you'd like. Yes, this is very hard working if you have to edit 300 lines, but you can just put quickly parse this on vim or another text editor, and replace all the beginning of the lines you want to change by a s
.
Like @mnagel said, you should have a very good reason for this though.
Cheers.
Vitor.
Upvotes: 0