liuhui998's new blog

using octopress

uMenu 电子菜单

| Comments

最近一直比较忙,在忙我们团队的产品 uMenu 电子菜单

封面

主界面

这是一个给餐厅代替传统纸质菜谱进行点菜的iPad app程序,下面是菜品的使用介绍视频。

说了这么多,怎么好像点“软文”的味道呀 :)

OK, 下面我们就说点实际的:

1) 我们team的所有代码(iOS & 后台)的都使用git & github 进行管理

使用 Git 的原因就不用我多解释了,但是在代码托管问题上,我想大家可能都有伤脑筋的时候。 自建的话:麻烦、成本高、无专人维护;最后我们下定决心,使用了github,在使用的过程的还比较顺利。大家之间一般fork & pull request 来进行协同;只是对于xcode 的pbxproject 文件的合并还没有什么好的办法。

2) 内部代码的打包、测试、发布基本上都用脚本实现了自动化。

这个就没有什么好说的,我想大家都一样;如果有兴趣的话就下次说:)

Firefox8兼容安装keysnail

| Comments

今天在用firefox上网时,firefox突然冒了一个升级提示,我不小心就被升级到了8.0。

当时我并没有在意,结果发现我平时用的 keysnail 就不能用了,提示不兼容。

以前我也碰到过同样的问题,我估计是: keysnail.xpi 里的版本设置问题。
我猜是firefox的版本更新的太快了,keysnail的作者来不及更新,于是我决定自己动手。

用git: “”https://github.com/mooz/keysnail.git">https://github.com/mooz/keysnail.git" clone了 keysnail 的最新代码

执行了 “./set_version_info.rb”

提示:
Input next version of this addon: 8

我随便输了一个addon版本号: 8。

提示:
Input next max version for target application: 8

因为现在firefox的版本是8,我也输入个: 8。

最后再执行: "./createpackage.sh "

就会生成 “keysnail.xpi”

在执行"./createpackage.sh" 有一点要注意的是:

在 MacOSX 有可能会出现下面的提示:“./createpackage.sh:50: command not found: xsel”。这是作者想把一些命令的输出复制到系统剪贴板上,需要使用一个叫 “xsel” 的命令。我们这里不需要复制内容到剪贴板,只直把这一行用 “#” 注释掉就可以了。

更新了 Git Community Book

| Comments

之前有一些朋友提交了书中的一些bug
虽然合并的仓库中,但是没有根据这些修改发布新版本
今天把修改发布到:

gitbook.liuhui998.com

我的主要工作环境切换到了 MacOSX 有一段时间了
现在基熟悉新了的环境后
我会的陆续写一些 git 相关的资料

大家如果在 MacOSX下工作的,可以看看下面这两个工具

GitX(L)
SourceTree

欢迎大家交流

InfoQ专栏 Git历险记(四)——索引与提交的幕后故事

| Comments

  1. 不一样的索引
    我想如果看过《Git历险记》的前面三篇文章的朋友可能已经知道怎么用git addgit commit这两个命令了;知道它们一个是把文件暂存到索引中为下一次提交做准备,一个创建新的提交(commit)。但是它们台前幕后的一些有趣的细节大家不一定知晓,请允许我一一道来。

Git 索引是一个在你的工作目录(working tree)和项目仓库间的暂存区域(staging area)。有了它, 你可以把许多内容的修改一起提交(commit)。 如果你创建了一个提交(commit),那么提交的一般是暂存区里的内容, 而不是工作目录中的内容。

一个Git项目中文件的状态大概分成下面的两大类,而第二大类又分为三小类:


  1. 未被跟踪的文件(untracked file)

  2. 已被跟踪的文件(tracked file)

    1. 被修改但未被暂存的文件(changed but not updated或modified)

    2. 已暂存可以被提交的文件(changes to be committed 或staged)

    3. 自上次提交以来,未修改的文件(clean 或 unmodified)

看到上面的这么多的规则,大家早就头大了吧。老办法,我们建一个Git测试项目来试验一下:

我们先来建一个空的项目:

1
2
3
4
5
$rm -rf stage_proj
$mkdir stage_proj
$cd stage_proj
$git init
Initialized empty Git repository in /home/test/work/test_stage_proj/.git/

我们还创建一个内容是“hello, world”的文件:
1
$echo "hello,world" > readme.txt

现在来看一下当前工作目录的状态,大家可以看到“readme.txt”处于未被跟踪的状态(untracked file):
1
2
3
4
5
6
7
8
9
10
$git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   readme.txt
nothing added to commit but untracked files present (use "git add" to track)

把“readme.txt"加到暂存区: $git add readme.txt

现在再看一下当前工作目录的状态:

1
2
3
4
5
6
7
8
9
10
$git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   readme.txt
#

可以看到现在"readme.txt"的状态变成了已暂存可以被提交(changes to be committed),这意味着我们下一步可以直接执行“git commit“把这个文件提交到本地的仓库里去了。

