Git与GitHub的简单了解(2)

时间:2022-04-16 16:09:30

3. 分支的操作

​ master 分支是 Git 默认创建的分支,因此基本上所有开发都是以这个分支为中心进行的 ,从 master 分支创
建 feature-A 分支和 fix-B 分支后,每个分支中都拥有自己的最新代码 。不同分支中,可以同时进行完全不同的作业。等该分支的作业完成之后再与 master 分支合并 ,利用分支可以使并行开发更加高效。


Git与GitHub的简单了解(2)

  • git branch ---- 显示分支一览表
$ git branch
* master

​ master 分支左侧标有“*”(星号),表示这是我们当前所在的分支。 结果中没显示其他的分支名,表示本地仓库中只存在master一个分支。

  • git checkout -b ---- 创建、切换分支
$ git checkout -b feature-A
Switched to a new branch 'feature-A'

​ 此时当前分支自动切换到了feature-A分支:

$ git branch
* feature-A
master

​ 在这个状态下像正常开发那样修改代码、执行 git add命令并进行提交的话,代 码 就 会 提 交 至 feature-A 分 支。

​ 现在我们在之前的README.md中添加一行feature-A,进行提交:

$ git add README.md
$ git commit -m "Add feature-A"
[feature-A 8a6c8b9] Add feature-A
1 file changed, 2 insertions(+)

​ 现在我们切换到master分支下,

$ git checkout master
Switched to branch 'master'

​ 现在我们再打开README.md文档,会发现并没有添加文字。

​ 现在在回到上一分支下,即feature-A分支下:

$ git checkout -
Switched to branch 'feature-A'

​ 用“-”(连字符)代替分支名,就可以切换至上一个分支。当然,我们直接输入 feature-A 同样可以切换到 feature-A 分支。


  • 特性分支(Topic)

特性分支顾名思义,是集中实现单一特性(主题),除此之外不进行任何作业的分支。


Git与GitHub的简单了解(2)

​ 之前我们创建了 feature-A 分支,这一分支主要实现 feature-A,除feature-A 的实现之外不进行任何作业。即便在开发过程中发现了 BUG,也需要再创建新的分支,在新分支中进行修正。

  • 主干分支-master

​ 主干分支是刚才我们讲解的特性分支的原点,同时也是合并的终点。通常人们会用 master 分支作为主干分支。主干分支中并没有开发到一半的代码,可以随时供他人查看。

  • git merge ---- 合并分支

​ 假设 feature-A 已经实现完毕,想要将它合并到主干分支 master 中。首先切换到 master 分支 :

$ git checkout master
Switched to branch 'master'

​ 下面合并 feature-A 分支。为了在历史记录中明确记录下本次分支合并,我们需要创建合并提交。因此,在合并时加上 --no-ff参数。

$ git merge --no-ff feature-A

​ 随后进入编辑器状态(笔者的电脑默认打开的是VIM编辑器),vim基本命令:链接 ,默认信息中已经包含了是从 feature-A 分支合并过来的相关内容,所以可以不做任何更改,将编辑器中显示的内容保存,关闭编辑器(-wq)。 会看到以下的结果:

Merge made by the 'recursive' strategy.
README.md | 2 ++
1 file changed, 2 insertions(+)
  • git log --graph ---- 以图表形式查看分支
$ git log --graph
* commit 83b0b94268675cb715ac6c8a5bc1965938c15f62
|\ Merge: fd0cbf0 8a6c8b9
| | Author: hirocaster <hohtsuka@gmail.com>
| | Date: Sun May 5 16:37:57 2013 +0900
| |
| | Merge branch 'feature-A'
| |
| * commit 8a6c8b97c8962cd44afb69c65f26d6e1a6c088d8
|/ Author: hirocaster <hohtsuka@gmail.com>
| Date: Sun May 5 16:22:02 2013 +0900
|
| Add feature-A
|
* commit fd0cbf0d4a25f747230694d95cac1be72d33441d
| Author: hirocaster <hohtsuka@gmail.com>
| Date: Sun May 5 16:10:15 2013 +0900
|
| Add index
|
* commit 9f129bae19b2c82fb4e98cde5890e52a6c546922
Author: hirocaster <hohtsuka@gmail.com>
Date: Sun May 5 16:06:49 2013 +0900

