The best practice is to keep an accurate history and just do a straight merge. That way, if you introduce a bug at C
, someone investigating it can say, "Oh, that makes sense because it was done before we put feature F
into origin
, but not merged until today." It also has the benefit of not changing any hashes. There are flags you can use to hide the topic branch history when it doesn't interest you.
If you must squash your commits, for example if origin
is controlled by another organization, then it depends on how many people use the topic branch, and how many of them need to do merges from your origin
. You're not going to be able to do it without inconveniencing someone. Some teams just work with the original history, and one person deals with all the merges. Some teams start over with a new topic branch every time it gets merged into origin
. Some teams continually rebase their topic branch to origin
, and just make it common practice to always do a force pull. You'll have to figure out what works for your team.
With Git, commits
- are immutable,
- and form a directed acyclic graph.
Squashing does not combine commits. Instead, it records a new commit with the changes from multiple other commits. Rebasing is similar, but doesn't combine commits. Recording a new commit with the same changes as an existing commit is called history rewriting. But as existing commits are immutable, this should be understood as “writing an alternative history.”
Merging tries to combine the changes of two commit's histories (branches) starting from a common ancestor commit.
So let's look at your history:
F feature2
/
1---2---3---4---5 feature1 (old)
/
-o---o---o---A---o---o---S master
A is the common ancestor, 1–5 the original feature branch, F the new feature branch, and S the squashed commit that contains the same changes as 1–5. As you can see, the common ancestor of F and S is A. As far as git is concerned, there is no relation between S and 1–5. So merging master with S on one side and feature2 with 1–5 on the other will conflict. Resolving these conflicts is not difficult, but it's unnecessary, tedious work.
Because of these constraints, there are two approaches for dealing with merging/squashing:
Either you use history rewriting, in which case you will get multiple commits that represent the same changes. You would then rebase the second feature branch onto the squashed commit:
F feature2 (old)
/
1---2---3---4---5 feature1 (old)
/
-o---o---o---A---o---o---S master
\
F' feature2
Or you don't use history rewriting, in which case you might get extra merge commits:
F feature2
/
1---2---3---4---5 feature1 (old)
/ \
-o---o---o---A---o---o-----------M master
When feature2 and master are merged, the common ancestor will be commit 5.
In both cases will you have some merging effort. This effort doesn't depend very much on which of the above two strategies you choose. But make sure that
- branches are short-lived, to limit how far they can drift from the master branch, and that
- you regularly merge master into your feature branch, or rebase the feature branch on master to keep the branches in sync.
When working in a team, it is helpful to coordinate who is currently working on what. This helps to keep the number of features under development small, and can reduce the number of merge conflicts.
Best Answer
This turns out to be pretty simple to do, using some
git merge
flags I wasn't familiar with.-e
flag allows you to edit the message that occurs when you merge.--log
flag appends the one-line commit message from all commits in the branch to be merged to the commit message, making it easier to remember what you've done.