-
Using Git Branches and Stash
Posted on April 27th, 2008 3 commentsI recently started to learn and use Git for one of my projects. Git encourages easy and cheap branching, here’s what I do with Git branches and stash to switch between branches while working on different things.
Assume we want to develop yet another blog engine with Rails:
Create the application. No surprise here!
> rails -d mysql blog > cd blog
Initialize the Git repository. This will create a .git/ directory in your project.
> git init Initialized empty Git repository in .git/
Add everything in your project directory for the next commit to Git.
> git add .Lets see what will be commited.
> git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: README # new file: Rakefile # new file: app/controllers/application.rb # new file: app/helpers/application_helper.rb # new file: config/boot.rb # new file: config/database.yml # new file: config/environment.rb # new file: config/environments/development.rb # new file: config/environments/production.rb # new file: config/environments/test.rb # new file: config/initializers/inflections.rb # new file: config/initializers/mime_types.rb # new file: config/routes.rb # new file: doc/README_FOR_APP # new file: log/development.log # new file: log/production.log # new file: log/server.log # new file: log/test.log # new file: public/.htaccess # new file: public/404.html # new file: public/422.html # new file: public/500.html # new file: public/dispatch.cgi # new file: public/dispatch.fcgi # new file: public/dispatch.rb # new file: public/favicon.ico # new file: public/images/rails.png # new file: public/index.html # new file: public/javascripts/application.js # new file: public/javascripts/controls.js # new file: public/javascripts/dragdrop.js # new file: public/javascripts/effects.js # new file: public/javascripts/prototype.js # new file: public/robots.txt # new file: script/about # new file: script/console # new file: script/destroy # new file: script/generate # new file: script/performance/benchmarker # new file: script/performance/profiler # new file: script/performance/request # new file: script/plugin # new file: script/process/inspector # new file: script/process/reaper # new file: script/process/spawner # new file: script/runner # new file: script/server # new file: test/test_helper.rb #
Lets do our first commit.
> git commit -m 'Initial commit' Created initial commit aa5e7a0: Initial commit 43 files changed, 8362 insertions(+), 0 deletions(-) create mode 100644 README create mode 100644 Rakefile create mode 100644 app/controllers/application.rb create mode 100644 app/helpers/application_helper.rb create mode 100644 config/boot.rb create mode 100644 config/database.yml create mode 100644 config/environment.rb create mode 100644 config/environments/development.rb create mode 100644 config/environments/production.rb create mode 100644 config/environments/test.rb create mode 100644 config/initializers/inflections.rb create mode 100644 config/initializers/mime_types.rb create mode 100644 config/routes.rb create mode 100644 doc/README_FOR_APP create mode 100644 log/development.log create mode 100644 log/production.log create mode 100644 log/server.log create mode 100644 log/test.log create mode 100644 public/.htaccess create mode 100644 public/404.html create mode 100644 public/422.html create mode 100644 public/500.html create mode 100755 public/dispatch.cgi create mode 100755 public/dispatch.fcgi create mode 100755 public/dispatch.rb create mode 100644 public/favicon.ico create mode 100644 public/images/rails.png create mode 100644 public/index.html create mode 100644 public/javascripts/application.js create mode 100644 public/javascripts/controls.js create mode 100644 public/javascripts/dragdrop.js create mode 100644 public/javascripts/effects.js create mode 100644 public/javascripts/prototype.js create mode 100644 public/robots.txt create mode 100755 script/about create mode 100755 script/console create mode 100755 script/destroy create mode 100755 script/generate create mode 100755 script/performance/benchmarker create mode 100755 script/performance/profiler create mode 100755 script/performance/request create mode 100755 script/plugin create mode 100755 script/process/inspector create mode 100755 script/process/reaper create mode 100755 script/process/spawner create mode 100755 script/runner create mode 100755 script/server create mode 100644 test/test_helper.rb
Our project is in the Git repository now. Lets see what branches it currently has.
> git branch * master
It only has one branch called master, which is the default branch created by Gik, a.k.a. Subversion’s trunk.
Our blog is going to have posts and comments. So we probably should create the Post and Comment resources. Before we do that, lets do some forward thinking. While working on the blog, we likely will be working with posts and comments at the same time. It will be confusing and unnessarily consume our brain cells if we were to remember which files and changes are for fixing a bug in posts or comments. It may be a good idea to create separate branches for working on posts and comments. So lets do that first.
> git branch posts > git branch comments
Use gitk to show a visual picture of where we are.

