2015年4月30日星期四

MAC_033:编译运行C/C++程序

环境:MAC OS X 10.10.3

1. 编译运行C程序:
(1)创建 hello.c 文件,内容如下:
#include <stdio.h>
main()
{
  printf("Hello World!\n");
}
(2)编译:$ gcc hello.c -o helloC
hello.c:2:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
main()
^
1 warning generated.
(3)运行:$ ./helloC
 Hello World!

2. 编译运行C++程序
(1)创建 hello.cpp 文件,内容如下:
#include <iostream>
#include <string>
using namespace std;
int main() {
  cout << "Hello world!" << endl;
return 0;
}
(2)编译:$ g++ hello.cpp -o helloC++
(3)运行:$ ./helloC++ Hello World!

2015年4月21日星期二

Git_012:学习笔记之十二:常用命令一览表(摘录+整理)



参考文献:
1. http://www.git-tower.com/blog/git-cheat-sheet/

Git_011:学习笔记之十一:忽略特殊文件(摘录+整理)

有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件等等。
每次git status都会显示“Untracked files …”,让人看了心里不爽。
好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。

不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。
所有配置文件可以直接在线浏览:https://github.com/github/gitignore。
以网站提供的Java.gitignore文件为例:
*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

你可以创建自己的.gitignore文件,然后把Java.gitignore文件的内容复制进来。

忽略文件的原则是:
(1)忽略操作系统自动生成的文件,比如缩略图等。
(2)忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件。
(3)忽略带有敏感信息的配置文件,比如存放口令的配置文件。

最后一步就是把.gitignore也提交到Git,就完成了!当然检验.gitignore的标准是git status命令是不是说“working directory clean”。

Git_010:学习笔记之十:标签管理(摘录+整理)

正式发布一个版本时,通常先在版本库中打一个标签,这样,就唯一确定了打标签时刻的版本。
将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针,跟分支很像,区别在于分支可以移动,标签不可以。

1. 创建标签
在Git中打标签非常简单,首先,切换到需要打标签的分支上:
$ git branch
* dev
  master
$ git checkout master
Switched to branch 'master'
然后,敲命令git tag 就可以打一个新标签:
$ git tag v1.0
可以用命令git tag查看所有标签:
$ git tag
v1.0

默认标签是打在最新提交的commit上的。如果忘了当时打标签,只要找到历史提交的commit id,然后打上标签就可以了:
$ git log --pretty=oneline --abbrev-commit
6a5819e merged bug fix 101
cc17032 fix bug 101
7825a50 merge with no-ff
6224937 add merge
59bc1cb conflict fixed
400b400 & simple
75a857c AND simple
fec145a branch test
d17efd8 remove test.txt
...

比方说要对“add merge”这次提交打标签,它对应的commit id是6224937,敲入命令:
$ git tag v0.9 6224937
再用命令git tag查看标签:
$ git tag
v0.9
v1.0

注意,标签不是按时间顺序列出,而是按字母排序的。可以用git show 查看标签信息:
$ git show v0.9
commit 622493706ab447b6bb37e4e2a2f276a20fed2ab4
Author: Michael Liao
Date:   Thu Aug 22 11:22:08 2013 +0800

    add merge

可以看到,v0.9确实打在“add merge”这次提交上。

还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 3628164

2. 操作标签
如果标签打错了,也可以删除:
$ git tag -d v0.1
Deleted tag 'v0.1' (was e078af9)

因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使用命令git push origin
$ git push origin v1.0
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
 * [new tag]         v1.0 -> v1.0

或者,一次性推送全部尚未推送到远程的本地标签:
$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 554 bytes, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
 * [new tag]         v0.2 -> v0.2
 * [new tag]         v0.9 -> v0.9

如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9
Deleted tag 'v0.9' (was 6224937)

然后,从远程删除。删除命令也是push,但是格式如下:
$ git push origin :refs/tags/v0.9
To git@github.com:michaelliao/learngit.git
 - [deleted]         v0.9

