乐者为王

Do one thing, and do it well.

Git笔记之branch,merge和rebase

1
2
3
4
5
6
7
8
git branch  # 列出所有分支以及当前在哪个分支上
git branch <branch>  # 建立分支
git branch -m <oldbranch> <newbranch>  # 修改分支的名字
git checkout <branch>  # 切换分支
git checkout -b <branch> <commit>  # 新建分支并切换过去
git branch -d <branch>  # 刪除分支
git merge <branch>  # 合并分支到当前分支上
git rebase <branch>  # 将提交迁移到上游分支

在merge/rebase的过程中,也许会出现冲突。在这种情况,Git会停止merge/rebase并让你去解决冲突,冲突内容以如下形式存在:

1
2
3
4
5
<<<<<<< HEAD
Here is the original change.
=======
Here is the modified chagne.
>>>>>>>

<<<<<<<下面的是当前版本的内容;=======和>>>>>>>之间的则是分支里与之对应的有冲突的内容。修复冲突要做的就是把<<<<<<< HEAD和>>>>>>>之间的内容改成我们想要的。在解决完冲突后,用git add命令去更新这些内容,如果是rebase,那么你无需执行git commit,只要执行git rebase --continue命令即可,这样Git会继续apply余下的补丁。

rebase的做法是先将HEAD指向目标分支的最新commit,这时HEAD的内容变为目标分支最新commit的SHA1值,然后将当前分支的commit,一个个重新apply到目标分支上,完成后再将HEAD指向新的commit。例如,当前分支是master,然后执行git rebase dev,就会把两个分支的共同祖先的commit之后的所有master的commit记录,重新在dev分支上再commit一遍。

fast-forward在Git中是一种merge术语,当dev分支是从master分支的最新commit分出来的时候,那么如果master要把dev分支merge进来,由于dev的parent commit是master的最新commit,所以这两个分支的合并不会有任何冲突,实际上的动作只是把master的HEAD指向dev的最新commit而已。线图上来看两个分支根本是同一条线。

Git笔记之tag

git tag的主要作用是给某个commit起一个好记的名字。这里列举了一些常用的tag命令:

1
2
3
4
git tag  # 显示所有标签
git tag v1.1.0  # 轻量级标签
git tag -a v1.1.0 -m "Release v1.1.0"  # 带注释的标签
git tag -d v1.1.0  # 删除特定标签

如果想给某个commit添加标签,可以使用如下命令:

1
git tag -a v1.1.0 <commit>

查看指定tag的信息可以用:

1
git show v1.1.0

要筛选同类标签的话,可以使用:

1
git tag -l 'v1.1.*'

它会列出前缀为v1.1.的所有标签。

有了标签要在团队之间分享怎么办?可以使用下面的命令把标签推送到远程仓库中:

1
2
git push origin v1.1.0  # 推送指定标签
git push origin --tags  # 推送所有标签

Git笔记之status

git status命令会显示当前项目状态的一个简单总结:

  • 当Git提示说“Untracked files”表示新增加的文件还没有被纳入到Git版本控制系统的追踪;
  • 如果提示说“Changed but not updated”表示在工作目录下做的修改还没有被添加到索引文件中;
  • 如果你看到提示说“Changes to be committed”则表示发现了你已经添加到索引文件里,但尚未提交的内容。

当然你也有可能喜欢短小的输出提示,那么可以使用-s选项:

1
git status -s
  • 它会用??表示“Untracked files”的文件;
  • 用红色的M表示“Changed but not updated”的文件;
  • 用绿色的M表示“Changes to be committed”;
  • 用绿色的A表示新增加但“Changes to be committed”的文件。

Git笔记之diff

今天,我们重点来探讨一下git diff的用法。

我们知道在Git提交环节存在三大部分:工作目录、索引文件、仓库。每当你对代码进行了修改,工作目录的状态就发生了改变。索引文件是连接工作目录和仓库的桥梁,每次当我们使用git add命令后,索引文件的内容就改变了,变得和工作目录同步。仓库是提交环节的最后阶段,只有在我们使用git commit命令将索引文件中的内容提交后,我们的代码才真正地进入了仓库。

git diff就是用来比较提交环节三大部分的差别。其中,纯粹的git diff是查看工作目录与索引文件之间的差别;git diff –cached是查看索引文件和仓库之间的差别;git diff HEAD则是查看工作目录和仓库之间的差别。

下图是三种查看方式的说明:

