Rational: In out environment review takes place on the branch that is here denoted as master>
. I would like to squash (better: combine) commits together in order to have all changes to a certain development-step together. Thus:
How do I get from left to right?
master> * C <feature
|\
* H <feature - just local | * H (merged)
| | |
* G - pushed to remote =??=> | * G (merged)
master> B * | - pushed to remote B * |
| * F - pushed to remote | * F (merged)
|/ |/
* A *
In reality the number of commits on the feature path is large (10+) and I'd like to squash them all. Parts of them are already published to the remote repository (and should not be changed or altered). However I just want to create one single commit on the master branch.
git merge --squash
apparently performs this, but it does not does not mark the commits as merged. Thus if I continue work on <feature
-Branch the next call to git merge
will lead to lots of conflicts. I found an explanation on stackoverflow: git merge --squash
leads to a patch unrelated to the source-commits.
So, what I want to achieve is to get from the right to the left situation and all commits on featurebranch (F
, G
and H
) will be marked as merged*) - if I continue working on the Featurebranch next merge does not lead to conflicts with my own changes. This Question is solved, in case all Changes on the Featurebranch are not published to the remote repository (see git merge --squash
-Question ).
PS: Of course it would be sufficient to mark the commits individually as merged, but I neither know how to do this, nor how git manages it's merge information.
PSS: Normal merge does it, but it fails iff there is no commit on master.
*): "marked as merged" means, that in gitk - iff you select the commit, the list of branches includes feature, remotes/origin/feature, master, remotes/origin/master. As result those commits wont be considered in subsequent call to git merge
.
After some research I learned the following: git
will select the method how to merge based on the state of the involved Branches - In the trivial (figure b) from my sketch below) git selects fast-foreward, thats when only one of the two branches has changes. In this case it might occure, that all changes from the feater-branch will be placed on top of the master branch.
Off-topic: If there are changes on more than one of the involved branches (figure a) from my sketch below) git selects a merge-Strategie according to the current state of the involved branches and the git-configuration. In additon You migt use the commandline to enforce certain behavior (https://git-scm.com/docs/merge-strategies or http://gitbu.ch/ch03.html).
With this knowlege there is an answer to my questions:
Answer: favor --no-ff
over --squash
If ever I want to avoid "fast-forward" merge you should use
git merge --no-ff --no-commit feature
and after this you should syncronize feature to main
git checkout feature
git merge --ff-only master
this brings you from left to right off the sketch in the Question AND each commit original made to the feature
-Branch will be marked as Present on the master
branch (This info is displayed in gitk when you select the commit).
There might be another reason to avoid "fast-foreward": The achieved situation will document, wich changes are originally checked in to the feature-Branch and which are done to the main-Branch.
Sketch to illustrate fast-foreward:
a) real merge b) trivial - no chanes on master
* H <feature * H <feature
| |
* G <feature/origin * G <feature/origin
master> B * | |
| * F * F
|/ /
* master> A *
a)
is the usual case whith commits on both sides where a mergestrategi is involved to resolve 'em. b)
is the trivial case, where fast foreward is posible.
Summary: In either case the given commands combines all the work commitet on the feature
branch to a single commit on master
without loosing the merge information.