Git_009:学习笔记之九:多人协作(摘录+整理)

当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且远程仓库的默认名称是origin。

1. 查看远程库的信息
$ git remote
origin
或者用 git remote -v 显示更详细的信息
$ git remote -v
origin    git@github.com:maping/learngit.git (fetch)
origin    git@github.com:maping/learngit.git (push)
上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。

2. 推送分支
推送分支就是把该分支上的所有本地提交推送到远程库。
推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上。
$ git push origin master
如果要推送其他分支,比如dev,就改成:
$ git push origin dev
那么,实际使用中,哪些分支需要推送呢?
master分支是主分支,因此要时刻与远程同步。
dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步。
bug分支只用于在本地修复bug,就没必要推到远程了。
feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。

3. 抓取分支
多人协作时,大家都会往master和dev分支上推送各自的修改。
现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆:
$ git clone git@github.com:maping/learngit.git
Cloning into 'learngit'...
remote: Counting objects: 44, done.
remote: Compressing objects: 100% (20/20), done.
remote: Total 44 (delta 22), reused 41 (delta 19), pack-reused 0
Receiving objects: 100% (44/44), done.
Resolving deltas: 100% (22/22), done.
Checking connectivity... done.

当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。
可以用git branch命令查看:
$ git branch
* master

现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:
$ git checkout -b dev origin/dev

现在,他就可以在dev上继续修改,比如修改test.txt文件,然后,时不时地把dev分支push到远程:
$ vim test.txt
$ git add test.txt
$ git commit -m "add def in test.txt"
[dev 37eab3d] add def in test.txt
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push origin dev

假设你的小伙伴已经向origin/dev分支推送了他的提交,而碰巧你也对test.txt文件的同一行作了修改,
$ vim test.txt
$ git add test.txt
$ git commit -m " add abcd in test.txt"
[dev 04e59fd]  add abcd in test.txt
 1 file changed, 1 insertion(+), 1 deletion(-)
并试图推送:
$ git push origin dev
Warning: Permanently added the RSA host key for IP address '192.30.252.131' to the list of known hosts.
To git@github.com:maping/learngit.git
 ! [rejected]        dev -> dev (fetch first)
error: failed to push some refs to 'git@github.com:maping/learngit.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突。
Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送:
$ git pull
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:maping/learngit
   3bbcb78..37eab3d  dev        -> origin/dev
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

    git pull

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/ dev

git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:
$ git branch --set-upstream dev origin/dev
The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
Branch dev set up to track remote branch dev from origin.

注意,这里提示--set-upstream已经不推荐使用,建议使用--set-upstream-to。
再次git pull
$ git pull
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.
这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。

解决后,提交,
$ vim test.txt
$ git add test.txt
$ git commit -m "fix conflict of test.txt"
[dev 9f9a615] fix conflict of test.txt

再push:
$ git push origin dev
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 523 bytes | 0 bytes/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To git@github.com:maping/learngit.git
   37eab3d..9f9a615  dev -> dev

4. 多人协作的工作模式通常是这样:
(1)首先,可以试图用git push origin branch-name推送自己的修改;
(2)如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
(3)如果合并有冲突,则解决冲突,并在本地提交;
(4)没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
(5)如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream branch-name origin/branch-name。

Git_008:学习笔记之八:解决冲突 (摘录+整理)

当两个分支都修改了同一个文件的同一行时,合并分支会出现冲突,请看下面的例子。

创建新的feature1分支,然后在新分支上开发:
$ git checkout -b feature1
Switched to a new branch 'feature1'
修改readme.txt最后一行,改为:
Creating a new branch is quick AND simple.
在feature1分支上提交:
$ git add readme.txt
$ git commit -m "AND simple"
[feature1 ae282f1] AND simple
 1 file changed, 1 insertion(+), 1 deletion(-)
