找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索本站精品资源

首页 教程频道 php教程 查看内容

Git学习

作者:模板之家 2020-10-25 20:24 14704人关注

Git属于分散型版本管理系统,是为版本管理而设计的软件。 Git入门Git简介 Git属于分散型版本管理系统,是为版本管理而设计的软件。 Linux的创始人Linus Torvalds在2005年开发了Git的原型程序。当时,由于在Linux内核 ...

Git属于分散型版本管理系统,是为版本管理而设计的软件。

Git入门

Git简介

Git属于分散型版本管理系统,是为版本管理而设计的软件。

Linux的创始人Linus Torvalds在2005年开发了Git的原型程序。当时,由于在Linux内核开发中使用的既有版本管理系统的开发方许可证发生了变更,为了更换新的版本管理系统,Torvalds开发了Git。

什么是版本管理

版本管理就是管理更新的历史记录。它为我们提供了一些在软件开发过程中必不可少的功能,例如记录一款软件添加或更改源代码的过程,回滚到特定阶段,恢复误删除的文件等。

在Git出现以前,人们普遍采用Subversion等集中型版本管理系统,而现在Git已成为主流。

集中型与分散型

不同点:

以Subversion为代表的集中型,会将仓库集中存放在服务器之中,所以只存在一个仓库。这就是为什么这种版本管理系统会被称作集中型。

集中型将所有数据集中存放在服务器当中,有便于管理的有点。但是一旦开发者所处的环境不能连接服务器,就无法获取最新的源代码,开发也就几乎无法进行。服务器宕机时也是同样的道理,而且万一服务器故障导致数据消失,恐怕开发者就再也见不到最新的源代码了。

以Git为代表的分散型,例如GitHub会将仓库Fork给每一个用户。Fork就是将GitHub的某个特定仓库复制到自己的账户下。Fork出的仓库与原仓库是两个不同的仓库,开发者可以随意编辑。分散型拥有多个仓库,相对而言稍显复杂。不过,由于本地的开发环境中就有仓库,所以开发者不必连接远程仓库就可以进行开发。

Git安装和初始设置

Mac与Linux

最近的Mac中都预装了Git。而各版本的Linux中也都以软件包(Package)的形式提供给用户了,所以各位可以直接使用。关于这两个环境特有的详细安装方法,暂时不做叙述。

Windows

在Windows环境中,最简单快捷的方法是使用msysGit(http://msysgit.github.io) 。请按照Downloads的向导下载安装包。安装包下载完毕后,只要双击运行,按照向导一步步安装即可。

初始设置

设置姓名和邮箱地址

首先开设置使用Git时的姓名和邮箱地址。名字请用英文输入。

1
2
git config --global user.name 'Firstname Lastname" 
git config --global user.email "your_email@example.com"

这个命令,会在“~/.gitconfig”中以如下形式输出设置文件。

1
2
3
[user] 
name = Firstname Lastname
email = your_email@example.com

想更改这些信息时,可以直接编辑这个设置文件。这里设置的姓名和邮箱地址会用在Git的提交日志中。由于在GitHub上公开仓库时,这里的姓名和邮箱地址也会随着提交日志一同被公开,所以请不要使用不便公开的隐私信息。

在GitHub上公开代码后,前来参考的程序员可能来自世界任何地方,所以请不要使用汉字,尽量用英文进行描述。当然,如果您不想使用真名,完全可以使用网络上的昵称。

提高命令输出的可读性

顺便一提,将color.ui设置为auto可以让命令的输出拥有更高的可读性。

1
git config --global color.ui auto

“~/.gitconfig”中会增加下面一行。

1
2
[color] 
ui = auto

这样一来,各种命令的输出就会变得更容易分辨。

Git学习之基本操作(一)

初始化仓库

git init

要使用Git进行版本管理,必须先初始化仓库。Git是使用git init命令进行初始化的。请实际建立一个目录并初始化仓库。

1
2
3
4
$ mkdir git-learn
$ cd git-learn/
$ git init
Initialized empty Git repository in /Users/weirubo/www/git-learn/.git/

如果初始化成功,执行了git init命令的目录下就会生成.git目录。这个.git目录里存储着管理当前目录内容所需的仓库数据。

Git中,我们将这个目录的内容称为“附属于该仓库的工作树”。文件的编辑等操作在工作树种进行,然后记录到仓库中,以此管理文件的历史快照。如果想将文件恢复到原先的状态,可以从仓库中调取之前的快照,在工作树中打开。开发者可以通过这种方式获取以往的文件。

查看仓库的状态

git status

git status命令用于显示Git仓库的状态。

工作树和仓库在被操作的过程中,状态会不断发生变化。在Git操作过程中时常用git status命令查看当前状态,可谓基本中的基本。

下面,就让我们来实际查看一下当前状态。

1
2
3
4
5
6
$ git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)

