第二章 Git基础
第一节 获取 Git 仓库
1. 在现有目录中初始化仓库
- git管理现有项目
- git init
2. 克隆现有的仓库
- clone项目
- git clone xxx.com name
3. 暂存已修改文件
- 文件分两种状态:已跟踪和未跟踪
- git add *.c
- git add lincense
- git commit -m 'initial project version'
第二节 记录每次更新到仓库
1. 检查当前文件状态
- 文件状态
- git status
- On branch master (所在分支)
- nothing to commit, working directory clean
- git stauts -s , git stauts --short
- 得到一种更为紧凑的格式输出
- M README //该文件被修改了但是还没放入暂存区
- MM Rakefile //上一次修改被放入暂存区,这一次修改未放入暂存区
- A lib/git.rb //新添加到暂存区中的文件
- M lib/simplegit.rb //该文件被修改了并放入了暂存区
- ?? LICENSE.txt //新添加的未跟踪文件
- git status
- git add 命令功能
- 可以用它开始跟踪新文件
- 或者把已跟踪的文件放到暂存区
- 还能用于合并时把有冲突的文件标记为已解决状态等
- 将这个命令理解为“添加内容到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。
2. 忽略文件
- cat .gitignore //创建一个名为 .gitignore 的文件
- *.[oa] //忽略所有以 .o 或 .a 结尾的文件
- *~ //忽略所有以波浪符(~)结尾的文件
3. 查看已暂存和未暂存的修改
- git diff
- 修改之后还没有暂存起来的变化内容
- git diff --cached
- 已暂存的将要添加到下次提交里的内容
4. 提交更新
- git commit -m "Story 182: Fix benchmarks for speed"
- 提交暂存区域并添加一条说明
- [master 61c9fe6] commit //当前是在哪个分支,SHA-1 校验
- 3 files changed, 4 insertions(+), 1 deletion(-) //有多少文件修订过,多少行添加和删改过
- create mode 100644 file.txt
- create mode 100644 readme.txt
- 提交暂存区域并添加一条说明
5. 跳过使用暂存区域
- 在提交的时候,给 git commit 加上 -a 选项,自动把所有已经跟踪过的文件暂存起来一并提交
- git commit -a -m 'added new benchmarks'
6. 移除文件
- git rm
- 从已跟踪文件清单中移除
- git rm --cached README
- 让文件保留在磁盘,但是并不想让 Git 继续跟踪
- git rm log/*.log
7. 移动文件
- git mv README.md README
- 等于下面三条命令
- $ mv README.md README
- $ git rm README.md
- $ git add README
第三节 查看提交历史
- git log
- 按提交时间列出所有的更新,最近的更新排在最上面。
- git log -p
- 用来显示每次提交的内容差异
- git log -p -2
- 仅显示最近两次提交
- git log --stat
- 附带一系列的总结性选项
- git log --pretty=oneline
- 将每个提交放在一行显示,查看的提交数很大时非常有用,另外还有 short,full 和 fuller 可以用,展示的信息或多或少有些不同f
1. 限制输出长度
- git log --since=2.weeks
- 最近两周内的提交
- git log --author=xxxxx
- 显示指定作者的提交
- git log --grep
- 搜索提交说明中的关键字。
- 得到同时满足这两个选项搜索条件的提交,就必须用 --all-match 选项
第四节 撤消操作
- git commit --amend
- 将暂存区中的文件提交,如果自上次提交以来你还未做任何修改,那么快照会保持不变,而你所修改的只是提交信息。
- 提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了
- $ git commit -m 'initial commit'
- $ git add forgotten_file
- $ git commit --amend
- 最终只会有一个提交,第二次提交将代替第一次提交的结果
1. 取消暂存的文件
- 如何只取消暂存两个中的一个呢?
- $ git reset HEAD CONTRIBUTING.md
2. 撤消对文件的修改
- 撤消修改 - 将它还原成上次提交时的样子
- $ git checkout -- CONTRIBUTING.md
第五节 远程仓库的使用
1. 查看远程仓库
- 如果想查看你已经配置的远程仓库服务器
- git remote
- 列出你指定的每一个远程服务器的简写
- $ git remote -v
- 显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL
2. 添加远程仓库
- 添加一个新的远程 Git 仓库,同时指定一个你可以轻松引用的简写
- $ git remote add pb github.com/paulboone/t…
- 使用字符串 pb 来代替整个 URL,拉取 Paul 的仓库中有但你没有的信息
- $ git fetch pb
- 它并不会自动合并或修改你当前的工作
3. 推送到远程仓库
- $ git push origin master
- 将 master 分支推送到 origin 服务器
4. 查看远程仓库
- $ git remote show origin
5. 远程仓库的移除与重命名
- $ git remote rename pb paul //修改
- $ git remote //查询
- origin
- paul
- $ git remote rm paul //移除
- $ git remote //查询
- origin
第六节 打标签
1. 列出标签
- $ git tag
- 如果只对 1.8.5 系列感兴趣
- $ git tag -l 'v1.8.5*'
2. 附注标签
- $ git tag -a v1.4 -m 'my version 1.4'
- -m 选项指定了一条将会存储在标签中的信息。
- $ git show v1.4
- 可以看到标签信息与对应的提交信息。
3. 轻量标签
- $ git tag v1.4
- 没有描述信息
4. 后期打标签
- $ git log --pretty=oneline
- $ git tag -a v1.2 9fceb02
5. 共享标签
- $ git push origin v1.5 // 推送单个
- $ git push origin --tags // 推送全部
6. 检出标签
- $ git checkout -b version2 v2.0.0
- git checkout -b [branchname] [tagname] 在特定的标签上创建一个新分支
第三章 Git分支
第一节 分支简介
提交对象
- 在进行提交操作时,Git 会保存一个提交对象(commit object)。
- 该提交对象会包含一个指向暂存内容快照的指针,还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针。
如何生成提交对象
- 暂存操作会为每一个文件计算校验和,然后会把当前版本的文件快照保存到 Git 仓库中(Git 使用 blob 对象来保存它们)。
- 当使用
git commit
进行提交操作时,Git 会先计算每一个子目录(本例中只有项目根目录)的校验和,然后在 Git 仓库中这些校验和保存为树对象。 - 随后,Git 便会创建一个提交对象,它除了包含上面提到的那些信息外,还包含指向这个树对象(项目根目录)的指针。
如何生成分支
- 做些修改后再次提交,那么这次产生的提交对象会包含一个指向上次提交对象(父对象)的指针。
- Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是
master
。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的master
分支。
分支创建
- $ git branch testing
- 在当前所在的提交对象上创建一个指针
- Git 又是怎么知道当前在哪一个分支上呢?
- 有一个名为
HEAD
的特殊指针,指向当前所在的本地分支
- 有一个名为
- 查看各个分支当前所指的对象
- $ git log --oneline --decorate
分支切换
- 切换到一个已存在的分支
- $ git checkout testing
- 再修改提交一次
testing
分支向前移动了,但是master
分支却没有,它仍然指向运行git checkout
时所指的对象。
- 切换回master分支
- 这条命令做了两件事。 一是使 HEAD 指回
master
分支,二是将工作目录恢复成master
分支所指向的快照内容。
- 这条命令做了两件事。 一是使 HEAD 指回
- 再修改提交一次
- 这个项目的提交历史已经产生了分叉
- 你可以在不同分支间不断地来回切换和工作,并在时机成熟时将它们合并起来。
- 而所有这些工作,你需要的命令只有
branch
、checkout
和commit
。
- git log --oneline --decorate --graph --all
- 输出你的提交历史、各个分支的指向以及项目的分支分叉情况。
第二节 分支的新建与合并
举个栗子
新建分支
- 假设你正在你的项目上工作
- 决定要解决你的公司使用的问题,新建一个分支并同时切换到那个分支上
- $ git checkout -b iss53
- 等同于下面两条命令:
- $ git branch iss53
- $ git checkout iss53
- 继续在 #53 问题上工作,并且做了一些提交
- 有个紧急问题等待你来解决
- $ git checkout master
- $ git checkout -b hotfix
- 进行一些提交后
- 将测试后的改动合并到master
- $ git checkout master
- $ git merge hotfix
- 合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者时,只会简单的将指针向前推进(指针右移),这就叫做 “快进(fast-forward)”。
- 合并之后删除hotfix分支
- $ git branch -d hotfix
- 切换回iss53继续工作
- $ git checkout iss53
- 已经修正了iss53问题,并且打算将你的工作合并入
master
分支- $ git checkout master
- $ git merge iss53
- Git 将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它。 这个被称作一次合并提交,它的特别之处在于他有不止一个父提交。
遇到冲突时的分支合并
- 如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,Git 就没法干净的合并它们。
- Git 会暂停下来,等待你去解决合并产生的冲突。
- 任何因包含合并冲突而有待解决的文件,都会以未合并状态标识出来。
- Git 会在有冲突的文件中加入标准的冲突解决标记,这样你可以打开这些包含冲突的文件然后手动解决冲突。
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
HEAD
所指示的版本,也就是你的master
分支所在的位置。(你当前分支的代码)- 上述的冲突解决方案仅保留其中一个分支的修改,并且
<<<<<<<
,=======
, 和>>>>>>>
这些行需要完全删除。 - 在你解决了所有文件里的冲突之后,对每个文件使用
git add
命令来将其标记为冲突已解决。 - 这时你可以输入
git commit
来完成合并提交。
分支管理
- $ git branch
- 当前所有分支信息
master
分支前的*
字符:它代表现在检出的那一个分支(HEAD分支)
iss53 * master testing
- $ git branch --merged
$ git branch --merged iss53 * master
- 查看哪些分支已经合并到当前分支
- 在这个列表中分支名字前没有
*
号的分支通常可以使用git branch -d
删除掉 - 你已经将它们的工作整合到了另一个分支,所以并不会失去任何东西。
- $ git branch --no-merged
- 查看所有包含未合并工作的分支
$ git branch --no-merged testing
- 因为它包含了还未合并的工作,尝试使用
git branch -d
命令删除它时会失败,但是可以使用-D
选项强制删除它。
分支开发工作流
长期分支
- 只在
master
分支上保留完全稳定的代码 develop
或者next
的平行分支,被用来做后续开发或者测试稳定性- 平行分支一旦达到稳定状态,它们就可以被合并入
master
分支了
特性分支
- 举个例子
- 你在
master
分支上工作到C1
,这时为了解决一个问题而新建iss91
分支,在iss91
分支上工作到C4
,然而对于那个问题你又有了新的想法,于是你再新建一个iss91v2
分支试图用另一种方法解决那个问题,接着你回到master
分支工作了一会儿,你又冒出了一个不太确定的想法,你便在C10
的时候新建一个dumbidea
分支,并在上面做些实验。 你的提交历史看起来像下面这个样子
- 你在
- 然后:
- 你决定使用第二个方案来解决那个问题,即使用在
iss91v2
分支中方案;另外,你将dumbidea
分支拿给你的同事看过之后,结果发现这是个惊人之举。 这时你可以抛弃iss91
分支(即丢弃C5
和C6
提交),然后把另外两个分支合并入主干分支。 最终你的提交历史看起来像下面这个样子
- 你决定使用第二个方案来解决那个问题,即使用在
远程分支
未完待续