切换到master分支:
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)
Git提示我们当前master分支比远程的master分支要超前1个提交。
在master分支上把readme.txt文件的最后一行改为:
Creating a new branch is quick & simple.
提交:
$ git add readme.txt
$ git commit -m "& simple"
[master d31216a] & simple
 1 file changed, 1 insertion(+), 1 deletion(-)
现在,master分支和feature1分支各自都分别有新的提交,变成了这样:



这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:
$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
果然冲突了!Git告诉我们,readme.txt文件存在冲突,必须手动解决冲突后再提交。git status也可以告诉我们冲突的文件:
$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add ..." to mark resolution)

    both modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
查看readme.txt内容:
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1
Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容。
现在只能手工解决冲突,手工修改readme.txt文件内容,冲突的内容修改如下:
Creating a new branch is quick and simple.
再提交:
$ git add readme.txt
$ git commit -m "conflict fixed"
[master 5ad1450] conflict fixed
现在,master分支和feature1分支变成了下图所示:


用带参数的git log也可以看到分支的合并情况:
$ git log --graph --pretty=oneline --abbrev-commit
*   5ad1450 conflict fixed
|\ 
| * ae282f1 AND simple
* | d31216a & simple
|/ 
* def512d branch test
* 52b439d add maping.txt
* 0c8b8f6 add test.txt
* c14c0fd remove test.txt
* e963d7c add test.txt
* 50f6556 git tracks changes of file
* 29b3a6f git tracks changes
* 35df8cb understand how stage works
* a98cca6 append GPL
* 6719ef3 add distributed
* ee16322 wrote a readme file
现在,删除feature1分支:
$ git branch -d feature1
Deleted branch feature1 (was ae282f1).

Git_007:学习笔记之七:创建与合并分支 (摘录+整理)

分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,别人还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
Git的分支比SVN的有分支管理快很多,无论创建、切换和删除分支,Git在1秒钟之内就能完成

1. Fast forward模式
截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:



每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长:
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:


Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!
不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:


假如在dev上的工作完成了,就可以把dev合并到master上。
Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:


所以Git合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,就剩下了一条master分支:

下面实际操作一下
创建dev分支,然后切换到dev分支
$ git checkout -b dev
Switched to a new branch 'dev'
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
使用git branch命令查看当前分支:
$ git branch
* dev
  master
git branch命令会列出所有分支,当前分支前面会标一个*号。
然后在dev分支上正常提交,比如对readme.txt做个修改,加上一行:Creating a new branch is quick.
然后提交:
$ git add readme.txt
$ git commit -m "branch test"
[dev def512d] branch test
 1 file changed, 1 insertion(+)
现在,dev分支的工作完成,切换回master分支:
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
切换回master分支后,查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变:

现在,我们把dev分支的工作成果合并到master分支上:
$ git merge dev
Updating 52b439d..def512d
Fast-forward
 readme.txt | 1 +
 1 file changed, 1 insertion(+)
git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。
注意到上面的Fast-forward,说明这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
当然,也不是每次合并都能Fast-forward,后面会将其他方式的合并。
合并完成后,就可以放心地删除dev分支了:
$ git branch -d dev
Deleted branch dev (was def512d).
删除后,查看branch,就只剩下master分支了:
$ git branch
* master

小结:
因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。

2. 禁用Fast forward模式
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
下面实战一下--no-ff方式的git merge:

首先,仍然创建并切换dev分支:
$ git checkout -b dev
Switched to a new branch 'dev'
修改readme.txt文件,并提交一个新的commit:

$ git add readme.txt
$ git commit -m "add merge"
[dev df5c80b] add merge
 1 file changed, 1 insertion(+)

现在,我们切换回master:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 4 commits.
  (use "git push" to publish your local commits)

准备合并dev分支,请注意--no-ff参数,表示禁用Fast forward:
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
 readme.txt | 1 +
 1 file changed, 1 insertion(+)

因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

合并后,我们用git log看看分支历史:

