Git merge strategy
We have a project hosted on Github with a main development branch called "Master". Some developers tend to merge project branches into Master. And others tend to merge Master into project branches.
Seems to me that the former adheres standard protocol. The later just doesn't make sense. Am I just being paranoid, or does it really make a difference?
To compound things, the project branches are then being pushed back to github with the merged Master branch
For those that merge Master into project, the argument is that they need to an up-to-date copy o开发者_运维知识库f Master. My answer; what does a merge have to do with it? Maybe to pick up changes that have been introduced by others and merged into master?
Shouldn't the process be: 1) checkout master, 2) git fetch or git pull
It makes total sense for the developers to merge the master branch into their project branch every now and then to make sure that they are not doing things that will not work once merged. This usually happens in their local repository.
Then, when they are done with the new feature, they merge it into master, and push, which will add that feature to the master branch of the public repository. Or they just push what's in their feature branch to the master branch of the public repository.
A git fetch
is just a way to fetch a repository from some remote. It will never do a merge at all. A git pull
will do the same thing, but also includes a merge.
So the process that you are suggesting will at best only merge changes to the public master branch with the local master branch. The developer will then still need to merge their local (now up-to-date) master branch with their feature branch or they will not be able to perform the sanity checks mentioned above.
In contrast to @richardolsson, I wouldn't recommend that they merge master into their topic branches, if by merge we mean git merge master
.
It is definitely a good idea for them to take updates that have happened on master and update their topic branches to reflect those changes, so as to avoid everything breaking terribly, but git provides a bit of a better tool for this particular use case, git rebase
.
Conceptually, they are very similar and the outcome in terms of the codebase is often identical, however using rebase
can make the history of the project much clearer to someone looking at the logs, and help keep from having a gigantic history graph to look through, even though those can look pretty sweet.
When you merge
, git takes the status of the two (or more) branches being merged, attempts to piece them together appropriately, and makes a commit reflecting that a merge has happened, unless the HEAD of the target branch is a direct descendant of the branch being merged in, in which case it doesn't need to do any diff/patch stuff and just plays the commits on top of each other (git calls this fast-forwarding).
When you rebase
, git (conceptually) takes the target branch, goes back to the last commit that it has in common with the branch it's being rebased on, makes the commits from that branch, and then makes the commits from the target branch. An example may be in order:
You have two branches, master
, with commits A
, B
, C
and D
and topic
, which was branched at B
and has the commits A
, B
, E
, and F
. If you are on topic
and git merge master
, you can end up with a commit history that will look like A B E F G
where G
is the commit made by merging. If you rebase, git first takes topic
and makes it's commit history the same as master
, and then makes the commits in topic
, so you get a commit history that looks like A B C D E F
.
One major advantage of doing this, other than the clarity in log history, is that as long as there haven't been changes in master
since you rebased, git checkout master && git merge topic
or similar will always be a fast-forward, since all of master
's history is contained in topic
. The big caveat here is to not
rebase branches that are meant to be publicly shared, because the SHA-1s of the commits have to be rewritten, which basically means a bunch of meaningless conflicts.
It took me a while for the benefit of this to take hold in my head. I've since found that (for me at least, and so far...), the "best" workflow is to:
- rebase topic branches
- merge tracking branches
Something like:
git checkout topic
git rebase master
# fix any conflicts, run tests, etc
git checkout master
git merge topic
This gives a very clear history, and pretty much ensures that if breakage happens, it happens on the topic branch. It also makes some of the tools like git bisect
a bit easier to use when you need to use them.
Anyhow, hope you found this way-too-long answer useful.
The better workflow would be, that the developers rebase their feature/project branches on the master branch, to avoid cluttering the history.
The first thing to realize is that branch names are technically only local to any given repository. The central version-2.0
might be my master
and your testing
. That being said, in practice, people usually use the same names as the repository they most often push to, so merging project
into master
then pushing master
is the standard way.
Merging master
into project
will produce this tree:
master A____B
project \__C_\_D
Merging project
into master
will produce this tree:
master A____B___D
project \__C__/
Note that both are essentially identical except for the branch names at D
are reversed, along with the order of its parents. As long as you specify git push origin project:master
if you do it the first way, then update master
to point to D
somehow before making another branch, you won't notice a difference in practice. However, that's creating extra mental effort for yourself, and you can screw things up if you don't do it right every time. Merging project
into master
allows you to set up defaults for push
that make it easy.
精彩评论