travis-ci.org/jdigger/git-process[image:https://travis-ci.org/jdigger/git-process.png?branch=master[Build Status]]

Purpose

This provides an easy way to work with a sane git workflow process that encourages using highly-focused branches to encourage collaboration, enable fearless changes, and improve team communication.

See the F.A.Q. for a much more complete explanation for the thoughts and assumptions that motivates this project.

Installation

Unix-based OS (OSX, Linux, etc.) Installation

If you are using a Ruby sandboxing system like rvm.io[RVM] or github.com/sstephenson/rbenv[rbenv] (either or which I would recommend) then simply do:

$ gem install git-process

If you are not using RVM or rbenv, you will likely need to precede that with “‘sudo`”.

Some older operating systems (such as OSX 10.6) are using an old version of RubyGems, which can cause installation problems. Do “‘gem update –system`” to fix.

Windows Installation

. Install Ruby (if you have not done so already) from rubyinstaller.org/ ** If it complains about not being able to compile native code, install rubyinstaller.org/downloads[DevKit]. ** See stackoverflow.com/questions/8100891/the-json-native-gem-requires-installed-build-tools/8463500#8463500[this StackOverflow] for help. . Open a command prompt and type ‘gem install git-process` . _THERE IS A KNOWN PROBLEM WITH ../../issues/140[HELP ON WINDOWS]_ ../../issues/140[(GH-120)].

Ruby Compatibility

Currently tested and maintained against Ruby 2.0 and Ruby 2.3

All Operating Systems

To get full ‘git help` and manpage support, do:

$ git config --global man.gem-man.cmd "gem man -s"
$ git config --global man.viewer gem-man
$ alias man="gem man -s"

Overview

Anticipated Use Cases

. User creates new local branch for focused work. . User pushes local branch to remote (as feature branch) by merging/rebasing with the integration branch, then pushing to the branch to remote. . User initiates GitHub “pull request” to ease collaboration. . User closes local branch by rebasing integration branch first, then pushing local to integration.

Command List

*All commands are well documented within themselves: Use the “git help” to see the full documentation.* (e.g., “‘git help sync`”)

Configurables

(See Notes for more details)

Assumptions

** “‘git sync`” makes it extremely easy for you to get any changes that are made in “`master`” into your branch so you can react to it immediately. ** “`git to-master`” then makes it easy to cleanly integrate the changes you have made. If you need to keep the current branch open, use the `–keep` option. Otherwise it closes the branch along with various other house-keeping duties.

** The exception here is “‘git pull-req`” since you typically do not use pull requests when working solo or when pair-programming.

Notes

Workflow Examples

Working Alone On A Local-Only Project

Jim is working on “my_project” and needs to start work on a new feature.


[a_branch]$ git new-fb save_the_planet

Creating save_tp off of master

[save_the_planet]$


He does lots of work. Checkin, checkin, checkin.

A sudden new brilliant idea happens.


[save_the_planet]$ git new-fb shave_the_bunnies

Creating shave_the_bunnies off of master

[shave_the_bunnies]$


After creating a Sheering class and tests, he commits his changes.


[shave_the_bunnies]$ git commit [shave_the_bunnies]$ git to-master

Rebasing shave_the_bunnies against master
Removing branch 'shave_the_bunnies'

[parking]$


Time to get back to work on “save_the_planet”.


[parking]$ git checkout save_the_planet [save_the_planet]$ git sync

Rebasing save_the_planet against master

[save_the_planet]$


Do more work. Commit. Commit. Commit.


[save_the_planet]$ git sync

Rebasing save_the_planet against master

[save_the_planet]$


Liking to have a clean history, he squashes and edits the commits to hide the evidence of false starts and stupid ideas so that anyone who sees the code in the future will think he was simply a genius.


[save_the_planet]$ git rebase -i

Rebasing save_the_planet against master

[save_the_planet]$ git to-master

Rebasing save_the_planet against master
Removing branch 'save_the_planet'

[parking]$


Time to release to a grateful world.

Working With A Team

John, Alice, Bill and Sally are working on “big_monies.” Alice and John are pairing and need to start work on a new feature.


john-$ git new-fb steal_underpants

Fetching the latest changes from the server
Creating steal_underpants off of origin/master

john-$


They do lots of work. Checkin, checkin, checkin. It has a lot of steps…

Meanwhile Bill has been working on his great idea:


bill-$ git new-fb awesomo4000