$ git log --graph --pretty=oneline --abbrev-commit
*   c9f6685 merge with no-ff
|\ 
| * df5c80b add merge
|/ 
*   5ad1450 conflict fixed
|\ 
| * ae282f1 AND simple
* | d31216a & simple
|/ 
* def512d branch test
* 52b439d add maping.txt
* 0c8b8f6 add test.txt
* c14c0fd remove test.txt
* e963d7c add test.txt
* 50f6556 git tracks changes of file
* 29b3a6f git tracks changes
* 35df8cb understand how stage works
* a98cca6 append GPL
* 6719ef3 add distributed
* ee16322 wrote a readme file

可以看到,禁用Fast forward模式,merge后就像这样:

3. Bug分支
每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交。
并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
$ git stash
首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:
$ git checkout master
$ git checkout -b issue-101
修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:
$ git checkout master
$ git merge --no-ff -m "merged bug fix 101" issue-101
$ git branch -d issue-101
现在,是时候接着回到dev分支干活了!
$ git checkout dev
工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看:
$ git stash list
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
(1)使用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除。
(2)使用git stash pop,恢复的同时把stash内容也删了。
$ git stash pop
再用git stash list查看,就看不到任何stash内容了:
$ git stash list

4. Feature分支
软件开发中,添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
现在,你接到了一个新任务:开发代号为Vulcan的新功能,于是准备开发:
$ git checkout -b feature-vulcan
开发完毕后,切回dev,准备合并:
$ git checkout dev
就在此时,接到上级命令,因经费不足,新功能必须取消!
虽然白干了,但是这个分支还是必须就地销毁:
$ git branch -d feature-vulcan
销毁失败。Git提示,feature-vulcan分支还没有被合并,如果删除,将丢失掉修改,如果要强行删除,需要使用命令git branch -D feature-vulcan。
现在强行删除:
$ git branch -D feature-vulcan

5. 分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:


Git_006:学习笔记之六:远程仓库 (摘录+整理)

GitHub网站提供Git仓库托管服务的,只要注册一个GitHub账号,就可以免费获得Git远程仓库。

1. 注册GitHub
(1)创建SSH Key。
在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。
如果没有,执行 $ ssh-keygen -t rsa -C “maping930883@hotmail.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/maping/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/maping/.ssh/id_rsa.
Your public key has been saved in /Users/maping/.ssh/id_rsa.pub.
The key fingerprint is:
18:7c:99:d1:af:0d:23:2b:24:ef:78:b4:01:e3:aa:6a maping930883@hotmail.com
The key's randomart image is:
+--[ RSA 2048]----+
|        ..       |
|     .   +.      |
|      o +  .     |
|    + .+. o .    |
|   . *. So =     |
|    . = . . .    |
|   . + +         |
| E. . +          |
|=.   .           |
+-----------------+

你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可。
如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。
(2)登陆GitHub
点击右上的齿轮图标,选择“Settings”,然后点击页面左边的“SSH Keys”,接着把id_rsa.pub内容复制到Key中,Title可以随便命名。

为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而且Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。
在GitHub上免费托管的Git仓库,任何人都可以看到,但只有你自己才能改,所以,不要把敏感信息放进去。
 2. 添加远程库
现在的情况是,你已经在本地创建了一个Git仓库:learngit,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作。
(1)登陆GitHub
点击右上角“+”号,选择“Create New…”,然后如下图操作。

在Repository name填入learngit,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的Git仓库。

目前,在GitHub上的这个learngit仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。

现在,我们根据GitHub的提示,在本地的learngit仓库下运行命令:

$ git remote add origin git@github.com:maping/learngit.git

注意,这里要替换成你自己的GitHub账户名,否则,你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在我的账户列表中。
添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

下一步,就可以把本地库的所有内容推送到远程库上:
$ git push -u origin master
The authenticity of host 'github.com (192.30.252.130)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,192.30.252.130' (RSA) to the list of known hosts.
Counting objects: 23, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (19/19), done.
Writing objects: 100% (23/23), 1.91 KiB | 0 bytes/s, done.
Total 23 (delta 7), reused 0 (delta 0)
To git@github.com:maping/learngit.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。
由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。


