2

I am trying to find out how to squash commits in Git from a range of commits. My specific situation is that I forked a repository and added several commits of work on top of it; however I'd like to squash all of the forked repo's commits to a single commit to keep the history clean.

Example

7e8d7f7 - (HEAD) My commit
809fc8b - My commit
e04692c - Forked repo's commit          \
2674323 - Forked repo's commit           > Turn these into a single commit
4e79731 - Forked repo's initial commit  /

Here's something I've tried

  1. Get the SHA for the initial commit via git rev-list --max-parents=0 HEAD for the lower bound of the range I want to squash (Source)
  2. Detach the HEAD to the upper bound of the range via git checkout <upper bound commit>
  3. Soft reset to the lower bound and commit (alternative to git rebase -i): git reset --soft <lower bound commit> && git commit (Source)
  4. Merge into master: git merge --no-ff master

I end up getting tons of merge conflicts this way. I feel that what I'm trying to achieve is possible with the commands I've encountered, but I'm at a loss at how to string them together to make it work.

Community
  • 1
  • 1
danyim
  • 1,274
  • 10
  • 27
  • This sounds like a particularly unwise solution. Did you try just copy-and-pasting the code and creating a new git repository there? Because it has the same effect. – Unapiedra Mar 24 '17 at 00:02
  • Please explain why you want to do this? It is absolutely clear that you would get merge conflicts. If you change previous commits, then you are creating a completely new repository. All the answers provided will give you merge conflicts. What is your inherent motivation to want "to keep the history clean"? – Unapiedra Mar 24 '17 at 00:29
  • @Unapiedra I forked a boilerplate project and made some work on top of it, but instead of deleting the `.git` folder before starting my work, I kept committing to the forked repo. Yes, I understand everyone's concerns here; please do not attempt this unless you know what you're doing. – danyim Mar 24 '17 at 22:31

2 Answers2

4

First of all, I would avoid doing this.

Git history is a beautiful thing and future users of you repo might want to know the exact point where you forked.

Or you may want to pull additional commits from the remote at a later time, and that will probably be easier if you don't go out of your way to mess up the shared history.

That said, this should work for you:

git checkout e04692c -b squashing_branch

git reset --soft $(git rev-list --max-parents=0 HEAD)
git commit --amend -m "Forked repo as one big commit"

git cherry-pick e04692c..master
Harald Nordgren
  • 11,693
  • 6
  • 41
  • 65
0
  1. Do not do this.
  2. You can just create a new repository. Because that is exactly the same as squashing all the commits before you are starting work. # Get the original git repository somehow $ git clone URL # Delete the old repo $ cd your-repo; rm -rf .git/ $ git init # create new repo. $ git add -a $ git commit -m 'Forked repo from X and squashed all commits' # Now start working. # Again, I think this whole undertaking is misguided.
  3. You create a new commit with no parent as the "squashed" commit. Let's assume that the real history is on a branch called "long_history".

    git checkout master  # assuming on master is the complete history.
    # Create a new branch without any history. A new root so to speak.
    git checkout --orphan squashed_master 
    # All the files from the original 'master' will be already added
    # to the index. 
    git commit -m 'Squashed all of the previous history as cloned from X'.
    # Delete the master branch and create it again
    git branch -D master
    git branch master
    git push --force -u origin master  # Assuming that 'origin' is the remote of your fork and not the original repository. Change accordingly...
    
  4. I still think that you should not do this.

Final note: I thought that subtree might be an option. I tried to use git subtree but that did not work with --prefix=..

Unapiedra
  • 15,037
  • 12
  • 64
  • 93