Generally, it's the responsibility of whoever made the changes to resolve conflicts (basically, git blame conflicting lines and the people who changed them get notified to resolve conflicts in that file). Distributing the work like this makes the merges more reasonable.
You first rebase against the master locally and push the merged feature branch after resolving all the conflicts yourself. Afterwards, you go to the master and merge it against the updated feature branch. The 2nd merge should not result in any conflicts.
This model can be annoying on running feature branches. Once you rebase, you have to force-push to the remote feature branch. It's not so bad if you use --force-with-lease to prevent blowing away work on the remote, but it still means a lot of rewriting history on anything other than one-off branches.
No no, you never force push to "published" branches, e.g., upstream master. What you're doing when you rebase onto the latest upstream is this: you're making your local history the _same_ as the upstream, plus your commits as the latest commits, which means if you push that, then you're NOT rewriting the upstream's history.
(In the Sun model one does rewrite project branch history, but one also leaves behind tags, and downstream developers use the equivalent of git rebase --onto. But the true upstream never rewrites its history.)
There's nothing stopping you from doing merges instead of rebases.
* latest feature commit #3 (feature)
* merge
/|
* | more master commits you wanted to include (master)
| * feature commit #2
| * merge
|/|
* | master commits you wanted to include
| * feature commit #1
|/
* original master tip
* master history...
Then, when you're done with feature, if you really care about clean history, just rebase the entire history of the feature branch into one or more commits based on the latest from master. I think checkout -b newbranch; rebase --squash master does the trick here:
* feature commits #1, #2 and #3 (newbranch)
| * latest feature commit (feature)
| * merge
|/|
* | more master commits you wanted to include (master)
| * feature commit #2
| * merge
|/|
* | master commits you wanted to include
| * feature commit #1
|/
* original master tip
* master history...
Then checkout master, rebase newbranch, test it out and if you're all good, delete or ignore the original.
* feature commits #1, #2 and #3 (master, newbranch)
* more master commits you wanted to include
* master commits you wanted to include
* original master tip
* master history...
I've described this. Downstreams of the feature branch rebase from their previous feature branch merge base (a tag for which is left behind to make it easy to find it) --onto the new feature branch head.
E.g., here's what the feature branch goes through:
feature$ git tag feature_05
<time passes; some downstreams push to feature branch/remote>
feature$ git fetch origin
feature$ git rebase origin/master
feature$ git tag feature_06
And here's what a downstream of the feature branch goes through:
downstream$ git fetch feature_remote
<time passes; this downstream does not push in time for the feature branch's rebase>
downstream$ git rebase --onto feature_remote/feature_06 feature_remote/feature_05
Easy peasy. The key is to make it easy to find the previous merge base and then use git rebase --onto to rebase from the old merge base to the new merge base.
Everybody rebases all the time. Everybody except the true master -- that one [almost] never rebases (at Sun it would happen once in a blue moon).
Yep, this is the way I work. Always rebase against master, and fix conflicts there, so branches merging into master should always be up-to-date and have zero conflicts.
reply