Git 基础

useful git basic theory which can help you version control in terminal

Posted by lizelin on April 20, 2019

Git 基础

1. Git 简史

同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代。

Linux 内核开源项目有着为数众广的参与者。 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。 到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码。

到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。 这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用 BitKeeper 时的经验教训,开发出自己的版本系统。 他们对新的系统制订了若干目标:

速度 简单的设计 对非线性开发模式的强力支持(允许成千上万个并行开发的分支) 完全分布式 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量) 自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。 它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统。

2. 主要概念

2.1 仓库

存放代码的目录,分为本地仓库和远程仓库,本地和远程可以通过 git remote add 建立关联。

本地仓库有三大分区:

工作区 (Working Directory): 是我们编辑代码的地方 暂存区 (Stage or Index): 数据暂时存放的区域,可以在工作区和版本库之间进行数据的交流 版本库 (Commit History): 存放已经提交的数据,push 的时候就是把这个区域的数据推送到远程仓库

2.2 分支

git 中的分支本质上是一个指向某个 commit 的指针。

2.3 文件的生命周

对于 git 仓库里的每一个文件(除了 .git 目录和被 .gitignore 忽略的文件),有如下几种状态:

Untracked 未跟踪 Unmodified 未修改 Modified 已修改 Staged 暂存区

3. 常用操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
git init # 在当前目录下初始化一个本地 git 仓库
git status # 检查当前文件状态
git diff # 比较工作区和暂存区
git diff HEAD # 比较工作区和版本库
git diff --cached # 比较暂存区和版本库
git add <filename> # 将 <filename> 添加到暂存区
git add -A # 将所有文件添加到暂存区
git add . # 将当前目录下的所有文件添加到暂存区
git commit # 提交更改(将暂存区的文件提交到 Commit History)
git commit --amend # 修改 commit 信息
git push origin <branch> # 将本地分支推送到远程仓库
git pull origin <branch> # 将远程仓库的分支拉取到本地
git clone <repository> [<directory>] # 克隆远程分支到本地,repository 可以由 schema 为 http[s], ssh, git, ftp[s], file 等各种 uri 表示,也可以是 scp 风格的路径表示。directory 表示克隆下来的仓库目录名
git config [--global|--local] user.name "<username>" # 设置用户名,用户名会出现在 commit 信息里,加了--local参数只影响当前仓库的配置,加--global参数会影响本机上所有仓库的配置,默认是--local
git config [--global|--local] user.email "<email>" # 设置用户邮箱,邮箱会出现在 commit 信息里
git remote add origin <repository> # 添加一个远程分支,命名为 origin
git log [--oneline] # 查看 commit 信息
git log --oneline --graph # 查看 commit 节点树

4. 高级操作

1
2
3
4
5
6
7
8
9
10
11
12
git branch # 查看本地分支
git branch -a # 查看所有分支,包括远程分支
git branch <name> # 创建一个和当前分支版本库一样的分支
git checkout <branch> # 切换分支
git checkout -b <branch> <start_point> # 创建一个新分支并切换,新分支的 HEAD 指针指向 start_point, start_point 可以是本地分支或远程分支的任意一个 commit
git reset --soft <commit> # 将版本库的 HEAD 指向 commit
git reset --mixed <commit> # 将版本库和暂存区的 HEAD 指向 commit
git reset --hard <commit> # 将版本库、暂存区和工作区的 HEAD 指向 commit,但不会影响为跟踪的文件
git rebase <branch> # 把当前分支变基到 branch 上
git stash # 将暂存区中的文件储藏起来
git stash apply # 恢复储藏的文件到暂存区
git revert <commit> # 撤销之前的某一个 commit

5. 冲突解决

当发生冲突的时候,冲突的文件中会出现以下格式的内容。

解决冲突的时候,可以选择保留当前修改,保留另一个分支的修改,或是两个都不保留,重新编辑。

解决冲突的时候既要解决文本冲突,也要注意逻辑冲突。当冲突解决完成后,应该将当前文件加入暂存区,并执行对应命令加上 –continue 参数。

1
2
3
4
5
<<<<<<< HEAD
            modification belongs to current branch
=======
            modification belongs to other branch
>>>>>>> commit 38a1cab...

6. .gitignore

文件 .gitignore 的格式规范如下:

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

1
2
# no .a files
*.a
1
2
# but do track lib.a, even though you're ignoring .a files above
!lib.a
1
2
# only ignore the TODO file in the current directory, not subdir/TODO
/TODO
1
2
# ignore all files in the build/ directory
build/
1
2
# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt
1
2
# ignore all .pdf files in the doc/ directory
doc/**/*.pdf

7. Merge & Rebase

Merge: 合并两个分支

Rebase: 改变分支的 base commit

这两种操作都可以合并分支,rebase 的优势在于可以使 commit history 的线性程度更高。线性程度高的好处在于,浏览历史的时候更整洁,不容易碰到分叉,分叉部分的代码差异可能更大。

1
2
git merge <branch> # 把 branch 合并到当前分支
git rebase <commit> # 把当前分支 rebase 到 commit 上

这两种操作解释起来可以单独写一篇博客了,运行下面的练习,体会以下不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash

commit() {
  touch $1 && git add $1 && git commit -m "$1"
}

git init

commit a
commit b
git checkout -b feat
commit c
commit d
git checkout master
commit e
commit f
commit g
git merge feat "Merge branch feat"

git log --oneline --graph

commit h
git checkout -b feat2
commit i
commit j
git checkout master
commit k
commit l
git rebase feat2

git log --oneline --graph

将上面的代码保存为 practice.sh 文件,运行练习

1
2
chmod +x practice.sh
./practice.sh

rebase黄金准则

永远不要 rebase 到一个共享的分支,只能 rebase 自己使用的私有分支。

8. License

本作品采用知识共享 署名-非商业性使用-相同方式共享 2.5 中国大陆 许可协议进行许可。要查看该许可协议,可访问 http://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 或者写信到 Creative Commons, PO Box 1866, Mountain View, CA 94042, USA。