0

Here is my structure:

* - commit 2
|
* - commit 1
|
* - Merge commit (feature #1)
|\  
| * - Feature #1 commit 
|/
*

I messed up previously and now my history doesn't look as clean as I'd like.

I'd like to know if there is a simple way to squash 'commit 1' and 'commit 2' into 'Merge commit (feature #1)', so that I end up with something like this:

* - Merge commit (feature #1)
|\  
| * - Feature #1 commit 
|/
*

rebase -i doesn't seem to recognise the merge commit, and seems like it will squash everything into 'Feature #1 commit', which is not desirable.
Thanks

3
  • 2
    I have to question whether the result is desireable. Why would you want to have additional modifications in the merge commit that are not in the "Feature #1 commit"?
    – j6t
    Commented Nov 25, 2020 at 7:53
  • I agree with @j6t wholeheartedly. Why do you make efforts to build a lie for your future self (if not coworkers)? History will not reflect what really happened. You could have specific reasons, though. No judgement here, only trying to understand. Commented Nov 25, 2020 at 8:08
  • I do agree with you guys, it seems somewhat of a cover up. In this specific case I am the only one currently on the repo (busy preparing it for use for others) and just for my sake would like to have the history as clean as possible. The changes in the two commits are not significant or tied to any specific piece of work, so I just thought if it's not too complex I'd just squash them.
    – zing
    Commented Nov 25, 2020 at 8:25

1 Answer 1

3

Make sure that you do not have anything staged (git added). Then just do

git reset --soft HEAD~2       # go back across the two commits
git commit --amend            # squash into the merge commit

git reset --soft does not change what you have in the working directory nor what you have staged. Therefore, if you have git added content after you made "commit 2", then the git commit --amend would commit those staged content as well. For this reason, you have to make sure that you have nothing staged when you begin. git status should tell you whether that is the case.

7
  • extra stress on "make sure you have nothing staged" or in any form modified since commit#2. git stash or git checkout -- . before starting are an option worth considering before beginning the squash. Also, this is not a squash in the strict sense: you are rewriting history. Now, with a squash I am certain that the 3 "old" commits are preserved. With a git reset I am not so sure, ref Commented Nov 25, 2020 at 8:12
  • @DaemonPainter Of course, squashing always rewrites history. That is no different in the case that you refer to. The pretty pictures just do a good job of hiding that fact.
    – j6t
    Commented Nov 25, 2020 at 8:16
  • they both rewrite history, but squash preserves knowledge in the repository of the SHA of the old commits, I'm not so sure about reset. Commented Nov 25, 2020 at 8:19
  • So, in my above example I mentioned that squashing *appeared to squash the 3 commits into one commit at the point where it was committed to the feature branch (ie. before the merge commit). Does that mean I would end up with a linear history with a single commit on the main branch? Or does it preserve the fact that the 3 commits where "on a separate branch" and then merged with a merge commit.
    – zing
    Commented Nov 25, 2020 at 8:33
  • By the way, thanks for the help @j6t. Exactly what I wanted.
    – zing
    Commented Nov 25, 2020 at 8:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.