Fetching the latest changes from the server
Creating awesomo4000 off of origin/master

bill-$


He creates his “Laaaaame” class and checks it in, with a pull request asking Sally to do a code review.


bill-$ git commit bill-$ git pull-req “A.W.E.S.O.M-0 4000 prototype” \

                  -d "@sally, can you make sure Butters won't recognize it?"
Pushing to 'awesomo4000' on 'origin'.
Creating a pull request asking for 'awesomo4000' to be merged into 'master' on big_monies.
Created pull request at https://github.com/big_monies/pull/3454

bill-$


Sally sees the email. After looking at it in the web interface, she wants to test it.


sally-$ git pull-req 3454

Getting #pr_number
Fetching the latest changes from the server
  new branch: awesomo4000
Setting upstream/tracking for branch 'awesomo4000' to 'origin/master'.

sally-$ git sync

Fetching the latest changes from the server
Rebasing awesomo4000 against origin/master
Pushing to 'awesomo4000' on 'origin'.

sally-$


After verifying that the tests still work and “it’s all good” she promotes the code to integration.


sally-$ git to-master

Fetching the latest changes from the server
Rebasing awesomo4000 against origin/master
Pushing to 'awesomo4000' on 'origin'.
Removing branch remote 'awesomo4000'
Removing branch local 'awesomo4000'
Closing a pull request #3454 on origin.

sally-[parking]$


Over lunch Alice gets a brainstorm (“a duck and rubber hose!”) and rushes off to her computer:


alice-$ git sync steal_underpants

Fetching the latest changes from the server
Creating steal_underpants off of origin/steal_underpants
Setting upstream/tracking for branch 'steal_underpants' to 'origin/master'.

alice-$


She makes her changes, syncs back up with the server, and heads over to pair with John again.


alice-$ git commit alice-$ git sync

Fetching the latest changes from the server
Rebasing steal_underpants against origin/master
Pushing to 'steal_underpants' on 'origin'.

alice-$


John, meanwhile, had made some changes of his own.


john-$ git commit john-$ git sync

Fetching the latest changes from the server
Remote branch has changed
Rebasing steal_underpants against origin/steal_underpants
Rebasing steal_underpants against origin/master
Pushing to 'steal_underpants' on 'origin'.

john-$


At this point, his local branch has Alice’s change as well as Bill and Sally’s A.W.E.S.O.M-O 4000 enhancements.

After confirming with Alice and Bill that everything looks good, he pushes his changes up for integration.


john-$ git to-master

Fetching the latest changes from the server
Rebasing steal_underpants against origin/master
Pushing to 'steal_underpants' on 'origin'.
Removing remote branch 'steal_underpants'
Removing local branch 'steal_underpants'

[parking]$


Profit!!

F.A.Q.

Q: How is this different from git-flow or GitHub flow?

nvie.com/posts/a-successful-git-branching-model[“git-flow”] is designed around having a very strongly defined process around keeping new development, hotfixes, release process changes, etc. all clearly separated. The problem I have with it is that it’s too much “process” for not enough gain. (It has a waterfall feel to it, very much against the more modern continuousdelivery.com[Continuous Delivery] approach.)

scottchacon.com/2011/08/31/github-flow.html[“GitHub Flow”] is a lot cleaner, but relies too heavily (IMHO) on web-based tools and on merging instead of rebasing. It is also focussed very tightly on a Continuous Deployment process, which is great for them, but not practical for everyone.

Q: Wait, I heard “branches are evil.” Why should I do something evil?

Branches are extremely powerful tools that allow for clean organization/modularization of development.

