The author concludes by saying:<p>>I think I've written before that this profusion of solutions is the sign of a well-designed system. The tools and concepts are powerful, and can be combined in many ways to solve many problems that the designers didn't foresee.<p>I disagree. I consider this to be a failure of Git. The set of different options (normal merge, rebase, filter-branch, etc) is complex and not cleanly orthogonal which makes for a very messy "mental model". Even experienced experts would have difficulty finding the clear, simple way to solve this problem and those less experienced would have little chance of proceeding cleanly.<p>I really wish some tool other than Git had "won" the version-control race; I honestly believe Git to be the worst of the contenders in the most recent generation of version control systems (albeit better than the previous generation in important ways).
The simplest solution is:<p><pre><code> # try the merge; you'll get conflicts on those files
git merge topic
# discard the versions from the topic branch;
# you know you already merged those changes in
# the funny "git checkout commit", so any differences
# are due to changes on master.
git checkout --ours new-file-{1,18}
# now you are free to fix up any real conflicts
# and resolve the merge
git commit
</code></pre>
This has the advantage of representing the true history. You had two lines of development (the original topic, and the "squashed" history created for deployment), and the merge shows them coming together and choosing the deployment-side content.
Participate in Atlassian Research<p>My name is Angela and I do research for Atlassian. I’m kicking off a round of discussions with people who use Git tools. Ideally, I’d like to talk to people that sit on a team of 3 or more. If this is you, I would love to talk to you about your experience with <using> Git tools, or just some of the pain points that are keeping you up at night when doing your jobs.<p>We’ll just need 30 mins of your time, and as a token of my thanks to those that participate, I’d like to offer a US$50 Amazon gift voucher. <p>If you’re interested, just shoot me an email with your availability over the next few weeks and we can set up a time to chat for 30 minutes. Please also include your timezone so we can schedule a suitable time (as I’m located in San Francisco). Hope to talk to you soon!<p>Cheers,
Angela Guo
aguo@atlassian.com
While an unorthodox merge strategy was used, this is what happens when you hole up in a topic branch for a long time. I bet this would've been easier had they merged smaller commits or PR's to master constantly. If one is afraid of deploying unfinished features, don't make them functional until they are ready. Tie them together once finished. Or did I miss something here?
> The next day he wanted to go ahead and merge the front-end changes, but he found himself in “a bit of a pickle”. The merge didn't go forward cleanly, perhaps because of other changes that had been made to master in the meantime. And trying to rebase the branch onto the new master was a complete failure. Many of those 406 commits included various edits to the 18 back-end files that no longer made sense now that the finished versions of those files were in the master branch he was trying to rebase onto.<p>Can one not instead merge master into the feature branch?
I don't understand the problem here, why didn't he just do a merge and resolve the 18 conflicts by using the version of the file from master?<p>And the problem wasn't in checkout-add-commit, that is a trivial issue, the WTF here is producing 406 new commits in a branch without ever thinking of merging master back into it or rebasing on master, to avoid having a giant merge later.
400 commits not cleanly applying? Not a big deal. I routinely merge 1000-2000 commits and rebase 30 active branches to that also. The solution is git rerere. It stores all the resolved merge resolutions forever, and cp or rb apply cleanly then, without any trouble.
Eg
<a href="https://medium.com/@porteneuve/fix-conflicts-only-once-with-git-rerere-7d116b2cec67#.8pj73vnex" rel="nofollow">https://medium.com/@porteneuve/fix-conflicts-only-once-with-...</a>
> <i>X decided to merge and deploy just the back-end changes, and then, once that was done and appeared successful, to merge the remaining front-end changes.</i><p>> "<i>What should X have done in the first place to avoid the pickle?</i>"<p>0. (Of course, not develop a 406 patch changeset and then have to pick it apart. Make smaller pushes, frequently.)<p>1. Create a topic branch right there at the tip where the 406 changes are locally committed.<p>2. Then use git's interactive rebase to rewrite this branch such that just the back-end commits are picked first, followed by the front end.<p>3. Make a back-end topic branch from the last back-end commit and test that. If it's cool, master can be rebased to that and pushed to origin/master upstream.<p>4. Test remaining front-end changes, rebase master to them, push.<p>Also:<p>3. a) If back-end changes need fixing, fix them on the back-end-topic branch. Then rebase the original topic to the back end topic to pick up these changes "under" it. (I.e. replay the front end over the new back end, and install as new front end).
Reading this was like watching a traffic accident in slow motion. I could hear myself yelling at the author as if he were a student driver:<p>"Use filter-branch!!! Use filter-branch!!! NOOOOOOOO NOT merge union with manual deletes!!!"<p>But... he went and did it anyways. Honestly, reading back through commit logs, you always find the part where the driver runs off the road, plows through a clearly marked gate, runs on a train track for a mile or two, then merges back onto the main street, carrying part of a mailbox and a deer carcass.<p>You can fault git if you want, but it seems like some of these cases just arrive naturally no matter what cvs is used. It would be great to have a "git education" repo that contains situations just like these to work through... sort of a "drivers ed" for managing a repo.
The Reddit discussion of this, though brief, was interesting and to the point.<p><a href="https://www.reddit.com/r/git/comments/5i3mpz/another_git_catastrophe_cleaned_up_story_of_a/" rel="nofollow">https://www.reddit.com/r/git/comments/5i3mpz/another_git_cat...</a>
Two fun things about git: It is deterministic, and it doesn't delete anything (readily).<p>This means you can't really have a catastrophe.<p>Just git reflog your way out.
People in the discussion here saying, somewhat blindly it appears to me, that using mercurial would have avoided this mess. I'm a huge mercurial fan and have dealt with some tricky situations similar to this (but never this situation exactly) and I'm not so sure how mercurial would have handled it. The best I can say is that I've never known even the most adventurous mercurial user to use checkout (actually revert in mercurial) on individual files in that way. Is that something git people do more often?<p>Aside from that, it'd be fun to see how mecurial handles this, but I'm not sure from reading the original post if I could exactly reproduce it.<p>Mercurial would let you do the checkout (revert) trick that started it all. I can imagine it causing merge conflicts as described. Mercurial does let you specify how to resolve merge conflicts for the whole merge, or you can tell it not to resolve conflicts at all and then you can run hg resolve on a file-per-file (or glob of files) basis and tell it to pick default (equivalent of master) for the files you want. I didn't quite follow the git way of doing this he described with .gitattributes, but using hg resolve sounds easier (but neither are things a non-expert user of either tool would know).<p>In the end some other solutions were proposed. I would not recommend using checkout (revert in mercurial) either. I don't know of a filter-branch equivalent in mercurial, but that sounds like a cool way to deal with this. In mercurial I probably would have reached for graft (equivalent of git's cherry pick), which isn't very different from git.
The problem with Git is that everyone is trying to use Git as central repository rather than distributed as if it were SVN, personally i blame GitHub for promoting among the new developers the wrong tool for the job causing all this unnecessary drama.
Git is the best version control system if and only if the project has a good leader checking everyone merges before commiting and letting everyone knows who is working on what and what parts will affect.
> But I couldn't think of anything, so I asked Rik Signes. Rik immediately said that X should have used git-filter-branch to separate the 406 commits into two branches, branch A with just the changes to the 18 back-end files and branch B with just the changes to the other files. (The two branches together would have had more than 406 commits, since a commit that changed both back-end and front-end files would be represented in both branches.) Then he would have had no trouble landing branch A on master and, after it was deployed, landing branch B.<p>Well. Okay. That's a technical solution and it'd work, it's probably no less time consuming than going and fixing the code in a new branch and merging cleanly (every time I end up needing to filter branch stuff I have to RTFM on it, and it takes ages) -- this problem is <i>NOT</i> a technical one though; it's a process one.<p>Why are you landing 400 commits in one go? Half of those were on files which then start causing merge conflicts for your team and wasted a huge amount of your time?<p>Use feature flags, fix your conflicts in branch, don't merge anything into master unless it's using the 'merge' button on github/gitlab/gogs/whatever. And really think/discuss/roundtable about how you're introducing features because it sounds like this is running away from you a bit here..<p>It doesn't need to be this complex, and these kinds of messes can't really be put on the tools -- although git certainly makes it easy to set a lot of things on fire..
I like Perforce. It may not be perfect. But it's idiot proof.<p>"Days since gitastrophe" is a common phrase. There is no Perforce equivalent. You can't blow your leg off. There aren't thousands of "Perforce made easy" blog posts because it's actually easy. There are no "fixing my p4 repo" tales because it never breaks.<p>Thanks Perforce.
In a corporate environment, I think I prefer a simpler workflow with a plain old centralized VCS and without using any branches at all. As code gets written, each commit goes on the trunk behind a feature flag (which you need anyway). That way each commit can benefit from continuous builds and testing, and other people can notice problems early. Branches would only be used for releases.<p>I've worked like that for years on some pretty big projects, and it never caused complicated problems like in the OP. The only caveat is that you need a strong safety net against breaking the trunk (lots of tests, mandatory code review, etc.)
Why wouldn't they reintegrate the mainline development branch with the new branch if it was so long lived? And/Or have the new code behind a feature flag so you could potentially have it deployed but disabled? So many ways this could have been avoided with some basic forward thinking...
So if I get this then he just added the files to master, then tried to work on the topic branch?<p>That really seems weird. I don't think it's git's fault. Also he could have done git merge master --accept-theirs if he really wanted some kind of history but I guess it would be worthless.
I humbly (re)submit this for your consideration <a href="https://git-man-page-generator.lokaltog.net/" rel="nofollow">https://git-man-page-generator.lokaltog.net/</a>
IMHO it's odd approach to the problem. I'd rather ask the author (who knows best in this case) to split this into two separate parts that can be nicely merged.
Worth noting that cherry-pick takes commit ID ranges in the form xxxxxx..yyyyyy, it may have simplified the driver.<p>Thanks for the tip re: --keep-redundant-commits!
I hate this shit. Rebasing always causes conflicts and dealing with them is such a giant pain. I get that in this case the designer really brought the pain on themselves but I wish using git didn't require this sort of surgery periodically, which in my experience it does.
I think everyone is overlooking the main point.<p>He said that one guy was only making changes to either the front end or back end code.<p>They should have been two separate repos. one for the front end code and one for the back end code.