Reputation: 33
We have worked on a complex feature with my colleague in a common branch and during that time, there were several branches already merged into master. I can not resolve his conflicts and he cannot resolve mines, so we have to share the task. We don't work in the same place. I have two ideas. One is to create a new branch and cherry-picking my commits to it, then merge this one only. The other is to manually copy the directories containing my work from the feature branch outside the repository and back into a new branch. I am sure you have better ideas. Thanks in advance.
Upvotes: 3
Views: 976
Reputation: 45649
Since you don't work in the same place, I would assume your changes are in some commits and your colleague's changes are in other commits. Of course those commits may depend on one another, so there's not going to be a perfect solution. Here are some options.
Just work together. Yes, I know - you aren't in the same place. But there are many options for working in collaboration even when remote. (Screen sharing, chat sessions... heck, just a phone call.) Your best bet in my opinion is to work together on a single merge back to master; any fancy git-wrangling is a distant Plan B.
Pass work back and forth. Ok, so you've decided you just can't make a collaborative merging session work. Well, how about this: You start the merge, and resolve the conflicts you can. You communicate your merging state to your coworker in one of the ways I'll discuss momentarily. Your coworker continues by resolving the conflicts they can.
So how to communicate the merging state? I'll admit, I tried to think of a way to do it within git - maybe some kludgery involving stashes and bundles? I think it could be done, but you'd have to trick git at every step and could get into more trouble than it's worth. So in the interest of keeping it simple, how about you resolve what you can in your work tree, then email your coworker - either the individual files or a ZIP or other archive - so they can start the merge themselves and then overlay your resolution work into their work tree.
Take turns merging commits. Say you have something like
X --- X --- X <--(master)
\
O1 --- T1 --- O2 --- T2 --- O3 --- O4 <--(branch)
where each On
is one of your commits, and each Tn
is one of your coworker's commits.
Well, what if you do
git checkout master
git merge `O1`
You resolve whatever conflicts from your first commit, then you've got
X --- X --- X --- M1 <--(master)
\ /
O1 ------------- T1 --- O2 --- T2 --- O3 --- O4 <--(branch)
Your coworker then does
git checkout master
git pull
git merge T1
You take turns; you do O2
, he does T2
, you can jump to O4
... And you end up with this
X --- X --- X --- M1 -- M2 --- M3 --- M4 --------- M5 <--(master)
\ / / / / /
O1 ------------- T1 --- O2 --- T2 --- O3 --- O4 <--(branch)
Well, that's a lot of merge commits, so if you don't like that...
Take turns rebasing commits. Same principle, but using rebases.
git rebase master O1
git branch -f master
gives
X --- X --- X --- O1' <--(master)
\
O1 --- T1 --- O2 --- T2 --- O3 --- O4 <--(branch)
Now of course O1'
is a code state that hasn't been tested; so unless you test it now, it may be a broken commit. Normally I'd consider this a down-side of rebasing vs. merging, but in this case all those intermediate merges from the "take turns merging" approach are just as likely to be broken, so whatever. In fact you may not want to test and fix this commit, because that just introduces potential for even more confusing conflicts when your coworker proceeds with
git rebase --onto master O1 T1
git branch -f master
Again you alternate rebases; each subsequent command keeps the --onto master
, lists the last thing the other guy rebased as the upstream, and lists what you're rebasing as the commit. And in the end you have
X --- X --- X --- O1' --- T1' --- O2' --- T2' --- O3' --- O4' <--(master)
\
O1 --- T1 --- O2 --- T2 --- O3 --- O4 <--(branch)
so might as well
git branch -d branch
And if you happen to like linear, rebased histories, that's as good as it's likely to get.
**Separate the commits into two branches*. Instead of rebasing directly to master, you could rebase to separate branches. Then you could merge those branches to master. It's actually an extra step, and it may be problematic if there are a lot of interdependencies between your work and their work. It reduces the number of back-and-forth steps (and potentially the number of conflict resolution steps). And it gives a different final topology, which you might like better or might not like as much.
git checkout branch
git branch mine
git branch yours
git rebase -i O1^ mine
You get a rebasing "TODO" list; delete from this list the coworker's commits (T1
and T2
). Save and exit the text editor. Then after the rebase finishes
git rebase -i O1^ yours
This time in the editor, delete the lines for your commits (O1
, O2
, O3
, `O4``). Save and exit again. When this rebase finishes you can
git branch -d branch
and you have
X --- X --- X <--(master)
|\
| O1' --- O2' --- O3' --- O4' <--(mine)
\
T1' --- T2' <--(yours)
So now you can merge mine
and your coworker can merge yours
. (Best to make sure one of you waits to get the other's merge commit, so that you don't end up with a more tangled knot of merges at the end.)
Cherry Pick. Cherry picking (either directly to master or to separate branches to be merged) is just another way of looking at the rebase approaches.
Upvotes: 2