Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git branch --merged / --no-merged and --squash option

Tags:

git

merge

squash

git branch --merged doesn't appear to play nicely with --squash.

If you do a normal git merge, then git branch --merged tells you which branches have been merged. This is not the case however if the --squash option is used, even though the resulting tree is the same.

I doubt this is a git defect and would like to know if there is some git-fu I'm missing, or if I have misunderstood something.

In short: I want to use --squash, but also want git to tell me if the branch I squashed into another one has been --merged.

like image 844
EdwardGarson Avatar asked Oct 11 '13 01:10

EdwardGarson


People also ask

What is the difference between squash and merge and merge?

Squash merging is a merge option that allows you to condense the Git history of topic branches when you complete a pull request. Instead of each commit on the topic branch being added to the history of the default branch, a squash merge adds all the file changes to a single new commit on the default branch.

Is it better to squash and merge?

You should consider using squash if your team prefers a linear project history. This means that the history held by your main branch should not contain merges. A squash merge makes it possible to keep changes condensed to a single commit, supporting this strategy nicely.

Does git merge squash by default?

Explanation. You can't make Git do a squash "merge" by default for all branches, but you can make it do a squash "merge" by default for some branches.

How do you squash commits when merging?

To enable commit squashing as the default option in your repository: Navigate to your chosen repository and open the Settings sub-tab. Open the General Settings page. Check the box for Squash commits on merge default enabled.


1 Answers

You can't get there from here (as the fellow giving directions said). More precisely, it does not make sense.

The problem is that git merge --squash does not actually do a merge. Suppose your branch history looks like this, for instance (with branches topic and devel):

          H ⬅ I ⬅ J     <-- topic         ⬋ ⬅ F ⬅ G         ⬉           K ⬅ L         <-- devel 

If you check out devel and merge topic you get a new merge commit M that contains the result of the merge, and M has two parents:

          H ⬅ I ⬅ J     <-- topic         ⬋         ⬆ ⬅ F ⬅ G           ⬆         ⬉         ⬆           K ⬅ L ⬅ M     <-- devel 

But if you use git merge --squash topic you get, instead, a new commit (let's label it S for squash):

          H ⬅ I ⬅ J     <-- topic         ⬋ ⬅ F ⬅ G         ⬉           K ⬅ L ⬅ S     <-- devel 

where (as you already noted) the contents (the tree) of commit S makes all the files come out the same as they would in commit M. But there's no back-link (parent arrow) from S to topic. It's not a merge at all, it's just taking all the changes from topic, squashing them into a single change, and adding that as an entirely independent commit.

Now, the other thing about git merge --squash is that it does not make the final commit. So you could create the .git files that git would on a "regular" merge, and do a commit that has the two parents you'd get on a "real" merge. And then you'd get ... exactly what you get if you run git merge topic, a commit (label it S or M, it does not matter) that has the same tree again, but now has two parent-arrows, pointing to L and J, just like M.

In fact, running git merge --squash is almost exactly the same as running git merge --no-commit, except for the tracing files left behind when the merge is done (git commit uses some of these to set up the parents). The squash version does not write to .git/MERGE, .git/MERGE_HEAD, and .git/MERGE_MODE. (It does create .git/MERGE_MSG, the same as git merge --no-commit, and it also creates .git/SQUASH_MSG.)

So, basically, you have your choice: a real merge (two or more parents on the final commit), or a squash (same tree-combining mechanisms, but only one parent on the final commit). And, since git branch --merged works by looking at the "parent arrows" of each commit stored in the repository, only a real merge is really a merge, so only a real merge can be discovered later by git branch.

like image 115
torek Avatar answered Sep 28 '22 11:09

torek