结果显示了我们当前正处于master分支下。接着还显示了没有可提交的内容。所谓提交(Commit),是指“记录工作树中所有文件的当前状态”。

尚没有可提交的内容,就是说当前我们建立的这个仓库中还没有记录任何文件的任何状态。这里,我们建议README.md文件作为管理对象,为第一次提交做前期准备。

1
2
3
4
5
6
7
8
9
10
11
12
$ touch README.md
$ git status
On branch master

Initial commit

Untracked files:
(use "git add <file>..." to include in what will be committed)

README.md

nothing added to commit but untracked files present (use "git add" to track)

可以看到在Untracked files中显示了README.md文件。类似地,只要对Git的工作树或仓库进行操作,git status命令的显示结果就会发生变化。

向暂存区中添加文件

git add

如果只是用Git仓库的工作树创建了文件,那么该文件并不会被记入Git仓库的版本管理对象当中。因此我们用git status命令查看README.md文件时,它会显示在Untracked files里。

要想让文件成为Git仓库的管理对象,就需要用git add命令将其加入暂存区(Stage或者Index)中。暂存区是提交之前的一个临时区域。

1
2
3
4
5
6
7
8
9
10
$ git add README.md
$ git status
On branch master

Initial commit

Changes to be committed:
(use "git rm --cached <file>..." to unstage)

new file: README.md

README.md文件加入暂存区后,git status命令的显示结果发生了变化。可以看到,README.md文件显示在Changes to be commited中了。

保存仓库的历史记录

git commit

git commit命令可以将当前暂存区中的文件实际保存到仓库的历史记录中。通过这些记录,我们就可以在工作树中复原文件。

记录一行提交信息

我们来实际运行一下git commit命令。

1
2
3
4
$ git commit -m "My first commit"
[master (root-commit) 858ba4b] My first commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md

-m参数后的”My first commit“称作提交信息,是对这个提交的概述。

记录详细提交信息

刚才我们只简洁地记述了一行提交信息,如果想要记述得更加详细,请不加-m,直接执行git commit命令。执行后编辑器就会启动,并显示如下结果。

1
2
3
4
5
# 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:
# modified: README.md

在编辑器中记述提交信息的格式如下。

  • 第一行:用一行文字简述提交的更改内容
  • 第二行:空行
  • 第三行以后:记述更改的原因和详细内容

只要按照上面的格式输入,今后便可以通过确认日志的命令或工具看到这些记录。

在以#(井号)标为注释的Changes to be committed(要提交的更改)栏中,可以查看本次提交中包含的文件。将提交信息按格式记述完毕后,请保存并关闭编辑器,以#(井号)标为注释的行不必删除。随后,刚才记述的提交信息就会被提交。

中止提交

如果在编辑器启动后想中止提交,请将提交信息留空并直接关闭编辑器,随后提交就会被中止。

查看提交后的状态

执行完git commit命令后再来查看当前状态。

1
2
3
$ git status
On branch master
nothing to commit, working directory clean

当前工作树处于刚刚完成提交的最新状态,所以结果显示没有更改。

查看提交日志

git log

git log命令可以查看以往仓库中提交的日志。包括可以查看什么人在什么时候进行了提交或合并,以及操作前后有怎样的差别。

我们先来看看刚才的git commit命令是否被记录了。

1
2
3
4
5
6
7
8
9
10
11
12
$ git log
commit c75e47ad83d604e234eac38bb3aec57226f79974
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 23:01:24 2016 +0800

测试使用编辑器记述详细提交信息

