Git使用
1.起步
1.1 Git原理
在 Git中,每当你提交更新或保存项目状态时,它基本上就会对当时的全部文件创建一个快照并保存这个快照的索引。为了效率,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个 快照流。
在进行提交操作时,Git 会保存一个提交对象(commit object)该提交对象会包含一个指向暂存内容快照的指针。 首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象, 而由多个分支合并产生的提交对象有多个父对象。
1.2 文件的三种装态
三种装态:已修改、 已暂存、已提交
你的文件可能处于三种装态其中之一:已修改(modified) => 已暂存(staged)=>已提交(committed)。
1.已修改表示修改了文件,但还没保存到数据库中。
2.已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
3.已提交表示数据已经安全地保存在本地数据库中。
三个阶段:工作区、暂存区 Git 目录。
- 工作区是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。
- 暂存区是一个文件,保存了下次将要提交的文件列表信息,一般在 Git 仓库目录中。 按照 Git 的术语叫做“索引”,不过一般说法还是叫“暂存区”。
- Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。 这是 Git 中最重要的部分,从其它计算机克隆仓库时,复制的就是这里的数据。
Git 工作流程
- 在工作区中修改文件。
- 将你想要下次提交的更改选择性地暂存,这样只会将更改的部分添加到暂存区。
- 提交更新,找到暂存区的文件,将快照永久性存储到 Git 目录。
如果 Git 目录中保存着特定版本的文件,就属于 已提交 状态。 如果文件已修改并放入暂存区,就属于 已暂存 状
态。 如果自上次检出后,作了修改但还没有放到暂存区域,就是 已修改 状态。
2.基础
2.1 获取 Git 仓库的两种方式
2.1.1将尚未进行版本控制的本地目录转换为 Git 仓库;
1.cd/本地目录
2.git init
git init 命令将创建一个名为 .git 的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件。
2.1.2 从其它服务器 克隆 一个已存在的 Git 仓库
克隆仓库的命令是 git clone ,比如:
git clone https://github.com/libgit2/libgit2
这会在当前目录下创建一个名为 “libgit2” 的目录,并在这个目录下初始化一个 .git 文件夹,从远程仓库拉取下所有数据放入 .git 文件夹,然后从中读取最新版本的文件的拷贝。
2.2 文件的生命周期
工作目录下的每一个文件都不外乎这两种状态:已跟踪 或 未跟踪。
- 已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后, 它们的状态可能是未修改,已修改或已放入暂存区。【换句话说就是】已跟踪的文件就是 Git 已经知道的文件。
- 除已跟踪文件外的其它所有文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有被放入暂存区。
2.3 检查当前文件状态
可以用 git status 命令查看哪些文件处于什么状态。 使用此命令,会看到类似这样的输出:
$ git status On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean
这说明你现在的工作目录相当干净。所有已跟踪文件在上次提交后都未被更改过。 此外,上面的信息还表明,当前目录下没有出现任何处于未跟踪状态的新文件,否则 Git 会在这里列出来。
2.4 跟踪新文件
使用命令 git add 开始跟踪一个文件。例如跟踪README文件:
$ git add README $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: README
只要在 Changes to be committed 这行下面的,就说明是已暂存状态。 如果此时提交,那么该文件在你运行 git add 时的版本将被留存在后续的历史记录中。
2.5 暂存已修改的文件
git add 文件名 将文件放到暂存区,例如将“README.md”放到暂存区
$ git add CONTRIBUTING.md $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: CONTRIBUTING.md
2.6 忽略文件
一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。 通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以创建一个名为 .gitignore的文件,列出要忽略的文件的模式。
- 文件 .gitignore 的格式规范如下:
- 所有空行或者以 # 开头的行都会被 Git 忽略。
- 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中。
- 匹配模式可以以(/)开头防止递归。
- 匹配模式可以以(/)结尾指定目录。
- 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。
- *****匹配零个或多个任意字符;
- [] 匹配任何一个列在方括号中的字符,如**[abc]**要么匹配一个 a,要么匹配一个 b,要么匹配一个 c;
- ? 只匹配一个任意字符;
- 如果在方括号中使用短划线分隔两个字符, 表示所有在这两个字符范围内的都可以匹配, [0-9] 匹配所有 0 到 9 的数字。
- 使用两个星号()表示匹配任意中间目录,比如 a//z 可以匹配 a/z 、 a/b/z 或 a/b/c/z 等。
2.6.1 IDEA中的.gitignore模板
# 所有class,后缀的文件
*.class
# 所有jar后缀的文件
*.jar
*.iml
*.war
# .idea文件夹
.idea
# out文件夹
out
target
2.7 查看提交历史
git log
$ git log commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <schacon@gee-mail.com> Date: Mon Mar 17 21:52:11 2008 -0700 changed the version number commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon <schacon@gee-mail.com> Date: Sat Mar 15 16:40:33 2008 -0700 removed unnecessary test commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon <schacon@gee-mail.com> Date: Sat Mar 15 10:31:28 2008 -0700 first commit
不传入任何参数的默认情况下,git log 会按时间先后顺序列出所有的提交,最近的更新排在最上面。 这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。
2.7.1 格式化输出提交日志。
git log --pretty=format 常用的选项
2.7.2 限制提交记录的输出
git log
- - 仅显示最近的 n 条提交。
- –since ,–after 仅显示指定时间之后的提交。
- –until, --before 仅显示指定时间之前的提交。
- –author 仅显示作者匹配指定字符串的提交。
- –committer 仅显示提交者匹配指定字符串的提交。
- –grep 仅显示提交说明中包含指定字符串的提交。
- -S 仅显示添加或删除内容匹配指定字符串的提交。
3.分支
Git 的分支,本质上是指向提交对象的可变指针。Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 master 分支会在每次提交时自动向前移动。
3.1 分支创建
git branch 分支名,例如:
$ git branch testing
这会在当前所在的提交对象上创建一个指针。通过一个名为 HEAD 的特殊指针,Git可以知道当前在哪一个分支上。
3.2 分支切换
git checkout 分之名 例如:
$ git checkout testing
切换到新创建的 testing 分支,这样 HEAD 就指向 testing 分支了。
HEAD 分支随着提交操作自动向前移动。如图所示:
再切换到master分支上时,可以看出HEAD随之移动到master分支上。
$ git checkout master
3.3 分支的合并
先切换到master分支上,然后合并分支
$ git checkout master $ git merge iss53
合并前后的提交节点描述图,如图所示:
3.4 分支的删除
$ git branch -d iss53
3.5 分支的开发工作流
3.5.1 长期分支
只在 master 分支上保留完全稳定的代码——有可能仅仅是已经发布或即将发布的代码。 他们还有一些名为 develop 或者 next 的平行分支,被用来做后续开发或者测试稳定性——这些分支不必保持绝对稳定,但是一旦达到稳定状态,它们就可以被合并入 master 分支了。 这样,在确保这些已完成的主题分支(短期分支,比如之前的 iss53 分支)能够通过所有测试,并且不会引入更多 bug 之后,就可以合并入主干分支中,等待下一次的发布。
事实上我们刚才讨论的,是随着你的提交而不断右移的指针。 稳定分支的指针总是在提交历史中落后一大截,而前沿分支的指针往往比较靠前。
3.6 变基
在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase。
需求:合并experiment与master分支
3.6.1 通过合并操作来整合分叉的历史
3.6.2 变基
它的原理是首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master) 的最近共同
祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向
目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。
3.6.3 变基的使用准则
如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。