git diff会输出全部的差别内容,但有时我们只想看看修改的内容的汇总,这时就可以使用--stat选项。这里是它的使用实例:

1
2
3
git diff --stat
git diff --cached --stat
git diff HEAD --stat

如果你想查看其它分支与当前分支的差别,只要运行以下命令即可:

1
git diff <otherbranch>

你也可以加上路径限定符,来比较某一个文件或目录:

1
git diff <otherbranch> <filename>

Git笔记之log

最简单的查看开发日志的命令是git log。如果你觉得git log给出的信息太单薄,那么可以使用git log -p,它不但会给出非常详细的开发日志,而且还会显示每次提交实际修改的内容。

git log支持很多的参数,可以将这些参数结合起来使用。下面是经常使用的一些参数:

1
2
3
4
5
6
7
-–name-only  # 只显示变更文件的名称
-–oneline    # 将提交信息压缩到一行显示
-–graph      # 显示所有提交的依赖树
-–reverse    # 按照逆序显示提交记录(最先提交的在最前面)
-–since      # 显示某个日期之后发生的提交
-–until      # 显示某个日期之前发生的提交
--decorate   # 显示每个commit的引用

如果你曾经与很多小伙伴工作在同一个分支上,也许会有这样的经历,master分支上的大量合并同步到你当前的分支。这使得我们很难分辨哪些变更是发生在master分支,哪些变更是发生在当前分支,且尚未合并到master分支。可以使用git log --no-merges master..查看尚未合并的变更。其中--no-merges选项表示着只显示没有合并到任何分支的变更,master..选项表示只显示没有合并到master分支的变更。

如果想查看文件中指定位置的变更怎么办?可以使用以下命令:

1
git log -L 1,1:<path>  # -L选项告诉Git只要输出指定文件中指定行的变更日志。

你还可以通过如下命令来定位具体的历史记录:

1
2
3
git log v3..v7                 # 显示v3之后直至v7的所有历史记录
git log v3..                   # 显示所有v3之后的历史记录
git log -–since="2 weeks ago"  # 显示2周前到现在的所有历史记录

如果这些都不够好用的话,还有一个--pretty选项,可以用来创建高级的自定义输出。譬如,你可以使用--pretty=raw查看日志的原始信息。

Git笔记之stash

在工作中,经常会碰到在修改代码以支持新功能时,发现线上版本出现问题需要在本地查错。因为还在进行中,所以并不想将半成品的代码提交,后面再来修改。这样就需要临时保存修改的文件,然后取出线上版本到工作目录。这个问题的解决之道就是使用git stash命令,它会暂存你的当前工作,这样以后随时可以再来修改:

1
git stash

现在,工作目录变得干净,可以安全地做些别的事情了。

要查看暂存的修改可以使用以下命令:

1
git stash list

稍后,在排除掉线上版本的错误后,你就可以取回所有暂存的修改:

1
git stash pop

现在让我们在脑中想象一个场景:在排除线上版本错误后,没有立即取回暂存的修改,而是做了其它的一些的变更,然后想把暂存的修改并入进来以完成工作。如果两次修改的代码没有冲突,那么事情完美结束;如果后修改的代码和暂存的修改有冲突,那么就会得到Merge conflict的警告。Git没有提供强制pop的功能,所以我们需要一些技巧来解决:

1
git stash show -p | git apply && git stash drop

git stash的其它一些可用选项如下所示:

1
2
3
4
git stash pop --index        # 不仅恢复工作目录,还恢复索引
git stash save "stash name"  # 使用save可以给暂存的修改添加名字
git stash save --keep-index  # 仅仅暂存未索引的文件
git stash clear              # 删除所有暂存的修改

Ubuntu 8.10下实现无线上网

机器是ThinkPad X60,自带Inter PRO/Wireless 3945ABG网卡。

查看网络设置

1
ifconfig

打开无线网卡电源

1
sudo iwconfig wlan0 txpower on

检索区域内的无线网络

1
iwlist wlan0 scan

无线网络设置

打开System -> Preferences -> Network Connections。在Wireless页上点击Add按钮,然后在SSID栏填写检索到的ESSID字符串NETGEAR。

如果无线连接需要输入密钥,那么可以在Wireless Security页上设置。譬如,我在路由器端设置的加密方式是WPA/WPA2-PSK (Wi-Fi Protected Access Pre-Shared Key),如图:

