7 ms·
This workflow is scary. A rebase should not be part of any everyday workflow and must be reserved _only_ for exceptional situations. Rebasing can cause the los
by nhance 10y ago
This workflow is scary. A rebase should not be part of any everyday workflow and must be reserved _only_ for exceptional situations.
Rebasing can cause the loss of history and developers should be as careful with it as system admins are with `sudo`. I can't recommend any workflow that includes it without treating is as a terrifying and scary thing. How easy is it to accidentally remove a line during interactive rebase and lose all work associated with it?
This is why my team and I moved to squash merging. Sure it has it's own drawbacks, but they're far less worrisome than rebasing. If you screw up a rebase, the history is re-written or force-pushed by accident. If you screw up a squash merge, you can still check out the intermediate commits if you know the hash.
We won a Ruby award for our work on Git Reflow. There are big improvements coming this week that can make it easy for teams to tweak the workflow to suit any special needs you might have. It works on github and bitbucket and automatically creates pull requests (and makes sure they're reviewed.) Gitlab support coming soon (maybe this month).
http://github.com/reenhanced/gitreflow http://github.com/reenhanced/gitreflow
- nhance 10y agoMy apologies if this comes across as overly harsh! This article was really quite well written, and it's only after having been burned through rebases that I've gotten so headstrong against it. We need more articles like this! Thank you for your work!
- stormbrew 10y ago> This is why my team and I moved to squash merging. Sure it has it's own drawbacks, but they're far less worrisome than rebasing. If you screw up a rebase, the history is re-written or force-pushed by accident. If you screw up a squash merge, you can still check out the intermediate commits if you know the hash Until the original branch is deleted and the refs are garbage collected, anyways. It seems strange to me to advocate for squash merging on a premise of not losing history. A squash merge is a rebase.
- steveklabnik 10y ago> A squash merge is a rebase. Well, it's not a rebase in the literal sense: the base commit isn't changing. It _is_ modifying history, though.
- stormbrew 10y agoIt probably is in the same sense that 'git rebase -i' often puts the new branch on a new base even if that wasn't your explicit intention. Usually merge squashes are reparented to the current head of the target branch. But my point was just that a merge squash is just a specific incantation of the git-rebase tool. And it is one of the most history destroying incantations, rather than the least.
- steveklabnik 10y agoAh, sorry, I'm probably mis-understanding a "squash merge". I thought you meant you have a graph like this: C -> D -> E / A -> B then you "squash merge" S------ / \ A -> B -> F where S is C + D + E. Whereas a rebase + (now fast-forward) merge would be A -> B -> C' -> D' -> E' and, if squashed during rebase -i or by some other means A -> B -> S It seems you're saying a "squash merge" is the last one, I thought it was the second one.
- stormbrew 10y agoI'm sure someone out there does it like that (the joy and pain of git being there's a million ways of doing things), but the name I think is derived from the idea that you're replacing a merge commit with a squash of the disjoint parent, rather than a merge of a squash. Also it's entirely possible I'm wrong, I'm a fan of merge bubbles (sometimes rebased for clarity), and avoid large squashes in general, so maybe I just don't understand how people do it. I don't know why you'd bother to keep both a merge and squash commit around, though.
- steveklabnik 10y agoNo, I think you're right; take a look at the graphs on https://github.com/blog/2141-squash-your-commits https://github.com/blog/2141-squash-your-commits for example. I don't know why you'd want to do it that way either! But I also don't understand why you'd want to "never rebase", so when it comes to git, I assume that someone has reasons for doing all kinds of things I don't understand.
- tanderson92 10y agoBut some of us use git-rebase every day perfectly fine and never lose information. Yes, you must be careful. No, you should never use it on public commits. I wouldn't recommend it to others as I don't trust them to read the man page and understand what git-rebase does. Those of us who use git-rebase also know how to recover the refs since before they are GCed, though I've never had to do that. It's dangerous to pronounce certain powerful features of a system as off limits for day to day private use. That's a different pronouncement than a decision not to share "why everyone should use git-rebase often".
- rralian 10y agoAnd we use git-rebase commonly on public commits without concern. Everyone uses git differently.
- K0nserv 10y agoI think this depends on your definition of public? For me public means "in stable branches". I sure hope you aren't rebasing master
- dimino 10y agoThat's a weird definition of 'public'; for most folks, I imagine 'public' to mean anything accessible without any authorization.
- _ikke_ 10y agoWhen people talk about public commits it means commits other people have access too, and more specific, were able to commit on top. Authorization has nothing to do with it. In practice it means anything you have pushed. An exception can be made for topic branches, especially in a pull-request workflow. These branches could be rebased / amended to update the final result, even after they have been pushed already.
- 10y ago
- igor_marques 10y agoThe rebase would ideally be the last thing you do on your branch, and very carefully. And I also mention in the post that we should always use what's best for our teams, so if the squash merge works best for you, go for it! :)
- shadowfiend 10y ago> How easy is it to accidentally remove a line during interactive rebase and lose all work associated with it? This is not only not easy, it's actually very difficult. If you drop something in an interactive rebase, you can reset your HEAD to the HEAD commit from before your rebase. It's a bit arcane, and has its own dangers, but it's also important to be clear that rebases are not destructive unless a git gc runs between your rebase and realizing you made a mistake. It's also the equivalent fix to checking out intermediate commits for a squash merge, as far as I know. Don't get me wrong, I don't think rebase should be the first tool you reach for and I don't particularly like “rebase everything to master” workflows. But it's not as dangerous as you're making it sound, IMO.
- Hello71 10y agocorrection: unless you wait 30 or 90 days (depending on what you do in the interim) and then run other git commands which trigger automatic gc (which typically only happens with large repositories) or manual gc (in which case you're just asking for problems)
- snuxoll 10y agoI'm so happy this uses squash merges, using rebase for this purpose is exceptionally overkill when you just want a clean commit history (due to the complexity of using the rebase tool), if you're writing a feature that involves a large amount of changes throughout the codebase it can be a handy tool to break up your work but for the general case of smaller PR's a squash merge is the way to go.
- jordigh 10y ago> This workflow is scary. A rebase should not be part of any everyday workflow and must be reserved _only_ for exceptional situations. This is what Mercurial Evolve tries to solve. There's nothing wrong with rewriting draft commits. The only potential problem is rewriting public commits. Mercurial uses phases to distinguish drafts from published commits and you may optionally designate certain repositories as non-publishing, so that they can be used for collaboratively editing draft commits. A similar de facto convention on git is to only rewrite certain branches (e.g. feature branches) but never rewrite others (e.g. master). Commits that are local-only can be rewritten at will. Mercurial just codifies this convention via phases.
- Ridikule 10y agoTypically, I see folks create a working branch, make incremental commits, such as a commit per day so as not to lose work, then rebase them all into a single commit before pushing back to origin. We haven't had any problems with this approach so far. YMMV
- K0nserv 10y agoI don't share this concern, I've been rebasing frequently(several times a day) for years now and never caused any unrecoverable problems. I would recommend that the last thing you do before pushing a branch you've rebased is git diff origin/master branch This way you can see if the diff looks like what you expect it to be. If it doesn't and you believe you messed something up while rebasing just git reset --hard origin/branch and redo the rebase
- DougWebb 10y agoRebase is absolutely a part of my everyday workflow, and the rest of my team's workflow as well. (Yesterday I had to show our CTO how to use it, because the rest of the team was getting annoyed by his merge commits.) Our workflow is: - locally, commit to local master or a local branch - occasionally checkout local master (if necessary) and pull using the 'rebase after fetch' option. - if we had local master commits, fixup any conflicts in our code - if we were working on a local branch, checkout that branch and rebase it on the new master, fixing any conflicts that arise - If our work is complete, possibly do a final rebase to reorder and squash local commits, and fast-forward merge to master if we were on a branch. Finally, push the local master to share our work. Note that we never rebase anything that's been pushed. Also, if we're worried that a rebase is potentially complex and error prone, we create a new branch at the existing HEAD so that the old commits don't get lost in the reflog. Once the rebase is done, we can delete that branch so the old commits can be garbage collected.
- dangerlibrary 10y ago> annoyed by his merge commits Getting rid of merge commits is literally the only benefit of your workflow over the standard branching model.
- DougWebb 10y agoNot true. We've also found that rebasing our own work onto the latest master makes it a lot easier to deal with conflicts. When you do a merge, the conflicts you see are a mixture of your own code and someone else's code, and it can be hard to tell which is correct because you're not familiar with the other person's changes. But when you rebases, all of the changes are code that you wrote, so it's easier to figure out how to fix the conflict. This may sound counter-intuitive, because you're thinking it's the same conflict either way. Most of the time it is; if you and someone else changed the same bit of code, the conflict will be shown to you the same way whether you merge or rebase. Those are easy to fix. What's harder is when someone reorganizes some code without making significant changes to it. In a merge, you'll see changes all over the place, but in a rebase git can usually figure out the new line numbers, and may not indicate a conflict at all. The other area where my team has had difficulty with merges is in Visual Studio sln and csproj files. When you add new projects to a solution or new references to a project, git can present a very confusing diff during a merge conflict. But for rebase only your additions are highlighted, and most of the time you can solve the conflict with "use theirs before mine".
- SonicSoul 10y agowe've adopted it daily to solve the issue with bad merge history. Seems that git will do a merge on the server and is confused on who did what. Care to elaborate on how you solved this problem w/out rebase?
- edbrown23 10y agoAt least locally within your repo, it's actually very hard to lose work completely with git, via any combination of resets or rebases. The reflog (git reflog) stores all the movements of HEAD such that you can recover from almost any mistake as long as you realize you made it. The fear of rebase seems to always come from its ability to "delete your work", but that fear is almost always unfounded and based on a lack of knowledge on git's internal structures. Of course, one of git's biggest and well recognized faults is that its UI makes no attempt to alleviate those fears.
- drakenot 10y agoI completely disagree with this. You can easily undo a rebase locally if you mess up by resetting to hashes you pull out of the reflog. When I'm dealing with my own work branches -- I absolutely rebase my commits before submitting a pull request to my team. I'll either squash irrelevant commits or I'll reword poorly written git commit messages. I also almost always default to `get pull --rebase` as well, as I hate the noise of merge commits littering up my commit log.
- tomstuart 10y agoThis is misleading advice, principally because “squash merging” is the very definition of losing history — it literally discards the commit history of your branch, which will then be lost to GC.
- elmigranto 10y ago> If you screw up a rebase, the history is re-written… https://git-scm.com/docs/git-reflog https://git-scm.com/docs/git-reflog > …or force-pushed by accident Well, you could nuke git folder "by accident" as well :) Jokes aside, don't force-push to "other's" branches).
- falsedan 10y agoIf you really feel like you do have to force-push to someone else's branch, please use git push --force-with-lease origin/other_branch so you at least won't trash any commits your collaborator pushed after you last fetched their branch. git will see that your origin/other_branch doesn't match origin's other_branch, and will bail out so you can pull the changes and decide how to incorporate them.
- Hello71 10y ago> If you screw up a squash merge, you can still check out the intermediate commits if you know the hash. if you're going to store commit hashes externally instead of using the reflog then it makes no difference whether you use rebase, merge, or even cherry-pick or reset. also, sudo itself poses no risk; it's much more important to evaluate what you're running, instead of a blanket restriction on what is just another tool. if I run "cd /; rm -rf *" on my desktop, it doesn't really matter whether I'm running as root or as my user, I'm going to have a bad day. "curl | sh" is equally as dangerous as "curl | sudo sh".
- golergka 10y agoWhy squash merge instead of simple merge?
- bogomipz 10y agoWhat is the harm in rewriting history in your private "topic branch"? This is not uncommon for the use case the author was describing. It certainly creates a cleaner logical history.
- echion 10y ago> A rebase should not be part of any everyday workflow and must be reserved _only_ for exceptional situations Git rebase is absolutely a vital part of the developer toolkit. If you're not using it, you're missing out on a big timesaver and git feature. I think you must be talking about rebasing public commits/history. In the article he is specifically talking about private history and has a nice big warning against rebasing public history. Linus has explained the distinction pretty well before: http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html http://www.mail-archive.com/dri-devel@lists.sourceforge.net/... .
- falsedan 10y agoThis is FUD. Many people use git-rebase flawlessly, without any of the issues you've encountered. Wouldn't your tests catch when lines get elided by manual merge conflict resolution? Have you see mjd's Git Habits[0], which lays out a foolproof way of rebasing without losing lines? [0] http://blog.plover.com/prog/git-habits.html http://blog.plover.com/prog/git-habits.html