1. 状态
1.1 文件状态
2. 分支
2.1 分支常用命令
- git branch xxx:新建分支
- git checkout xxx:切换分支
- git checkout -b xxx:新建分支并切换到该分支(相当于上面两条命令)
- git branch -d xxx:删除分支
- git branch:查看分支列表
- git push origin --delete xxx:删除远程分支
- git fetch:从服务器上拉取数据,当 git fetch 命令从服务器上抓取本地没有的数据时,它并不会修改工作目录中的数据,它只会获取数据然后让你自己合并。
- git pull:在大多数情况下它的含义是一个 git fetch 紧接着一个 git merge / git rebase 命令
2.2 分支合并
分支合并主要有两种方式:git merge / git rebase
2.2.1 git merge
git merge 会把两个分支的最新快照以及二者最近的公共祖先进行三方合并,合并的结果是生成一个新的快照(并提交)
工作中的使用流程
现有主分支 master,开发某种功能的分支 dev,dev 上面的内容已经开发完成了,现在要将 dev 分支上的内容合并到 master
- git checkout master
- git pull(拉取最新代码,也可以使用 git fetch)
- git merge dev
- ... (解决冲突)
- git push (提交到服务器)
2.2.2 git rebase
现在同样有主分支 master 与 开发分支 dev,需要将 dev 合并到 master
git rebase 的原理是先找到两个分支(master 与 dev)的最近公共祖先,然后对比 dev 分支对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标分支(master)的最新一次的提交,最后将之前另存为临时文件的修改依序应用
工作中的使用流程
- git checkout master(切换到目标分支)
- git pull (拉取最新代码)(也可以直接执行 git rebase master dev,省去步骤3和步骤4 )
- git checkout dev (切换到开发分支)
- git rebase master (执行变基操作)
- git checkout master (切换到主分支)
- git merge dev (将 dev 分支上的修改变基到主分支)
- git push (提交到服务器)
变基操作前的分支图
变基完成后的分支图
无论是 rebase 还是 merge ,整合的最终结果所指向的快照始终是一样的,只不过提交的历史不同罢了。变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起
3. 常用命令
3.1 汇总
git add -i:进入交互式终端模式,可以快速选择某些文件被暂存,达成部分提交的目的。另外该模式下还有多种快捷功能。
git commit --amend:修改最近一次提交的提交信息
git rebase -i:交互式的运行变基,修改多个提交信息(注意无论是 git commit --amend 还是 git rebase -i 都不能涉及到已经推送到服务器的提交)
git revert:撤销(还原)某次提交
3.2 git reset 的不同模式
3.2.1 git reset --soft HEAD~
首先要明白 git 的 “三棵树”,HEAD、Index 以及 Working Directory,HEAD 是指已经 commit 快照,可以将它看做是 该分支上的最后一次提交;Index 是 “暂存区”,是预期的下一次提交;Working Directory 是我们自己的工作目录,我们在工作目录中对文件进行修改,然后添加到暂存区,最后再 commit,HEAD 指向我们最后一次的 commit。
我们运行 git reset --soft HEAD~ 会产生什么效果?下图是我们现在的分支状态和 “三棵树” 的状态
然后我们运行 git reset --soft HEAD~
可以看到,Index 区和 Working Directory 区的状态并没有发生变化,只有 HEAD 指针向前移动了一个节点,git reset --soft HEAD~ 的本质上是撤销了上一次 git commit 命令。当我们运行 git commit 时,Git 会创建一个新的提交,并移动 HEAD 所指向的分支来使其指向该提交,当将它 reset 回 HEAD~(HEAD 的父结点)时,其实就是把该分支移动回原来的位置,而不会改变 Index 和 Work Directory。现在可以再次运行 git commit 以达到和 git commit --amend 相同的效果。
3.2.2 git reset [--mixed] HEAD~
mixed 是 git reset 操作的默认参数,git reset --mixed HEAD~ 可以重置 Index (暂存区)的文件与上次的 commit 保持一致,Work Directory 的内容保持不变。
当我们运行 git reset --mixed HEAD~ 时,reset 会用 HEAD 指向的当前快照的内容来更新索引
git reset --mixed HEAD~ 操作共有两个步骤
- 将 HEAD 指针向前移动一个节点,也就是 git reset --soft HEAD~ 操作
- 重置 Index (暂存区)的文件与 HEAD 指向的节点保持一致
3.2.3 git reset --hard HEAD~
--hard 是 reset 命令唯一的危险用法,git reset --hard HEAD~ 命令会撤销最后的提交、git add 和 git commit 命令以及 Work Directory 中所有的工作
git reset --hard HEAD~ 总共有三个步骤
- 将 HEAD 指针向前移一个节点,也就是 git reset --soft HEAD~ 操作
- 重置 Index (暂存区)的文件与 HEAD 指向的节点保持一致,也就是 git reset --mixed HEAD~ 操作
- 重置 Work Directory 的文件与 HEAD 和 Index 保持一致
3.2.4 git reset 的其他用法
git reset file.txt(其实是 git reset --mixed HEAD file.txt 的简写形式),它的实质是将 file.txt 从 HEAD 复制到 Index ,该命令总共有两个步骤:
- 移动 HEAD 分支的指向(因为我们给 reset 指定了一个路径,所以它的作用范围限定为指定的文件或文件集合,而 HEAD 只是一个指针,无法让它指向两个提交中各自的一部分,所以该步骤会跳过,HEAD 的指向不变)
- 让 Index 看起来像 HEAD
因为 git reset file.txt 会产生 Index 与 HEAD 中 file.txt 文件一模一样的结果,所以 file.txt 会从 Index (暂存区)被移除,git reset file.txt 与 git add file.txt 所做的事正好相反,所以我们可以使用 git reset file_name 来取消暂存一个文件。
我们也可以通过指针一个具体的提交来拉取对应的文件版本,类似于 git reset eb43bf file.txt,这时候再运行 git commit,就会将该版本的 file.txt 提交。
另外,可以使用 git reset --soft HEAD~n 来达到压缩提交的效果
3.3 git checkout
git checkout [branch]:切换分支,与 git reset --hard [branch] 非常相似,它会更新 “三棵树”,HEAD、Index、WorkDirectory,不同于 reset --hard,checkout 对于工作目录是安全的,它会通过检查来确保不会将已更改的文件弄丢。并且 reset 会移动 HEAD 分支的走向,而 checkout 只会移动 HEAD 自身来指向另一个分支
git checkout file.txt:它就像 git reset [branch] file 那样用那次提交中的那个文件来更新 Index,同时也会覆盖工作目录中对应的文件,并不会移动 HEAD
4. git 底层命令
4.1 .git 目录
- config: 项目特有的配置选项
- info: 包含一个全局性排除文件,用以放置哪些不希望被记录在
.gitignore
文件中的忽略模式 - hooks: 包含客户端或服务端的钩子脚本
- objects: 存储所有的数据内容
- refs: 存储指向数据(分支、远程仓库和标签等)的提交对象的指针
- HEAD: 指向目前被检出的分支
- index: 保存暂存区信息