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

  1. git checkout master
  2. git pull(拉取最新代码,也可以使用 git fetch)
  3. git merge dev
  4. … (解决冲突)
  5. git push (提交到服务器)

2.2.2 git rebase

现在同样有主分支 master 与 开发分支 dev,需要将 dev 合并到 master

git rebase 的原理是先找到两个分支(master 与 dev)的最近公共祖先,然后对比 dev 分支对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标分支(master)的最新一次的提交,最后将之前另存为临时文件的修改依序应用

工作中的使用流程

  1. git checkout master(切换到目标分支)
  2. git pull (拉取最新代码)(也可以直接执行 git rebase master dev,省去步骤3和步骤4 )
  3. git checkout dev (切换到开发分支)
  4. git rebase master (执行变基操作)
  5. git checkout master (切换到主分支)
  6. git merge dev (将 dev 分支上的修改变基到主分支)
  7. 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~ 操作共有两个步骤

  1. 将 HEAD 指针向前移动一个节点,也就是 git reset –soft HEAD~ 操作

  2. 重置 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~ 总共有三个步骤

  1. 将 HEAD 指针向前移一个节点,也就是 git reset –soft HEAD~ 操作
  2. 重置 Index (暂存区)的文件与 HEAD 指向的节点保持一致,也就是 git reset –mixed HEAD~ 操作
  3. 重置 Work Directory 的文件与 HEAD 和 Index 保持一致

3.2.4 git reset 的其他用法

git reset file.txt(其实是 git reset –mixed HEAD file.txt 的简写形式),它的实质是将 file.txt 从 HEAD 复制到 Index ,该命令总共有两个步骤:

  1. 移动 HEAD 分支的指向(因为我们给 reset 指定了一个路径,所以它的作用范围限定为指定的文件或文件集合,而 HEAD 只是一个指针,无法让它指向两个提交中各自的一部分,所以该步骤会跳过,HEAD 的指向不变)
  2. 让 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: 保存暂存区信息