从现在起,只要本地作了提交,就可以通过命令:
$ git push origin master
把本地master分支的最新修改推送至GitHub,现在,你就拥有了真正的分布式版本库!

3. 从远程库克隆
添加远程库讲的是先有本地库,后有远程库的情况下如何关联远程库。
其实比较好的方式是先创建远程库,然后从远程库克隆。
首先,登陆GitHub,创建一个新的仓库,名字叫gitskills:


勾选Initialize this repository with a README,这样GitHub会自动为我们创建一个README.md文件。创建完毕后,可以看到README.md文件。

现在,远程库已经准备好了,下一步是用命令git clone克隆一个本地库:
$ git clone git@github.com:maping/gitskills.git
Cloning into 'gitskills'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
Checking connectivity... done.

注意把Git库的地址换成你自己的,然后进入gitskills目录看看,已经有README.md文件了。
如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。
你也许注意到GitHub给出的地址不止一个,还可以用https://github.com/maping/gitskills.git这样的地址。
实际上,Git支持多种协议,默认的git://使用ssh协议,但也可以使用https等其他协议。
使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。

2015年4月20日星期一

Git_005:学习笔记之五:版本库高级操作之修改 (摘录+整理)

Git比SVN优秀的另一个原因是:Git跟踪并管理的是修改,而非文件。

那么什么是修改?新增了一行,是修改,删除了一行,也是修改,更改了某些字符,是修改,删了一些又加了一些,也是修改,甚至创建一个新文件,也算修改。

1. 如果你做了修改,但是没有先执行 git add,而是直接执行了git commit,那会怎样?
还是做个实验来验证一下吧。
(1)修改readme.txt,增加一行内容:
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes.
(2)$ git add readme.txt
(3)$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

    modified:   readme.txt

(4)再次修改readme.txt,修改最后一行内容:
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
(5)$ git commit -m "git tracks changes"
[master 29b3a6f] git tracks changes
 1 file changed, 1 insertion(+)
(6)$ git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

    modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")

咦,怎么第二次的修改没有被提交?
(7)对比工作区和版本库中的readme.txt区别
$ git diff HEAD -- readme.txt
diff --git a/readme.txt b/readme.txt
index 76d770f..a9c5755 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,4 +1,4 @@
 Git is a distributed version control system.
 Git is free software distributed under the GPL.
 Git has a mutable index called stage.
-Git tracks changes.
+Git tracks changes of files.

可见,第二次修改确实没有被提交。

(8)$ git add readme.txt
(9)$ git commit -m "git tracks changes of file"

2. 撤销修改

(1)修改readme.txt,增加一行内容:
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
My stupid boss still prefers SVN.
(2)在你准备提交前,你发现了“stupid boss”这一句并不合适,你想回到修改之前的版本。
(3)$ git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

    modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
从输出中,Git告诉我们可以使用 $ git checkout -- file 可以丢弃工作区的修改:
(4)$ git checkout -- readme.txt
readme.txt 自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;

注意,git checkout -- file 命令中的--很重要,没有--,就变成了“创建一个新分支”的命令。

(5)如果你做完了第(1)步,并且执行了 $ git add readme.txt
(6)$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

    modified:   readme.txt
从输出中,Git告诉我们可以使用 $ git reset HEAD ... 可以暂存区的修改撤销。
这里的HEAD表示当前最新的版本。
(7)$ git reset HEAD readme.txt
Unstaged changes after reset:
M    readme.txt
(8)$ git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

    modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
现在暂存区是干净的,工作区有修改。
(9)$ git checkout -- readme.txt
现在撤销工作区的修改
(10)$ git status
On branch master
nothing to commit, working directory clean
整个世界终于清静了!

再进一步,假设你执行了 git add 和 git commit操作,现在后悔了,应该怎么办呢?
还记得怎么做回退操作吗?
注意回退的前提是你没有推送到远程库。

