tags:

views:

72

answers:

4

In Git, is there a way to merge all changes from one branch into another, but squash to a single commit at the same time?

I often work on a new feature in a separate branch and will regularly commit/push - mainly for backup or to transfer what I'm working on to another machine. Mostly those commits say "Feature xxx WIP" or something redundant.

Once that work is finished and I want to merge WIP branch back into master, I'd like to discard all those intermediate commits, and just a have a single clean commit.

Is there an easy way to do this?

Alternatively, how about a command that squashes all commits on a branch since the point where it was branched?

A: 

You can do this with the "rebase" command. Let's call the branches "main" and "feature":

git checkout feature
git rebase main

The rebase command will replay all of the commits on "feature" as one commit with a parent equal to "main".

You might want to run git merge main before git rebase main if "main" has changed since "feature" was created (or since the most recent merge). That way, you still have your full history in case you had a merge conflict.

After the rebase, you can merge your branch to main, which should result in a fast-forward merge:

git checkout main
git merge feature

See the rebase page of Understanding Git Conceptually for a good overview

NamshubWriter
This didn't work for me. I just created a simple test repo, with a WIP branch and tried the above and got merge conflicts (even though I hadn't made any changes on master).
cantabilesoftware
If feature was created from main (git checkout -b feature main) and you had a recent merge from main, you shouldn't get conflicts from the rebase
NamshubWriter
OK, tried it again. Didn't get conflicts this time, but the history wasn't squashed.
cantabilesoftware
Taking another look at the git-merge documentation, you are right, some of the commits will stay. If you have done previous merges from "main" to "feature" then the rebase will remove some of them, but not all.
NamshubWriter
A: 

Try git rebase -i master on your feature branch. You can then change all but one 'pick' to 'squash' to combine the commits. See squashing commits with rebase

Finally, you can then do the merge from master branch.

fseto
Yes that works, but I don't want the hassle of interactive rebase. I just want everything since the branch flattened.
cantabilesoftware
+1  A: 

Found it! Merge command has a --squash option

git checkout master
git merge --squash WIP

at this point everything is merged, possibly conflicted, but not committed. So I can now:

git add .
git commit -m "Merged WIP"
cantabilesoftware
+3  A: 

Another option is git merge --squash <feature branch> then finally do a git commit.

From Git merge

--squash

--no-squash

Produce the working tree and index state as if a real merge happened (except for the merge information), but do not actually make a commit or move the HEAD, nor record $GIT_DIR/MERGE_HEAD to cause the next git commit command to create a merge commit. This allows you to create a single commit on top of the current branch whose effect is the same as merging another branch (or more in case of an octopus).

fseto
Thanks fseto. I just posted the same answer, I'll accept yours though.
cantabilesoftware