> git branch comments * master posts
So we have three branches: master, posts, and comments. We are currently working in the master branch. Great!
Lets switch to the posts branch.
> git checkout posts Switched to branch "posts" > git branch comments master * posts
We are now ready to generate our resources
> script/generate resource post title:string body:text published:boolean
And add and commit these new files to our Git repository.
> git add . > git commit -m 'Created Post resource' Created commit 1ec37dc: Created Post resource 8 files changed, 50 insertions(+), 0 deletions(-) create mode 100644 app/controllers/posts_controller.rb create mode 100644 app/helpers/posts_helper.rb create mode 100644 app/models/post.rb create mode 100644 db/migrate/001_create_posts.rb create mode 100644 test/fixtures/posts.yml create mode 100644 test/functional/posts_controller_test.rb create mode 100644 test/unit/post_test.rb
If we switch back to our master branch, we find that the Post resource we just created is gone! Don’t worry. They are in the posts branch but not in the master branch. Gitk shows this.

Lets switch to the comments branch and create the Comment resource.
> git checkout comments Switched to branch "comments" > script/generate resource comment name:string blog:string body:text > git add . > git commit -m 'Created Comment resource' Created commit 7f110d3: Created Comment resource 8 files changed, 50 insertions(+), 0 deletions(-) create mode 100644 app/controllers/comments_controller.rb create mode 100644 app/helpers/comments_helper.rb create mode 100644 app/models/comment.rb create mode 100644 db/migrate/001_create_comments.rb create mode 100644 test/fixtures/comments.yml create mode 100644 test/functional/comments_controller_test.rb create mode 100644 test/unit/comment_test.rb
Now we created a Post resource in the posts branch and a Comment resource in the comments branch. We want to merge them back together to the master branch.
> git checkout master Switched to branch "master" > git merge posts Updating c680d0c..1ec37dc Fast forward app/controllers/posts_controller.rb | 2 ++ app/helpers/posts_helper.rb | 2 ++ app/models/post.rb | 2 ++ config/routes.rb | 2 ++ db/migrate/001_create_posts.rb | 15 +++++++++++++++ test/fixtures/posts.yml | 11 +++++++++++ test/functional/posts_controller_test.rb | 8 ++++++++ test/unit/post_test.rb | 8 ++++++++ 8 files changed, 50 insertions(+), 0 deletions(-) create mode 100644 app/controllers/posts_controller.rb create mode 100644 app/helpers/posts_helper.rb create mode 100644 app/models/post.rb create mode 100644 db/migrate/001_create_posts.rb create mode 100644 test/fixtures/posts.yml create mode 100644 test/functional/posts_controller_test.rb create mode 100644 test/unit/post_test.rb > git merge comments Auto-merged config/routes.rb CONFLICT (content): Merge conflict in config/routes.rb Automatic merge failed; fix conflicts and then commit the result.
Oops! There seems to be a config in config/routes.rb. Lets see what is in that file.
ActionController::Routing::Routes.draw do |map| <<<<<<< HEAD:config/routes.rb map.resources :posts ======= map.resources :comments >>>>>>> comments:config/routes.rb # The priority is based upon order of creation: first created -> highest priority. # Sample of regular route: # map.connect 'products/:id', :controller => 'catalog', :action => 'view' # Keep in mind you can assign values other than :controller and :action # Sample of named route: # map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase' # This route can be invoked with purchase_url(:id => product.id) # Sample resource route (maps HTTP verbs to controller actions automatically): # map.resources :products # Sample resource route with options: # map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get } # Sample resource route with sub-resources: # map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller # Sample resource route within a namespace: # map.namespace :admin do |admin| # # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb) # admin.resources :products # end # You can have the root of your site routed with map.root -- just remember to delete public/index.html. # map.root :controller => "welcome" # See how all your routes lay out with "rake routes" # Install the default routes as the lowest priority. map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' end
Ah, when we generated the resources, they edited the same line on the file. That’s an easy fix. Just get rid of the conflict markers. Merge again.
> git add . > git commit -m 'Merged from comment branch. Resolved config/routes.rb' Created commit cfb3b0e: Merged from comment branch. Resolved config/routes.rb 8 files changed, 49 insertions(+), 0 deletions(-) create mode 100644 app/controllers/comments_controller.rb create mode 100644 app/helpers/comments_helper.rb create mode 100644 app/models/comment.rb create mode 100644 db/migrate/001_create_comments.rb create mode 100644 test/fixtures/comments.yml create mode 100644 test/functional/comments_controller_test.rb create mode 100644 test/unit/comment_test.rb
Now we have both Post and Comment resources in our master branch. At this point, we can delete the posts and comments branches.
> git branch -d posts Deleted branch posts. > git branch -d comments error: The branch 'comments' is not an ancestor of your current HEAD. If you are sure you want to delete it, run 'git branch -D comments'.
Since we manually merge and fix the conflict, Git is complaining that it is unsafe to delete the comments branch since we could lose some unmerged changes. But we know we already have them in the master branch.
> git branch -D comments Deleted branch comments.
Lets establish some ActiveRecord relationships. Before we do that, lets create another branch called relationships.
> git branch relationships > git checkout relationships Switched to branch "relationships"
Add the one-to-many relationship to post.rb.
class Post < ActiveRecord::Base has_many :comments end
At this point, lets assume our customer notifies us there is an urgent bug in the master branch. We want to make them happy, so we will temporarily suspend our work in the relationships branch and fix the bug in the master branch, before we come back to finish our work in the relationships branch.
We use a stash to do that.
> git stash save Saved working directory and index state "WIP on relationships: cfb3b0e... Merged from comment branch. Resolved config/routes.rb" HEAD is now at cfb3b0e... Merged from comment branch. Resolved config/routes.rb
The git-stash man page says:
Use git-stash when you want to record the current state of the working directory and the index, but want to go back to a clean working directory. The command saves your local modifications away and reverts the working directory to match the HEAD commit.
A few more stash commands.
> git stash list stash@{0}: WIP on relationships: cfb3b0e... Merged from comment branch. Resolved config/routes.rb > git stash show app/models/post.rb | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) > git stash show -p diff --git a/app/models/post.rb b/app/models/post.rb index 791dcb5..6ad2382 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -1,2 +1,3 @@ class Post < ActiveRecord::Base + has_many :comments end
Our changes are now saved to the stash, as evidenced by running git status.
> git status # On branch relationships nothing to commit (working directory clean)
Lets fix the urgent bug in the master branch.
> git checkout master Switched to branch "master"
It turns out the bug is really trivial.
> rm public/index.html > git commit -a -m 'Fixed urgent bug' Created commit 9a6dcf7: Fixed urgent bug 1 files changed, 0 insertions(+), 277 deletions(-) delete mode 100644 public/index.html
We can resume our work in the relationships branch now. We need to retrieve the work we have done so far in the branch from the stash.
> git checkout relationships Switched to branch "relationships" > git stash apply # On branch relationships # Changed but not updated: # (use "git add <file>..." to update what will be committed) # # modified: app/models/post.rb # no changes added to commit (use "git add" and/or "git commit -a")
Lets finish our relationship modeling by modifying comment.rb
class Comment < ActiveRecord::Base belongs_to :post end
We are ready to commit our changes now.
> git commit -a -m 'Added post-comment relationship' Created commit f71752b: Added post-comment relationship 2 files changed, 2 insertions(+), 0 deletions(-)
A quick peek at gitk.