3. 删除与撤销删除
(1)新添加一个文件:test.txt,并提交。
$ git add test.txt
$ git commit -m "add test.txt"
[master e963d7c] add test.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt
(2)$ rm test.txt
这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了:
(3)$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

    deleted:    test.txt

no changes added to commit (use "git add" and/or "git commit -a")
现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit:
(4)$ git rm test.txt
(5)$ git commit -m "remove test.txt"
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:
(6)$ git checkout -- test.txt

Git_004:学习笔记之四:工作区和暂存区 (摘录+整理)

Git和SVN的另外一个不同之处是暂存区。

工作区(Working Directory):就是你在电脑里能看到的目录,比如learngit文件夹就是一个工作区:
版本库(Repository):工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。

使用git add把文件添加进去,实际上就是把文件修改添加到暂存区。
使用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一的一个master分支,所以git commit就是往master分支上提交更改。
可以简单理解为,需要提交的文件修改通通放到暂存区,然后一次性提交暂存区的所有修改。

我们通过以下实验来理解暂存区。
1. 先对readme.txt做个修改,增加一行内容,添加后内容如下:
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.

2. 在工作区新增一个LICENSE文件

3. 运行 git status 查看状态
$ git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

    modified:   readme.txt

Untracked files:

  (use "git add ..." to include in what will be committed)

    LICENSE

no changes added to commit (use "git add" and/or "git commit -a")

Git非常清楚地告诉我们,readme.txt被修改了,而LICENSE还从来没有被添加过,所以它的状态是Untracked。

4. 添加readme.txt和LICENSE文件
(1)$ git add readme.txt
(2)$ git add LICENSE

5. 再次运行 git status 查看状态
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

    new file:   LICENSE
    modified:   readme.txt
现在,暂存区的状态就变成这样了:



6. 提交修改
$ git commit -m "understand how stage works"
[master 35df8cb] understand how stage works
 2 files changed, 1 insertion(+)
 create mode 100644 LICENSE
现在版本库变成了这样,暂存区就没有任何内容了:

所以,git add命令把要提交的所有修改放到暂存区,然后,执行git commit可以一次性把暂存区的所有修改提交到分支。

Git_003:学习笔记之三:版本库高级操作之回退 (摘录+整理)


再次修改readme.txt文件如下:
Git is a distributed version control system.
Git is free software distributed under the GPL.
增加并提交本次修改:
$ git add readme.txt
$ git commit -m "append GPL"
[master a98cca6] append GPL
 1 file changed, 1 insertion(+), 1 deletion(-)

现在,我们回顾一下readme.txt文件一共有几个版本被提交到Git仓库里了:
版本1:wrote a readme file
Git is a version control system.
Git is free software.

版本2:add distributed
Git is a distributed version control system.
Git is free software.

版本3:append GPL
Git is a distributed version control system.
Git is free software distributed under the GPL.

可以使用命令 git log 来查看版本的历史记录(日期由近到远)
$ git log readme.txt
commit a98cca6ddf6708d12717fd6c06b7b10ecfc30a55
Author: maping
Date:   Mon Apr 20 17:30:39 2015 +0800

    append GPL

commit 6719ef3df6910b4a9772030963625aa86a8ba5ca
Author: maping
Date:   Mon Apr 20 17:23:34 2015 +0800

    add distributed

commit ee163220c9008f074c0f757593a2cf3d50cf85cf
Author: maping
Date:   Mon Apr 20 17:02:46 2015 +0800

    wrote a readme file

如果嫌输出信息太多,看得眼花缭乱的,可以加上--pretty=oneline参数:
$ git log --pretty=oneline
a98cca6ddf6708d12717fd6c06b7b10ecfc30a55 append GPL
6719ef3df6910b4a9772030963625aa86a8ba5ca add distributed
ee163220c9008f074c0f757593a2cf3d50cf85cf wrote a readme file