commit 858ba4b5b0368c1af88856ea94c5cbbd9eab51fc
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 22:49:19 2016 +0800

My first commit

如上所示,显示了刚刚的提交操作。commit栏旁边显示的“c75e47......”是指向这个提交的哈希值。Git的其它命令中,在指向提交时会用到这个哈希值。

Author栏中显示我们给Git设置的用户名和邮箱地址。Date栏中显示提交执行的日期和时间。再往下就是该提交的提交信息。

只显示提交信息的第一行

如果只想让程序显示第一行简述信息,可以在git log命令后加上--pretty=short。这样一来开发人员就能够更轻松地把握多个提交。

1
2
3
4
5
6
7
8
$ git log --pretty=short
commit c75e47ad83d604e234eac38bb3aec57226f79974
Author: frankphper <1678723151@qq.com>

测试使用编辑器记述详细提交信息

commit 858ba4b5b0368c1af88856ea94c5cbbd9eab51fc
Author: frankphper <1678723151@qq.com>

只显示指定目录、文件的日志

只要在git log命令后加上目录名,便会只显示该目录下的日志。如果加的是文件名,就会只显示与该文件相关的日志。

1
$ git log README.md

显示文件的改动

如果想查看提交所带来的改动,可以加上-p参数,文件的前后差别就会显示在提交信息之后。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ git log -p
commit c75e47ad83d604e234eac38bb3aec57226f79974
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 23:01:24 2016 +0800

测试使用编辑器记述详细提交信息

diff --git a/README.md b/README.md
index e69de29..5dbdb31 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1 @@
+Git Learn

commit 858ba4b5b0368c1af88856ea94c5cbbd9eab51fc
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 22:49:19 2016 +0800

My first commit

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29

比如,执行下面的命令,就可以只查看README.md文件的提交日志以及提交后的差别。

1
$ git log -p README.md

如上所述,git log命令可以利用多种参数帮助开发者把握以往提交的内容。

查看更改前后的差别

git diff

git diff命令可以查看工作树、暂存区、最新提交之间的差别。

我们在刚刚提交的README.md中写点东西。

#Git学习

这里用Markdown语法写下了一行题目。

查看工作树和暂存区的差别

执行git diff命令,查看当前工作树与暂存区的差别。

1
2
3
4
5
6
7
8
$ git diff
diff --git a/README.md b/README.md
index 5dbdb31..247921a 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
Git Learn
+#Git学习

由于我们尚未用git add命令向暂存区添加任何东西,所以程序只会显示工作树与最新提交状态之间的差别。
这里解释一下显示的内容。“+”号标出的是新添加的行,被删除的行则用“-”号标出。我们可以看到,这次只添加了一行。

git add命令将README.md文件加入暂存区。

$ git add README.md
查看工作树和最新提交的差别

如果现在执行git diff命令,由于工作树和暂存区的状态并无差别,结果什么都不会显示。要查看与最新提交的差别,请执行以下命令。

1
2
3
4
5
6
7
8
$ git diff HEAD
diff --git a/README.md b/README.md
index 5dbdb31..247921a 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
Git Learn
+#Git学习

不妨养成这样一个好习惯:在执行git commit命令之前先执行git diff HEAD命令,查看本次提交与上次提交之间有什么差别,等确认完毕后再进行提交。这里HEAD是指向当前分支中最新一次提交的指针。

由于我们刚刚确认过这两个提交之间的差别,所以直接运行git commit命令。

1
2
3
$ git commit -m "Add #Git学习"
[master c87f9ae] Add #Git学习
1 file changed, 1 insertion(+)

保险起见,我们查看一下提交日志,确认提交是否成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ git log
commit c87f9ae6da0ccffedda289c55e55e7bc7900dfe0
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 23:33:16 2016 +0800

Add #Git学习

commit c75e47ad83d604e234eac38bb3aec57226f79974
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 23:01:24 2016 +0800

测试使用编辑器记述详细提交信息

commit 858ba4b5b0368c1af88856ea94c5cbbd9eab51fc
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 22:49:19 2016 +0800

My first commit

成功查看了第三个提交。

Git学习之分支的操作(二)

显示分支一览表

git branch

git branch命令可以将分支名列表显示,同时可以确认当前所在的分支。