First commit

​ git log --graph命令可以用图表形式输出提交日志,非常直观!

4. 更改提交操作

  • git reset --- 回溯历史版本

​ Git 的另一特征便是可以灵活操作历史版本。借助分散仓库的优势,可以在不影响其他仓库的前提下对历史版本进行操作。

​ 先创建为一个名为fix-B的特性分支:


Git与GitHub的简单了解(2)

​ 要让仓库的 HEAD、暂存区、当前工作树回溯到指定状态,需要用到 git rest --hard命令。只要提供目标时间点的哈希值 ,就可以完全恢复至该时间点的状态。

$ git reset --hard fd0cbf0d4a25f747230694d95cac1be72d33441d
HEAD is now at fd0cbf0 Add inde

​ 由于所有文件都回溯到了指定哈希值对应的时间点上, README.md 文件的内容也恢复到了当时的状态。

​ 创建fix-B分支:

$ git checkout -b fix-B
Switched to a new branch 'fix-B'

​ 在 README.md 文件中添加一行文字 :- fix-B,接着提交README.md :

$ git add README.md

$ git commit -m "Fix B"
[fix-B 4096d9e] Fix B
1 file changed, 2 insertions(+)

​ 我们对于fix-B分支的下一步目标:


Git与GitHub的简单了解(2)

Git与GitHub的简单了解(2)


​ 首先恢复到 feature-A 分支合并后的状态。不妨称这一操作为“推进历史”。

git log命令只能查看以当前状态为终点的历史日志。所以这里要使用 git reflog命令,查看当前仓库的操作日志。在日志中找出回溯历史之前的哈希值,通过 git reset --hard命令恢复到回溯历史前的状态 !

​ 通过git reflog命令查看当前仓库执行过的操作日志:

$ git reflog
4096d9e HEAD@{0}: commit: Fix B
fd0cbf0 HEAD@{1}: checkout: moving from master to fix-B
fd0cbf0 HEAD@{2}: reset: moving to fd0cbf0d4a25f747230694d95cac1be72d33441d
83b0b94 HEAD@{3}: merge feature-A: Merge made by the 'recursive' strategy.
fd0cbf0 HEAD@{4}: checkout: moving from feature-A to master
8a6c8b9 HEAD@{5}: checkout: moving from master to feature-A
fd0cbf0 HEAD@{6}: checkout: moving from feature-A to master
8a6c8b9 HEAD@{7}: commit: Add feature-A
fd0cbf0 HEAD@{8}: checkout: moving from master to feature-A
fd0cbf0 HEAD@{9}: commit: Add index
9f129ba HEAD@{10}: commit (initial): First commit

​ 在日志中,我们可以看到 commit、 checkout、 reset、 merge 等 Git 命令的执行记录。只要不进行 Git 的 GC(Garbage Collection,垃圾回收),就可以通过日志随意调取近期的历史状态 。即便开发者错误执行了 Git 操作,基本也都可以利用 git reflog命令恢复到原先的状态,所以务必牢记本部分!

​ 上面第四行表示 feature-A 特性分支合并后的状态,对应哈希值为 83b0b94 ,将 HEAD、暂存区、工作树恢复到这个时间点的状态。

$ git checkout master
$ git reset --hard 83b0b94
HEAD is now at 83b0b94 Merge branch 'feature-A'

​ 当前状态为:


Git与GitHub的简单了解(2)

​ 现在只要合并 fix-B 分支,就可以得到我们想要的状态 。

$ git merge --no-ff fix-B
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Recorded preimage for 'README.md'
Automatic merge failed; fix conflicts and then commit the result.

​ 系统告诉我们 README.md 文件发生了冲突(Conflict)。系统在合并 README.md 文件时, feature-A 分支更改的部分与本次想要合并的 fix-B 分支更改的部分发生了冲突 ,不解决冲突就无法完成合并,所以我们打开 README.md 文件,解决这个冲突。 (cat、vim指令可以打开)