** For example, I commit “green to green”: Doing en.wikipedia.org/wiki/Test-driven_development[TDD], I commit every time I have a newly passing test case. So, assuming I’m in a regular development flow, I’m committing my changes every five minutes or so. Tiny commits, but lots of them. What that means is that if I make a “less than wise choice” at some point, it’s trivial to rewind to before I’d made the mistake, potentially keep the throw-away code in another branch while I do my cleanup, and generally use the full power of a revision control system to make my life safer and easier. The branch(es) are pretty chaotic, but that’s not a problem because before integrating with the mainline, I take a moment to cleanup: Squash related commits together, write clearer commit messages (since now I know what “the answer” is), and generally move from my drafts to a more finished result. (See below on objections related to “lying with rebase.”) That may just be me, though, because I’m very paranoid when it comes to computers. I tend to automatically hit Cmd/Ctl-S every time I type a period when I’m writing, or when I close a block when I’m programming. I have a minimum of three copies/backups around the world of all my important documents. And I “‘git sync`” frequently to make sure my machine isn’t the only place where all my hard work is being stored. Have I mentioned I don’t trust computers?

** Branches encourage being less “shy” about your code. I have heard, on a number of occasions, developers say “I’m not ready to push this to the server yet because [it’s still rough (and embarrassing)]/[it may break other people]/etc.” All of those reasons for “hoarding” code are moot with branches.

Jez Humble, a brilliant Principle at ThoughtWorks Studios, talks a lot about how “branches are evil.” Unfortunately, people hear that, know how smart he is, and simply repeat it without really understanding what his objections are. Fortunately, he continuousdelivery.com/2011/07/on-dvcs-continuous-integration-and-feature-branches[posted clarification about what’s really meant by that]. He essentially says that the problem is that developers abuse branches by not merging with mainline (i.e., “master”) on a regular basis. Not constantly getting changes from mainline makes life rough when it comes time to integrate. Not putting your changes into mainline means that your changes are not being validated (via martinfowler.com/articles/continuousIntegration.html[Continuous Integration], or - better - with continuousdelivery.com[Continuous Delivery]). Both are, in fact, sins akin to not doing automated testing.

Making it “easier to do things right than wrong” (i.e., using branches and keeping them synced with mainline) was the primary motivation for this project. Every command here is focused on making it trivial to use branches that stay in sync with mainline and encourage collaboration.

Q: Why so much emphasis on rebasing? Isn’t rebasing a dangerous lie?

Like any powerful tool, ‘git rebase` is “dangerous” if used incorrectly, just like `rm`/`del`. You simply need to know when and how to use it safely. And in the world of version control systems, “`rebasing`” is easily one of the most _useful_ tools to come around since the `commit` command.

paul.stadig.name/2010/12/thou-shalt-not-lie-git-rebase-ammend.html[A famous article] that people have been parroting in various forms for a while makes the case that rebasing (and its various forms, such as squashing, amending commits, etc.) is a “lie.” As with so many things, context is everything.

You almost certainly should not rebase things that you have “‘published.`” Generally this really means “`Don’t rebase the ‘master’ branch!‘” Fortunately, these scripts make it impossible to rebase the mainline by accident.

Rebasing “‘your`” code is an extremely useful way of communicating clearly. In the “green to green” scenario above about branches, a lot of noise is generated. If someone wants to review my code, or cherry-pick in my changes, it’s too much of a mess to effectively do so. Also, as part of the process of squashing, I have the opportunity to write clearer commit message based upon my newly enhanced understanding. The intermediate commits were my “drafts” and I’m now submitting my cleaned up copy.

If you have ever seen an “active” project that uses a process like “‘git-flow`” that encourages a lot of branching and merging, you’ve seen how hard it can be to follow a particular line of development. Branch lines are flying around everywhere, and half the commits are pretty much pure noise. (e.g., “Merge branch ‘master’ of … into master”.) It’s also hard to follow the order in which commits actually impacted the mainline. In many ways, in practice merges turn into “‘a truth effectively being a lie`” (because it’s buried in the noise) versus rebases that are “a lie (changed from it’s ‘original’ form) to tell an effective truth” (clean and very clear about its impact).

One significant advantage of using automation like this is that it lets you have the best of both worlds. For example, ‘git sync` uses “`rebase`” instead of “`merge`” in a way to is completely safe for collaboration on the same branch. As long as the other people are also using `git sync`, it will make sure that changes are automatically incorporated with and brought in line. (See the extensive test suite in spec/sync_spec.rb[sync_spec.rb] if you want to see how this works.)

This project is trying to promote clear communication about reality as it applies to the code, over micro-management over no-longer-relevant history. Thus rational for the judicious use of rebase.

Development

Uses github.com/sstephenson/rbenv[rbenv] for Ruby versioning and bundler.io/[Bundler] for Gem management.

To get started, install rbenv and Bundler, then ‘bundle install`

Most tasks are run using rake.rubyforge.org/[Rake], defined in ./Rakefile[‘Rakefile`]

The scripts themselves are in the ./bin[‘bin`] directory, whereas the logic is in the ./lib/git-process[`lib/git-process`] directory. Test specifications are in ./spec[`spec`]

For local testing of the generated Gems, ./local-build.rb[‘local-build.rb`] will uninstall the current `git-process` gems and install the the new ones.

License

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.