How to properly use git merge --squash
Asked Answered
D

3

29

I'm fairly new to git and only work by myself so I don't use many of the features it can do but I am running into a process that either I am thinking about it wrong or doing something wrong.

I have a master branch with 1 commit (init).

I have a develop branch with 180 commits.

Today I am finally ready to merge the develop branch into the master, I did some reading and found out about squash. This seems like something useful since I wouldn't pollute the master branch with the same WIP commits that are in the develop branch.

So I ran

git checkout master
git merge --squash develop
git commit

From here everything looks as I expected, master has 2 commits, develop still has 180. In my head I now check out develop again and continue working. I pushed to bitbucket and took a look around at my project to see this merge and noticed the following:

1 commit(s) on master and not on develop
179 commit(s) on develop and not on master

Is this just expected behaviour and I am supposed to ignore it or did I do something wrong.

Defection answered 5/4, 2016 at 22:5 Comment(0)
R
26

This is expected since git merges all your commits into a single commit, which will be a different one compared to the ones in your develop branch. Think of the commits as a container of a set of changes, if you change the contents you'll have a different one.

You'll either have to accept this scenario, or you could adapt your workflow by working in feature-branches, e.g. master - develop - feature-branch.

Once a feature is done you make a squash-merge from feature-branch to develop and delete the feature-branch. Now you can make merges from develop to master without all the WIP commits, e.g. when you make new releases or such.

Rankin answered 5/4, 2016 at 22:17 Comment(3)
Makes sense. I think I will just have to accept it. The feature branch makes sense but likely I'll end up merge-squash several features into develop before I bring that into master so I'd end up in the same boat, just a few levels deep.Defection
master - develop - feature-branch scenario is the best way imo, that helps maintain master in stable state. If one needs simpler way, then I would recommend master - feature-branch, where each new feature/fix is created in separate local feature branchQuip
Like the original poster, I'm fairly new to git and also work primarily as an individual. Is there any reason not to do the squash merge for dev into main, and then merge from main back to dev? That seems to give you the desired single squashed commit in main, but still a common point from which to continue new work on dev.Chloropicrin
B
5

From git merge --help:

Note that fast-forward updates do not create a merge commit and therefore there is no way to stop those merges with --no-commit. Thus, if you want to ensure your branch is not changed or updated by the merge command, use --no-ff with --no-commit.

This also explains why the suggestion by @josemigallas is not enough.

Thus you can do:

git switch master
git merge dev --no-ff --no-commit

This will properly merge the histories of the two branches (see git log --graph) and give you exactly one extra commit on the master branch (instead of all 180).

Bulter answered 19/6, 2022 at 22:10 Comment(0)
D
4

When you squash commits in Git, it combines them into one single commit. However, when you want to combine changes from several commits into a new commit, you merge.

In your case, what I believe you intended to do was a merge with no "fastforwarding". With this kind of merge, your would have in the end 2 commits in master (initial and merge) and 180 commits in dev.

The code would be (after last commit in dev):

git checkout master
git merge dev --no-ff
Deutschland answered 5/4, 2016 at 22:30 Comment(5)
This does sound like what I want but I just tried it and it ends up with 180 commits in both.Defection
That's just what happens if the merge is fastforwarded. With no-fastforward, the 180 commits remain in dev, while in master you have one commit with all changes squashed. Did you try the exact code?Deutschland
Yes, exact code yielded me 181 commits in master and 180 commits in develop. Verified by git rev-list --count HEADDefection
Merging creates a new commit with a new tree based on all parents. It does not just "combine several commits into a new commit". It does so with a new (additional) node in history (so if you started with n commits you now have n+1 for the merge). Merging is about applying patches from some other branch to the current branch+tree. And keeping track of how that occurred. The benefit to keeping track (as opposed to squashing or cherry-picking) being that the merges get a lot simpler when Git knows better what really changed. But merges are also complicated to understand. Make your merges count.Preclinical
You may want to use git rev-list --count --first-parent HEAD. Many CLI commands support options to follow the first parent, e.g. git log --first-parent. For GUI tools it depends.Nonpartisan

© 2022 - 2024 — McMap. All rights reserved.