I\'ve been using Git now for a couple of months on a project with one other developer. I have several years of experience with SVN, so I guess I bring a lot of baggage to th
With Git there is no “correct” workflow. Use whatever floats your boat. However, if you constantly get conflicts when merging branches maybe you should coordinate your efforts better with your fellow developer(s)? Sounds like the two of you keep editing the same files. Also, watch out for whitespace and subversion keywords (i.e., “$Id$” and others).
From what I have observed, git merge tends to keep the branches separate even after merging, whereas rebase then merge combines it into one single branch. The latter comes out much cleaner, whereas in the former, it would be easier to find out which commits belong to which branch even after merging.
"Conflicts" mean "parallel evolutions of a same content". So if it goes "all to hell" during a merge, it means you have massive evolutions on the same set of files.
The reason why a rebase is then better than a merge is that:
I confirm that the correct workflow in that case (evolutions on common set of files) is rebase first, then merge.
However, that means that, if you push your local branch (for backup reason), that branch should not be pulled (or at least used) by anyone else (since the commit history will be rewritten by the successive rebase).
On that topic (rebase then merge workflow), barraponto mentions in the comments two interesting posts, both from randyfay.com:
Using this technique, your work always goes on top of the public branch like a patch that is up-to-date with current
HEAD
.
(a similar technique exists for bazaar)
git push --force
(instead of a git pull --rebase
for instance)I only use rebase workflow, because it is visually clearer(not only in GitKraken, but also in Intellij and in gitk
, but I recommend the first one most): you have a branch, it originates from the master, and it goes back to master. When the diagram is clean and beautiful, you will know that nothing goes to hell, ever.
My workflow is almost the same from yours, but with only one small difference: I squash
commits into one in my local branch before rebase
my branch onto the latest changes on master
, because:
rebase
works on basis of each commit
which means, if you have 15 commits changing the same line as master
does, you have to check 15 times if you don't squash, but what matters is the final result, right?
So, the whole workflow is:
Checkout to master
and pull to ensure that you have the latest version
From there, create a new branch
Do your work there, you can freely commit several times, and push to remote, no worries, because it is your branch.
If someone tells you, "hey, my PR/MR is approved, now it is merged to master", you can fetch them/pull them. You can do it anytime, or in step 6.
After doing all your work, commit them, and if you have several commits, squash them(they are all your work, and how many times you change a line of code does not matter; the only important thing is the final version). Push it or not, it doesn't matter.
Checkout to master
, pull
again to ensure you have the latest master
in local. Your diagram should be similar to this:
As you can see, you are on your local branch, which originates from an outdated status on master
, while master
(both local and remote) has moved forward with changes of your colleague.
master
and choose "Rebase"; another reason why I like it.)
After that, you will be like:So now, you have all the changes on the latest master
, combined with changes on your branch. You can now push to your remote, and, if you have pushed before, you will have to force push; Git will tell you that you cannot simply fast forward. That's normal, because of the rebase, you have changed the start point of your branch. But you should not fear: wisely use the force, but without fear. In the end, the remote is also your branch so you do not affect master
even if you do something wrong.
Create PR/MR and wait until it is approved, so master
will have your contribution. Congrats! So you can now checkout to master
, pull your changes, and delete your local branch in order to clean up the diagram. The remote branch should be deleted too, if this is not done when you merge it into master.
The final diagram is clean and clear again:
In my workflow, I rebase as much as possible (and I try to do it often. Not letting the discrepancies accumulate drastically reduces the amount and the severity of collisions between branches).
However, even in a mostly rebase-based workflow, there is a place for merges.
Recall that merge actually creates a node that has two parents. Now consider the following situation: I have two independent feature brances A and B, and now want to develop stuff on feature branch C which depends on both A and B, while A and B are getting reviewed.
What I do then, is the following:
Now branch C includes changes from both A and B, and I can continue developing on it. If I do any change to A, then I reconstruct the graph of branches in the following way:
This way I can actually maintain arbitrary graphs of branches, but doing something more complex than the situation described above is already too complex, given that there is no automatic tool to do the rebasing when the parent changes.
I have one question after reading your explanation: Could it be that you never did a
git checkout master
git pull origin
git checkout my_new_feature
before doing the 'git rebase/merge master' in your feature branch?
Because your master branch won't update automatically from your friend's repository. You have to do that with the git pull origin
. I.e. maybe you would always rebase from a never-changing local master branch? And then come push time, you are pushing in a repository which has (local) commits you never saw and thus the push fails.