tl;dr You can, but it's a pain and throws away most of the value of Git.
I'm going to guess you're making a private repository public and there's some things in there you'd rather not have the world see. Passwords, trade secrets, swearing at customers, etc... Instead of throwing out your history before publishing, rewrite your history to make it safe to publish. Use git filter-branch
and git rebase -i
to selectively rewrite history and the BFG Repo Cleaner to remove files en masse.
Then you can publish your freshly scrubbed, less embarrassing repository.
I think you want two repositories like this.
A - B - C - D - E - F - G [master]
Q - E - F - G [master]
Where A - B - C - D
is the unsquashed history, Q
is the squashed commit, and E - F - G
are commits going forward.
The best you can get is this.
A - B - C - D - E - F - G [master]
Q - E1 - F1 - G1 [master]
Where E1 - F1 - G1
are the same content as E - F - G
but they have different commit IDs. Very different commit IDs. Totally unrelated commit IDs. It's messy and it throws away all the power of Git.
A Git commit is the content of that commit plus all previous commits. The commit ID is a checksum of all the content of the commit, things like the date, author, and log message, and the commit ID of the parent commit(s). If you change the repository by squashing, you change the commit ID and you change the commit ID of every commit that goes on top of it. If you change the commit ID Git won't consider them to be the same commits anymore.
To accomplish what you want, you have to essentially replace each commit after the squash as if it were a fresh commit on top of your new repository. git cherry-pick
will do this. These commits will get fresh commit IDs, so Git won't recognize them as the same commits. You'll have to manually manage the last time you did a cherry pick.
For example, you'd have the original repository set up as a remote of the squashed repository and a tag to track the sync point.
[sync]
A - B - C - D [origin/master]
Q [master]
Periodically you'd git fetch
to get updates.
[sync]
A - B - C - D - E - F [origin/master]
Q [master]
Then you'd cherry pick from the sync point.
git cherry-pick sync..origin/master
[sync]
A - B - C - D - E - F [origin/master]
Q - E1 - F1 [master]
And update the sync point.
[sync]
A - B - C - D - E - F [origin/master]
Q - E1 - F1 [master]
Branches will be interesting to deal with. It's possible you can use git rebase
instead which can deal with branches.