所以在Wireless Security页上Securiy栏中选择WPA & WPA2 Personal,然后在Password栏输入设置的密码。然后就点OK,Ubuntu就去寻找网络了,等到状态从Never变为Now的时候就表示已经联网了。

2009/3/19更新

今天早上忽然发现笔记本不能无线上网了,iwlist wlan0 scan后发现结果为No scan result。使用sudo iwlist wlan0 scan命令,然后再执行iwlist wlan scan就可以看到AP了(原因为何还不知道)。

Git笔记之gitignore

通常我们会有些文件不希望纳入Git的管理,也不希望它们总是出现在未跟踪文件列表中。这些文件大多是些自动生成的文件,譬如编译过程中生成的临时文件,或者一些本地的配置文件。为解决此类问题,Git提供了文件忽略机制,我们可以创建一个名为.gitignore的文件,在其中列出需要忽略的文件模式。文件.gitignore的格式规范如下:

  • 所有空行或者以#开头的行都会被忽略;
  • 可以使用标准的glob模式匹配;
  • 匹配模式可以以“/”开头防止递归;
  • 匹配模式可以以“/”结尾指定目录;
  • 要忽略指定模式以外的文件或目录,可以在模式前加上“!”取反。

上面所谓的glob模式是指简化了的正则表达式:“*”匹配零个或多个任意字符;“[abc]”匹配任何一个列在方括号中的字符;“?”匹配一个任意字符;“[a-z]”匹配所有在这两个字符范围内的字符。“**”匹配任意中间目录,比如a/**/z可以匹配a/z,a/b/z或a/b/c/z等。

要养成一开始就设置好.gitignore文件的习惯,避免将来误提交一些无用的文件。

Git笔记之reset

git reset的作用是重置当前HEAD到指定状态,它有三个选项:--soft、--mixed和--hard。

  • --soft选项既不重置索引内容,也不改变工作目录中的任何内容,它仅仅是重置当前HEAD到指定commit。使用该选项后,git diff的返回信息不变,而git diff --cached和git diff HEAD的返回信息有变化。
  • --mixed是git reset的默认选项,它的作用是重置索引内容,将其定位到指定的commit,但不改变工作目录中的任何内容。使用该选项后,git diff和git diff HEAD的返回信息有变化,而git diff --cached的返回信息不变。
  • --hard选项会重置索引内容,将其定位到指定的commit,并且工作目录中的内容也会完全回退到指定commit时的状态。所以使用该选项后,git diff、git diff --cached和git diff HEAD的返回信息都为空。由于这个选项的杀伤力太大,使用时需要谨慎。

以下是根据三个选项的特性制作的表格:

是否重置索引 是否重置工作目录
--soft N N
--mixed Y N
--hard Y Y

有时候你可能刚刚把一个文件添加到暂存区里,然后就发现这是错误的,接着你可能想从暂存区中删除该文件,这时你可以使用下面这个命令:

1
git reset <file>

它仅从索引中移除文件,但不会触及工作目录。

Git笔记之项目创建

Git的官网地址:https://git-scm.com/

学习路线推介:新手请浏览gittutorial(7),然后是Everyday Git,接着是“git help command”,需要更全面的了解Git请看Git User's Manual

1、初始化仓库

1
2
3
mkdir gittest
cd gittest
git init  # 创建.git隐藏目录,即所谓的Git仓库,用来存储项目的所有历史和元信息

2、告诉项目你的信息

1
2
git config --global user.name "yourname"
git config --global user.email yourname@example.com

3、跟踪新文件

1
2
echo 'Hello Git!' > greeting
git add greeting

这里Git给greeting这个文件的内容生成快照,并把快照存储在Git称之为索引的暂存区。你也可以使用git add .来将当前目录下所有的文件内容加入到暂存区。

4、查看项目当前状态

1
git status

5、提交内容到仓库

1
git commit  # 将暂存区的内容写入仓库

在输入git commit后按回车会跳出一个文本编辑器窗口,要求开发者输入这次提交的开发信息。

git commit的选项:

  • -s 在提交日志信息末尾添加提交者的Signed-off-by行。
  • -m 使用给定的信息作为提交信息。没有该选项会自动打开一个编辑器以填写提交信息。
  • -a 自动将修改过的文件添到暂存区中(新建但没有git add的文件不会受到影响)。

6、查看项目历史

1
git log

如果你想看下每次提交的大致变动情况,可使用以下命令:

1
git log --stat --summary