暂存区(staging area)一般存放在“git目录“下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。索引是一个二进制格 式的文件,里面存放了与当前暂存内容相关的信息,包括暂存的文件名、文件内容的SHA1哈希串值和文件访问权限,整个索引文件的内容以暂存的文件名进行排 序保存的。

但是我不想马上就把文件提交,我想看一下暂存区(staging area)里的内容,我们执行git ls-files命令看一下:

1
2
$git ls-files --stage
100644 2d832d9044c698081e59c322d5a2a459da546469 0   readme.txt

我们如果有看过上一篇文章里 的"庖丁解牛", 你会发现“git目录“里多出了”.git/objects/2d/832d9044c698081e59c322d5a2a459da546469”这 么一个文件,再执行“git cat-file -p 2d832d” 的话,就可以看到里面的内容正是“hello,world"。Git在把一个文件添加暂存区时,不但把它在索引文件(.git/index)里挂了号,而 且把它的内容先保存到了“git目录“里面去了。

如果我们执行”git add“命令时不小心把不需要的文件也加入到暂存区中话,可以执行“git rm —cached filename" 来把误添加的文件从暂存区中移除。

现在我们先在"readme.txt"文件上做一些修改后:

1
$echo "hello,world2" >> readme.txt

再来看一下暂存区的变化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   readme.txt
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   readme.txt
#

大家可以看到命令输出里多了一块内容:“changed but not updated …… modified: readme.txt”。大家可能会觉得很奇怪,我前面不是把"readme.txt"这个文件给添加到暂存区里去了吗,这里怎么又提示我未添加到暂存区 (changed but not updated)呢,是不是Git搞错了呀。

Git 没有错,每次执行“git add”添加文件到暂存区时,它都会把文件内容进行SHA1哈希运算,在索引文件中新加一项,再把文件内容存放到本地的“git目录“里。如果在上次执行 “git add”之后再对文件的内容进行了修改,那么在执行“git status”命令时,Git会对文件内容进行SHA1哈希运算就会发现文件又被修改了,这时“readme.txt“就同时呈现了两个状态:被修改但未 被暂存的文件(changed but not updated),已暂存可以被提交的文件(changes to be committed)。如果我们这时提交的话,就是只会提交第一次“git add"所以暂存的文件内容。

我现在对于“hello,world2"的这个修改不是很满意,想要撤消这个修改,可以执行git checkout这个命令:

1
$git checkout -- readme.txt

现在再来看一下仓库里工作目录的状态:
1
2
3
4
5
6
7
8
9
10
$git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   readme.txt
#

好的,现在项目恢复到我想要的状态了,下面我就用git commit 命令把这个修改提交了吧:
1
2
$git commit -m "project init"
[master (root-commit) 6cdae57] project init   1 files changed, 1 insertions(+), 0 deletions(-)    create mode 100644 readme.txt

现在我们再来看一下工作目录的状态:
1
2
3
$git status
# On branch master
nothing to commit (working directory clean)

大家可以看到“nothing to commit (working directory clean)”;如果一个工作树(working tree)中所有的修改都已提交到了当前分支里(current head),那么就说它是干净的(clean),反之它就是脏的(dirty)。

  1. SHA1值内容寻址
    正如Git is the next Unix 一文中所说的一样,Git是一种全新的使用数据的方式(Git is a totally new way to operate on data)。Git把它所管理的所有对象(blob,tree,commit,tag……),全部根据它们的内容生成SHA1哈希串值作为对象名;根据目 前的数学知识,如果两块数据的SHA1哈希串值相等,那么我们就可以认为这两块数据是相同 的。这样会带来的几个好处:

    1. Git只要比较对象名,就可以很快的判断两个对象的内容是否相同。

    2. 因为在每个仓库(repository)的“对象名”的计算方法都完全一样,如果同样的内容存在两个不同的仓库中,就会存在相同的“对象名”。

    3. Git还可以通过检查对象内容的SHA1的哈希值和“对象名”是否匹配,来判断对象内容是否正确。


    我们通过下面的例子,来验证上面所说的是否属实。现在创建一个和“readme.txt“内容完全相同的文件”readme2.txt“,然后再把它提交到本地仓库中:
    1
    2
    3
    4
    5
    6
    
    $echo "hello,world" > readme2.txt
    $git add readme2.txt
    $git commit -m "add new file: readme2.txt"
    [master 6200c2c] add new file: readme2.txt
    1 files changed, 1 insertions(+), 0 deletions(-)
    create mode 100644 readme2.txt

    下面的这条很复杂的命令是查看当前的提交(HEAD)所包含的blob对象:
    1
    2
    3
    
    $git cat-file -p HEAD | head -n 1 | cut -b6-15 | xargs git cat-file -p
    100644 blob 2d832d9044c698081e59c322d5a2a459da546469    readme.txt
    100644 blob 2d832d9044c698081e59c322d5a2a459da546469    readme2.txt

    我们再来看看上一次提交(HEAD^)所包含的blob对象:
    1
    2
    
    $git cat-file -p HEAD^ | head -n 1 | cut -b6-15 | xargs git cat-file -p
    100644 blob 2d832d9044c698081e59c322d5a2a459da546469    readme.txt

    很明显大家看到尽管当前的提交比前一次多了一个文件,但是它们之间却是在共用同一个blob对象:“2d832d9”。
  2. No delta, just snapshot
    Git 与大部分你熟悉的版本控制系统,如Subversion、CVS、Perforce 之间的差别是很大的。传统系统使用的是: “增量文件系统” (Delta Storage systems),它们存储是每次提交之间的差异。而Git正好与之相反,它是保存的是每次提交的完整内容(snapshot);它会在提交前根据要提交 的内容求SHA1哈希串值作为对象名,看仓库内是否有相同的对象,如果没有就将在“.git/objects"目录创建对应的对象,如果有就会重用已有的 对象,以节约空间。