这里你看到的一大串数字是commit id(版本号),和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示。
为什么commit id需要用这么一大串数字表示呢?因为Git是分布式的版本控制系统,后面我们还要研究多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,那肯定就冲突了。

1. 版本回退
首先,必须知道当前版本是哪个版本,在Git中用HEAD表示当前版本,这里是a98cca6ddf6708d12717fd6c06b7b10ecfc30a55。
上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。
可以使用git reset命令把当前版本“append GPL”回退到上一个版本“add distributed”:
$ git reset --hard HEAD^
HEAD is now at 6719ef3 add distributed

看看readme.txt的内容是不是版本“add distributed”:
$ cat readme.txt
Git is a distributed version control system.
Git is free software.
果然。
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向“append GPL”:

 
改为指向“add distributed”:

用git log再看看现在版本库的状态:
$ git log
commit 6719ef3df6910b4a9772030963625aa86a8ba5ca
Author: maping
Date:   Mon Apr 20 17:23:34 2015 +0800

    add distributed

commit ee163220c9008f074c0f757593a2cf3d50cf85cf
Author: maping
Date:   Mon Apr 20 17:02:46 2015 +0800

    wrote a readme file
最新的那个版本“append GPL”已经看不到了!
如果想要回到最新的版本,可以使用
$ git reset --hard a98cca6dd
HEAD is now at a98cca6 append GPL
版本号没必要写全,前几位就可以了,Git会自动去找。当然也不能只写前一两位,因为Git可能会找到多个版本号,就无法确定是哪一个了。
看看readme.txt的内容是不是版本“append GPL”:
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
果然回来了。

如果不记得了commit id,可以使用 git reflog 用来记录你的每一次命令:

$ git reflog
a98cca6 HEAD@{0}: reset: moving to a98cca6dd
6719ef3 HEAD@{1}: reset: moving to HEAD^
a98cca6 HEAD@{2}: commit: append GPL
6719ef3 HEAD@{3}: commit: add distributed
ee16322 HEAD@{4}: commit (initial): wrote a readme file

Git_002:学习笔记之二:版本库基本操作 (摘录+整理)

版本库又名仓库,英文名repository,可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

1. 创建版本库
(1)选择一个合适的地方,创建一个空目录
$ mkdir learngit
$ cd learngit
$ pwd
/Users/maping/learngit
(2)初始化版本库
$ git init
Initialized empty Git repository in /Users/maping/learngit/.git/
现在成功初始化了一个空的仓库,变成了Git可以管理的仓库。
你会发现在当前目录下多了一个隐藏目录:.git,这个目录是Git来跟踪管理版本库的。

2. 添加文件到版本库
所有的版本控制系统,其实只能跟踪文本文件的改动,Git也不例外。
因此要真正使用版本控制系统,就要以纯文本方式编写文件,因为文本是有编码的,这里强烈建议使用标准的UTF-8编码。
(1)创建一个readme.txt文件,放到learngit目录下,其内容如下:
Git is a version control system.
Git is free software.
(2)把文件添加到仓库
$ git add readme.txt
(3)把文件提交到仓库
$ git commit -m "wrote a readme file"
[master (root-commit) ee16322] wrote a readme file
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt
git commit 命令执行成功后会告诉你,1个文件被改动(我们新添加的readme.txt文件),插入了两行内容(readme.txt有两行内容)。
git commit 命令可以一次提交很多文件,所以你可以执行多次git add命令添加多个不同的文件,然后在执行一次git commit 命令提交所有添加的文件。

3. 修改文件
(1)修改readme.txt文件内容,修改后内容如下:
Git is a distributed version control system.
Git is free software.
现在,运行 git status 命令看看状态:
$ git status
[master (root-commit) ee16322] wrote a readme file
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt
MaPingdeMacBook-Pro:learngit maping$ vim readme.txt
MaPingdeMacBook-Pro:learngit maping$ git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

    modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")

git status 命令可以让我们时刻掌握仓库当前的状态,上面的命令告诉我们,readme.txt被修改过了,但还没有准备提交的修改。