1
$ git branch * master

可以看到master分支左侧标有“*”(星号),表示这是我们当前所在的分支。也就是说,我们正在master分支下进行开发。结果中没有显示其他分支名,表示本地仓库中只存在master一个分支。

创建、切换分支

git checkout -b

如果想以当前的master分支为基础创建新的分支,我们需要用到git checkout -b命令。

切换到feature-A分支并进行提交。

执行下面的命令,创建名为feature-A的分支。

1
2
$ git checkout -b feature-A
Switched to a new branch 'feature-A'

实际上,连续执行下面两条命令也能收到同样的效果。

1
2
$ git branch feature-A
$ git checkout feature-A

创建feature-A分支,并将当前分支切换为feature-A分支。这时再来查看分支列表,会显示我们处于feature-A分支下。

1
2
3
$ git branch
* feature-A
master

feature-A分支左侧标有“*”,表示当前分支为feature-A。在这个状态下像正常开发那样修改代码、执行git add命令并进行提交的话,代码就会提交至feature-A分支。像这样不断对一个分支(例如feature-A)进行提交的操作,我们称为“培育分支”。

下面来实际操作一下,在README.md文件中添加一行。

feature-A

这里我们添加了feature-A这样一行字母,然后进行提交。

1
2
3
4
$ git add README.md
$ git commit -m "Add feature-A"
[feature-A 320739b] Add feature-A
1 file changed, 1 insertion(+)

于是,这一行就添加到feature-A分支中了。

切换到master分支

现在我们再来看一看master分支有没有受影响。首先切换至master分支。

1
2
$ git checkout master
Switched to branch 'master'

然后查看README.md文件,会发现README.md文件仍然保持原先的状态,并没有被添加文字。feature-A分支的更改不会影响到master分支,这正是在开发中创建分支的优点。只要创建多个分支,就可以在不互影响的情况下同时进行多个功能的开发。

切换回上一个分支

现在,我们再切换回feature-A分支。

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

像上面这样用“-”(连字符)代替分支名,就可以切换至上一个分支。当然,将“-”替换成feature-A同样可以切换至feature-A分支。

特性分支

特性分支顾名思义,是集中实现单一特性(主题),除此之外不进行任何作业的分支。在日常开发中,往往会创建数个特性分支,同时在此之外再保留一个随时可以发布软件的稳定分支。稳定分支的角色通常由master分支担当。

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

基于特定主题的作业在特性分支中进行,主题完成后再与master分支合并。只要保持这样一个开发流程,就能保证master分支可以随时供人查看。这样一来,其他开发者也可以放心大胆地从master分支创建新的特性分支。

主干分支

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

有时我们需要让这个主干分支总是配置在正式环境中,有时又需要用标签Tag等创建版本信息,同时管理多个版本发布,拥有多个版本发布时,主干分支也有多个。

合并分支

git merge

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

1
2
$ git checkout master
Switched to branch 'master'

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

1
$ git merge --no-ff feature-A

随后编辑器会启动,用于录入合并提交的信息。

1
2
3
4
5
6
7
Merge branch 'feature-A'

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.

默认信息中已经包含了是从feature-A分支合并过来的相关内容,所以可不必做任何更改。将编辑器中显示的内容保存,关闭编辑器,然后就会看到下面的结果。

1
2
3
Merge made by the 'recursive' strategy.
README.md | 1 +
1 file changed, 1 insertion(+)

这样一来,feature-A分支的内容就合并到master分支中了。

以图表形式查看分支

git log --graph

git log --graph命令进行查看的话,能很清楚地看到特性分支(feature-A)提交的内容已被合并。除此之外,特性分支的创建以及合并也都清楚明了。

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
$ git log --graph
* commit a5f6cbf52a36dd104e131e32e67531656640c0c3
|\ Merge: c87f9ae 320739b
| | Author: frankphper <1678723151@qq.com>
| | Date: Mon Apr 11 08:16:48 2016 +0800
| |
| | Merge branch 'feature-A'
| |
| * commit 320739b163a92ab90e24abfb814ab7fc09e9c9a0
|/ Author: frankphper <1678723151@qq.com>
| Date: Mon Apr 11 07:59:05 2016 +0800
|
| Add feature-A
|
* commit c87f9ae6da0ccffedda289c55e55e7bc7900dfe0
| Author: frankphper <1678723151@qq.com>
| Date: Sun Apr 10 23:33:16 2016 +0800
|
| Add #Git学习
|
* commit c75e47ad83d604e234eac38bb3aec57226f79974
| Author: frankphper <1678723151@qq.com>
| Date: Sun Apr 10 23:01:24 2016 +0800
|
| 测试使用编辑器记述详细提交信息
|
* commit 858ba4b5b0368c1af88856ea94c5cbbd9eab51fc
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 22:49:19 2016 +0800

