6 ms·
A Rebase Workflow for Git
- ef4 14y agoThis strategy throws away some of the most powerful features of distributed version control. It only works if you're going to work in a silo and then suddenly share your changes, fully finished, with the world. In any collaborative environment, or even as a solo developer working from multiple machines, rebasing is a pain in the ass. It breaks your ability to seamlessly synchronize your work across branches and across machines. Don't fear merge commits. Git is built around the expectation that there will be plenty of them, and the tools handle merge commits just fine. The author seems to be trying to limit the damage from colleagues who don't understand how to use git by severely restricting what parts of git they use. I think that's an ultimately self-defeating strategy.
- lnguyen 14y agoIf you're working in a group and structure your branches around releases (or really any logical way), you need to use rebase. It can be a pain in the ass but it's the only way to guarantee that you're all consistently working from the same set of files/commits and that the your updates don't mix in other changes (aka chances for errors/regression). See http://gitguru.com/2009/02/03/rebase-v-merge-in-git/ http://gitguru.com/2009/02/03/rebase-v-merge-in-git/
- pnathan 14y agoI don't understand how rebasing is usable in a corporate environment (with a central server that's backed up) unless you have some sort of temp repo that you plan to squash down and send to the canonical repo.
- lnguyen 14y agoThere shouldn't be any issue about where rebase is usable versus merge. It's more process than technical except if you're expecting git to handle things right out of the box. None of these arguments are anything new: Any one who's worked with ClearCase should recognize them [1]. Read up on the UCM lifecycle. [1] Software Configuration Management Strategies and Rational ClearCase (1st edition: http://www.amazon.com/Software-Configuration-Management-Strategies-ClearCase/dp/0201604787 http://www.amazon.com/Software-Configuration-Management-Stra...). And yes, it's from over 10 years ago...
- wanderr 14y agoRemember, git's major strength is its distributed nature. Forking and branching are the easiest thing in the world to do. What we do here is, developers work in a fork and/or a topic branch, when they think it is complete the code goes through a review and when it's ready to merge, is rebased onto the latest canonical repo/branch before being merged in. Clean, linear history, no problems with corporate environment. Am I missing something about the perceived problem?
- lnguyen 14y agoI'm going just a bit pedantic on this part: "when it's ready to merge, is rebased onto the latest canonical repo/branch before being merged in" should read "when it's ready to merge, we rebase the local development branch to the latest canonical repo/branch, resolve the rebase merge issues, and then merge the changes into the canonical repo/branch" It's probably what you're doing but just saying it more precisely in the use of git (and SCM) terminology.
- grayrest 14y agoYou do feature based branches that get rebased against master on a regular basis and push -f your dev branch in the evening so your changes are backed up. When two devs are working on the same branch they coordinate via chat who (or whoever comes in first) does the daily rebase and the other does a fetch and hard reset. For when a significant fraction of the team is working on a branch, you just have a running branch/merge. Everything works off the central repo and there's a git hook to prevent push -f to master.
- pnathan 14y agoIt's the push -f that I was missing. That would solve my point. :-)
- deleted 14y ago[deleted]
- j_baker 14y agoI'm convinced rebase vs merge is the new spaces vs tabs or emacs vs vim. There are reasons to use both, and it usually isn't worth your time to try and convince the other side they're wrong.
- cpeterso 14y agoMercurial tries to avoid the "rebasing public changes" problem with a new hg 2.1 feature called "phases" that tracks whether a changeset has been shared. Unfortunately, it is a little simple-minded because pushing to any other hg repo, even on your same machine, will mark the changeset as "public". http://www.logilab.org/blogentry/88203 http://www.logilab.org/blogentry/88203
- mindajar 14y agoThat's not the case if the 'other' repo is configured as a non-publishing repository. http://mercurial.selenic.com/wiki/Phases#Publishing_Repository http://mercurial.selenic.com/wiki/Phases#Publishing_Reposito...
- erso 14y agoMerge commits do so much harm, it's outrageous that anyone would think they're any good (save for git merge --no-ff a branch that has already been rebased onto the branch it's being merged into). If I'm working along on a branch and someone commits something remotely, I can: git pull and get their changes as a merge commit or git rebase origin/master and get their changes below mine The big difference here is that if I have a conflict with their changes and I do a merge, I resolve those conflicts in the merge commit. This is terrible for a few reasons: * It means my commits are inherently broken. They're only made un-broken by the merge commit * When anyone else looks at my commit history, they have to look not only at the commits that I made but at the merge commit that resolved the conflicts from the prior commit, otherwise they're using a bad commit as a reference * When I do eventually merge my branch in, there will be a mess of commits from master splayed all throughout my commits, so that nobody can easily see what commits were actually mine without doing a git log origin/master..my_branch to see just what my branch is adding Now, if I decide to use rebase instead of merge, I resolve those conflicts at the point in which they would have occurred on my branch, thereby making my commits conflict-free. My history is also compact as it isn't spread over time with (possibly multiple) merge commits from master. If you happen to do merge commits you cannot easily rebase that branch without ripping out the merges first using something like git rebase --onto (http://pivotallabs.com/users/khicks/blog/articles/2118-git-rebase-onto http://pivotallabs.com/users/khicks/blog/articles/2118-git-r...). You can have git try to replay the merges at the point they occurred via git rebase -p (preserve merges), but that's dangerous and not useful territory to be in. The brunt of your argument seems to be that you'd prefer people to be constantly pushing to master features that are incomplete or otherwise don't work, all for the sake of having other people have your broken or incomplete features available for them to start writing code against. This is madness. You have to manage that mess with feature flags or other song-and-dance nonsense that you could avoid entirely by using rebase instead of merge and only putting your stuff on top of master (either via rebasing your commits onto master as the OP notes or by --no-ff merging the branch, as I noted earlier). In addition to that, you can no longer easily even tell what a feature was. Maybe you use commit messages that have a story/card/bug ID that you can use to track, but man, I'd hate to rely on that. I've used the rebase strategy for multiple years now with teams of 20-60 people, distributed across countries with great success. I have yet to hear a reasonable argument for merging other than "but, but.. you can't silo your work!" The hell I can't. I'm going to work on the feature branch until, at minimum, the feature is passed by QA as being feature-complete. Until the point of me putting my work onto master I have absolute control over squashing/rearranging commits, messages, deleting commits, and doing whatever the hell else I want to do to make sure my commits are all green (passing all tests), conflict-free, and sensible. Hell, I've even done talks on my rebase-based Git workflow. Until that point, my commits aren't useful to anyone because the work is by definition incomplete. I care more about a clean, readable, green commit history than someone's idea that having all code pushed to master as soon as it's written is somehow better.
- yonran 14y agoThis is basically how people use git-svn, because svn only understands rebase and not merge. I'm a lone git-svn user in a svn workplace, and I've been satisfied following this basic workflow. I have my configuration differences, personal changes, and unfinished work in little commits on my branch. At the end of the day I rebase -i or cherry-pick onto the upstream git-svn branch, clean up the commits, and dcommit. At the beginning of each day I rebase yesterday's work onto the tip of upstream and continue working.
- e28eta 14y agoSame thing with git-p4, which is how I primarily use git. You do miss out on the benefits of distributed version control, but I really prefer it over working with Perforce directly.
- e28eta 14y agoSame thing with git-p4, which is how I primarily use git. You do miss out on the benefits of distributed version control, but I really prefer it over working with Perforce directly.
- wanderr 14y agoHaving a clean, easy to read commit history in upstream is, in my opinion, worth the few downsides of this approach. I care a lot less about when a commit was made, I'm much more interested in when it made it in to upstream, so having a linear history that makes that obvious is extremely valuable to me.
- shin_lao 14y agoI don't understand the remark about the history. You can merge and "squash" your history into a single commit. I don't understand what rebase brings.
- merlincorey 14y agoIn addition to squash merging, you can merge without fast forwarding (--no-ff), which is a great method to make topical branches of related commits one single atomic conflict free commit.
- languagehacker 14y agoRebasing when pulling instead of merging has been a best practice for like 3 years now. Am I missing something?
- shawnps 14y agoRebase also helps me make less useless commits. For example, if I commit something on a branch, and then later realize I made a typo in that commit, I can make a commit that fixes the typo, then use git rebase -i and make it a fixup commit. Fixup squashes the commit into another one, and discards the message.
- chrismsnz 14y agoI use 'git commit --amend' which does basically the same thing. Both have to be done before pushing to remote, anyway.
- erso 14y agoThis works great but can only be used to amend HEAD. If you want to amend a commit that's HEAD~1 or further back, you need to either use the fixup strategy I mentioned above, or, if you really want to use --amend: * git rebase -i SHA-to-be-amended~1 * select SHA-to-be-amended for edit * make your changes * git commit --amend -CHEAD (This takes the message from HEAD without presenting you with the editor. If you wanted to edit the message, use -cHEAD.) * git rebase --continue It's good to know when and how to use both. The fixup strategy is much quicker and doesn't require you to do the rebase immediately. I will sometimes stack a few fixup commits and just do the interactive rebase (with autosquash) later.
- erso 14y agoI used to do the process you describe, but have greatly improved it using autosquash: * Add your changes to the index * git commit --fixup SHA, where SHA is the commit you want to fixup into * git rebase -i --autosquash, now or later When you commit with --fixup, Git will make a commit with a message that begins with fixup! and continues with the message of the SHA you gave it. When you enter the interactive rebase, Git will automatically have moved the fixup commit just below the commit it's going to be fixup'd into. With this method you don't have to manage moving around the fixup commits, or use a system to tell you where they need to go. I used to do messages like "git commit -m 'f into a98oe6e'", which works until you do a rebase and the SHAs change. You can also enable autosquash in your gitconfig (git config --global rebase.autosquash true) so you don't need to pass --autosquash when doing the interactive rebase.
- mck- 14y agoIn the comments section where he explains it with pictures, it's much clearer than the actual article.