Lesson Two: Creating and Modifying a Repository
- Learn how to create a repository and save versions of your project.
- Learn about the staging area, committing your code, branching, and merging.
课程二主要介绍了 Repository 的创建,Staging Area 暂存区,Git 的提交 (commit)、分支 (branch) 以及合并 (merge) 的概念和操作。
Resitory 的创建
一个 Repository 代码库内有一个 .git
隐藏文件夹,可以在 Git Bash 或 Terminal 输入 ls -a
指令查看。它存储了 Repository 历史记录相关的元数据,用户无需直接与这些数据交互。除了使用 git clone URL
指令创建 Repository 之外,还可以用 git init
在一个空目录或已有文件的目录下创建 Repository 。
创建一个 Repository 后,可以输入 git status
查看当前代码库的状态,包括当前分支 (master),当前文件状态(如有,一般为 untracked),提示信息。如果输入 git log
查看提交信息,一般会显示 fatal: bad default revision ‘HEAD’
(Git 版本不同,显示信息可能不同),HEAD 代表当前的 commit 状态,新创建的 Repository 没有任何 commit ,所以显示此警告信息。
Staging Area(暂存区)
Repository 内新建或修改的文件需要 commit 才属于代码库的文件,未 commit 的文件所处的目录称为 Working Directory(工作目录)。在 Git 中,与其每个文件单独 commit,Git 引入了 Staging Area(暂存区)的概念,将要 commit 的文件暂时存储起来,等项目有逻辑变更时一起 commit 到 Repository,实现了多文件绑定统一提交。
在 Git Bash 或 Terminal 中输入 git add file_name
将 Working Directory 的文件放到 Staging Area ,准备 commit 到 Repository 。此时输入 git status
应该可以查看到对应的文件状态由 untracked 变为 changed to be commited。
当前已介绍的所有 Git 概念的关系图如下。
Git 提交 (commit)
将位于 Staging Area 的文件上传到 Repository 的操作就是 commit,所以 git add file_name
指令需要指定文件名,而 commit 只需要在 Git Bash 或 Terminal 中输入 git commit
自动打开 Notepad++ 或 Sublime Text 输入提交信息,保存后关闭编辑器,回到 Git Bash 或 Terminal 即成功 commit;或者输入 git commit -m “commit message”
直接填写提交信息。虽然提交信息的风格因人而异,但最好能遵循一些规范的信息样式,可参考 Udacity 的指南。
除了 git diff old_commit_id new_commit_id
指令可以对比 Repository 的文件外,对比 Working Directory 与 Staging Area 之间的文件,使用 git diff
指令,无需添加参数;对比 Staging Area 与 Repository 之间的文件,使用 git diff --staged
指令,无需添加参数。
指令 | 作用域 |
---|---|
git diff commit_id_one commit_id_two |
Repository 的文件 |
git diff |
Working Directory 与 Staging Area 之间的文件 |
git diff --staged |
Staging Area 与 Repository 之间的文件 |
其他一些 Git 指令:
# 将 Repository 恢复到 master 的最新状态
git checkout master
# 撤销 Working Directory 和 Staging Area 的所有更改
git reset --hard
Git 分支 (branch)
Git 不同版本的标记就是分支,创建 Repository 时自动标注 master 分支;创建一个 branch 后每次 commit 都会保持在该分支上,不影响其他分支。每个分支上最新的 commit 称为该分支的顶点 (tip)。
下面看 branch 的操作。
# 显示所有分支
git branch
# 创建 branch_one 分支
git branch branch_one
# 查看到当前处于 master 分支
git branch
# 切换到 branch_one 分支
git checkout branch_one
# 查看到已处于 branch_one 分支
git branch
在 Git Bash 或 Terminal 的头部字符也可以看到当前 branch 信息,格式为 用户名 (当前分支) 目录名 $
,例如 hsujin (master) asteroids $
。
与他人协作同一个项目时,可以使用
git log --graph --oneline master branch_one
直观查看两个 branches 之间的 commits 记录,进而画出图表即可直观显示 branches 之间的 commit 关系。
如上图有 a 和 b 两个 branches ,他们由 commit e3d 开始分开,这里就引入了 Reachability(可访问性)的概念。首先要了解到每个 commit 都知道其 parent commit,例如 branch a 的 commit 3fc 的 parent commit 即 f26,使用 git log
指令可查到一个 branch 的所有 commits ,一直跟踪到无 parent commit 的那一个为止。因此通过 git log
可知 branch a 的 commit 列表为 3fc, f26, 3fc, branch b 的 commit 列表为 4d9, 7dc, 2c4, e3d,branch a 的 commit 不会出现在 branch b 的上面,反之亦然。
另外,detached HEAD(游离状态)的 commit(无分支标记)也是无法访问 (unreachable) 的,例如上图的 commit f36。对于 detached HEAD,有三种处理方法:
- commit to master;
- discard(撤销更改),不影响任何其他分支;
-
git checkout -b new_branch
相当于两条指令,git branch new_branch
创建一个新分支和git checkout new_branch
切换到 new_branch 分支。
Git 合并 (merge)
Merge 是 Git 根据 commits 历史数据,通过一些合并策略,将 Repository 的两个或多个分支合并为一个。
如果要 merge 两个分支,那么一定要先 git checkout 其中一个分支,例如要合并 master 和 branch_one 这两个分支,操作如下:
# 首先检出 master 分支
git checkout master
git merge master branch_one
# master 和 branch_one 的顺序无关,可删去 master 指令简化为
# git merge branch_one
弹出 Notepad++ 或 Sublime Text 自动填写 merge 信息,保存关闭返回 Git Bash 或 Terminal 即成功 merge 操作。
输入 git log
可查到一个关于 merge 的 commit 信息,说明 git merge 始终将所有指定的分支合并到当前检出的分支中,上例即 master 分支,并为该分支新建一个提交。
如果要 merge 三个分支,操作如下:
git checkout branch_one
git merge branch_two branch_three
一般情况下不会要求同时 merge 三个分支。
分支合并成功后可以使用 git branch -d branch_one
删除 branch_one,删除分支操作只是删除该分支的标记,分支的 commits 仍保留,在合并到 master 的 commits 一起按时间顺序排列显示。这导致了一个问题,即无法直接使用 git diff 指令来比较两个 commits ,因为合并后的 commits 无法获知其 parent commit ,所以这里要用 git show commit_id
无需指定 parent commit 即可与其对比。
Git 合并时经常会发现合并冲突 (conflicts),即有些文件修改需要人为确认,此时 Git 会在存在冲突的文件中添加字符,帮助开发者识别修改文件。格式如下:
<<<<<< HEAD
当前分支的文件状态
|||||| merged common ancestors
原始文件
======
另一分支(master)的文件状态
>>>>>> master
解决冲突后删去<<< 、||| 、=== 、>>> 等符号,保存修改好的文件。
# 查看到文件状态为 both modified ,说明在即将 merge 的两个分支都修改了
Git status
# 提交解决方案
Git add file_conflict
# 完成 merge
Git commit
# 显示仅有一次 merge commit
Git log
如果无法解决冲突,可以使用 git merge --abort
指令恢复合并前的状态。
当前已介绍的所有 Git 概念的关系图如下。
本课学习到的 Git 指令
1. ls -a
2. git init
3. git status
4. git add file_name
5. git commit
6. git commit -m “commit message”
7. git checkout master
8. git reset --hard
9. git branch
10. git branch branch_one
11. git log --graph --oneline master branch_one
12. git checkout -b new_branch
13. git merge branch_one
14. git branch -d branch_one
15. git show commit_id
16. git merge --abort