Sunday, January 20, 2008

Using git for newbie

I am doing some experiment with Rubinius code base, which uses distributed SCM git. Comparing with Subversion, Git is a little bit more difficult, so It takes me a while to understand its commands and find the proper way to work with it. Without commit right, here are typical commands I use in my work flow.

Clone a remote repository into the local disk - repository is create as a clone of the remote repository identified by a given url
git clone git://git.rubini.us/code 
cd code # goto directory containing local repository 
git config user.name "le huy"  #configure your name 
git config user.email "lehuy20@gmail.com" #and email that will be used when committing
Sample .git/config - git create a .git directory to store it's data, file .git/config contains configuration data including remote repository, which remote branch is link with which local one
cat .git/config 
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[remote "origin"]
        url = git://github.com/evanphx/rubinius.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[gui]
        geometry = 885x450+5+65 399 192
[branch "master"]
        remote = origin
        merge = refs/heads/master
[branch "cpp"]
        remote = origin
        merge = refs/heads/cpp
Submodule - git submodule is used to link to external repository (equivalent to subversion extern)
cat .gitmodules
[submodule "mspec"]
        path = mspec
        url = git://github.com/brixen/mspec.git
[submodule "spec/frozen"]
        path = spec/frozen
        url = git://github.com/brixen/rubyspec.git
init and update submodule from external repository
git submodule init # init submodule repository based on .gitmodules
git submodule update
Show current branch - show which branch we are working on, switch between them
git branch # will show us local branches 
* cpp
  master

git branch -a # will show us all branches including local and remote 
* cpp
  master
  origin/cmakebuild
  origin/cpp
  origin/fusion-experiment
  origin/instance_eval
  origin/master
  origin/wilson64

git checkout master # switch to branch named 'master'
git checkout dev # switch to branch named 'dev'
We can sometime create new branches in addition to 'master' to work concurrently on many features
Create new branch
git branch working  # create branch 'working' 
git checkout working # switch to branch named 'working'
git branch dev --track origin/dev # create local branch 'dev' that track the remote branch origin/dev
The current working branch is now 'working'

Delete branch - we can remove unused branch if it is no longer needed
git branch -d working # delete 'working' branch
Update from remote repository - e.g. wait until someone commit the patch to the main trunk then update changes from git://git.rubini.us/code
git pull will perform merge change on remote branch to local branch
git pull
git rebase will save local changes away, update from remote branch, and then reapply them
git rebase master 
Push change to remote repository
git push # push will update a --track branch in remote repository,
Edit source code - do some source code editing
gedit kernel/core/kernel.rb
Show modification - show what I have modify without committing change
git diff HEAD # HEAD is symbol for latest/head version of current branch
Revert back -when recognizing that there is something wrong, we can undo the modification, all changes are lost
git reset --hard HEAD
Edit source code - Do some source code editing again
gedit kernel/core/module.rb
Commit changes - commit change in current branch
git commit -a -s # vi editor will be popped up for entering committing message
Create patch - create patch containing changes between 2 branches local 'master' and remote 'origin/master'
git checkout master # switch to branch 'master'
git format-patch origin/master --stdout # to standard output
git format-patch origin/master -o ../patch # create formated patch as a file and store in directory ../patch
Create a ticket - goto in http://rubinius.lighthouseapp.com/m create a ticket and attach a patch file to it

Revert change - switch to branch named 'master' and revert back directory tree in original state, all changes are lost
git checkout master
git reset --hard HEAD 
Resolve conflict - if there is a conflict on file, git stop doing and ask for manually resolve, to inform that the conflict has been resolved on e.g. kernel/core/module.rb, use
gedit kernel/core/module.rb # after manually resolve conflict
git add kernel/core/module.rb # inform git that conflict on file kernel/core/module.rb is resolved
Apply patch
git-apply ../patch/0001-Fixes-for-Class-include-and-Class-extend-to-handle-c.patch
Apply patch partly - if a patch contains modification of multi files and there are conflict with some of them during patching, then use --reject option to modify only non-conflicted files and create filename.rej for those conflicted
git-apply --reject ../patch/0001-Fixes-for-Class-include-and-Class-extend-to-handle-c.patch 
Remove file from stage Making change into git repository actually happens in two steps, 1) add the new/modified file into stage area 2) commit stage area. If for some reason, we want to revert the step 1) we can do as follow
$git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached ..." to unstage)
#
# new file: dict_parser/tests/dict_tests.py
#
$ git rm --cached dict_parser/tests/dict_tests.py
rm 'dict_parser/tests/dict_tests.py'
$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
# dict_parser/
Git getting popular now when many open source projects moved from subversion to git, Zack Rusin has done very nice git cheat sheet summarizing git usage scenarios below

Friday, December 21, 2007

Saturday, November 24, 2007

Saturday, October 13, 2007

Useful unix tricks

link touseful unix tricks from Paul Gross
part 1
part 2

Tuesday, October 2, 2007

Sea Fish

This picture named 'Sea Fish' is from Le Ngoc Mai, my 8 year old daughter.

Tuesday, September 11, 2007

Friday, September 7, 2007

Calling Java from JRuby

Current JRuby is lack of detail documentation with regard to Java integration, so in certain cases it take me and my colleague a while to figure out how to do.
String to/from Java byte's array
In our recent application, we need to pass image from Ruby to image processing method written in Java. The Java method accept byte array and has result as byte array also. So we need convert Ruby String to Java byte[] and back.
The require 'java' add two methods to Ruby String class
String#to_java_bytes # instance method return Java byte[] 
String::from_java_bytes # class method return Ruby string from Java byte[]
The below code snippet demonstrate it.
require 'java'
include_class 'net.csetech.sq.image.ImageHelper'

File.open('duongpl.jpg') do |f|
  f.binmode
  @original = f.read
end

@reduced_j = ImageHelper.reduce_to_fix_size(@original.to_java_bytes,15000)
@reduced_r = String.from_java_bytes(@reduced_j)

File.open('duongpl-15k.jpg','w') do |f|
  f.binmode
  f.write(@reduced_r)
end
Ruby Array to Java Array
Other example, that we may need is to convert Ruby Array to Java Array. The require 'java' add method Array::to_java(Symbol), that convert Ruby Array to Java Array, where Symbol represent Java Class of the Array's elements. If it is omitted, the result is Java Object[].
['a','b'].to_array(:String) # return Java String[]
['a','b'].to_array # return java Object[]
More about method to_array is on JRuby Cookbook

Saturday, September 1, 2007