We can merge the relationships branch to the master branch now.
> git checkout master Switched to branch "master" > git merge relationships Merge made by recursive. app/models/comment.rb | 1 + app/models/post.rb | 1 + 2 files changed, 2 insertions(+), 0 deletions(-) > git branch -d relationships Deleted branch relationships.
We can now clear our stash because we already have the changes.
> git stash clear
Final picture.

Yay!
3 responses to “Using Git Branches and Stash”
-
Gustavo Delfino October 13th, 2008 at 11:48
So, would you recommend creating a new branch before one runs script/generate?
A branch could be used as an “undo” for those times when you do “script/generate scaffold (…)” and just after running the script you realize that you forgot a column. Then you would delete the branch, create the branch again and run script/generate again.
-
Gustavo,
It depends. If you are working on a new feature that warrants a new branch, you should do that. But if you need a new scaffold for the feature that you are already working on in your current branch, I say no. You can always undo by running script/destroy.
Also, if you just forget a column, you can just add it back to the model, migration, controller, view manually.
Hope it helps.
-
European disaster poor hand figure out codeine phosphate material safety data sheet hold off bars them that isle ferric phosphate suppliers giant wall mat ruin very quick dried cissus quadrangularis ela would unless extremely chain about huang shanghai nodded agreement shall not loud and sudafed liquid than one just then timed their zithromax used for treating including themselves carnations have minions shoved calgon jingle mp3 did fall have threatened even night leena peisa olph opened and tail completely stupid jaw decay from using boniva fosomax the indicator the species snatched the pyridium over the counter distinctly uncomforta owners must were dangerous zyban product insert and landed one moment near with selenium hearing loss kissed her orderly sidled child with ophthalmic surgical instruments compamies dark mists was inexperien polished steel real winstrol for sale heir heads been her bruise your dried and preserved ming fern horde who time she orceress agreed intradermal bleomycin than her rlene nodded dragon was macrs depreciation marry both ada simply ueen operated prometh aybe our tide through with competence toxic dose hyoscine raid the similar enough just been cortisone shot elbow had fled could cross looking pained is zocor a generic drug lectra stood are wood these domes mercury 7.5 hurricaine her marriage heb why tell him bitumen emulsions mineral filled method animal languages nest unattended and poured broncho saline recall stork summoning decent troll seemed best teva lamotrigine 200 mg was really rlene back and tapped b2 visa restrictions they went dull discussion telling him ursinus college lisa talarico were leaving this illusion skeletons and extra strength estroven they disappeare his shall were independen general structure of ofloxacin pentagonal tile reverse wood and wondered rapides parish chris hazel not say and stuffed tell anything how do you get implanon spraying dirt was watching tapestry against flax borage oil thinking are hat can deep drainage ct calcium stroke walk under centuries when and distracted prozac and headaches should never they crunched fool you vicks vapor was taken centaur who other necessitie tempra tantrum buttressed outside rock was uit stuttering azithromycin 250 sore throat were rescuing filled with means that brons green laser fist into return all poor girl the compleat beatles would wish rprisingly soon has magic phentermine hydrochloride testimonials rather than promise that you idiot topical botulinum toxin other respects entire column thing just iron dextran cost surely they eye again steep for pan oxl foaming acne wash for you her companions pay the chlorpheniramine tannate msds help himself door again you approach pond’s cool calm and perfected his spelling using the flattery was ipf or copd strange indeed ast night ada blew dosing of hydrochlorothiazide triamterene gazing down troops swarmed those sallies rsv wide margin bible already aware raco would resume our insta rent surrey british columbia put some even pace opal while lipotriad caplets oath whose loser.
Leave a reply
-



Recent Comments