My first commit

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

Git学习之回溯历史版本(三)

回溯历史版本

git reset

通过前面学习的操作,我们已经学会如何在实现功能后进行提交,累积提交日志作为历史记录,借此不断培育一款软件。

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

在这里,为了让各位熟悉对历史版本的操作,我们先回溯历史版本,创建一个名为fix-B的特性分支。

回溯到创建feature-A分支前

让我们先回溯到上一节feature-A分支创建之前,创建一个名为fix-B的特性分支。

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

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
$ git log
commit a5f6cbf52a36dd104e131e32e67531656640c0c3
Merge: c87f9ae 320739b
Author: frankphper <1678723151@qq.com>
Date: Mon Apr 11 08:16:48 2016 +0800

Merge branch 'feature-A'

commit 320739b163a92ab90e24abfb814ab7fc09e9c9a0
Author: frankphper <1678723151@qq.com>
Date: Mon Apr 11 07:59:05 2016 +0800

Add feature-A

commit c87f9ae6da0ccffedda289c55e55e7bc7900dfe0
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 23:33:16 2016 +0800

Add #Git学习

commit c75e47ad83d604e234eac38bb3aec57226f79974
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 23:01:24 2016 +0800

测试使用编辑器记述详细提交信息

commit 858ba4b5b0368c1af88856ea94c5cbbd9eab51fc
Author: frankphper <1678723151@qq.com>
Date: Sun Apr 10 22:49:19 2016 +0800

My first commit
1
2
$ git reset --hard c87f9ae6da0ccffedda289c55e55e7bc7900dfe0 
HEAD is now at c87f9ae Add #Git学习

我们已经成功回溯到特性分支(feature-A)创建之前的状态。由于所有文件都回溯到了指定哈希值对应的时间点上,README.md文件的内容也恢复到了当时的状态。

创建fix-B分支

现在我们来创建特性分支(fix-B

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

我们在README.md文件中添加一行文字。

1
2
3
Git Learn
#Git学习
fix-B

然后直接提交README.md文件。

1
2
3
4
$ git add README.md
$ git commit -m "fix-B"
[fix-B 6814da3] fix-B
1 file changed, 1 insertion(+)

接下来,我们的目标是主干分支合并feature-A分支的修改后,又合并了fix-B的修改。

推进至feature-A分之合并后的状态

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

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

首先执行git reflog命令,查看当前仓库执行过的操作的日志。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git reflog
6814da3 HEAD@{0}: commit: fix-B
c87f9ae HEAD@{1}: reset: moving to c87f9ae6da0ccffedda289c55e55e7bc7900dfe0
a5f6cbf HEAD@{2}: checkout: moving from master to fix-B
a5f6cbf HEAD@{3}: merge feature-A: Merge made by the 'recursive' strategy.
c87f9ae HEAD@{4}: checkout: moving from feature-A to master
320739b HEAD@{5}: checkout: moving from master to feature-A
c87f9ae HEAD@{6}: checkout: moving from feature-A to master
320739b HEAD@{7}: commit: Add feature-A
c87f9ae HEAD@{8}: checkout: moving from master to feature-A
c87f9ae HEAD@{9}: commit: Add #Git学习
c75e47a HEAD@{10}: commit: 测试使用编辑器记述详细提交信息
858ba4b HEAD@{11}: commit (initial): My first commit

在日志中,我们可以看到commitcheckoutresetmergeGit命令的执行纪律。只要不进行GitGCGarbage Collection,垃圾回收),就可以通过日志随意调取近期的历史状态,就像给时间机器指定一个时间点,在过去未来中自由穿梭一般。即便开发者错误执行了Git操作,基本也都可以利用git reflog命令恢复到原先的状态。

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

