概述
Git入门系列包括git客户端的安装配置,日常开发中常用命令。本文是第二篇,介绍日常开发中常用的命令。
Git初始化
配置Git提交时的用户名和邮箱
1 | git config --global user.name "xxxxx" |
注:git config 命令有3个级别的范围参数,分别是global、local和system,建议上google百度一下他们的区别。
对已有代码目录进行Git初始化
假设你刚刚在GitLab上创建了一个Project,它的Git地址为 git@git.xxxx.com:xxxx/test.git 。这个项目里面什么文件也没有。
而现在我们在本地有一套项目代码,在test-project目录下,有两个文件:1
2$ ls test-project/
a.txt b.txt
现在想把它托管给GitLab,则可以通过下面的命令完成1
2
3
4
5
6cd test-project
git init
git remote add origin git@git.xxxx.com:xxxx/test.git
git add a.txt b.txt
git commit -m 'commit initialize'
git push origin master
Git 独奏
Git克隆
假设现在团队里另外一个成员(xxxx)加进这个项目了,他也需要为这个项目贡献代码。那么他要做的第一件事就是把代码从GitLab上克隆(clone)下来,如下:
git clone git@git.xxxx.com:xxxx/test.git
查看提交日志(commit log)
clone下来后,可以看看提交日志:1
2
3
4
5
6
7
8$ git log --stat --pretty=full
commit 37510d9d26ec125148815a596a6345176d65dc27
Author: xxxx <xxxx@xxxx.com>
Commit: xxxx <xxxx@xxxx.com>
commit initialize
a.txt | 1 +
b.txt | 1 +
2 files changed, 2 insertions(+)
可以看到,这个项目有一次提交,commit的唯一ID(37510d9d26ec125148815a596a 6345176d65dc27),提交人(xxxx),commit的说明(commit initialize),和提交了哪些文件等信息。
查看当前所在分支
1 | $ git branch |
星号表示当前所在分支,是master。clone下来默认在master分支内。
新建分支
现在xxxx需要建一个新分支, 他的代码都提交到这个分支上。首先通过checkout命令创建分支:
1
2
3
4
5$ git checkout -b f_test_1.2.0
Switched to a new branch 'f_test_1.2.0'
$ git branch
* f_test_1.2.0
master
checkout 命令加上-b 选项 可同时完成创建新分支和切换到该分支上。
提交代码
xxxx开始工作了:修改a.txt ,删除b.txt,增加c.txt,如下1
2
3
4
5
6$ echo "add something" >> a.txt
$ rm b.txt
$ echo "add by xxxx" > c.txt
$ ls
a.txt c.txt
通过 git status -s 命令 显示精简格式的状态输出:
前面红色字样 M - Modify,D- Delete,?-新增(新增文件是2个呢问号)
通过 git diff 可以查看修改前后文件的差异:
上面的修改能不能直接提交?试验下:
提交成功了吗?看下提交日志:
只有第一次的提交记录,说明刚刚的提交没有成功。留意上面git commit不成功后的提示“Changes not staged for commit” 一句,意思是说:下列修改没有加入到暂存区(stage),不会被提交。暂存区?什么东东?
下面简单说下Git做了什么。Git把本地文件分成3个区域:工作区、暂存区、版本库。我们一般做的修改、新增、删除文件是针对工作区的,只有执行git add 命令后才会把工作区的变动提交到暂存区;执行git commit命令后,才把暂存区的变动提交到版本库。执行git push命令后,把版本库的变动提交到远程代码仓库(好了,暂时只能说这么多了,想更详细的理解这三个区域的关系建议找google了)
为了能成功提交,让我们把上面所在的改动从工作区提交到暂存区吧。
git add -i
加上-i 选项的git add 是个很有Geek范的命令! 它的作用是让我们能挑选哪些文件来提交到暂存区。下面我们用它来把改动提交到暂存区。
最后输入7 或者 q退出 git add -i。 这时再输入git diff 发现已经没有差异输出,因为工作区和暂存区里的文件已经没有差异。 嗯,这也说明git diff 是比较工作区和暂存区的。加上–cached 选项再执行下git diff 看看:
差异又回来了,其实这是因为加了–cached 的 git diff 是比较暂存区和版本库的。因为我们还没把暂存区的改动提交到版本库,所以它们之间当然有文件差异。好,commit一下:1
2
3
4$ git commit -m 'commit by xxxx'
3 files changed, 2 insertions(+), 1 deletion(-)
delete mode 100644 b.txt
create mode 100644 c.txt
这时再运行git diff –cached 也没有差异输出了。看下提交日志,commit已成功。
下一步就是把这次提交push到远程代码库即GitLab上了。1
2
3
4
5
6
7$ git checkout f_test_1.2.0
Branch f_test_1.2.0 set up to track remote branch f_test_1.2.0 from origin.
Switched to a new branch 'f_test_1.2.0'
$ git branch
* f_test_1.2.0
master
这次push也顺便把新建的分支f_test_1.2.0提交到远程Gitlab了。 当然在本地新创建的分支可以在git checkout -b 后执行git push 推送到远程,不必等到有commit后再push。
GIt交响乐
上面介绍的都是用户单独使用Git的场景,实际工作中,更多的是团队协作。下面模拟2个用户同时在一个分支进行协同开发的场景,来介绍常用的Git命令。
切换分支
现在用户xxxx加入 f_test_1.2.0分支一起工作了。他执行git clone 把代码拉到本地后,执行git checkout命令切换到 f_test_1.2.0分支,如下1
2
3
4
5
6
7$ git checkout f_test_1.2.0
Branch f_test_1.2.0 set up to track remote branch f_test_1.2.0 from origin.
Switched to a new branch 'f_test_1.2.0'
$ git branch
* f_test_1.2.0
master
推送
现在用户xxxx和 xxxx1的工作区是相同的。假设这样一种场景:如果两人各自在本地版本库中进行独立的提交,然后再分别向共享版本库GitLab推送,会相互覆盖吗?通过下面的实践就能知道答案。
首先,用户xxxx修改了c.txt 的第一行,然后在本地版本库中提交,再把提交推送到GitLab。操作步骤如下:
(1)用户xxxx修改c.txt 的第一行并提交到本地版本库1
2
3
4
5
6
7
8
9
10
11
12$ cat c.txt
add by xxxx
test crlf
#修改第一行后保存,如下
$ cat c.txt
add by xxxx modify by xxxx
test crlf
#提交到本地版本库
$ git add c.txt
$ git commit -m 'xxxx modify'
[f_test_1.2.0 a362394] xxxx modify
1 file changed, 1 insertion(+), 1 deletion(-)
(2)用户xxxx将本地提交推送到GitLab上1
2
3
4
5
6
7
8$ git push origin f_test_1.2.0
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 312 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@git.xxxx.com:xxxx/test.git
cff6bc9..a362394 f_test_1.2.0 -> f_test_1.2.0
通过上面的操作,用户xxxx已成功更新了远程GitLab上的代码。如果用户xxxx1不知道用户xxxx所做的上述操作,仍在基于GitLab旧数据同步而来的本地版本库中进行改动,然后用户xxxx1向GitLab推送,会有什么结果?用下面的操作验证过下。
(1)用户xxxx修改c.txt 的第二行并提交到本地版本库1
2
3
4
5
6
7
8
9
10
11
12
13$ cat c.txt
add by xxxx
test crlf
# 修改第二行,如下
$ cat c.txt
add by xxxx
test crlf modify by xxxx
#提交到本地版本库
$ git add c.txt
$ git commit -m 'xxxx modify'
[f_test_1.2.0 f17bbfe] xxxx modify
1 file changed, 1 insertion(+), 1 deletion(-)
(2)用户xxxx将本地提交推送到服务器会出错1
2
3
4
5
6
7
8
9
10
11bash
$ git push origin f_test_1.2.0
To git@git.xxxx.com:xxxx/test.git
! [rejected] f_test_1.2.0 -> f_test_1.2.0 (fetch first)
error: failed to push some refs to
'git@git.xxxx.com:xxxx/test.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
用户xxxx的推送被拒绝,hint里说明了原因:远程版本库包含你本地没有的改动,通常是因为有其他人push了。需要先通过git pull 命令来合并之后再push。git pull 命令会把改动拉到本地,并进行自动合并。1
2
3
4
5
6
7
8
9
10
11
12$ git pull origin f_test_1.2.0
Enter passphrase for key '/c/Users/dellzj/.ssh/id_rsa':
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From git1.kuaiwifi.com:xxxx/test
* branch f_test_1.2.0 -> FETCH_HEAD
cff6bc9..a362394 f_test_1.2.0 -> origin/f_test_1.2.0
Auto-merging c.txt
CONFLICT (content): Merge conflict in c.txt
Automatic merge failed; fix conflicts and then commit the result.
提示“CONFLICT (content): Merge conflict in c.txt”,自动合并过程出现了冲突。好,那就先解决冲突,执行命令 git mergetool 打开图形工具,默认会选择系统中已经安装的工具,如kdiff3。
冲突解决
执行git mergetool 命令后,会提示使用kdiff3,按回车后自动打开kdiff3窗口,如下图
kdiff3上方三个窗口由左至右显示冲突文件的三个版本,分别是:
A:共同祖先版本
B:本地更改的版本(这里就是用户xxxx更改的版本)
C:远程版本(这里就是用户xxxx push到GitLab的版本)
kdiff3下方的窗口是合并后文件的编辑窗口。
通过下图红框内的箭头或者红框内的红色标记,选中某个冲突行(如第一行),然后选中紫框内的C,表示使用C窗口中的内容作为合并后的内容。同样的操作,第二行则使用B窗口的内容。确定完成后点击保存按钮,关闭kdiff3窗口退出。
这时执行git status,会看到冲突已经解决。不过mergetool会产生一些临时文件,如.orig,不要提交,手动删除即可。
执行git commit命令,会打开commit注释窗口(如下图),git已经为你准备好一个*默认注释,就是刚刚合并冲突的注释。保存退出即可。
查看刚刚解决冲突的提交日志1
2
3
4$ git log --oneline
0ffed81 Merge remote-tracking branch 'refs/remotes/origin/f_test_1.2.0' into f_test_1.2.0
f17bbfe xxxx modify
a362394 xxxx modify
执行推送,这次成功了。1
2
3
4
5
6
7
8$ git push origin f_test_1.2.0
Counting objects: 10, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 667 bytes | 0 bytes/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To git@git.xxxx.com:xxxx/test.git
a362394..0ffed81 f_test_1.2.0 -> f_test_1.2.0
写在最后
Git说到底也只是个工具,足以应付日常工作即可,更多请参考廖雪峰的Git教程~