下面我们来试验一下Git是否真的是以“snapshot”方式保存提交的内容。

先修改一下"readme.txt",给里面加点内容,再把它暂存,最后提交到本地仓库中:

1
2
3
4
$echo "hello,world2" >> readme.txt
$git add readme.txt
$git commit -m "add new content for readme.txt"
[master c26c2e7] add new content for readme.txt   1 files changed, 1 insertions(+), 0 deletions(-)

我们现在看看当前版本所包含的blob对象有哪些:
1
2
3
$git cat-file -p HEAD | head -n 1 | cut -b6-15 | xargs git cat-file -p
100644 blob 2e4e85a61968db0c9ac294f76de70575a62822e1    readme.txt
100644 blob 2d832d9044c698081e59c322d5a2a459da546469    readme2.txt

从上面的命令输出,我们可以看到"readme.txt"已经对应了一个新的blob对象:“2e4e85a”,而之前版本的"readme.txt“对应的blob对象是:“2d832d9”。下面我们再来看一看这两个”blob“里面的内容和我们的预期是否相同:
1
2
3
4
5
$git cat-file -p 2e4e85a
hello,world
hello,world2
$git cat-file -p 2d832d9
hello,world

大家可以看到,每一次提交的文件内容还是全部保存的(snapshot)。

  1. 小结
    Git内在机制和其它传统的版本控制系统(VCS)间存在本质的差异,所以Git的里"add"操作的含义和其它VCS存在差别也不足为奇,“git add“不但能把未跟踪的文件(untracked file)添加到版本控制之下,也可以把修改了的文章暂存到索引中。

同时,由于采用“SHA1哈希串值内容寻值“和”快照存储(snapshot)“,让Git成为一个速度非常非常快的版本控制系统(VCS)。

  1. 参考
  2. 致谢
    感谢上帝对我的眷顾,让我可以有写作专栏的这样一个机会。

感谢朋友们在写作过程的无私帮助:张凯峰刘炜许晓斌Fenng……

特别要感謝家人默默支持:)

本文已经首发于InfoQ中文站,版权所有,原文为Git历险记(四)——索引与提交的幕后故事如需转载,请务必附带本声明,谢谢。
InfoQ中文站是一个面向中高端技术人员的在线独立社区,为Java、.NET、Ruby、SOA、敏捷、架构等领域提供及时而有深度的资讯、高端技术大会如QCon 、线下技术交流活动QClub、免费迷你书下载如架构师》等。


原创文章,转载请注明出处, 本文地址:http://liuhui998.com/2011/03/17/git-adventures-index-commit/

添加新的 QQ 快捷键

| Comments

老实讲,我不是很喜欢用QQ,但是因为工作的关系,必须要用。

QQ虽然提供了一些快捷键,但是很多我想要的没有,平时用起来很不方便;我又不是小马哥,怎么办,自动手加吧。

平时用的比较的多两个没有快捷键的功能:

1
2
1)  消息盒子”里的“忽略”按钮
2)  定位到QQ主界面的”搜索框

如果自己从头用vc来写程序就太麻烦了,我现在用AutoHotkey来写脚本定义这些我需要的快捷键:

我现在用的是QQ2011,我先用工具测得了”搜索框“相关对主界面原点(0,0)的偏移量大约是(130,120),然后我只要找到一个名为“QQ2011”的窗口,再然再往(130,120)这个点上发送击事件就可以了。

这个操作我绑定的快捷键是 “Win” + A , 要求QQ2011 主界面没有隐藏才可以操作:

1
2
3
4
5
6
7
8
#A::
IfWinExist QQ2011
{   

    WinActivate
    Send {Click 130,120}
}
return

对于”消息盒子“里的”忽略“按钮也是一样的处理,测出按钮相对于它所在窗口的偏移量,然后再向那个位置发送一个点击事件。

这个操作我绑定的快捷键是 “Win” + B , 要求QQ2011 消息盒子没有隐藏才可以操作(在用的时候把nickname改成自己的呢称):

1
2
3
4
5
6
7
#B::
IfWinExist nickname - 消息盒子
{
    WinActivate
    Send {Click 527,100}
}
return

有兴趣的朋友可以看看这里:小众软件,AutoHotkey

原创文章,转载请注明出处: liuhui998博客