# Git教程

<<<<<<< HEAD
- feature-A
=======
- fix-B
>>>>>>> fix-B

​ ======= 以上的部分是当前 HEAD 的内容,以下的部分是要合并的 fix-B 分支中的内容。修改文档后,执行 git add命令与 git commit命令 。

git add README.md

$ git commit -m "Fix conflict"
Recorded resolution for 'README.md'.
[master 6a97e48] Fix conflict
  • git commit --amend ---- 修改提交信息

​ 我们将上一条提交信息记为了 "Fix conflict",但它其实是 fix-B 分支的合并,解决合并时发生的冲突只是过程之一,这样标记实在不妥。于是,我们要修改这条提交信息。

$ git commit --amend

​ 此时进入vim编辑器模式,我们将Fix conflict 修改为Merge branch 'fix-B' 即可。(按照之前的vim命令链接操作,1、光标选中Fix后,按“i”键,进入写模式,删除第一行,添加即可,2、按下ESC键,进入编辑模式,输入:wq保存退出)

Fix conflict

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
# (use "git reset HEAD^1 <file>..." to unstage)
#
# modified: README.md
#
  • git rebase -i ---- 压缩历史

​ 在合并特性分支之前,如果发现已提交的内容中有些许拼写错误等,不妨提交一个修改,然后将这个修改包含到前一个提交之中,压缩成一个历史记录。

​ 首先创建特性分支feature-C:

$ git checkout -b feature-C
Switched to a new branch 'feature-C'

​ 此外打开REDME.md文档故意添加一行错误的文字: - faeture-C ,提交这个小小的变更没必要先执行 git add命令再执行 git commit命令,我们用 git commit -am命令来一次完成这两步操作。

$ git commit -am "Add feature-C"
[feature-C 7a34294] Add feature-C
1 file changed, 1 insertion(+)

​ 现在来修正刚才预留的拼写错误,修正后的差别为:

$ git diff
diff --git a/README.md b/README.md
index ad19aba..af647fd 100644
--- a/README.md
+++ b/README.md
@@ -2,4 +2,4 @@

- feature-A
- fix-B
- - faeture-C
+ - feature-C

​ 我们将提交信息记为 "Fix typo" 进行提交。

​ 实际上,我们不希望在历史记录中看到这类提交 ,所以我们要更改历史。

更改历史

​ 更改历史,将 " Fix typo"修正的内容与之前一次的提交合并,在历史记录中合并为一次完美的提交。为此,我们要用到git rebase命令。

$ git rebase -i Head~2

注:此处为波浪~符号,而非减法-号

​ 此时编辑器显示:

pick 7a34294 Add feature-C
pick 6fba227 Fix typo


# Rebase 2e7db6f..6fba227 onto 2e7db6f
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

​ 我们将 6fba227 的 Fix typo 的历史记录压缩到 7a34294 的 Add feature-C里。按照下图所示,将 6fba227 左侧的 pick 部分删除,改写为 fixup,保存好编辑器后:

[detached HEAD 51440c5] Add feature-C
1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/feature-C.

​ 再次查看日志有:

$ git log --graph
* commit 51440c55b23fa7fa50aedf20aa43c54138171137
| Author: hirocaster <hohtsuka@gmail.com>
| Date: Sun May 5 17:07:36 2013 +0900
|
| Add feature-C
|
* commit 2e7db6fb0b576e9946965ea680e4834ee889c9d8
|\ Merge: 83b0b94 4096d9e
| | Author: hirocaster <hohtsuka@gmail.com>
| | Date: Sun May 5 16:58:27 2013 +0900
| |
| | Merge branch 'fix-B'
| |
| * commit 4096d9e856995a1aafa982aabb52bfc0da656b74
| | Author: hirocaster <hohtsuka@gmail.com>
| | Date: Sun May 5 16:50:31 2013 +0900
| |
| | Fix B
省略

​ 现在将feature-C分支合并到master分支中:

$ git checkout master
Switched to branch 'master'

$ git merge --no-ff feature-C
Merge made by the 'recursive' strategy.
README.md | 1 +
1 file changed, 1 insertion(+)