1
2
3
4
$ git checkout master
Switched to branch 'master'
$ git reset --hard a5f6cbf
HEAD is now at a5f6cbf Merge branch 'feature-A'

之前我们使用git reset --hard命令回溯了历史,这里又再次通过它恢复到了回溯前的历史状态。

Git学习之消除冲突和修改提交信息(四)

消除冲突

现在我们只要合并fix-B分支,就会发生冲突。

1
2
3
4
$ git merge --no-ff fix-B 
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

系统告诉我们README.md文件发生了冲突(Conflict)。系统在合并README.md文件时,feature-A分支更改的部分与本次想要合并的fix-B分支更改的部分发生了冲突。

不解决冲突就无法完成合并,所以我们打开README.md文件,解决这个冲突。

查看冲突部分并将其解决

用编辑器打开README.md文件,就会发现其内容变成了下面这个样子。

1
2
3
4
5
6
7
Git Learn 
#Git学习
<<<<<<< HEAD
feature-A
=======
fix-B
>>>>>>> fix-B

=======以上的部分是当前HEAD的内容,以下的部分还要合并的fix-B分支中的内容。我们在编辑器中将其改成想要的样子。

1
2
3
4
5
Git Learn 
#Git学习

feature-A
fix-B

如上所示,本次修正让feature-Afix-B的内容并存于文件之中。但是在实际的软件开发中,往往需要删除其中之一,所以各位在处理冲突时,务必要仔细分析冲突部分的内容后再行修改。

提交解决后的结果

冲突解决后,执行git add命令与git commit命令。

1
2
3
$ git add README.md 
$ git commit -m "Fix conflict"
[master d8d0c37] Fix conflict

由于本次更改解决了冲突,所以提交信息记为“Fix conflict”。

修改提交信息

git commit --amend

要修改上一条提交信息,可以使用git commit --amend命令。

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

1
$ git commit --amend

执行上面的命令后,编辑器就会启动

1
2
3
4
5
6
7
8
9
10
11
Fix conflict

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Tue Apr 12 11:20:56 2016 +0800
#
# On branch master
# Changes to be committed:
# modified: README.md
#

编辑器中显示的内容如上所示,其中包含之前的提交信息。请将提交信息的部分修改为Merge branch 'fix-B',然后保存文件,关闭编辑器。

1
2
[master d1726c9] Merge branch 'fix-B'
Date: Tue Apr 12 11:20:56 2016 +0800

随后会显示上面这条结果。现在执行git log --graph命令,可以看到提交日志中的相应内容也已经被修改。

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
32
33
34
35
36
37
38
39
40
 git log --graph
* commit a51fda63bfebdb1c9f83b4385d8e8cfdacff9e19
|\ Merge: a5f6cbf 6814da3
| | Author: frankphper <1678723151@qq.com>
| | Date: Tue Apr 12 11:20:56 2016 +0800
| |
| | Merge branch 'fix-B'
| |
| * commit 6814da3bcfc5935580f873190cb24f18db0017ec
| | Author: frankphper <1678723151@qq.com>
| | Date: Tue Apr 12 09:49:32 2016 +0800
| |
| | fix-B
| |
* | commit a5f6cbf52a36dd104e131e32e67531656640c0c3
|\ \ Merge: c87f9ae 320739b
| |/ Author: frankphper <1678723151@qq.com>
|/| Date: Mon Apr 11 08:16:48 2016 +0800
| |
| | Merge branch 'feature-A'
| |
| * commit 320739b163a92ab90e24abfb814ab7fc09e9c9a0
|/ Author: frankphper <1678723151@qq.com>
| Date: Mon Apr 11 07:59:05 2016 +0800
|
| Add feature-A
|
* commit c87f9ae6da0ccffedda289c55e55e7bc7900dfe0
| Author: frankphper <1678723151@qq.com>
| Date: Sun Apr 10 23:33:16 2016 +0800
|
| Add #Git学习
|
* commit c75e47ad83d604e234eac38bb3aec57226f79974
| Author: frankphper <1678723151@qq.com>
| Date: Sun Apr 10 23:01:24 2016 +0800
|
| 测试使用编辑器记述详细提交信息
|
* commit 858ba4b5b0368c1af88856ea94c5cbbd9eab51fc

