Ruby on Rails 中文博客聚合
博客聚合每天都定时收集来自其中的每个博客的当然信息,并整合发布,同时提供整合的RSS Feed,是结交朋友、切磋技术、了解Rails在国内应用和发展动态的好工具。如果您有使用博客阅读器(比如Google Reader,Blogline),可以在浏览器中直接订阅整合后的RSS Feed.
ROR ÕÐÆ¸ Î人
ÎÒÃÇÕýÔÚÕÐÆ¸³ÌÐòÔ±£¬µØµãÔÚÎ人¡£Çëµã»÷ÒÔÏÂÁ´½Ó¡£
ÎÒÃÇͬʱҲÌṩÅàѵµÄְλ¸øÓÐÓÃÆäËûÓïÑÔÍøÂ翪·¢¾ÑéµÄ³ÌÐòÔ±£¬Èç¹ûÄú¸ÐÐËȤÇë·¢¼òÀú¸øÎÒÃÇ¡£
¹ùÀò
tony spencer - aka notsleepy
http://www.tonyspencer.com/category/ruby-on-rails/
tony spencer - aka notsleepy,blog,about Ruby on Rails
http://www.tonyspencer.com/category/ruby-on-rails/
tony spencer - aka notsleepy,blog,about Ruby on Rails
Git服务器安装
Git on Ubuntu Server
安装Git-Core:
1
2
3
4
sudo apt-get update # 可选步骤
sudo apt-get dist-upgrade # 可选步骤
sudo apt-get install git-core
因为要用到 Gitosis ,所有,需要安装python setuptools
1
sudo apt-get install python-setuptools
安装 Gitosis
1
2
3
4
5
6
mkdir ~/src
cd ~/src
git clone git://eagain.net/gitosis
cd gitosis
sudo python setup.py install
增加名为Git的用户
1
sudo adduser --system --shell /bin/sh --gecos 'git version control' --group --disabled-password --home /home/git git
上传公钥到USER用户的根目录下(如果没有,用 ssh-keygen -t rsa 生成)
1
2
3
scp .ssh/id_rsa.pub USER@YOUR_SERVER:
sudo -H -u git gitosis-init < /home/USER/id_rsa.pub
sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update
到这一步,基本上都安装好了,到本地进行测试:
1
git clone git@YOUR_SERVER:gitosis-admin.git
成功后,在本地将有一个gitosis-admin目录,里面有gitosis.conf,keydir。
为Rails项目配置git
打开gitosis.conf,增加一块内容,members为某个用户的公钥~/.ssh/id_rsa.pub中的名字(在该文件的最后在)
1
2
3
[group myrailsapp]
members = vince@urbanpuddle
writable = myrailsapp
然后,提交修改
1
2
git commit -a -m "created a new repository"
git push
将本地代码提交到git中
1
2
cd myrailsapp
git init
创建 .gitignore 文件,用于忽略某些不需要进行代码管理的内容
1
2
3
4
5
.DS_Store
log/*.log
tmp/**/*
config/database.yml
db/*.sqlite3
提交代码
1
2
3
4
git remote add origin git@YOUR_SERVER:myrailsapp.git
git add .
git commit -a -m "initial import"
git push origin master:refs/heads/master
接下来,可以增加成员的公钥到系统中了
1
2
3
4
cd gitosis-admin
cp ~/alice.pub keydir/
cp ~/bob.pub keydir/
git add keydir/alice.pub keydir/bob.pub
修改gitosis.conf
1
2
3
4
[group myteam]
- members = jdoe
+ members = jdoe alice bob
writable = free_monkey
提交修改
1
2
git commit -a -m "Granted Alice and Bob commit rights to FreeMonkey"
git push
其它成员就可以获取代码了
1
git clone git@YOUR_SERVER:myrailsapp.git
请参考 Hosting Git repositories, The Easy (and Secure) Way
原文请参考 : http://enjoyrails.com/wikis/Git安装
Related posts:
- Git详解(一) 我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的: commit fa6f27b7de063c2f301b0e7148b5bd5e813faa98 tree 5e7a19c158b89fbc52a078771a833ee839727404 parent 76f31606376180ca88efa12be341dbb14fb06fdf 咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:...
- Git一分钟教程 流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器 取代码及修改全局设置 设置用户名与邮箱 git...
- Git详解(二) Git中级用法: Ignoring files 项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:...
Related posts brought to you by Yet Another Related Posts Plugin.
Git on Ubuntu Server
安装Git-Core:
1 2 3 4 | sudo apt-get update # 可选步骤 sudo apt-get dist-upgrade # 可选步骤 sudo apt-get install git-core |
因为要用到 Gitosis ,所有,需要安装python setuptools
1 | sudo apt-get install python-setuptools |
安装 Gitosis
1 2 3 4 5 6 | mkdir ~/src cd ~/src git clone git://eagain.net/gitosis cd gitosis sudo python setup.py install |
增加名为Git的用户
1 | sudo adduser --system --shell /bin/sh --gecos 'git version control' --group --disabled-password --home /home/git git |
上传公钥到USER用户的根目录下(如果没有,用 ssh-keygen -t rsa 生成)
1 2 3 | scp .ssh/id_rsa.pub USER@YOUR_SERVER: sudo -H -u git gitosis-init < /home/USER/id_rsa.pub sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update |
到这一步,基本上都安装好了,到本地进行测试:
1 | git clone git@YOUR_SERVER:gitosis-admin.git |
成功后,在本地将有一个gitosis-admin目录,里面有gitosis.conf,keydir。
为Rails项目配置git
打开gitosis.conf,增加一块内容,members为某个用户的公钥~/.ssh/id_rsa.pub中的名字(在该文件的最后在)
1 2 3 | [group myrailsapp] members = vince@urbanpuddle writable = myrailsapp |
然后,提交修改
1 2 | git commit -a -m "created a new repository" git push |
将本地代码提交到git中
1 2 | cd myrailsapp git init |
创建 .gitignore 文件,用于忽略某些不需要进行代码管理的内容
1 2 3 4 5 | .DS_Store log/*.log tmp/**/* config/database.yml db/*.sqlite3 |
提交代码
1 2 3 4 | git remote add origin git@YOUR_SERVER:myrailsapp.git git add . git commit -a -m "initial import" git push origin master:refs/heads/master |
接下来,可以增加成员的公钥到系统中了
1 2 3 4 | cd gitosis-admin cp ~/alice.pub keydir/ cp ~/bob.pub keydir/ git add keydir/alice.pub keydir/bob.pub |
修改gitosis.conf
1 2 3 4 | [group myteam] - members = jdoe + members = jdoe alice bob writable = free_monkey |
提交修改
1 2 | git commit -a -m "Granted Alice and Bob commit rights to FreeMonkey" git push |
其它成员就可以获取代码了
1 | git clone git@YOUR_SERVER:myrailsapp.git |
请参考 Hosting Git repositories, The Easy (and Secure) Way
原文请参考 : http://enjoyrails.com/wikis/Git安装
Related posts:
- Git详解(一) 我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的: commit fa6f27b7de063c2f301b0e7148b5bd5e813faa98 tree 5e7a19c158b89fbc52a078771a833ee839727404 parent 76f31606376180ca88efa12be341dbb14fb06fdf 咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:...
- Git一分钟教程 流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器 取代码及修改全局设置 设置用户名与邮箱 git...
- Git详解(二) Git中级用法: Ignoring files 项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:...
Related posts brought to you by Yet Another Related Posts Plugin.
Rails中检测SWF尺寸
安装:
1
2
cd vendor/plugins
svn export http://ruby-imagespec.googlecode.com/svn/trunk/ image_spec
使用:
1
2
3
4
image = ImageSpec::Dimensions.new('/path/to/your/file')
image.width
image.height
例子:
1
2
3
4
5
6
>> image = ImageSpec::Dimensions.new("#{RAILS_ROOT}/a.swf")
=> #<ImageSpec::Dimensions:0x2570d94 @height=670, @width=868>
>> image.width
=> 868
>> image.height
=> 670
Related posts:
- Rails应用添加配置的方法 方法一: 使用 app_config 插件 script/plugin install http://svn.jarmark.org/rails/app_config Rails::Initializer.run do |config|...
Related posts brought to you by Yet Another Related Posts Plugin.
安装:
1 2 | cd vendor/plugins svn export http://ruby-imagespec.googlecode.com/svn/trunk/ image_spec |
使用:
1 2 3 4 | image = ImageSpec::Dimensions.new('/path/to/your/file') image.width image.height |
例子:
1 2 3 4 5 6 | >> image = ImageSpec::Dimensions.new("#{RAILS_ROOT}/a.swf") => #<ImageSpec::Dimensions:0x2570d94 @height=670, @width=868> >> image.width => 868 >> image.height => 670 |
Related posts:
- Rails应用添加配置的方法 方法一: 使用 app_config 插件 script/plugin install http://svn.jarmark.org/rails/app_config Rails::Initializer.run do |config|...
Related posts brought to you by Yet Another Related Posts Plugin.
¼±ÎÊÌ⣡£¡£¡
ÎÒÏë°²×°rails±È½ÏµÍµÄ°æ±¾£¬¶ø²»ÏëÓÃgemÔÚÏß°²×°×îа汾£¬Ôõô°ì£¿
Áí£¬ÎÒÏÂÔØÁËInstantRails,µ«mysqlÈ´Æô¶¯²»ÁË£¬Ìáʾ´íÎó£ºUnexpected end of Mysql,Ôõ÷á°ì£¿
лл¸÷λ
页面调用flash文件之路径问题(IE)
今天发现一个很诡异的问题 :
页面调用一个swf文件(该文件在kecheng.example.net/courses 这个目录下),该swf文件内部as调用其他的swf文件(文件在其他的域名目录下,跟页面调用的那个swf文件不在同目录下),在ie下 第一次可以调用 刷新后无法调用。
(页面地址:http://kecheng.example.net/courses/flash_s/4)
调用代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
function show_flash(swf_url) {
var so = new SWFObject(swf_url,'aa','710','532','8','#ffffff');
so.addParam('allowscriptaccess','always');
so.addParam('wmode','transparent');
var base_url = swf_url.replace(/\/[^/]*$/, '/')
so.addParam('base', base_url);
so.addParam('allowfullscreen','true');
so.addVariable('width','710');
so.addVariable('height','532');
so.write('flash_viewer');
}
show_flash('');
查询adobe网站查到 有base这个属性 (官网地址)
base - . or [base directory] or [URL]. Specifies the base directory or URL used to resolve all relative path statements in the Flash Player movie. This attribute is helpful when your Flash Player movies are kept in a different directory from your other files.
这个属性可以指定as调用swf文件的相对路径的路径基准.
例如: a.swf文件处于 www.aa.com/kecheng 下,b1.swf、b2.swf 2个文件处于www.bb.com/kecheng 下其中b1.swf文件as代码调用b2.swf文件 。在www.aa.com/kecheng下的a.swf文件调用b1.swf文件 ,如果不加base这个属性的话 b1.swf是调用不到b2.swf这个文件的(因为b2.swf文件的路径已经变成www.aa.com/kecheng 了) 加上属性 就可以指定其相对路径的基准是www.bb.com/kecheng 这样就可以调用到b2.swf文件了。
但是在IE6.7下刷新页面后b2.swf文件就调用不到了 使用iewatch 发现页面刷新后b2.swf的路径已经变成www.aa.com/kecheng了,base属性在ie下失效了,但是删除ie临时文件又可以了,然后刷新又不可以了。
通过iewatch 观察后,发现可能是ie缓存的问题 ,就在调用地址上加了上一个随机数字
1
show_flash('?'+ Math.random());
问题解决。
此问题非常诡异,虽然解决了,但是更深层次的原因还是没弄明白,望哪位高手解释下!
No related posts.
今天发现一个很诡异的问题 :
页面调用一个swf文件(该文件在kecheng.example.net/courses 这个目录下),该swf文件内部as调用其他的swf文件(文件在其他的域名目录下,跟页面调用的那个swf文件不在同目录下),在ie下 第一次可以调用 刷新后无法调用。
(页面地址:http://kecheng.example.net/courses/flash_s/4)
调用代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function show_flash(swf_url) { var so = new SWFObject(swf_url,'aa','710','532','8','#ffffff'); so.addParam('allowscriptaccess','always'); so.addParam('wmode','transparent'); var base_url = swf_url.replace(/\/[^/]*$/, '/') so.addParam('base', base_url); so.addParam('allowfullscreen','true'); so.addVariable('width','710'); so.addVariable('height','532'); so.write('flash_viewer'); } show_flash(''); |
查询adobe网站查到 有base这个属性 (官网地址)
base - . or [base directory] or [URL]. Specifies the base directory or URL used to resolve all relative path statements in the Flash Player movie. This attribute is helpful when your Flash Player movies are kept in a different directory from your other files.
这个属性可以指定as调用swf文件的相对路径的路径基准.
例如: a.swf文件处于 www.aa.com/kecheng 下,b1.swf、b2.swf 2个文件处于www.bb.com/kecheng 下其中b1.swf文件as代码调用b2.swf文件 。在www.aa.com/kecheng下的a.swf文件调用b1.swf文件 ,如果不加base这个属性的话 b1.swf是调用不到b2.swf这个文件的(因为b2.swf文件的路径已经变成www.aa.com/kecheng 了) 加上属性 就可以指定其相对路径的基准是www.bb.com/kecheng 这样就可以调用到b2.swf文件了。
但是在IE6.7下刷新页面后b2.swf文件就调用不到了 使用iewatch 发现页面刷新后b2.swf的路径已经变成www.aa.com/kecheng了,base属性在ie下失效了,但是删除ie临时文件又可以了,然后刷新又不可以了。
通过iewatch 观察后,发现可能是ie缓存的问题 ,就在调用地址上加了上一个随机数字
1 | show_flash('?'+ Math.random()); |
问题解决。
此问题非常诡异,虽然解决了,但是更深层次的原因还是没弄明白,望哪位高手解释下!
No related posts.
Git一分钟教程
流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器
取代码及修改全局设置
设置用户名与邮箱
1
2
git config --global user.name "My Name"
git config --global user.email "my@email.com"
从已有的git库中提取代码
1
git clone git@server:app.git myrepo
每次更改代码的操作
更新本地代码到最新版本(需要merge才能合到本地代码中)
1
git fetch
合并更新后的代码到本地
1
git merge
更新代码方式的另一种方法(git pull是git fetch和git merge命令的一个组合)
1
git pull
修改代码后,查看已修改的内容
1
git diff --cached
将新增加文件加入到git中
1
git add file1 file2 file3
从git中删除文件
1
2
git rm file1
git rm -r dir1
提交修改
1
git commit -m 'this is memo'
如果想省掉提交之前的 git add 命令,可以直接用
1
git commit -a -m 'this is memo'
commit和commit -a的区别, commit -a相当于:
- 第一步:自动地add所有改动的代码,使得所有的开发代码都列于index file中
- 第二步:自动地删除那些在index file中但不在工作树中的文件
- 第三步:执行commit命令来提交
提交所有修改到远程服务器,这样,其它团队成员才能更新到这些修改
1
git push
其它常用命令
显示commit日志
1
git log
不仅显示commit日志,而且同时显示每次commit的代码改变。
1
git log -p
回滚代码:
1
git revert HEAD
你也可以revert更早的commit,例如:
1
git revert HEAD^
将branchname分支合并到当前分支中。(如果合并发生冲突,需要自己解决冲突)
1
git merge branchname
解决冲突
当merge命令自身无法解决冲突的时候,它会将工作树置于一种特殊的状态,并且给用户提供冲突信息,以期用户可以自己解决这些问题。当然在这个时候,未发生冲突的代码已经被git merge登记在了index file里了。如果你这个时候使用git diff,显示出来的只是发生冲突的代码信息。
在你解决了冲突之前,发生冲突的文件会一直在index file中被标记出来。这个时候,如果你使用git commit提交的话,git会提示:filename.txt needs merge
在发生冲突的时候,如果你使用git status命令,那么会显示出发生冲突的具体信息。
在你解决了冲突之后,你可以使用如下步骤来提交:
第一步(如果需要增加文件):
1
git add file1
第二步:
1
git commit
Related posts:
- Git详解(一) 我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的: commit fa6f27b7de063c2f301b0e7148b5bd5e813faa98 tree 5e7a19c158b89fbc52a078771a833ee839727404 parent 76f31606376180ca88efa12be341dbb14fb06fdf 咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:...
- Git详解(二) Git中级用法: Ignoring files 项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:...
- Git服务器安装 Git on Ubuntu Server 安装Git-Core: sudo apt-get update # 可选步骤...
Related posts brought to you by Yet Another Related Posts Plugin.
流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器
取代码及修改全局设置
设置用户名与邮箱
1 2 | git config --global user.name "My Name" git config --global user.email "my@email.com" |
从已有的git库中提取代码
1 | git clone git@server:app.git myrepo |
每次更改代码的操作
更新本地代码到最新版本(需要merge才能合到本地代码中)
1 | git fetch |
合并更新后的代码到本地
1 | git merge |
更新代码方式的另一种方法(git pull是git fetch和git merge命令的一个组合)
1 | git pull |
修改代码后,查看已修改的内容
1 | git diff --cached |
将新增加文件加入到git中
1 | git add file1 file2 file3 |
从git中删除文件
1 2 | git rm file1
git rm -r dir1 |
提交修改
1 | git commit -m 'this is memo' |
如果想省掉提交之前的 git add 命令,可以直接用
1 | git commit -a -m 'this is memo' |
commit和commit -a的区别, commit -a相当于:
- 第一步:自动地add所有改动的代码,使得所有的开发代码都列于index file中
- 第二步:自动地删除那些在index file中但不在工作树中的文件
- 第三步:执行commit命令来提交
提交所有修改到远程服务器,这样,其它团队成员才能更新到这些修改
1 | git push |
其它常用命令
显示commit日志
1 | git log |
不仅显示commit日志,而且同时显示每次commit的代码改变。
1 | git log -p |
回滚代码:
1 | git revert HEAD |
你也可以revert更早的commit,例如:
1 | git revert HEAD^ |
将branchname分支合并到当前分支中。(如果合并发生冲突,需要自己解决冲突)
1 | git merge branchname |
解决冲突
当merge命令自身无法解决冲突的时候,它会将工作树置于一种特殊的状态,并且给用户提供冲突信息,以期用户可以自己解决这些问题。当然在这个时候,未发生冲突的代码已经被git merge登记在了index file里了。如果你这个时候使用git diff,显示出来的只是发生冲突的代码信息。
在你解决了冲突之前,发生冲突的文件会一直在index file中被标记出来。这个时候,如果你使用git commit提交的话,git会提示:filename.txt needs merge
在发生冲突的时候,如果你使用git status命令,那么会显示出发生冲突的具体信息。
在你解决了冲突之后,你可以使用如下步骤来提交:
第一步(如果需要增加文件):
1 | git add file1 |
第二步:
1 | git commit |
Related posts:
- Git详解(一) 我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的: commit fa6f27b7de063c2f301b0e7148b5bd5e813faa98 tree 5e7a19c158b89fbc52a078771a833ee839727404 parent 76f31606376180ca88efa12be341dbb14fb06fdf 咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:...
- Git详解(二) Git中级用法: Ignoring files 项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:...
- Git服务器安装 Git on Ubuntu Server 安装Git-Core: sudo apt-get update # 可选步骤...
Related posts brought to you by Yet Another Related Posts Plugin.
ɽ¶«Ê¡´ú¿ª·þÎñÒµÒµÓéÀÖÒµÎÄ»¯ÌåÓýҵͨÓ÷¢Æ±13313197276ÁÖС½ã
ÎÒ˾¿ÉÒÔΪÆäËûµ¥Î»£¨¹«Ë¾£©¹©Ó¦£ºÓà¶î·¢/ƱÏêÇéÈçÏ£ºÒòϸڷöÖ²µÄ˰ÊÕÕþ²ß£¬¼ÓÉϽøÏî½Ï¶àÍê³É²»ÁËÿÔ¶¨Ë°¶î¶È,±¾¹«Ë¾ÏÖÓÐÓà¶î·¢.Ʊ£¬±¾¹«Ë¾Óë¶à¼Ò¹«Ë¾£¨ÆóÒµ£©ÓÐÒµÎñÍùÀ´£¬¿É¸ù¾Ý¿Í»§ÔÚ¡°»¥»Ý»¥Àû¡± µÄºÏ×÷»ù´¡ÉÏΪ¿Í»§(´ú¡£¿ª·¢Æ±)£¡
¹óÆóÒµ(¹«Ë¾)ÈôÓÐÒÔÏÂÇé¿öÇëÀ´µçÁª
´úÀí³ö¿ÚºËÏúµ¥´úÀí³ö¿ÚÊÕ»ãºËÏúµ¥13313197276ÁÖС½ã
ÉîÛÚ´úÀí±¨¹Ø³ö¿ÚºËÏúµ¥²úµØÖ¤13313197276ÁÖС½ã ,ÉîÛÚÊкãͨóÒ×ÓÐÏÞ¹«Ë¾ ºÏ×÷ÏîÄ¿£º ÌṩºËÏúµ¥µ½È«¹ú¸÷¸Û¿Ú±¨¹Ø ÎÒÃÇÉîÛÚ½ø³ö¿Ú¹«Ë¾¿ÉÒÔÔÚÍâ¹Ü¾ÖÁì³öµÄºËÏúµ¥Ô¶Ô¶³¬³öÁ˳ö¿ÚµÄÓÃÁ¿£¬ÉîÛÚ½øÍâ»ãÓв¹ÌùÏà¶Ô¶øÑԱȽÏÓŻݡ£ÖÁÓÚ¶àÓàºËÏúµ¥£¬ÎÒÃÇÒÑ¾È«ÃæÏòÆäËü¸Û¿Ú£¨Ìì½ò¡¢±±¾
ɽ¶«Ê¡´ú¿ª·þÎñÒµÒµÓéÀÖÒµÎÄ»¯ÌåÓýҵͨÓ÷¢Æ±13313197276ÁÖС½ã
ÎÒ˾¿ÉÒÔΪÆäËûµ¥Î»£¨¹«Ë¾£©¹©Ó¦£ºÓà¶î·¢/ƱÏêÇéÈçÏ£ºÒòϸڷöÖ²µÄ˰ÊÕÕþ²ß£¬¼ÓÉϽøÏî½Ï¶àÍê³É²»ÁËÿÔ¶¨Ë°¶î¶È,±¾¹«Ë¾ÏÖÓÐÓà¶î·¢.Ʊ£¬±¾¹«Ë¾Óë¶à¼Ò¹«Ë¾£¨ÆóÒµ£©ÓÐÒµÎñÍùÀ´£¬¿É¸ù¾Ý¿Í»§ÔÚ¡°»¥»Ý»¥Àû¡± µÄºÏ×÷»ù´¡ÉÏΪ¿Í»§(´ú¡£¿ª·¢Æ±)£¡
¹óÆóÒµ(¹«Ë¾)ÈôÓÐÒÔÏÂÇé¿öÇëÀ´µçÁª
API的查询
在开发的时候经常要用得着这东西
相对于google baidu这种解决问题的搜索方法
查API可能更有效一些
rails api
http://api.rubyonrails.org/
http://www.railsbrain.com
ruby api
http://www.ruby-doc.org/core/
在开发的时候经常要用得着这东西
相对于google baidu这种解决问题的搜索方法
查API可能更有效一些
rails api
http://api.rubyonrails.org/
http://www.railsbrain.com
ruby api
http://www.ruby-doc.org/core/
打造Blog-10:has_many更好一些
has_and_belongs_to_many在其中一表删除数据后
关系表中对应项不会自动删除
这样会遗留很多不可用数据
但是用has_many加:dependent => :destroy
就能解决这一些问题
class Blog < ActiveRecord::Base
has_many :comments
has_many :blogs_tagss,:dependent => :destroy # BlogsTags
has_many :tags,:through => :blogs_tagss
end
class Tag < ActiveRecord::Base
has_many :blogs_tagss,:dependent => :destroy # BlogsTags
has_many :blogs,:through => :blogs_tagss
end
class BlogsTags < ActiveRecord::Base
belongs_to :blog
belongs_to :tag
end
has_and_belongs_to_many在其中一表删除数据后
关系表中对应项不会自动删除
这样会遗留很多不可用数据
但是用has_many加:dependent => :destroy
就能解决这一些问题
class Blog < ActiveRecord::Base
has_many :comments
has_many :blogs_tagss,:dependent => :destroy # BlogsTags
has_many :tags,:through => :blogs_tagss
end
class Tag < ActiveRecord::Base
has_many :blogs_tagss,:dependent => :destroy # BlogsTags
has_many :blogs,:through => :blogs_tagss
end
class BlogsTags < ActiveRecord::Base
belongs_to :blog
belongs_to :tag
end
打造Blog-9:多对多关系创建Tags标签2
然后创建控制器tags
class TagsController < ApplicationController
def show
@blogs = Tag.find(params[:id]).blogs
respond_to do |format|
format.html{render :template => "blogs/index",:object => @blogs }
end
end
end
然后修改blogs/index.html.erb里的render项 加上"blogs"
把will_paginate项删除 或再对其进行处理下
运行能显示对应Tag的所有blogs项即可
之后请大家自己在对应地方加上Tags的连接
然后创建控制器tags
class TagsController < ApplicationController
def show
@blogs = Tag.find(params[:id]).blogs
respond_to do |format|
format.html{render :template => "blogs/index",:object => @blogs }
end
end
end
然后修改blogs/index.html.erb里的render项 加上"blogs"
把will_paginate项删除 或再对其进行处理下
运行能显示对应Tag的所有blogs项即可
之后请大家自己在对应地方加上Tags的连接
打造Blog-8:多对多关系创建Tags标签1
首先生成两个model
Tag name:string
BlogsTags blog_id:integer tag_id:integer
然后在模型
blog.rb加入
has_and_belongs_to_many :tags
tag.rb加入
has_and_belongs_to_many :blogs
然后进入控制台测试
首先生成两个model
Tag name:string
BlogsTags blog_id:integer tag_id:integer
然后在模型
blog.rb加入
has_and_belongs_to_many :tags
tag.rb加入
has_and_belongs_to_many :blogs
然后进入控制台测试
央视网首页布局
上 CCAV 网站查看今天 NBA 直播时间,央视网飘出一个友情提示:

非常“友好”,就是根本让人闹不明白“恢复初始”和“暂不恢复”是什么意思。符合 CCAV 一贯作风。
上 CCAV 网站查看今天 NBA 直播时间,央视网飘出一个友情提示:

非常“友好”,就是根本让人闹不明白“恢复初始”和“暂不恢复”是什么意思。符合 CCAV 一贯作风。
Git详解(一)
我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的:
commit fa6f27b7de063c2f301b0e7148b5bd5e813faa98
tree 5e7a19c158b89fbc52a078771a833ee839727404
parent 76f31606376180ca88efa12be341dbb14fb06fdf
咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:
Git通过简单比较object name就可以快速的确定这两个对象是否相等。
因为object name在每个repository里都是以相同的方法来计算的,所以在不同的两个repository的同一个内容都会被存储在相同的object name下。
Git可以在读取对象的时候检查错误,检查该对象的名称是否还是它的内容的SHA1 hash。
The Objects
每个对象都由三个东东组成:type,size,content。size当然是content的size了,而content却是依赖于这个对象是个什么type了。而type又有四类:“blob”,”tree”, “commit”, “tag”。
blob - 通常被用来存储文件数据,一般是个文件。
tree - 基本上像个目录结构,比如x / yyy
commit - 它指向一个单独的tree,它标记了一个时刻的项目的面貌,就像给这个project照了个艳照一样。它包含那个时刻的元信息,例如时间戳,改变本次提交的作者,前一个提交的指向标等等。
tag - 专门用来指定某些特殊行为的commits。
和svn的不同是?
传统的SCM系统,比如svn,CVS, perforce, Mercuial等,它们存储的都是本次和下次提交的differents。 而Git不同,这是关键的一点。Git就像一个狗仔队的记者一样,把你项目的所有文件以及每次提交时候的tree 结构都拍了个照, 把这个照片存储下来而已。这点对于理解Git来说,相当重要!
Blob Object
刚才说了,这是指文件数据。
git show 命令可以帮助你看type,具体用法可以参照(http://www.kernel.org/pub/software/scm/git/docs/git-show.html)例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
git show
commit cf70117f3cc497fba42890171d29ae404061d25f
Author: Alex <blackanger.z@gmail.com>
Date: Sun Dec 7 05:55:46 2008 +0800
modify .gitignore
diff --git a/.gitignore b/.gitignore
index deb5b7c..77573ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-log/
+/log
.DS_Store
因为blob是由它的数据决定的实体,如果在目录tree里有两个内容相同的blob,那么它们就会共享同一个blob对象。该对象是完全独立于它在目录tree里的位置的,并且你重命名文件的话也不会改变与这个文件相关联的那个blob对象。
Tree Object
这是个简单的对象,它就是指向一堆blob对象和其他的tree目录。它一般表现的是目录和子目录的内容。你用git ls-tree命令可以把tree 对象看的更详细。例如:
git ls-tree cf701
100644 blob 77573ab40c4f010c0e050f1bbff2ad3ab78f1428 .gitignore
100644 blob f8cd794a2d06e6c409737d5bcd39a20abb62db26 README
100644 blob 3bb0e8592a41ae3185ee32266c860714980dbed7 Rakefile
040000 tree ee99c7a2e9842acbab05fcd02ec510ea917218b2 app
040000 tree 0aff84690f37df01a7cac96529657222cbeeebf6 config
040000 tree 92aaeee021e9c7da661bac141ab55c17a3ae79ee db
040000 tree 0269300738b048a5cc34769d1436d9f228499018 doc
040000 tree 1e384157d8bc3cd7aab5b0b5605e9a78d0612426 features
040000 tree 9f87e761776449b7d43ea112573f8ae27faaf826 lib
040000 tree 4875662d9a7e07a7b95b68958e518fdd65235124 public
040000 tree 11741373949f86364c10af17db764d1af3bc048f script
040000 tree 20433690c23ae3a299b5a02147f68fdf94820370 spec
040000 tree 646d8b1458d23ba0ec396ef5748205977b023f3f stories
040000 tree cc48cdef8eba2b5333c6a01d5795bb6efb43182f test
040000 tree e85767f4716fd20a53d7d6455972c6ec6571c833 vendor
cf701.。。是上一个tree对象,是整个app的tree对象,熟悉Rails的人就可以看得出来这个tree目录。
请注意这些文件到mode为644或755,以保证git执行时候有足够到权限。
Commit Object
你可以用git show或git log加–pretty=raw参数来检查你的提交,例如:
1
2
3
4
5
6
7
8
git show -s --pretty=raw cf701
commit cf70117f3cc497fba42890171d29ae404061d25f
tree 6ccb7edcdb14205861feb263a7607b8921c75fa3
parent 3e794f3e4dcb8d362bfb11464c849070bd04a35f
author Alex <blackanger.z@gmail.com> 1228600546 +0800
committer Alex <blackanger.z@gmail.com> 1228600546 +0800
modify .gitignore
看见没有?
有个parent, 这基本上是每个commit都有的,但是当一个commit没有parent的时候,那么就叫root commit,这是初始化工程第一次提交才有的。每个project必然会有一个root commit,有的有多个root commit,不过很少见(project 套project ?)。
author是这次提交的人。
committer实际创建这次提交的人,它和author有可能不同,例如,我写的代码发email给你,你帮我commit的,但实际author并不是你,对不?
comment是对这次提交的描述。这里没有我不知道为什么 。。。
Tag Object
到这里可以看到如何创建和验证一个object对象。
http://www.kernel.org/pub/software/scm/git/docs/git-tag.html
Git Directory and Working Directory
1. The Git Directory
git directory是存储你工程所有Git历史和元信息的目录。包括所有的对象,所有到不同分支的指向。
每个project仅有一个git directory。这个目录就是你工程根目录下的那个.git。例如:
1
2
3
4
cd .git
~/work/mars/.git>ls
COMMIT_EDITMSG branches description index logs refs
HEAD config hooks info objects
2.The Working Directory
工作目录自然就是你当前检出文件的目录了,大白话就是项目的目录,你要在这里面工作的。。。
The Git Index
如果把你当前修改过的这些文件比作是你从你的部队你精选出来的突击队的话,把commit比作深入敌后的话,那么这个git index就是你这支突击队在深入敌后之前的排练场,你需要在这里点兵,看看有没有怕死的逃兵漏掉。因为你要提交的只是你修改的文件,而不是全部文件,所有你只需要有一个修改文件集合就可以了。
用这个命令来看:
1
2
3
git status
# On branch master
nothing to commit (working directory clean)
我距离上次提交没有改动过任何文件,自然不会出现什么文件列表了。我无耻的抄个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$git status
# On branch master
# Your branch is behind 'origin/master' by 11 commits, and can be fast-forwarded.
#
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: daemon.c
#
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: grep.c
# modified: grep.h
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# blametree
# blametree-init
# git-gui/git-citool
用过svn的人也很容易懂把。
Setup and Initialization
安装就不说了,用mac或linux的人都会安装,用windows的人我只能无耻的抄一句别人的话来骂你:
who fucking need to run a separate software just for using git。
Git Config
1
2
3
4
5
6
7
8
$ git config --global user.name "Alex Zhang"
$ git config --global user.email “blackanger.z@gmail.com"
然后你
vi ~/.gitconfig
就会看到:
[user]
name = Alex Zhang
email = blackanger.z@gmail.com
如果你想为指定的项目用别的git 配置,那么你可以使用git config命令来修改你的信息,不需要加--global参数。
Getting a Git Repository
那么现在我需要一个Git仓库了。怎么办?
两个办法:
克隆一个已经存在的。
初始化一个新的。
如果你要clone的话,你需要知道一个project的git url。git操作跨越多个协议,例如:
git url : git clone git://git.kernel.org/pub/scm/git/git.git
或者
http : git clone http://www.kernel.org/pub/scm/git/git.git
请记住git:// 协议是更快的。但是当你有防火墙或其他原因的时候,还得用http。
Initializing a New Repository
假如你有个工程叫project,那么:
1
2
3
4
cd project
git init
则会输出:
Initialized empty Git repository in .git/
你可以去这里看git的视频:
http://www.gitcasts.com/
Normal Workflow
一般的工作流程就是:
1.增加一些新的文件
$ git add file1 file2 file3 把新文件加到git index里。
2. git diff –cached
你可能需要显示你刚add到git index里的那些改变。如果没有--cached,那么就不会显示刚add到index的改变。 你也可以用git status来看。
git commit 你可能需要提交了。
git commit -a 把新近的改变加到index里顺便提交。
为每次commit写message是最佳实践。
svn或其他的版本控制工具也有add方法,它们只是把新加的文件加到index里来跟踪。但是git的add更加强大, git add,不仅仅是增加新文件到index里,还包括最新的修改。
Basic Branching and Merging
一个单一的git仓库就可以提供多个分支给开发者。创建一个新的分支:
1
2
3
4
5
git branch experimental
<pre lang="bash" line="1">
如果你现在运行:
<pre lang="bash" line="1">
git branch
你就会得到一个所有分支的列表。
1
2
experimental
* master
experimenta是刚刚创建的那个,那个master是默认的分支。星号标识的是你当前所处的分支。
1
git checkout experimental
来选择那个experimental的分支内容。如果修改了一个文件,commit这个改变,并且选择回到master 分支:
(edit file)
1
2
$ git commit -a
git branch
输出
1
2
* experimental
master
1
2
$ git checkout master
git branch
输出:
1
2
experimental
master
然后你这master分支里做了一个不同的改变,然后提交。 那么现在master和experimental这两分支里都有了不同的修改,那么我们来合并这些不同:
git merge experimental
注意,你现在是这master里,把其他分支的不同合并到master里来。
如果没有冲突还好,那么有冲突怎么办?
git diff 呀
查看不同,然后解决冲突,再提交一次。
命令行里输入:
gitk
会出来一个x-windows工具,很挫的,截图给大家看,太难看,github上有个好看的工具介绍,我忘了名字了。
来看看如何解决冲突:
1
2
3
4
5
$ git merge next
100% (4/4) done
Auto-merged file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.
merge的时候有冲突,会有警告信息,这可真墨迹。
git status来看冲突的地方:
<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
那么你需要编辑文件来解决冲突,然后:
1
2
$ git add file.txt
$ git commit
具体可以看gitcasts的视频六:GitCast #6: Branching and Merging
查看历史:
git log 版本号
加各种参数可以让log格式化输入便于阅读。
以上都是简单的情况。 大体命令都去查文档吧。
Distributed Workflows
麻烦的情况怎么处理呢?
Alice有个新的工程,存储这一个git仓库:/home/alice/project, 但是Bob,在同一台机器上也有一个home目录。
Bob:
1
$ git clone /home/alice/project myrepo
创建了一个新的project,叫myrepo。
Bob修改了一些文件,然后提交它们:
(edit files)
1
2
$ git commit -a
(repeat as necessary)
当他准备好以后,他告诉Alice去更新这些改变从他的项目里:/home/bob/myrepo
那么Alice她是这么做的:
1
2
$ cd /home/alice/project
$ git pull /home/bob/myrepo master (此命令,master参数不是必须的)
这个操作把bob的master分支合并到了Alice的当前的master分支里。但是如果此时Alice有自己的改变,有可能会出现冲突。因此pull命令是两个操作:
从远程分支取一些改变。
merge到本地当前分支。
为了避免这种麻烦,我们可以这么做:
1
$ git remote add bob /home/bob/myrepo
然后先取回来bob的修改,但是并不去merge
1
$ git fetch bob
然后看看日志:
1
$ git log -p master..bob/master
然后就会显示bob的所有改变,再检查完这些改变以后,Alice就可以合并这些改变到她的分支里了:
1
$ git merge bob/master
这一步也可以这么做:
1
$ git pull . remotes/bob/master
之后, Bob更新Alice最新的改变就可以用:
1
$ git pull
没有alice的路径是因为,是bob clone的alice的代码。你可以用这个命令查看:
1
2
$ git config --get remote.origin.url
/home/alice/project
Git也可以做一份Alice master分支的原始拷贝在“origin/master”下:
1
$ git branch -r
输出
origin/master
Public git repositories
使用一个公共的仓库,这是通用的做法,这样可以把一些私有的工作过程清晰的和版本库清晰的分离出来。你只需要在你私人的仓库里完成你的工作,然后把你做的改变提交到你的那个公共仓库里,别的开发者可以从你的公共仓库里更新代码。同样,别的开发者push他的改变到他的公共仓库,你从他的公共仓库获取更新。
you push
your personal repo ——————> your public repo
^ |
| |
| you pull | they pull
| |
| |
| they push V
their public repo <——————- their repo
Pushing changes to a public repository
1
2
3
$ git push ssh://yourserver.com/~you/proj.git master:master
或者是
$ git push ssh://yourserver.com/~you/proj.git master
当然你可以设置.git/config:
$ cat >>.git/config <<EOF
[remote "public-repo"]
url = ssh://yourserver.com/~you/proj.git
EOF
这样你就可以使用命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ git push public-repo master
</pr>
以GitHub为例子, 保存在github上的一个项目, 我查看它的config:
[remote "origin"]
url = git@github.com:blackanger/mars.git
fetch = +refs/heads/*:refs/remotes/origin/*
这样,我每次往github push代码就是用命令:
git push origin master
详细的可以去看 www.gitcasts.com
<em><strong>Git Tag</strong></em>
1.Lightweight Tags
~/work/mars>git tag stable-1 cf701
~/work/mars>git show stable-1
commit cf70117f3cc497fba42890171d29ae404061d25f
Author: Alex <blackanger.z@gmail.com>
Date: Sun Dec 7 05:55:46 2008 +0800
modify .gitignore
。。。
使用tag和一个object关联起来。这是创建一个轻量级的tag。
Tag Objects
如果加上-a,-s或-u <key-id>参数,则是创建一个tag对象。
<pre lang="bash" line="1">
$ git tag -a stable-1 1b2e1d63ff
Related posts:
- Git服务器安装 Git on Ubuntu Server 安装Git-Core: sudo apt-get update # 可选步骤...
- Git详解(二) Git中级用法: Ignoring files 项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:...
- Git一分钟教程 流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器 取代码及修改全局设置 设置用户名与邮箱 git...
Related posts brought to you by Yet Another Related Posts Plugin.
我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的:
commit fa6f27b7de063c2f301b0e7148b5bd5e813faa98
tree 5e7a19c158b89fbc52a078771a833ee839727404
parent 76f31606376180ca88efa12be341dbb14fb06fdf
咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:
Git通过简单比较object name就可以快速的确定这两个对象是否相等。
因为object name在每个repository里都是以相同的方法来计算的,所以在不同的两个repository的同一个内容都会被存储在相同的object name下。
Git可以在读取对象的时候检查错误,检查该对象的名称是否还是它的内容的SHA1 hash。
The Objects
每个对象都由三个东东组成:type,size,content。size当然是content的size了,而content却是依赖于这个对象是个什么type了。而type又有四类:“blob”,”tree”, “commit”, “tag”。
blob - 通常被用来存储文件数据,一般是个文件。
tree - 基本上像个目录结构,比如x / yyy
commit - 它指向一个单独的tree,它标记了一个时刻的项目的面貌,就像给这个project照了个艳照一样。它包含那个时刻的元信息,例如时间戳,改变本次提交的作者,前一个提交的指向标等等。
tag - 专门用来指定某些特殊行为的commits。
和svn的不同是?
传统的SCM系统,比如svn,CVS, perforce, Mercuial等,它们存储的都是本次和下次提交的differents。 而Git不同,这是关键的一点。Git就像一个狗仔队的记者一样,把你项目的所有文件以及每次提交时候的tree 结构都拍了个照, 把这个照片存储下来而已。这点对于理解Git来说,相当重要!
Blob Object
刚才说了,这是指文件数据。
git show 命令可以帮助你看type,具体用法可以参照(http://www.kernel.org/pub/software/scm/git/docs/git-show.html)例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | git show commit cf70117f3cc497fba42890171d29ae404061d25f Author: Alex <blackanger.z@gmail.com> Date: Sun Dec 7 05:55:46 2008 +0800 modify .gitignore diff --git a/.gitignore b/.gitignore index deb5b7c..77573ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -log/ +/log .DS_Store |
因为blob是由它的数据决定的实体,如果在目录tree里有两个内容相同的blob,那么它们就会共享同一个blob对象。该对象是完全独立于它在目录tree里的位置的,并且你重命名文件的话也不会改变与这个文件相关联的那个blob对象。
Tree Object
这是个简单的对象,它就是指向一堆blob对象和其他的tree目录。它一般表现的是目录和子目录的内容。你用git ls-tree命令可以把tree 对象看的更详细。例如:
git ls-tree cf701
100644 blob 77573ab40c4f010c0e050f1bbff2ad3ab78f1428 .gitignore
100644 blob f8cd794a2d06e6c409737d5bcd39a20abb62db26 README
100644 blob 3bb0e8592a41ae3185ee32266c860714980dbed7 Rakefile
040000 tree ee99c7a2e9842acbab05fcd02ec510ea917218b2 app
040000 tree 0aff84690f37df01a7cac96529657222cbeeebf6 config
040000 tree 92aaeee021e9c7da661bac141ab55c17a3ae79ee db
040000 tree 0269300738b048a5cc34769d1436d9f228499018 doc
040000 tree 1e384157d8bc3cd7aab5b0b5605e9a78d0612426 features
040000 tree 9f87e761776449b7d43ea112573f8ae27faaf826 lib
040000 tree 4875662d9a7e07a7b95b68958e518fdd65235124 public
040000 tree 11741373949f86364c10af17db764d1af3bc048f script
040000 tree 20433690c23ae3a299b5a02147f68fdf94820370 spec
040000 tree 646d8b1458d23ba0ec396ef5748205977b023f3f stories
040000 tree cc48cdef8eba2b5333c6a01d5795bb6efb43182f test
040000 tree e85767f4716fd20a53d7d6455972c6ec6571c833 vendor
cf701.。。是上一个tree对象,是整个app的tree对象,熟悉Rails的人就可以看得出来这个tree目录。
请注意这些文件到mode为644或755,以保证git执行时候有足够到权限。
Commit Object
你可以用git show或git log加–pretty=raw参数来检查你的提交,例如:
1 2 3 4 5 6 7 8 | git show -s --pretty=raw cf701 commit cf70117f3cc497fba42890171d29ae404061d25f tree 6ccb7edcdb14205861feb263a7607b8921c75fa3 parent 3e794f3e4dcb8d362bfb11464c849070bd04a35f author Alex <blackanger.z@gmail.com> 1228600546 +0800 committer Alex <blackanger.z@gmail.com> 1228600546 +0800 modify .gitignore |
看见没有?
有个parent, 这基本上是每个commit都有的,但是当一个commit没有parent的时候,那么就叫root commit,这是初始化工程第一次提交才有的。每个project必然会有一个root commit,有的有多个root commit,不过很少见(project 套project ?)。
author是这次提交的人。
committer实际创建这次提交的人,它和author有可能不同,例如,我写的代码发email给你,你帮我commit的,但实际author并不是你,对不?
comment是对这次提交的描述。这里没有我不知道为什么 。。。
Tag Object
到这里可以看到如何创建和验证一个object对象。
http://www.kernel.org/pub/software/scm/git/docs/git-tag.html
Git Directory and Working Directory
1. The Git Directory
git directory是存储你工程所有Git历史和元信息的目录。包括所有的对象,所有到不同分支的指向。
每个project仅有一个git directory。这个目录就是你工程根目录下的那个.git。例如:
1 2 3 4 | cd .git ~/work/mars/.git>ls COMMIT_EDITMSG branches description index logs refs HEAD config hooks info objects |
2.The Working Directory
工作目录自然就是你当前检出文件的目录了,大白话就是项目的目录,你要在这里面工作的。。。
The Git Index
如果把你当前修改过的这些文件比作是你从你的部队你精选出来的突击队的话,把commit比作深入敌后的话,那么这个git index就是你这支突击队在深入敌后之前的排练场,你需要在这里点兵,看看有没有怕死的逃兵漏掉。因为你要提交的只是你修改的文件,而不是全部文件,所有你只需要有一个修改文件集合就可以了。
用这个命令来看:
1 2 3 | git status # On branch master nothing to commit (working directory clean) |
我距离上次提交没有改动过任何文件,自然不会出现什么文件列表了。我无耻的抄个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $git status # On branch master # Your branch is behind 'origin/master' by 11 commits, and can be fast-forwarded. # # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: daemon.c # # Changed but not updated: # (use "git add <file>..." to update what will be committed) # # modified: grep.c # modified: grep.h # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # blametree # blametree-init # git-gui/git-citool |
用过svn的人也很容易懂把。
Setup and Initialization
安装就不说了,用mac或linux的人都会安装,用windows的人我只能无耻的抄一句别人的话来骂你:
who fucking need to run a separate software just for using git。
Git Config
1 2 3 4 5 6 7 8 | $ git config --global user.name "Alex Zhang" $ git config --global user.email “blackanger.z@gmail.com" 然后你 vi ~/.gitconfig 就会看到: [user] name = Alex Zhang email = blackanger.z@gmail.com |
如果你想为指定的项目用别的git 配置,那么你可以使用git config命令来修改你的信息,不需要加--global参数。
Getting a Git Repository
那么现在我需要一个Git仓库了。怎么办?
两个办法:
克隆一个已经存在的。
初始化一个新的。
如果你要clone的话,你需要知道一个project的git url。git操作跨越多个协议,例如:
git url : git clone git://git.kernel.org/pub/scm/git/git.git
或者
http : git clone http://www.kernel.org/pub/scm/git/git.git
请记住git:// 协议是更快的。但是当你有防火墙或其他原因的时候,还得用http。
Initializing a New Repository
假如你有个工程叫project,那么:
1 2 3 4 | cd project git init 则会输出: Initialized empty Git repository in .git/ |
你可以去这里看git的视频:
http://www.gitcasts.com/
Normal Workflow
一般的工作流程就是:
1.增加一些新的文件
$ git add file1 file2 file3 把新文件加到git index里。
2. git diff –cached
你可能需要显示你刚add到git index里的那些改变。如果没有--cached,那么就不会显示刚add到index的改变。 你也可以用git status来看。
git commit 你可能需要提交了。
git commit -a 把新近的改变加到index里顺便提交。
为每次commit写message是最佳实践。
svn或其他的版本控制工具也有add方法,它们只是把新加的文件加到index里来跟踪。但是git的add更加强大, git add,不仅仅是增加新文件到index里,还包括最新的修改。
Basic Branching and Merging
一个单一的git仓库就可以提供多个分支给开发者。创建一个新的分支:
1 2 3 4 5 | git branch experimental <pre lang="bash" line="1"> 如果你现在运行: <pre lang="bash" line="1"> git branch |
你就会得到一个所有分支的列表。
1 2 | experimental
* master |
experimenta是刚刚创建的那个,那个master是默认的分支。星号标识的是你当前所处的分支。
1 | git checkout experimental |
来选择那个experimental的分支内容。如果修改了一个文件,commit这个改变,并且选择回到master 分支:
(edit file)
1 2 | $ git commit -a
git branch |
输出
1 2 | * experimental
master |
1 2 | $ git checkout master git branch |
输出:
1 2 | experimental master |
然后你这master分支里做了一个不同的改变,然后提交。 那么现在master和experimental这两分支里都有了不同的修改,那么我们来合并这些不同:
git merge experimental
注意,你现在是这master里,把其他分支的不同合并到master里来。
如果没有冲突还好,那么有冲突怎么办?
git diff 呀
查看不同,然后解决冲突,再提交一次。
命令行里输入:
gitk
会出来一个x-windows工具,很挫的,截图给大家看,太难看,github上有个好看的工具介绍,我忘了名字了。
来看看如何解决冲突:
1 2 3 4 5 | $ git merge next 100% (4/4) done Auto-merged file.txt CONFLICT (content): Merge conflict in file.txt Automatic merge failed; fix conflicts and then commit the result. |
merge的时候有冲突,会有警告信息,这可真墨迹。
git status来看冲突的地方:
<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
那么你需要编辑文件来解决冲突,然后:
1 2 | $ git add file.txt $ git commit |
具体可以看gitcasts的视频六:GitCast #6: Branching and Merging
查看历史:
git log 版本号
加各种参数可以让log格式化输入便于阅读。
以上都是简单的情况。 大体命令都去查文档吧。
Distributed Workflows
麻烦的情况怎么处理呢?
Alice有个新的工程,存储这一个git仓库:/home/alice/project, 但是Bob,在同一台机器上也有一个home目录。
Bob:
1 | $ git clone /home/alice/project myrepo |
创建了一个新的project,叫myrepo。
Bob修改了一些文件,然后提交它们:
(edit files)
1 2 | $ git commit -a (repeat as necessary) |
当他准备好以后,他告诉Alice去更新这些改变从他的项目里:/home/bob/myrepo
那么Alice她是这么做的:
1 2 | $ cd /home/alice/project $ git pull /home/bob/myrepo master (此命令,master参数不是必须的) |
这个操作把bob的master分支合并到了Alice的当前的master分支里。但是如果此时Alice有自己的改变,有可能会出现冲突。因此pull命令是两个操作:
从远程分支取一些改变。
merge到本地当前分支。
为了避免这种麻烦,我们可以这么做:
1 | $ git remote add bob /home/bob/myrepo |
然后先取回来bob的修改,但是并不去merge
1 | $ git fetch bob |
然后看看日志:
1 | $ git log -p master..bob/master |
然后就会显示bob的所有改变,再检查完这些改变以后,Alice就可以合并这些改变到她的分支里了:
1 | $ git merge bob/master |
这一步也可以这么做:
1 | $ git pull . remotes/bob/master |
之后, Bob更新Alice最新的改变就可以用:
1 | $ git pull |
没有alice的路径是因为,是bob clone的alice的代码。你可以用这个命令查看:
1 2 | $ git config --get remote.origin.url /home/alice/project |
Git也可以做一份Alice master分支的原始拷贝在“origin/master”下:
1 | $ git branch -r |
输出
origin/master
Public git repositories
使用一个公共的仓库,这是通用的做法,这样可以把一些私有的工作过程清晰的和版本库清晰的分离出来。你只需要在你私人的仓库里完成你的工作,然后把你做的改变提交到你的那个公共仓库里,别的开发者可以从你的公共仓库里更新代码。同样,别的开发者push他的改变到他的公共仓库,你从他的公共仓库获取更新。
you push
your personal repo ——————> your public repo
^ |
| |
| you pull | they pull
| |
| |
| they push V
their public repo <——————- their repo
Pushing changes to a public repository
1 2 3 | $ git push ssh://yourserver.com/~you/proj.git master:master 或者是 $ git push ssh://yourserver.com/~you/proj.git master |
当然你可以设置.git/config:
$ cat >>.git/config <<EOF
[remote "public-repo"]
url = ssh://yourserver.com/~you/proj.git
EOF
这样你就可以使用命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | $ git push public-repo master </pr> 以GitHub为例子, 保存在github上的一个项目, 我查看它的config: [remote "origin"] url = git@github.com:blackanger/mars.git fetch = +refs/heads/*:refs/remotes/origin/* 这样,我每次往github push代码就是用命令: git push origin master 详细的可以去看 www.gitcasts.com <em><strong>Git Tag</strong></em> 1.Lightweight Tags ~/work/mars>git tag stable-1 cf701 ~/work/mars>git show stable-1 commit cf70117f3cc497fba42890171d29ae404061d25f Author: Alex <blackanger.z@gmail.com> Date: Sun Dec 7 05:55:46 2008 +0800 modify .gitignore 。。。 使用tag和一个object关联起来。这是创建一个轻量级的tag。 Tag Objects 如果加上-a,-s或-u <key-id>参数,则是创建一个tag对象。 <pre lang="bash" line="1"> $ git tag -a stable-1 1b2e1d63ff |
Related posts:
- Git服务器安装 Git on Ubuntu Server 安装Git-Core: sudo apt-get update # 可选步骤...
- Git详解(二) Git中级用法: Ignoring files 项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:...
- Git一分钟教程 流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器 取代码及修改全局设置 设置用户名与邮箱 git...
Related posts brought to you by Yet Another Related Posts Plugin.
Git详解(二)
Git中级用法:
Ignoring files
项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ vi .gitignore
# Lines starting with '#' are considered comments.
# Ignore any file named foo.txt.
foo.txt
# Ignore (generated) html files,
*.html
# except foo.html which is maintained by hand.
!foo.html
# Ignore objects and archives.
*.[oa]
# Ignore log direction and .DS_Store files
/log
.DS_Store
你可以到http://www.kernel.org/pub/software/scm/git/docs/gitignore.html看gitignore的详细解释。你也可以把.ignore文件当到你工作目录里的任意tree目录里,然后你只需要把这个.ignore文件加到你的git 控制下,使用git add命令。
Rebasing
假设你在远程的分支origin上创建了一个分支mywork。
1
$ git checkout -b mywork origin
创建一个新分支并选中它。
然后你做了一些改变:
1
2
3
4
$ vi file.txt
$ git commit
$ vi otherfile.txt
$ git commit
与此同时,另外一些人在origin branch 上也做了一些工作,创建了两个提交。这就意味着origin和mywork会有冲突。在这一点上,你可以用pull来merge你的改变,结果是创建了一个新的merge commit。 但是你只想在mywork分支上保留你的commit历史,而不需要任何merge,那么你可以选择使用git rebase:
1
2
$ git checkout mywork
$ git rebase origin
这个命令会把你每次从mywork的提交都会以补丁的形式暂时保存在一个叫.git/rebase的目录下,当更新到origin的最新版本的时候,就会把这个补丁给新的mywork打回去,这样,就不会有任何merge commit在历史记录里。
一旦你的‘mywork’引用指向的是新被创建的那个commit对象,那么老的commit对象会被遗弃,如果你运行垃圾回收器(git gc),它们很可能会被移除。
如果rebase的过程发现冲突,那么在你解决冲突以后,使用git add命令把它们再次更新到git index里,然后你要使用:
1
$ git rebase --continue
接着中断前的rebase来,但是如果你想返回到你rebase前的状态,那只能让这个过程流产了:
1
$ git rebase --abort
Interactive Rebasing
你可以使用互动的rebase,使用这个模式,你可以在把它们提交到某地之前重写你自己的commit对象。 它可以让你容易分离merge和re-order commit, 你也可以清除已经pull到本地的commits。
你可以在git rebase后面加参数 -i,和 --interactive来给commit应用interactive模式。$ git rebase -i origin/master
一旦你执行了git rebase -i,你就会被扔到编辑模式,我本地的代码库已经乱了,所以偷个例子吧,呵呵:
pick fc62e55 added file_size
pick 9824bf4 fixed little thing
pick 21d80a5 added number to log
pick 76b9da6 added the apply command
pick c264051 Revert “added file_size” - not implemented correctly
# Rebase f408319..b04dc3d onto f408319
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
这是说,你有5个提交。每个提交遵循下面的格式:
(action) (partial-sha) (short commit message)
现在你可以改变那个action(默认是pick),可以改成,edit或squash,或者只是保留pick。你也可以reorder commit,移除你不想要的那行就行了。当你退出编辑模式,git就会尝试应用新的commit。
Interactive Adding
这是个好方法,你可以用它来微操你的每次git add 文件到git index。 启动这个模式的命令就是:
1
git add -i
然后输出:
1
2
3
4
5
6
7
8
9
10
11
12
$>git add -i
staged unstaged path
1: unchanged +4/-0 assets/stylesheets/style.css
2: unchanged +23/-11 layout/book_index_template.html
3: unchanged +7/-7 layout/chapter_template.html
4: unchanged +3/-3 script/pdf.rb
5: unchanged +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now>
看到那些命令了吧。你可以选择,如果不懂,可以输入8,然后回车,就会输出帮助:
1
2
3
4
5
6
7
8
9
10
status - show paths with changes
update - add working tree state to the staged set of changes
revert - revert staged set of changes back to the HEAD version
patch - pick hunks and update selectively
diff - view diff between HEAD and index
add untracked - add contents of untracked files to the staged set of changes
*** Commands ***
1: [s]tatus 2: [u]pdate 3: [r]evert 4: [a]dd untracked
5: [p]atch 6: [d]iff 7: [q]uit 8: [h]elp
What now>
当然你不输入数字,直接输入help也是一样的效果。
这种模式下,你有多种选择。当你选择完毕以后,那么输入7或q退出,然后git commit你的改变,记住这里不要用git commit -a,否则你前面都做无用功了。
Stashing
当你在工作中发现一个不相关的但是却显而易见微不足道的bug的时候,你可能想在继续你的工作之前修复它。你可以用git stash来保存当前的工作状态,在修复完那个bug之后,再回来继续。
1
$ git stash "work in progress for foo feature"
这个命令会把你当前的改变保存到stash,并且会重新设置你的工作tree和匹配index到你修改bug的状态,这样在你提交修改bug代码的时候,就不会和你之前做的工作相冲突了:
… edit and test …
1
$ git commit -a -m "fix:bugs"
然后,你可以回到你之前的工作状态:
1
$ git stash apply
很好很强大。 svn好像没这功能吧?
Stash Queue
你可以stashing了多个状态(老是修bug)
这可以看到这个stash list:
1
2
3
$>git stash list
stash@{0}: WIP on book: 51bea1d... fixed images
stash@{1}: WIP on master: 9705ae6... changed the browse code to the official repo
你可以使用命令来回到你想去的那个stash:
1
git stash apply stash@{1}
清除stash可以用命令:
1
git stash clear
Git Treeishes
除了吃力的写出那40位的sha乱码来引用一个commit对象或是tree对象之外,还有很多方法。在Git里这些被称为 treeish。
Partial Sha
如果你的commit sha是980e3ccdaac54a0d4de358f3fe5d718027d96aae,git可以通过下列标识来识别它:
980e3ccdaac54a0d4de358f3fe5d718027d96aae
980e3ccdaac54a0d4
980e3cc
我自己试了试前5位,ms也能识别。
Branch, Remote or Tag Name
你也可以用branch,remote,tag name代替一个sha。
如果你的master 分支是在980e3 commit上,而且你也把它push到了origin,并且它也有一个tag name叫v1.0,那么下面这些是等价的:
980e3ccdaac54a0d4de358f3fe5d718027d96aae
origin/master
refs/remotes/origin/master
master
refs/heads/master
v1.0
refs/tags/v1.0
都代表同一个commit object
1
2
3
$ git log master
$ git log refs/tags/v1.0
输出是一样的。
Date Spec
1
2
git log master@{yesterday}
git log master@{1 month ago}
注意这种格式的,得到的sha会是不同的。
Ordinal Spec
git log master@{5}, 同上。
Carrot Parent
这会给你一个特别commit的第n次父类。这个格式仅对merge commits有用 - commit对象有大于一个的父类。
master^2
Tilde Spec
给你第n次commit对象的外祖父类。上上级。
master~2
这会返回这个master指向的commit对象的第一个parent的第一个parent。等价于:
master^^
你也可以这么做:
master^^^^^^
master~3^~2
master~6
Tree Pointer
master^{tree}
Blob Spec
master:/path/to/file
Range
你可能指定一个commit的范围,那么:
7b593b5..51bea1
它会包含从7b593b5开始的每次提交:
7b593b5..
Tracking Branches
一个tracking branche是指链接到远程分支的一个本地分支。当你往这个分支push和pull的时候,会自动的的push或pull到远程的那个分支。
git clone命令会自动的设置一个master分支,它是origin/master的tracking branch。
你也可以通过–track参数手动创建一个tracking branch:
1
git branch --track experimental origin/experimental
然后,当你运行:
$ git pull experimental
它会自动的从origin取代码,并且merge origin/experimental到你本地的experimental分支。
同样,当你push到origin,它会push你experimental分支到origin的experimental。
Finding with Git Grep
使用git grep(http://www.kernel.org/pub/software/scm/git/docs/git-grep.html)可以很方便的查找文件。这和通常的unix命令grep功能类似。
例如,我想查看在git版本库里用到def的每个地方,我可以运行:
1
2
3
4
5
6
7
8
9
10
11
$ git grep def
config/boot.rb:RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
config/boot.rb: def boot!
config/boot.rb: def booted?
config/boot.rb: defined? Rails::Initializer
config/boot.rb: def pick_boot
config/boot.rb: def vendor_rails?
config/boot.rb: def preinitialize
config/boot.rb: def preinitializer_path
config/boot.rb: def run
...
如果我想看行数,我也可以加-n参数:
1
2
3
4
5
6
7
8
9
10
11
$ git grep -n def
config/boot.rb:4:RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
config/boot.rb:8: def boot!
config/boot.rb:15: def booted?
config/boot.rb:16: defined? Rails::Initializer
config/boot.rb:19: def pick_boot
config/boot.rb:23: def vendor_rails?
config/boot.rb:27: def preinitialize
config/boot.rb:31: def preinitializer_path
config/boot.rb:37: def run
...
如果是仅仅感兴趣它在哪个文件,我们可以用–name-only参数:
1
2
3
4
5
6
7
$ git grep --name-only def
config/boot.rb
config/environment.rb
config/initializers/inflections.rb
config/initializers/new_rails_defaults.rb
config/routes.rb
...
我们也可以看有多少行匹配def:
1
2
3
4
5
6
$ git grep -c def
config/boot.rb:18
config/environment.rb:9
config/initializers/inflections.rb:1
config/initializers/new_rails_defaults.rb:2
config/routes.rb:2
更多可以看git grep的文档。
Undoing in Git - Reset, Checkout and Revert
Fixing un-committed mistakes
如果你已经混乱了你的working tree,但是还没有提交,那么可以使用这个命令来恢复到最近提交时候的状态:
1
$ git reset --hard HEAD
这个命令会扔掉你所有的改变,包括已经加到git index里的改变。
如果你只是想restore一个文件,那么使用checkout:
1
2
$ git checkout -- hello.rb
$ git checkout HEAD hello.rb
Fixing committed mistakes
对于已经提交的错误,有两个方法:
你可以创建一个新的commit,去undo你旧的提交做的那些事情。这是个正确的做法。
你也可以返回来修改旧的commit。一般不要这样做。
Fixing a mistake with a new commit
使用git revert命令:
1
$ git revert HEAD
你也可以revert更早的commit,例如:
1
$ git revert HEAD^
Fixing a mistake by modifying a commit
可以使用git rebase -i 修改你的commit,或用–amend参数。
Maintaining Git
Ensuring good performance
对于一个大的git仓库,可能会有一些历史信息占用了太多的空间或内存。那么可以用命令:
1
2
3
4
5
6
7
8
9
10
git gc
输出:
git gc
Counting objects: 810, done.
Compressing objects: 100% (723/723), done.
Writing objects: 100% (810/810), done.
Total 810 (delta 95), reused 0 (delta 0)
Removing duplicate objects: 100% (256/256), done.
Ensuring reliability
git fsck命令会在代码仓里执行一些检查并返回一些问题报告,最常见的警告是关于dangling对象:
1
2
git fsck
dangling blob 1b2b2a5e3f9518e2aa243337683391451b281d7c
Setting Up A Public Repository
假设你的私人repos是在~/.proj下面。我们首先要创建一个repos的新的clone,并且告诉git-daemon 它是public的:
1
2
$ git clone --bare ~/proj proj.git
$ touch proj.git/git-daemon-export-ok
这个结果是导出一个‘赤裸的’git repos。
下一步copy proj.git到你计划作为一个public repos的服务器。你可以用scp,rsync,或者其他。
Exporting a git repository via the git protocol
这是首选的方法。
可以启动git daemon服务,详细的看:http://www.kernel.org/pub/software/scm/git/docs/git-daemon.html
Exporting a git repository via http
1
2
3
4
$ mv proj.git /home/you/public_html/proj.git
$ cd proj.git
$ git --bare update-server-info
$ chmod a+x hooks/post-update
最后两行代码可以参看:
http://www.kernel.org/pub/software/scm/git/docs/git-update-server-info.html
http://www.kernel.org/pub/software/scm/git/docs/githooks.html
这样就可以了:
1
$ git clone http://yourserver.com/~you/proj.git
Setting Up a Private Repository
Repo Access over SSH
最简单的方式是通过ssh来使用git。
1
2
$ git clone --bare /home/user/myrepo/.git /tmp/myrepo.git
$ scp -r /tmp/myrepo.git myserver.com:/opt/git/myrepo.git
Multiple User Access using Gitosis
如果不想为每个用户都开一个单独的帐号,你需要用一个叫gitosis的工具。
http://www.urbanpuddle.com/articles/2008/07/11/installing-git-on-a-server-ubuntu-or-debian
Related posts:
- Git一分钟教程 流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器 取代码及修改全局设置 设置用户名与邮箱 git...
- Git服务器安装 Git on Ubuntu Server 安装Git-Core: sudo apt-get update # 可选步骤...
- Git详解(一) 我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的: commit fa6f27b7de063c2f301b0e7148b5bd5e813faa98 tree 5e7a19c158b89fbc52a078771a833ee839727404 parent 76f31606376180ca88efa12be341dbb14fb06fdf 咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:...
Related posts brought to you by Yet Another Related Posts Plugin.
Git中级用法:
Ignoring files
项目里总会出现你不想跟踪的文件。当然这些文件你不对它们进行git add操作就行了,但是这样也很麻烦, 如果使用git add .命令和git commit -a命令呢?你能告诉git去忽略一些文件,我们只需要在我们工作目录顶级创建一个.gitignore文件就可以了。就像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ vi .gitignore # Lines starting with '#' are considered comments. # Ignore any file named foo.txt. foo.txt # Ignore (generated) html files, *.html # except foo.html which is maintained by hand. !foo.html # Ignore objects and archives. *.[oa] # Ignore log direction and .DS_Store files /log .DS_Store |
你可以到http://www.kernel.org/pub/software/scm/git/docs/gitignore.html看gitignore的详细解释。你也可以把.ignore文件当到你工作目录里的任意tree目录里,然后你只需要把这个.ignore文件加到你的git 控制下,使用git add命令。
Rebasing
假设你在远程的分支origin上创建了一个分支mywork。
1 | $ git checkout -b mywork origin |
创建一个新分支并选中它。
然后你做了一些改变:
1 2 3 4 | $ vi file.txt $ git commit $ vi otherfile.txt $ git commit |
与此同时,另外一些人在origin branch 上也做了一些工作,创建了两个提交。这就意味着origin和mywork会有冲突。在这一点上,你可以用pull来merge你的改变,结果是创建了一个新的merge commit。 但是你只想在mywork分支上保留你的commit历史,而不需要任何merge,那么你可以选择使用git rebase:
1 2 | $ git checkout mywork $ git rebase origin |
这个命令会把你每次从mywork的提交都会以补丁的形式暂时保存在一个叫.git/rebase的目录下,当更新到origin的最新版本的时候,就会把这个补丁给新的mywork打回去,这样,就不会有任何merge commit在历史记录里。
一旦你的‘mywork’引用指向的是新被创建的那个commit对象,那么老的commit对象会被遗弃,如果你运行垃圾回收器(git gc),它们很可能会被移除。
如果rebase的过程发现冲突,那么在你解决冲突以后,使用git add命令把它们再次更新到git index里,然后你要使用:
1 | $ git rebase --continue |
接着中断前的rebase来,但是如果你想返回到你rebase前的状态,那只能让这个过程流产了:
1 | $ git rebase --abort |
Interactive Rebasing
你可以使用互动的rebase,使用这个模式,你可以在把它们提交到某地之前重写你自己的commit对象。 它可以让你容易分离merge和re-order commit, 你也可以清除已经pull到本地的commits。
你可以在git rebase后面加参数 -i,和 --interactive来给commit应用interactive模式。$ git rebase -i origin/master
一旦你执行了git rebase -i,你就会被扔到编辑模式,我本地的代码库已经乱了,所以偷个例子吧,呵呵:
pick fc62e55 added file_size
pick 9824bf4 fixed little thing
pick 21d80a5 added number to log
pick 76b9da6 added the apply command
pick c264051 Revert “added file_size” - not implemented correctly
# Rebase f408319..b04dc3d onto f408319
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
这是说,你有5个提交。每个提交遵循下面的格式:
(action) (partial-sha) (short commit message)
现在你可以改变那个action(默认是pick),可以改成,edit或squash,或者只是保留pick。你也可以reorder commit,移除你不想要的那行就行了。当你退出编辑模式,git就会尝试应用新的commit。
Interactive Adding
这是个好方法,你可以用它来微操你的每次git add 文件到git index。 启动这个模式的命令就是:
1 | git add -i |
然后输出:
1 2 3 4 5 6 7 8 9 10 11 12 | $>git add -i staged unstaged path 1: unchanged +4/-0 assets/stylesheets/style.css 2: unchanged +23/-11 layout/book_index_template.html 3: unchanged +7/-7 layout/chapter_template.html 4: unchanged +3/-3 script/pdf.rb 5: unchanged +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now> |
看到那些命令了吧。你可以选择,如果不懂,可以输入8,然后回车,就会输出帮助:
1 2 3 4 5 6 7 8 9 10 | status - show paths with changes update - add working tree state to the staged set of changes revert - revert staged set of changes back to the HEAD version patch - pick hunks and update selectively diff - view diff between HEAD and index add untracked - add contents of untracked files to the staged set of changes *** Commands *** 1: [s]tatus 2: [u]pdate 3: [r]evert 4: [a]dd untracked 5: [p]atch 6: [d]iff 7: [q]uit 8: [h]elp What now> |
当然你不输入数字,直接输入help也是一样的效果。
这种模式下,你有多种选择。当你选择完毕以后,那么输入7或q退出,然后git commit你的改变,记住这里不要用git commit -a,否则你前面都做无用功了。
Stashing
当你在工作中发现一个不相关的但是却显而易见微不足道的bug的时候,你可能想在继续你的工作之前修复它。你可以用git stash来保存当前的工作状态,在修复完那个bug之后,再回来继续。
1 | $ git stash "work in progress for foo feature" |
这个命令会把你当前的改变保存到stash,并且会重新设置你的工作tree和匹配index到你修改bug的状态,这样在你提交修改bug代码的时候,就不会和你之前做的工作相冲突了:
… edit and test …
1 | $ git commit -a -m "fix:bugs" |
然后,你可以回到你之前的工作状态:
1 | $ git stash apply |
很好很强大。 svn好像没这功能吧?
Stash Queue
你可以stashing了多个状态(老是修bug)
这可以看到这个stash list:
1 2 3 | $>git stash list stash@{0}: WIP on book: 51bea1d... fixed images stash@{1}: WIP on master: 9705ae6... changed the browse code to the official repo |
你可以使用命令来回到你想去的那个stash:
1 | git stash apply stash@{1} |
清除stash可以用命令:
1 | git stash clear |
Git Treeishes
除了吃力的写出那40位的sha乱码来引用一个commit对象或是tree对象之外,还有很多方法。在Git里这些被称为 treeish。
Partial Sha
如果你的commit sha是980e3ccdaac54a0d4de358f3fe5d718027d96aae,git可以通过下列标识来识别它:
980e3ccdaac54a0d4de358f3fe5d718027d96aae
980e3ccdaac54a0d4
980e3cc
我自己试了试前5位,ms也能识别。
Branch, Remote or Tag Name
你也可以用branch,remote,tag name代替一个sha。
如果你的master 分支是在980e3 commit上,而且你也把它push到了origin,并且它也有一个tag name叫v1.0,那么下面这些是等价的:
980e3ccdaac54a0d4de358f3fe5d718027d96aae
origin/master
refs/remotes/origin/master
master
refs/heads/master
v1.0
refs/tags/v1.0
都代表同一个commit object
1 2 3 | $ git log master $ git log refs/tags/v1.0 |
输出是一样的。
Date Spec
1 2 | git log master@{yesterday} git log master@{1 month ago} |
注意这种格式的,得到的sha会是不同的。
Ordinal Spec
git log master@{5}, 同上。
Carrot Parent
这会给你一个特别commit的第n次父类。这个格式仅对merge commits有用 - commit对象有大于一个的父类。
master^2
Tilde Spec
给你第n次commit对象的外祖父类。上上级。
master~2
这会返回这个master指向的commit对象的第一个parent的第一个parent。等价于:
master^^
你也可以这么做:
master^^^^^^
master~3^~2
master~6
Tree Pointer
master^{tree}
Blob Spec
master:/path/to/file
Range
你可能指定一个commit的范围,那么:
7b593b5..51bea1
它会包含从7b593b5开始的每次提交:
7b593b5..
Tracking Branches
一个tracking branche是指链接到远程分支的一个本地分支。当你往这个分支push和pull的时候,会自动的的push或pull到远程的那个分支。
git clone命令会自动的设置一个master分支,它是origin/master的tracking branch。
你也可以通过–track参数手动创建一个tracking branch:
1 | git branch --track experimental origin/experimental |
然后,当你运行:
$ git pull experimental
它会自动的从origin取代码,并且merge origin/experimental到你本地的experimental分支。
同样,当你push到origin,它会push你experimental分支到origin的experimental。
Finding with Git Grep
使用git grep(http://www.kernel.org/pub/software/scm/git/docs/git-grep.html)可以很方便的查找文件。这和通常的unix命令grep功能类似。
例如,我想查看在git版本库里用到def的每个地方,我可以运行:
1 2 3 4 5 6 7 8 9 10 11 | $ git grep def config/boot.rb:RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT) config/boot.rb: def boot! config/boot.rb: def booted? config/boot.rb: defined? Rails::Initializer config/boot.rb: def pick_boot config/boot.rb: def vendor_rails? config/boot.rb: def preinitialize config/boot.rb: def preinitializer_path config/boot.rb: def run ... |
如果我想看行数,我也可以加-n参数:
1 2 3 4 5 6 7 8 9 10 11 | $ git grep -n def config/boot.rb:4:RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT) config/boot.rb:8: def boot! config/boot.rb:15: def booted? config/boot.rb:16: defined? Rails::Initializer config/boot.rb:19: def pick_boot config/boot.rb:23: def vendor_rails? config/boot.rb:27: def preinitialize config/boot.rb:31: def preinitializer_path config/boot.rb:37: def run ... |
如果是仅仅感兴趣它在哪个文件,我们可以用–name-only参数:
1 2 3 4 5 6 7 | $ git grep --name-only def config/boot.rb config/environment.rb config/initializers/inflections.rb config/initializers/new_rails_defaults.rb config/routes.rb ... |
我们也可以看有多少行匹配def:
1 2 3 4 5 6 | $ git grep -c def config/boot.rb:18 config/environment.rb:9 config/initializers/inflections.rb:1 config/initializers/new_rails_defaults.rb:2 config/routes.rb:2 |
更多可以看git grep的文档。
Undoing in Git - Reset, Checkout and Revert
Fixing un-committed mistakes
如果你已经混乱了你的working tree,但是还没有提交,那么可以使用这个命令来恢复到最近提交时候的状态:
1 | $ git reset --hard HEAD |
这个命令会扔掉你所有的改变,包括已经加到git index里的改变。
如果你只是想restore一个文件,那么使用checkout:
1 2 | $ git checkout -- hello.rb
$ git checkout HEAD hello.rb |
Fixing committed mistakes
对于已经提交的错误,有两个方法:
你可以创建一个新的commit,去undo你旧的提交做的那些事情。这是个正确的做法。
你也可以返回来修改旧的commit。一般不要这样做。
Fixing a mistake with a new commit
使用git revert命令:
1 | $ git revert HEAD |
你也可以revert更早的commit,例如:
1 | $ git revert HEAD^ |
Fixing a mistake by modifying a commit
可以使用git rebase -i 修改你的commit,或用–amend参数。
Maintaining Git
Ensuring good performance
对于一个大的git仓库,可能会有一些历史信息占用了太多的空间或内存。那么可以用命令:
1 2 3 4 5 6 7 8 9 10 | git gc 输出: git gc Counting objects: 810, done. Compressing objects: 100% (723/723), done. Writing objects: 100% (810/810), done. Total 810 (delta 95), reused 0 (delta 0) Removing duplicate objects: 100% (256/256), done. Ensuring reliability |
git fsck命令会在代码仓里执行一些检查并返回一些问题报告,最常见的警告是关于dangling对象:
1 2 | git fsck dangling blob 1b2b2a5e3f9518e2aa243337683391451b281d7c |
Setting Up A Public Repository
假设你的私人repos是在~/.proj下面。我们首先要创建一个repos的新的clone,并且告诉git-daemon 它是public的:
1 2 | $ git clone --bare ~/proj proj.git $ touch proj.git/git-daemon-export-ok |
这个结果是导出一个‘赤裸的’git repos。
下一步copy proj.git到你计划作为一个public repos的服务器。你可以用scp,rsync,或者其他。
Exporting a git repository via the git protocol
这是首选的方法。
可以启动git daemon服务,详细的看:http://www.kernel.org/pub/software/scm/git/docs/git-daemon.html
Exporting a git repository via http
1 2 3 4 | $ mv proj.git /home/you/public_html/proj.git $ cd proj.git $ git --bare update-server-info $ chmod a+x hooks/post-update |
最后两行代码可以参看:
http://www.kernel.org/pub/software/scm/git/docs/git-update-server-info.html
http://www.kernel.org/pub/software/scm/git/docs/githooks.html
这样就可以了:
1 | $ git clone http://yourserver.com/~you/proj.git |
Setting Up a Private Repository
Repo Access over SSH
最简单的方式是通过ssh来使用git。
1 2 | $ git clone --bare /home/user/myrepo/.git /tmp/myrepo.git $ scp -r /tmp/myrepo.git myserver.com:/opt/git/myrepo.git |
Multiple User Access using Gitosis
如果不想为每个用户都开一个单独的帐号,你需要用一个叫gitosis的工具。
http://www.urbanpuddle.com/articles/2008/07/11/installing-git-on-a-server-ubuntu-or-debian
Related posts:
- Git一分钟教程 流程:取代码 → 每次工作前更新代码到最新版本 → 修改代码 → 提交代码到服务器 取代码及修改全局设置 设置用户名与邮箱 git...
- Git服务器安装 Git on Ubuntu Server 安装Git-Core: sudo apt-get update # 可选步骤...
- Git详解(一) 我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的: commit fa6f27b7de063c2f301b0e7148b5bd5e813faa98 tree 5e7a19c158b89fbc52a078771a833ee839727404 parent 76f31606376180ca88efa12be341dbb14fb06fdf 咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:...
Related posts brought to you by Yet Another Related Posts Plugin.
ruby中10进制和16进制的转换
16进制到10进制:
>> "B0A0".hex
=> 45216
或
>> "B0A0".to_i(16)
=> 45216
10进制到16进制:
>> 45216.to_s(16)
=> "b0a0"
>> "B0A0".hex
=> 45216
或
>> "B0A0".to_i(16)
=> 45216
10进制到16进制:
>> 45216.to_s(16)
=> "b0a0"
ÓиöеÄRUBYרҵÉçÇø´ó¼Ò¿´¿´
¶àÁ˸ö¿ÉÒÔ½»Á÷µÄµØ·½£¬,²»¹ýÄÚÈÝ»¹±È½ÏÉÙ
为所有HTML标签添加Hover效果
在制作网页时经常会用到onmouseover和onmouseout效果来改善用户体验,最常见的就是在指定Element中添加如下的代码来实现背景色的切换。
onmouseover='this.style.background=#666;' onmouseout="this.style.background=#fff;"
其实到达这个效果有两种方式:Javascript和CSS,上面提到是用JS来完成的,我个人更喜欢用CSS来解决类似问题。
用CSS的hover来解决这个问题,不仅简单高效,关键是低侵入性,页面上不会写太多东西。例如在li上添加这个效果:
li {background:#fff;}
li:hover {background:#666;}
这样的代码看起来简洁且方便日后维护,但也有一个问题就是在IE6下并不是所有HTML标签都支持hover这个属性,还好已经有人为IE做了这个Pacth,只需要添加一下就好了。点击下载csshover
在制作网页时经常会用到onmouseover和onmouseout效果来改善用户体验,最常见的就是在指定Element中添加如下的代码来实现背景色的切换。
onmouseover='this.style.background=#666;' onmouseout="this.style.background=#fff;"
其实到达这个效果有两种方式:Javascript和CSS,上面提到是用JS来完成的,我个人更喜欢用CSS来解决类似问题。
用CSS的hover来解决这个问题,不仅简单高效,关键是低侵入性,页面上不会写太多东西。例如在li上添加这个效果:
li {background:#fff;}
li:hover {background:#666;}
这样的代码看起来简洁且方便日后维护,但也有一个问题就是在IE6下并不是所有HTML标签都支持hover这个属性,还好已经有人为IE做了这个Pacth,只需要添加一下就好了。点击下载csshover
深入理解Blocks,Procs和lambdas
Blocks, Procs和lambdas是Ruby里最重要的方面,同时也是难点之一。这是因为Ruby处理闭包(closures)的方式比较特别。更复杂的是,Ruby有4种使用闭包的方式,它们之间还稍有不同。
First Up, Blocks
大多数情况下,使用闭包最Ruby的方式就是用Block了。
array = [1,2,3,4]
#[1, 2, 3, 4]
array.collect! do |n|
n ** 2 (求平方)
end
#[1, 4, 9, 16]
puts array.inspect
# [1, 4, 9, 16]
so ,what’s going on here?
我们发送了‘collect!’方法给一个block代码的数组
在collect!方法内部给每个变量作平方(此处为n)
我们现在来实现自己的collect!方法,我们先建立一个iterate!方法:
class Array
def iterate!
self.each_with_index do |n,i|
self[i] = yield(n)
end
end
end
array = [1,2,3,4]
#[1, 2, 3, 4]
array.iterate! do |n|
n ** 2
end
#[1, 4, 9, 16]
和属性不一样,你并不需要在你的方法内部指定block名字,你只需要使用yield关键字就ok了。请注意上例是如何给yield传参数n的。整个过程可以解释为:
给Array对象发送iterate!方法
当yield被调用的时候,把n(第一次1,第二次4,以此类推)传给被给的block里
block里有了可用的值,也就是n,那么就平方它。
yield输出block里返回的值,并且重写了array里面的值。
使用yield只是使用block代码的一个方法而已,这里还有另外一个,那就是作为一个Proc来调用它。看看:
class Array
def iterate!(&code)
self.each_with_index do |n,i|
self[i] = code.call(n)
end
end
end
arr = [1,2,3,4]
arr.iterate! do |n|
n ** 2
end
#[1, 4, 9, 16]
和上一个例子非常相似。然而有两点不同。第一个就是iterate!的参数形式。第二点就是call方法。 输出结果是相似的,但是为什么语法不同呢?
def what_am_i(&block)
block.class
end
puts what_am_i{}
#Proc
这是一个Proc对象。block是一个Proc。
<pre lang="RUBY">def what_am_i
yield.class
end
puts what_am_i{ puts "x"}
=> x
NilClass
puts what_am_i{ "x"}
# String
这说明,使用yield直接返回的是block表达式里的值。
那么什么是Proc了?
Procedures, AKA, Procs
我们经常需要使用一个块在多个地方,这样我们就需要不断的重复我们的block,那么为了解决这个问题,做到代码复用,我们就可以使用Proc, 其实block和Proc的唯一区别就是, block是个一次性的Proc。
class Array
def iterate!(code)
self.each_with_index do |n, i|
self[i] = code.call(n)
end
end
end
arr1 = [1,2,3,4]
arr2 = [2,3,4,5]
square = Proc.new do |n|
n ** 2
end
arr1.iterate!(square)
#[1, 4, 9, 16]
arr2.iterate!(square)
#[4, 9, 16, 25]
你可能会说,用block不就完了吗?整个Proc不是多此一举。 那么请问,如果我们想给一个方法传多个closures怎么办?使用block会很不灵活。 但是用Proc就好多了:
def callbacks(procs)
procs[:starting].call
puts "Still going"
procs[:finishing].call
end
callbacks(:starting #Proc.new{puts "Starting"},:finishing #Proc.new{puts "Finishing"})
#
Starting
Still going
Finishing
那么什么时候用block,什么时候用Proc呢?
Block: 当你的方法是被分成多个小片段,而你想让你的用户与这些片段做一些交互。
Block: 当你需要运行多个原子性表达式的时候,比如数据库迁移(migration)
Proc : 当你需要重用一个block的时候。
Proc : 当你的方法有一个或多个callbacks的时候。
Lambdas
匿名函数,在其他语言里也有。Ruby里也可用:
class Array
def iterate(code)
self.each_with_index do |n,i|
self[i] = code.call(n)
end
end
end
arr = [1,2,3,4]
arr.iterate(lambda{|n| n**2 })
#[1, 4, 9, 16]
咋看上去,lambda和Proc执行的好像是一样。但是这里有两个细微的不同点。第一个不同就是lambda检查参数的个数。
def arguments(code)
one, two = 1, 2
code.call(one,two)
end
arguments(Proc.new { |a, b, c| puts "Give me a #{a} and a #{b} and a #{c.class}" })
#Give me a 1 and a 2 and a NilClass
arguments(lambda { |a, b, c| puts "Give me a #{a} and a #{b} and a #{c.class}" })
#ArgumentError: wrong number of arguments (2 for 3)
第二个不同就是,lambda有一个‘微小’的返回,什么意思呢?Proc返回会阻止一个方法的执行,并返回这个值。lambda返回它们的值,但是方法还会继续执行。看看例子:
def proc_return
Proc.new { return "Proc.new"}.call
return "proc_return method finished"
end
def lambda_return
lambda{ return "lambda"}.call
return "lambda_return method finished"
end
puts proc_return #Proc.new
puts lambda_return #lambda_return method finished
为什么会不同?答案就是procedures(过程)和methods(方法)的概念不同。Procs在Ruby里是代码片段,不是方法。因为这个,Proc return的就是proc_return这个方法的return,因为Proc那段就是那个方法里的代码片段。而lambdas的行为像一个方法,它检查参数的个数,而且不会覆盖调用方法的return。由于这个原因,你最好把lambdas理解为写一个方法的另类方式,只不过是匿名的而已。那么什么时候该用lamda代替Proc呢?看例子:
def generic_return(code)
code.call
return "generic_return method finished"
end
puts generic_return(Proc.new{return "Proc.new"})
#LocalJumpError: unexpected return
puts generic_return(lambda{return "lambda"})
# => generic_return method finished
Ruby语法里,参数部分不能带return,然而lambda行为像方法,所以它可以有个内部return。
def generic_return(code)
one, two = 1, 2
three, four = code.call(one, two)
end
puts generic_return(lambda { |x, y| return x + 2, y + 2 })
puts generic_return(Proc.new { |x, y| return x + 2, y + 2 })
puts generic_return(Proc.new { |x, y| x + 2; y + 2 })
puts generic_return(Proc.new { |x, y| [x + 2, y + 2] })
# Give me a 3 and a 4
#*.rb:11: unexpected return (LocalJumpError)
#Give me a 4 and a
# Give me a 3 and a 4
这个generic_return方法返回的是两个值,使用lambda,一切都很easy,而使用Proc,我们还不得不用数组指定x,y。
a,b = generic_return(lambda { |x, y| return x + 2, y + 2 })
#[3, 4]
a
#3
b
#4
c,d = generic_return(Proc.new { |x, y| x + 2; y + 2 })
#[4]
c
#4
d
#nil
e,f = generic_return(Proc.new { |x, y| [x + 2, y + 2] })
#[3, 4]
e
#3
f
#4
Method Objects
如果你有一个工作完好的方法,你想把它传到另一个方法里,作为闭包,也为了使你的代码DRY,那么你可以使用这个method方法:
class Array
def iterate!(code)
self.each_with_index do |n,i|
self[i] = code.call(n)
end
end
end
def square(n)
n ** 2
end
arr = [1,2,3,4]
arr.iterate!(method(:square))
#[1, 4, 9, 16]
puts method(:square).class
# Method
这个方法对象的行为像是lambda,那么到底。。。:
puts lambda {}.class
# Proc
呵呵,它是个Proc。
现在明白Ruby 的这四种闭包方式了吧。
block,Proc的行为更像一个代码片段,lambdas和method方法的行为更像方法。
block,Proc, lambdas都是Proc对象,而method,是Method对象。
原文请看这里。
No related posts.
Blocks, Procs和lambdas是Ruby里最重要的方面,同时也是难点之一。这是因为Ruby处理闭包(closures)的方式比较特别。更复杂的是,Ruby有4种使用闭包的方式,它们之间还稍有不同。
First Up, Blocks
大多数情况下,使用闭包最Ruby的方式就是用Block了。
array = [1,2,3,4] #[1, 2, 3, 4] array.collect! do |n| n ** 2 (求平方) end #[1, 4, 9, 16] puts array.inspect # [1, 4, 9, 16]
so ,what’s going on here?
我们发送了‘collect!’方法给一个block代码的数组
在collect!方法内部给每个变量作平方(此处为n)
我们现在来实现自己的collect!方法,我们先建立一个iterate!方法:
class Array def iterate! self.each_with_index do |n,i| self[i] = yield(n) end end end array = [1,2,3,4] #[1, 2, 3, 4] array.iterate! do |n| n ** 2 end #[1, 4, 9, 16]
和属性不一样,你并不需要在你的方法内部指定block名字,你只需要使用yield关键字就ok了。请注意上例是如何给yield传参数n的。整个过程可以解释为:
给Array对象发送iterate!方法
当yield被调用的时候,把n(第一次1,第二次4,以此类推)传给被给的block里
block里有了可用的值,也就是n,那么就平方它。
yield输出block里返回的值,并且重写了array里面的值。
使用yield只是使用block代码的一个方法而已,这里还有另外一个,那就是作为一个Proc来调用它。看看:
class Array def iterate!(&code) self.each_with_index do |n,i| self[i] = code.call(n) end end end arr = [1,2,3,4] arr.iterate! do |n| n ** 2 end #[1, 4, 9, 16]
和上一个例子非常相似。然而有两点不同。第一个就是iterate!的参数形式。第二点就是call方法。 输出结果是相似的,但是为什么语法不同呢?
def what_am_i(&block) block.class end puts what_am_i{} #Proc 这是一个Proc对象。block是一个Proc。 <pre lang="RUBY">def what_am_i yield.class end puts what_am_i{ puts "x"} => x NilClass puts what_am_i{ "x"} # String
这说明,使用yield直接返回的是block表达式里的值。
那么什么是Proc了?
Procedures, AKA, Procs
我们经常需要使用一个块在多个地方,这样我们就需要不断的重复我们的block,那么为了解决这个问题,做到代码复用,我们就可以使用Proc, 其实block和Proc的唯一区别就是, block是个一次性的Proc。
class Array def iterate!(code) self.each_with_index do |n, i| self[i] = code.call(n) end end end arr1 = [1,2,3,4] arr2 = [2,3,4,5] square = Proc.new do |n| n ** 2 end arr1.iterate!(square) #[1, 4, 9, 16] arr2.iterate!(square) #[4, 9, 16, 25]
你可能会说,用block不就完了吗?整个Proc不是多此一举。 那么请问,如果我们想给一个方法传多个closures怎么办?使用block会很不灵活。 但是用Proc就好多了:
def callbacks(procs) procs[:starting].call puts "Still going" procs[:finishing].call end callbacks(:starting #Proc.new{puts "Starting"},:finishing #Proc.new{puts "Finishing"}) # Starting Still going Finishing
那么什么时候用block,什么时候用Proc呢?
Block: 当你的方法是被分成多个小片段,而你想让你的用户与这些片段做一些交互。
Block: 当你需要运行多个原子性表达式的时候,比如数据库迁移(migration)
Proc : 当你需要重用一个block的时候。
Proc : 当你的方法有一个或多个callbacks的时候。
Lambdas
匿名函数,在其他语言里也有。Ruby里也可用:
class Array def iterate(code) self.each_with_index do |n,i| self[i] = code.call(n) end end end arr = [1,2,3,4] arr.iterate(lambda{|n| n**2 }) #[1, 4, 9, 16]
咋看上去,lambda和Proc执行的好像是一样。但是这里有两个细微的不同点。第一个不同就是lambda检查参数的个数。
def arguments(code) one, two = 1, 2 code.call(one,two) end arguments(Proc.new { |a, b, c| puts "Give me a #{a} and a #{b} and a #{c.class}" }) #Give me a 1 and a 2 and a NilClass arguments(lambda { |a, b, c| puts "Give me a #{a} and a #{b} and a #{c.class}" }) #ArgumentError: wrong number of arguments (2 for 3)
第二个不同就是,lambda有一个‘微小’的返回,什么意思呢?Proc返回会阻止一个方法的执行,并返回这个值。lambda返回它们的值,但是方法还会继续执行。看看例子:
def proc_return Proc.new { return "Proc.new"}.call return "proc_return method finished" end def lambda_return lambda{ return "lambda"}.call return "lambda_return method finished" end puts proc_return #Proc.new puts lambda_return #lambda_return method finished
为什么会不同?答案就是procedures(过程)和methods(方法)的概念不同。Procs在Ruby里是代码片段,不是方法。因为这个,Proc return的就是proc_return这个方法的return,因为Proc那段就是那个方法里的代码片段。而lambdas的行为像一个方法,它检查参数的个数,而且不会覆盖调用方法的return。由于这个原因,你最好把lambdas理解为写一个方法的另类方式,只不过是匿名的而已。那么什么时候该用lamda代替Proc呢?看例子:
def generic_return(code) code.call return "generic_return method finished" end puts generic_return(Proc.new{return "Proc.new"}) #LocalJumpError: unexpected return puts generic_return(lambda{return "lambda"}) # => generic_return method finished
Ruby语法里,参数部分不能带return,然而lambda行为像方法,所以它可以有个内部return。
def generic_return(code) one, two = 1, 2 three, four = code.call(one, two) end puts generic_return(lambda { |x, y| return x + 2, y + 2 }) puts generic_return(Proc.new { |x, y| return x + 2, y + 2 }) puts generic_return(Proc.new { |x, y| x + 2; y + 2 }) puts generic_return(Proc.new { |x, y| [x + 2, y + 2] }) # Give me a 3 and a 4 #*.rb:11: unexpected return (LocalJumpError) #Give me a 4 and a # Give me a 3 and a 4
这个generic_return方法返回的是两个值,使用lambda,一切都很easy,而使用Proc,我们还不得不用数组指定x,y。
a,b = generic_return(lambda { |x, y| return x + 2, y + 2 }) #[3, 4] a #3 b #4 c,d = generic_return(Proc.new { |x, y| x + 2; y + 2 }) #[4] c #4 d #nil e,f = generic_return(Proc.new { |x, y| [x + 2, y + 2] }) #[3, 4] e #3 f #4
Method Objects
如果你有一个工作完好的方法,你想把它传到另一个方法里,作为闭包,也为了使你的代码DRY,那么你可以使用这个method方法:
class Array def iterate!(code) self.each_with_index do |n,i| self[i] = code.call(n) end end end def square(n) n ** 2 end arr = [1,2,3,4] arr.iterate!(method(:square)) #[1, 4, 9, 16] puts method(:square).class # Method
这个方法对象的行为像是lambda,那么到底。。。:
puts lambda {}.class # Proc
呵呵,它是个Proc。
现在明白Ruby 的这四种闭包方式了吧。
block,Proc的行为更像一个代码片段,lambdas和method方法的行为更像方法。
block,Proc, lambdas都是Proc对象,而method,是Method对象。
原文请看这里。
No related posts.
custom exceptions in merb
在开发应用过程中难免需要根据实际情况自定义一些异常处理机制,这方面Merb已经将底部的架子为我们准备好了,我们只需要简单的在此基础上进行扩展就可以搞的很舒服。
Merb默认生成的Application会提供一个Exception的Controller,并包含了两个样版异常NotFound和NotAcceptable。现在我们添加一个自定义的异常在这里,假定名称为NotExists,并为其创建对应的View。
在Action中调用
def show
product = Product.find(params[:id])
raise NotExists unless product
[...]
end
这时会报错,称并不存在NotExists常量,Google了一下并没有找到合理的解释,直接看了Merb的源代码才发现,自定义异常不是这样的用法。
在Merb里如果要自定义异常,需要将自定义异常继承自一个Merb自身已存的异常,比如这样
class NotExists < Merb::ControllerExceptions::NotFound ; end
并且需要在使用该异常的Controller里进行声明(放在Application里自然会是一个不错的选择),再跑一下上面报错的程序应该就可以得到正确的结果啦~ BTW:为了这个我可查了好一会资料 :)
以下是Merb对标准Http异常的封装
class Informational < Merb::ControllerExceptions::Base; end
class Continue < Merb::ControllerExceptions::Informational; self.status = 100; end
class SwitchingProtocols < Merb::ControllerExceptions::Informational; self.status = 101; end
class Successful < Merb::ControllerExceptions::Base; end
class OK < Merb::ControllerExceptions::Successful; self.status = 200; end
class Created < Merb::ControllerExceptions::Successful; self.status = 201; end
class Accepted < Merb::ControllerExceptions::Successful; self.status = 202; end
class NonAuthoritativeInformation < Merb::ControllerExceptions::Successful; self.status = 203; end
class NoContent < Merb::ControllerExceptions::Successful; self.status = 204; end
class ResetContent < Merb::ControllerExceptions::Successful; self.status = 205; end
class PartialContent < Merb::ControllerExceptions::Successful; self.status = 206; end
class Redirection < Merb::ControllerExceptions::Base; end
class MultipleChoices < Merb::ControllerExceptions::Redirection; self.status = 300; end
class MovedPermanently < Merb::ControllerExceptions::Redirection; self.status = 301; end
class MovedTemporarily < Merb::ControllerExceptions::Redirection; self.status = 302; end
class SeeOther < Merb::ControllerExceptions::Redirection; self.status = 303; end
class NotModified < Merb::ControllerExceptions::Redirection; self.status = 304; end
class UseProxy < Merb::ControllerExceptions::Redirection; self.status = 305; end
class TemporaryRedirect < Merb::ControllerExceptions::Redirection; self.status = 307; end
class ClientError < Merb::ControllerExceptions::Base; end
class BadRequest < Merb::ControllerExceptions::ClientError; self.status = 400; end
class MultiPartParseError < Merb::ControllerExceptions::BadRequest; end
class Unauthorized < Merb::ControllerExceptions::ClientError; self.status = 401; end
class PaymentRequired < Merb::ControllerExceptions::ClientError; self.status = 402; end
class Forbidden < Merb::ControllerExceptions::ClientError; self.status = 403; end
class NotFound < Merb::ControllerExceptions::ClientError; self.status = 404; end
class ActionNotFound < Merb::ControllerExceptions::NotFound; end
class TemplateNotFound < Merb::ControllerExceptions::NotFound; end
class LayoutNotFound < Merb::ControllerExceptions::NotFound; end
class MethodNotAllowed < Merb::ControllerExceptions::ClientError; self.status = 405; end
class NotAcceptable < Merb::ControllerExceptions::ClientError; self.status = 406; end
class ProxyAuthenticationRequired < Merb::ControllerExceptions::ClientError; self.status = 407; end
class RequestTimeout < Merb::ControllerExceptions::ClientError; self.status = 408; end
class Conflict < Merb::ControllerExceptions::ClientError; self.status = 409; end
class Gone < Merb::ControllerExceptions::ClientError; self.status = 410; end
class LengthRequired < Merb::ControllerExceptions::ClientError; self.status = 411; end
class PreconditionFailed < Merb::ControllerExceptions::ClientError; self.status = 412; end
class RequestEntityTooLarge < Merb::ControllerExceptions::ClientError; self.status = 413; end
class RequestURITooLarge < Merb::ControllerExceptions::ClientError; self.status = 414; end
class UnsupportedMediaType < Merb::ControllerExceptions::ClientError; self.status = 415; end
class RequestRangeNotSatisfiable < Merb::ControllerExceptions::ClientError; self.status = 416; end
class ExpectationFailed < Merb::ControllerExceptions::ClientError; self.status = 417; end
class ServerError < Merb::ControllerExceptions::Base; end
class InternalServerError < Merb::ControllerExceptions::ServerError; self.status = 500; end
class NotImplemented < Merb::ControllerExceptions::ServerError; self.status = 501; end
class BadGateway < Merb::ControllerExceptions::ServerError; self.status = 502; end
class ServiceUnavailable < Merb::ControllerExceptions::ServerError; self.status = 503; end
class GatewayTimeout < Merb::ControllerExceptions::ServerError; self.status = 504; end
class HTTPVersionNotSupported < Merb::ControllerExceptions::ServerError; self.status = 505; end
在开发应用过程中难免需要根据实际情况自定义一些异常处理机制,这方面Merb已经将底部的架子为我们准备好了,我们只需要简单的在此基础上进行扩展就可以搞的很舒服。
Merb默认生成的Application会提供一个Exception的Controller,并包含了两个样版异常NotFound和NotAcceptable。现在我们添加一个自定义的异常在这里,假定名称为NotExists,并为其创建对应的View。
在Action中调用
def show
product = Product.find(params[:id])
raise NotExists unless product
[...]
end
这时会报错,称并不存在NotExists常量,Google了一下并没有找到合理的解释,直接看了Merb的源代码才发现,自定义异常不是这样的用法。
在Merb里如果要自定义异常,需要将自定义异常继承自一个Merb自身已存的异常,比如这样
class NotExists < Merb::ControllerExceptions::NotFound ; end
并且需要在使用该异常的Controller里进行声明(放在Application里自然会是一个不错的选择),再跑一下上面报错的程序应该就可以得到正确的结果啦~ BTW:为了这个我可查了好一会资料 :)
以下是Merb对标准Http异常的封装
class Informational < Merb::ControllerExceptions::Base; end
class Continue < Merb::ControllerExceptions::Informational; self.status = 100; end
class SwitchingProtocols < Merb::ControllerExceptions::Informational; self.status = 101; end
class Successful < Merb::ControllerExceptions::Base; end
class OK < Merb::ControllerExceptions::Successful; self.status = 200; end
class Created < Merb::ControllerExceptions::Successful; self.status = 201; end
class Accepted < Merb::ControllerExceptions::Successful; self.status = 202; end
class NonAuthoritativeInformation < Merb::ControllerExceptions::Successful; self.status = 203; end
class NoContent < Merb::ControllerExceptions::Successful; self.status = 204; end
class ResetContent < Merb::ControllerExceptions::Successful; self.status = 205; end
class PartialContent < Merb::ControllerExceptions::Successful; self.status = 206; end
class Redirection < Merb::ControllerExceptions::Base; end
class MultipleChoices < Merb::ControllerExceptions::Redirection; self.status = 300; end
class MovedPermanently < Merb::ControllerExceptions::Redirection; self.status = 301; end
class MovedTemporarily < Merb::ControllerExceptions::Redirection; self.status = 302; end
class SeeOther < Merb::ControllerExceptions::Redirection; self.status = 303; end
class NotModified < Merb::ControllerExceptions::Redirection; self.status = 304; end
class UseProxy < Merb::ControllerExceptions::Redirection; self.status = 305; end
class TemporaryRedirect < Merb::ControllerExceptions::Redirection; self.status = 307; end
class ClientError < Merb::ControllerExceptions::Base; end
class BadRequest < Merb::ControllerExceptions::ClientError; self.status = 400; end
class MultiPartParseError < Merb::ControllerExceptions::BadRequest; end
class Unauthorized < Merb::ControllerExceptions::ClientError; self.status = 401; end
class PaymentRequired < Merb::ControllerExceptions::ClientError; self.status = 402; end
class Forbidden < Merb::ControllerExceptions::ClientError; self.status = 403; end
class NotFound < Merb::ControllerExceptions::ClientError; self.status = 404; end
class ActionNotFound < Merb::ControllerExceptions::NotFound; end
class TemplateNotFound < Merb::ControllerExceptions::NotFound; end
class LayoutNotFound < Merb::ControllerExceptions::NotFound; end
class MethodNotAllowed < Merb::ControllerExceptions::ClientError; self.status = 405; end
class NotAcceptable < Merb::ControllerExceptions::ClientError; self.status = 406; end
class ProxyAuthenticationRequired < Merb::ControllerExceptions::ClientError; self.status = 407; end
class RequestTimeout < Merb::ControllerExceptions::ClientError; self.status = 408; end
class Conflict < Merb::ControllerExceptions::ClientError; self.status = 409; end
class Gone < Merb::ControllerExceptions::ClientError; self.status = 410; end
class LengthRequired < Merb::ControllerExceptions::ClientError; self.status = 411; end
class PreconditionFailed < Merb::ControllerExceptions::ClientError; self.status = 412; end
class RequestEntityTooLarge < Merb::ControllerExceptions::ClientError; self.status = 413; end
class RequestURITooLarge < Merb::ControllerExceptions::ClientError; self.status = 414; end
class UnsupportedMediaType < Merb::ControllerExceptions::ClientError; self.status = 415; end
class RequestRangeNotSatisfiable < Merb::ControllerExceptions::ClientError; self.status = 416; end
class ExpectationFailed < Merb::ControllerExceptions::ClientError; self.status = 417; end
class ServerError < Merb::ControllerExceptions::Base; end
class InternalServerError < Merb::ControllerExceptions::ServerError; self.status = 500; end
class NotImplemented < Merb::ControllerExceptions::ServerError; self.status = 501; end
class BadGateway < Merb::ControllerExceptions::ServerError; self.status = 502; end
class ServiceUnavailable < Merb::ControllerExceptions::ServerError; self.status = 503; end
class GatewayTimeout < Merb::ControllerExceptions::ServerError; self.status = 504; end
class HTTPVersionNotSupported < Merb::ControllerExceptions::ServerError; self.status = 505; end
hack truncate in ruby 1.8.7 compability issue
add follows code into rails app environment.rb and restart the service
# http://rails.lighthouseapp.com/projects/8994/tickets/867-undefined-method-length-for-enumerable
class String
def chars
ActiveSupport::Multibyte::Chars.new(self)
end
alias_method :mb_chars, :chars
end
##
module ActionView
module Helpers
module TextHelper
def truncate(text, length = 30, truncate_string = "...")
if text.nil? then return end
l = length - truncate_string.chars.to_a.size
(text.chars.to_a.size > length ? text.chars.to_a[0...l].join + truncate_string : text).to_s
end
end
end
end
add follows code into rails app environment.rb and restart the service
# http://rails.lighthouseapp.com/projects/8994/tickets/867-undefined-method-length-for-enumerable
class String
def chars
ActiveSupport::Multibyte::Chars.new(self)
end
alias_method :mb_chars, :chars
end
##
module ActionView
module Helpers
module TextHelper
def truncate(text, length = 30, truncate_string = "...")
if text.nil? then return end
l = length - truncate_string.chars.to_a.size
(text.chars.to_a.size > length ? text.chars.to_a[0...l].join + truncate_string : text).to_s
end
end
end
end
process base64 encode in ruby
在Ruby世界中,语言本身就支持标准的Base64编码实现,而且还有不止一种实现,一个是类库base64中提供的实现(使用时需要require),一个是Ruby基础数据类型Array提供的,可直接使用.具体使用方法如下:
使用Array的实现
str = "imabase64encode"
base64_str = [str].pack(”m”)
original = base64_str.unpack(”m”)
使用Base64的实现
require "base64"
enc = Base64.encode64('Send reinforcements')
plain = Base64.decode64(enc)
请注意方法pack(’m')、unpack(’m')以及encode64和decode64的用法
建议使用Array方式的实现,在Ruby1.9中将会去除Base64这个类库 
在Ruby世界中,语言本身就支持标准的Base64编码实现,而且还有不止一种实现,一个是类库base64中提供的实现(使用时需要require),一个是Ruby基础数据类型Array提供的,可直接使用.具体使用方法如下:
使用Array的实现
str = "imabase64encode"
base64_str = [str].pack(”m”)
original = base64_str.unpack(”m”)
使用Base64的实现
require "base64"
enc = Base64.encode64('Send reinforcements')
plain = Base64.decode64(enc)
请注意方法pack(’m')、unpack(’m')以及encode64和decode64的用法
建议使用Array方式的实现,在Ruby1.9中将会去除Base64这个类库 ![]()
http authentication
some information about http authentication :
–
As for authentication, the HTTP protocol includes the basic access authentication and the digest access authentication protocols, which allow access to a Web page only when the user has provided the correct username and password. If the server requires such credential for granting access to a Web page, the browser requests them to the user; once obtained, the browser stores and uses them also for accessing subsequent pages, without requiring the user to provide them again. From the point of view of the user, the effect is the same as if cookies were used: username and password are only requested once, and from that point on the user is given access to the site. In the basic access authentication protocol, a combination of username and password is sent to the server in every browser request. This means that someone listening in on this traffic can simply read this information and store for later use. This problem is overcome in the digest access authentication protocol, in which the username and password are encrypted using a random nonce created by the server.
see more http://en.wikipedia.org/wiki/Basic_access_authentication
some information about http authentication :
–
As for authentication, the HTTP protocol includes the basic access authentication and the digest access authentication protocols, which allow access to a Web page only when the user has provided the correct username and password. If the server requires such credential for granting access to a Web page, the browser requests them to the user; once obtained, the browser stores and uses them also for accessing subsequent pages, without requiring the user to provide them again. From the point of view of the user, the effect is the same as if cookies were used: username and password are only requested once, and from that point on the user is given access to the site. In the basic access authentication protocol, a combination of username and password is sent to the server in every browser request. This means that someone listening in on this traffic can simply read this information and store for later use. This problem is overcome in the digest access authentication protocol, in which the username and password are encrypted using a random nonce created by the server.
see more http://en.wikipedia.org/wiki/Basic_access_authentication
´ú¿ª¼Ó¹¤Î¬ÐÞ·¢Æ±´ú¿ª½¨Öþ·¢Æ±13313197276
±¾¹«Ë¾ºÍÈ«¹ú¸÷µØÖڶ๫˾ÓÐÒµÎñÍùÀ´£¬¿ÉÒÔÌṩ˰Îñ»ú¹Ø´ú¿ª·¢Æ±×Éѯ¡£×Éѯ·¶Î§£ºÉÌÆ·ÆÕͨÏúÊÛ·¢Æ±¡¢¹ã¸æ·¢Æ±
¡¢½¨Öþ°²×°·¢Æ±£¬·þÎñÒµ·¢Æ±£¬×âÁÞ·¢Æ±£¬·¿Îݳö×ⷢƱ£¬Ó°ÊÓÖÆ×÷·¢Æ±£¬Åàѵ×Éѯ·¢Æ±£¬ÍøÂç·þÎñ·¢Æ±£¬·Ò뷢Ʊ£¬Ó¡Ë¢·¢Æ±£¬»áÎñ»áÒ鷢Ʊ£¬²ÍÒûסËÞ·¢Æ±£¬ÎÄ»¯ÓéÀÖ
ɽ¶«Ê¡ÇൺÊдú¿ª·þÎñҵͳһ·¢Æ±ÑéÖ¤ºó¸¶¿î13313197276
ÎÒ¹«Ë¾±¾×ÅΪ¹óµ¥Î»ºÏÀíºÏ·¨,½ÚÊ¡¾Óª³É±¾ºÍ¿ªÖ§, ÔÚ³ÏÐű£ÃܵĻù´¡ÉÏ,Ìṩ·¢Æ±×Éѯ¹ÜÀí·þÎñ¡£·þÎñ·¶Î§£ºÉÌÆó·¢Æ±¡¢·þÎñ·¢Æ±¡¢¹ã¸æ·¢Æ±¡¢ÔËÊ䷢Ʊ¡¢¹«Â·ÄÚºÓ·¢Æ±¡¢µÀ·½»Í¨·¢Æ±¡¢ÔËÊäװж·¢Æ±·¿ÎÝ×âÁÞ·¢Æ±¡¢×âÁÞ·¢Æ±¡¢½¨Öþ·¢Æ±¡¢²ÍÒû·¢Æ±¡¢Ò½ÁÆ·¢Æ±¡¢»ú¶¯³µÏúÊÛ·¢Æ±µÈ¡£Ëù¿ª·
¹ã¶«Ê¡¹ãÖÝÊж«Ý¸Êдú¿ªÉÌÆ·ÏúÊÛͳһ·¢Æ±13313197276
ÎÒ˾¿ÉÒÔΪÆäËûµ¥Î»£¨¹«Ë¾£©¹©Ó¦£ºÓà¶î·¢/ƱÏêÇéÈçÏ£ºÒòϸڷöÖ²µÄ˰ÊÕÕþ²ß£¬¼ÓÉϽøÏî½Ï¶àÍê³É²»ÁËÿÔ¶¨Ë°¶î¶È,±¾¹«Ë¾ÏÖÓÐÓà¶î·¢.Ʊ£¬±¾¹«Ë¾Óë¶à¼Ò¹«Ë¾£¨ÆóÒµ£©ÓÐÒµÎñÍùÀ´£¬¿É¸ù¾Ý¿Í»§ÔÚ¡°»¥»Ý»¥Àû¡± µÄºÏ×÷»ù´¡ÉÏΪ¿Í»§(´ú¡£¿ª·¢Æ±)£¡
¹óÆóÒµ(¹«Ë¾)ÈôÓÐÒÔÏÂÇé¿öÇëÀ´µçÁª
ruby on rails招聘 北京十六方数字科技有限公司12月24日
Ruby网站主站开发工程师
工作年限:1-2年 招聘人数:若干人
语言能力:不限
工作地点:北京
学历:不限
职位描述/要求:
在十六方您加入的是一个创业型团队,十六方提供的是创新前沿的工作,您的工作可能对整个化工行业的发展产生实质性的影响。我们并不看重应聘者的学历和专业以及毕业学校,我们只关心素质能力和经验。热爱程序, 热爱设计, 热爱编写美丽的代码。
热爱学习跟踪最新的软件项目,热爱open source项目。
熟悉Ruby on Rails, 此外至少掌握诸如Python/PHP/Perl/C/Java/Actio
Ruby网站主站开发工程师
工作年限:1-2年 招聘人数:若干人
语言能力:不限
工作地点:北京
学历:不限
职位描述/要求:
在十六方您加入的是一个创业型团队,十六方提供的是创新前沿的工作,您的工作可能对整个化工行业的发展产生实质性的影响。我们并不看重应聘者的学历和专业以及毕业学校,我们只关心素质能力和经验。热爱程序, 热爱设计, 热爱编写美丽的代码。
热爱学习跟踪最新的软件项目,热爱open source项目。
熟悉Ruby on Rails, 此外至少掌握诸如Python/PHP/Perl/C/Java/Actio