现在,运行 git diff readme.txt 命令查看具体修改了什么内容
$ git diff readme.txt
diff --git a/readme.txt b/readme.txt
index 46d49bf..9247db6 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
-Git is a version control system.
+Git is a distributed version control system.
 Git is free software.

知道了对readme.txt作了什么修改后,再把它提交到仓库就放心多了,提交修改和提交新文件的步骤是一样的。
$ git add readme.txt
再次运行 git status 命令查看状态
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

    modified:   readme.txt

git status告诉我们,将要被提交的修改包括readme.txt,接下来就可以放心地提交了。

$ git commit -m "add distributed"
[master 6719ef3] add distributed
 1 file changed, 1 insertion(+), 1 deletion(-)

提交后,再用 git status 命令看看仓库的当前状态:
$ git status
On branch master
nothing to commit, working directory clean

git status 告诉我们当前没有需要提交的修改,而且工作目录是干净的。

Git_001:学习笔记之一:安装 (摘录+整理)

本系列文章来自廖雪峰的《Git教程》,在此感谢廖雪峰的辛勤劳动。

Git名字的由来:”Git which is British English slang for a stupid or unpleasant person.”
开发人员所熟悉的SVN是集中式的版本控制系统,而Git是分布式版本控制系统,集中式和分布式版本控制系统有什么区别呢?

集中式版本控制系统,版本库是集中存放在中央服务器的,写代码的时候,需要先从中央服务器取得最新的版本下载到本地电脑,然后在本地电脑开始干活,干完活了,再把自己的修改推送给中央服务器。
中央服务器就集中式版本控制系统最大的毛病就是必须联网才能工作,如果网速慢的话,将令人无法忍受。

图1 集中式版本控制系统
分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。
为了多人协作,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
图2 分布式版本控制系统

1. 在MAC下安装Git
(1)安装Xcode
Xcode是Apple官方免费IDE,功能非常强大,是开发Mac和iOS App的必选装备,Xcode中自带Git。
因此安装了Xcode后,就不用再单独安装Git了。
Git安装后位置在:/usr/bin/git。
(2)使用homebrew安装Git
如果你装了homebrew了的话,运行brew install git即可安装Git。
Git安装后位置在:/usr/local/bin/git。

2. Git配置
因为Git是分布式版本控制系统,所以每个机器都必须自报家门:你的名字和Email地址。
注意,这里的git config命令的--global参数,表示你这台机器上所有的Git仓库都会使用这个配置。
$ git config --global user.name "maping"
$ git config --global user.email "maping930883@hotmail.com"

当然也可以对某个仓库指定不同的用户名和Email地址,不过这是后话。
让Git显示颜色,会让命令输出看起来更醒目。
$ git config --global color.ui true

参考文献
1. http://segmentfault.com/q/1010000000095119

2015年4月17日星期五

MAC_032:为自带词典软件添加词库

环境:MAC OS X 10.10.3

MAC本身自带一个词典软件,还算好用,就是词库太少了,很多词查不出来。
添加词库步骤如下:

1.下载并安装 DictUnifier
下载地址:https://code.google.com/p/mac-dictionary-kit/
这个软件是用来转换成符合MAC自带词典软件的格式。

2. 下载词库
网上有很多下载的地方,为了方便,我放到了自己的网盘上。
下载地址:http://yunpan.cn/cVWVWzu4bhiWS (提取码:30fa)

3. 解压并安装词库
解压词库后,会有很多目录,每个目录是一个词库:
以目录21shijishuangxiangcidian为例,运行DictUnifier,把目录中的21shijishuangxiangcidian.ifo文件拖放到DictUnifier中,等待转换,根据词库大小,时间长短不同。

转换完毕后,重新启动词典软件,然后勾上新添加的词库,现在你就可以使用这些新词库查单词啦。


MAC中的词库是存在这里的:/资源库/Dictionaries,不过你不用手工管理,DictUnifer转换后,会自动把词库复制到这里。