Git学习之压缩历史(五)

压缩历史

git rebase -i

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

创建feature-C分支

首先,新建一个feature-C特性分支。

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

我们在README.md文件中添加一行文字,并且故意拼写错误,以便之后修正。

1
2
3
4
5
6
Git Learn
#Git学习

feature-A
fix-B
faeture-C

我们用git commit -am命令。

1
2
3
$ git commit -am "Add feature-C"
[feature-C e57cbf9] Add feature-C
1 file changed, 1 insertion(+)

修正拼写错误

修正README.md文件的内容,修正后的差别如下所示:

1
2
3
4
5
6
7
8
9
10
11
$ git diff
diff --git a/README.md b/README.md
index a51326b..1fdef41 100644
--- a/README.md
+++ b/README.md
@@ -3,4 +3,4 @@ Git Learn

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

然后进行提交。

1
2
3
$ git commit -am "Fix typo"
[feature-C a12e149] Fix typo
1 file changed, 1 insertion(+), 1 deletion(-)

错字漏字等失误称作typo,所以我们将提交信息记为“Fix typo”。

实际上,我们不希望在历史尽量中看到这类提交,因为健全的历史记录并不需要它们。如果能在最初提交之前就发现并修正这些错误,也就不会出现这类提交了。

更改历史

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

1
2
3
$ git rebase -i HEAD-2
fatal: Needed a single revision
invalid upstream HEAD~2

用上述方式执行git rebase命令,可以选定当前分支中包含HEAD(最新提交)在内的两个最新历史记录为对象,并在编辑器中打开。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pick e57cbf9 Add feature-C
pick a12e149 Fix typo

# Rebase a51fda6..a12e149 onto a51fda6 (2 command(s))
#
# 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
# d, drop = remove commit
#
# 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

我们将a12e149Fix typo的历史记录压缩到e57cbf9Add feature-C里。将a12e149左侧的pick部分删除,改写为fixup

保存编辑器里的内容,关闭编辑器。

1
2
3
4
[detached HEAD ad10e53] Add feature-C
Date: Tue Apr 12 12:58:05 2016 +0800
1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/feature-C.

系统显示rebase成功。也就是以下面这两个提交作为对象,将“Fix typo”的内容合并到了上一个提交“Add feature-C”中,改写成了一个新的提交。

  • e57cbf9 Add feature-C
  • a12e149 Fix typo

现在再查看提交日志时会发现Add feature-C的哈希值已经不是e57cbf9了,这证明提交已经被更改。

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
32
33
34
35
36
37
38
39
40
$ git log --graph
* commit ad10e53aad0618b3c3e850635a013f3e2eb44282
| Author: frankphper <1678723151@qq.com>
| Date: Tue Apr 12 12:58:05 2016 +0800
|
| Add feature-C
|
* commit a51fda63bfebdb1c9f83b4385d8e8cfdacff9e19
|\ Merge: a5f6cbf 6814da3
| | Author: frankphper <1678723151@qq.com>
| | Date: Tue Apr 12 11:20:56 2016 +0800
| |
| | Merge branch 'fix-B'
| |
| * commit 6814da3bcfc5935580f873190cb24f18db0017ec
| | Author: frankphper <1678723151@qq.com>
| | Date: Tue Apr 12 09:49:32 2016 +0800
| |
| | fix-B
| |
* | commit a5f6cbf52a36dd104e131e32e67531656640c0c3
|\ \ Merge: c87f9ae 320739b
| |/ Author: frankphper <1678723151@qq.com>
|/| Date: Mon Apr 11 08:16:48 2016 +0800
| |
| | Merge branch 'feature-A'
| |
| * commit 320739b163a92ab90e24abfb814ab7fc09e9c9a0
|/ Author: frankphper <1678723151@qq.com>
| Date: Mon Apr 11 07:59:05 2016 +0800
|

路过

雷人

握手

鲜花

鸡蛋
原作者: 网络收集 来自: 网络收集

全部回复(0)