- 1. 前言
- 2. 为什么使用Git
- 3. 为什么使用命令行
- 4. 安装
- 5. 配置
- 5.1. 用户信息
- 5.2. 文本编辑器
- 5.3. 差异分析工具
- 5.4. 查看配置信息
- 6. 基本操作
- 6.1. 获得Git仓库
- 6.1.1. 在现存的目录下创建新的Git仓库
- 6.1.2. 从已有的仓库克隆
- 6.2. 基本概念
- 6.3. 提交版本
- 6.4. 查看提交历史
- 6.5. 推送数据到远程仓库
- 6.6. 拉取远程仓库中的更新
- 6.7. 忽略某些文件
- 6.1. 获得Git仓库
- 7. 分支
- 7.1. 查看分支
- 7.2. 创建分支
- 7.3. 切换分支
- 7.4. 创建并切换分支
- 7.5. 分支共用工作区
- 7.6. 查看所有分支的提交历史
- 7.7. 分支只是一个指针并且共享共同的历史
- 7.8. 合并分支
- 7.9. 查看冲突内容
- 7.10. 解决冲突
- 7.11. 删除分支
- 8. 获取帮助
- 9. Git和Subversion的命令的对比
- 10. 相关文章
1. 前言
本文是 Git 入门级教程,针对的是那些不会使用git的人群;通过该教程,能让你循序渐进地掌握 Git 的基本概念、基本操作流程 和 常用命令;
如果你已经会了 Git 的基本操作,希望在使用git时作为手册去查询,那你可以查看我的另一篇文章Git命令大全;
如果你在使用Git中遇到了难题,你可以参考 Git技巧和问题解决方案
2. 为什么使用Git
详情请参考选择Git的理由
3. 为什么使用命令行
Git 有2种使用方式:
- 命令行方式;
- 可视化界面的 GUI 方式;
本文中,将使用命令行方式,理由如下:
- 命令行模式能够进行Git的所有操作;而 GUI 方式只能进行较常用的Git操作;如果你会命令行的方式,那 GUI 的方式也就会了,反之,则不成立;
- GUI 方式的 Git 软件太多,不同的人喜欢的可能不一样,也不一定都装了 GUI 的Git,但每个人基本上都会有命令行工具,如:Mac 系统里有 Terminal(终端),Windows 系统有 CMD、PowerShell 等等;
4. 安装
安装 Git 命令行工具:
- Windows系统:从 https://git-scm.com/downloads 下载并安装 Git命令行工具
- MacOS系统:
-
方式1:
- 打开终端;(如果找不到终端软件,可点击 屏幕右上角的放大镜,然后输入“终端”来查找并打开终端软件)
- 执行命令:
xcode-select --install
;按照提示操作安装 xcode 命令行工具,如果让输入密码,就输入 电脑的开机密码;
-
方式2:如果你的电脑上已经安装了
brew
命令(Homebrew),你也可以用 brew 安装;安装方式如下,在终端中执行如下命令:brew install git
-
5. 配置
安装Git后,使用Git之前,需要先对Git做一些常用的信息的配置;
配置工作只需一次,以后升级时还会沿用现在的配置。当然,如果需要,你随时可以用相同的方式修改已有的配置。
5.1. 用户信息
第一个要配置的是你个人的用户名称和电子邮件地址。这两条配置很重要,每次 Git 提交时都会携带这两条信息,用于说明是谁提交了代码:
git config --global user.name "郭斌勇"
git config --global user.email [email protected]
5.2. 文本编辑器
接下来要设置的是默认使用的文本编辑器。Git 需要你输入一些额外消息的时候,会自动调用一个外部文本编辑器给你用。默认会使用操作系统指定的默认编辑器,一般可能会是 Vi 或者 Vim。如果你有其他偏好,比如 Emacs 的话,可以重新设置:
git config --global core.editor emacs
5.3. 差异分析工具
还有一个比较常用的是,在解决合并冲突时使用哪种对比工具。
比如要改用 vimdiff 的话:
git config --global merge.tool vimdiff
Git 可以理解 kdiff3,tkdiff,meld,xxdiff,emerge,vimdiff,gvimdiff,ecmerge,和 opendiff 等合并工具的输出信息。当然,你也可以指定使用自己开发的工具;
5.4. 查看配置信息
要检查已有的配置信息,可以使用如下命令:
git config --list
有时候会看到重复的变量名,那就说明它们来自不同的配置文件(比如 /etc/gitconfig
和 ~/.gitconfig
),不过最终 Git 实际采用的是最后一个
也可以直接查阅某个环境变量的设定,只要把特定的名字跟在后面即可,像这样:
git config user.name
6. 基本操作
6.1. 获得Git仓库
有两种获得Git仓库的方法:
- 在现存的目录下创建新的Git仓库。
- 从已有的Git仓库克隆新的镜像仓库。
6.1.1. 在现存的目录下创建新的Git仓库
要对现有的某个项目开始用 Git 管理,只需到此项目的根目录,执行如下命令来创建并初始化Git仓库:
git init
初始化后,在当前目录下会出现一个名为 .git
的目录,Git 仓库的所有信息都包含在该目录中。
6.1.2. 从已有的仓库克隆
如果Git仓库已经存了,那我们可以通过如下命令将该仓库克隆到本机上:
命令格式:
git clone [url]
示例:
git clone https://gitee.com/guobinyong/GitTest.git
注意:如果克隆的是私有仓库,可能会弹出对话框让输入的用户名和密码,输入被克隆的仓库的用户名和密码即可
这会在当前目录下创建一个名为 GitTest 的目录,其中包含一个 .git
的目录,用于保存仓库的所有信息。
如果想指定克隆到本机的仓库的名字,可以使用如下命令格式:
git clone [url] [仓库名字]
示例:
git clone https://gitee.com/guobinyong/GitTest.git Test
6.2. 基本概念
我们先来理解下Git 工作区、暂存区和版本库概念
- 工作区:就是你在电脑里能看到的目录。
- 仓库:工作区有一个隐藏目录
.git
,它不属于工作区,而是Git的仓库。它里面存放着Git仓库的所有数据; - 暂存区:英文叫 stage 或 index ,一般存放在仓库(
.git
目录)下的index
文件(.git/index
)中,所以有时我们也会把暂存区也叫作索引(index)。 - 版本库:版本库是仓库中用来存放Git版本(提交记录)的地方,
下图展示了仓库、版本库、暂存区 和 工作区 之间的关系:
6.3. 提交版本
要把更改添加到版本库,需要两步:
- 用
git add
命令把更改添加到暂存区; - 用
git commit
命令将暂存区中的所有内容提交到 版本库,生成新的版本节点;
下面具体演示下操作步骤:
- 在项目目录下创建一个文件
file1.txt
,内容如下:
a
a
a
a
a
- 查看一下当前工作区的状态
git status
输出结果提示 file1.txt
未被跟踪;
- 使用如下命令将
file1.txt
文件添加到暂存区
git add file1.txt
若想一次添加所有的文件,可以使用以下方式之一:
-
git add .
: 添加新文件(new)和被修改(modified)文件,不包括被删除(deleted)文件;在Shell里,后面的.
代表当前目录, 所以相当于将当前目录传给了add
命令; -
git add *
:添加所有非隐藏的的文件的变化;*
是 shell 语言中的通配符,能匹配所有非隐藏的文件 和 目录,所以相当于将匹配的到文件和目录都传给了add
命令; -
git add -A
:添加所有变化; -
git add -u
: 添加被修改(modified)和 被删除(deleted)文件,不包括新文件(new);
再查看一下工作区的状态
file1.txt
未跟踪的信息已经没有了;但列出了一些将被提交的文件;
- 我们再次修改一下
file1.txt
的内容,将第3行换成b
,内容如下:
a
a
b
a
a
然后再查看一下工作区的状态:
又多了一条新提示,提示我们有一个 file1.txt
文件的修改没有被暂存;
- 再次添加变更
git add file1.txt
add
是个多功能命令,根据目标文件的状态不同,此命令的效果也不同:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等;
再查看一下工作区的状态
跟第一次执行 git add file1.txt
后的结果一样,这意味着 对同一个文件暂存多次变更,git 会合并多次变更,视为一个变更;
- 用如下命令将暂存区中的变更提交到版本库,并为这次提交创建一个新的版本;
git commit
这种方式会启动文本编辑器以便输入本次提交的说明,如下图。(默认会启用 shell 的环境变量 $EDITOR 所指定的软件,一般都是 vim 或 emacs。当然也可以使用 git config --global core.editor
命令设定你喜欢的编辑软件。)
另外也可以用 -m 参数后跟提交说明的方式,在一行命令中提交更新:
git commit -m “说明文字"
Git 提供了一个跳过使用暂存区域的方式,只要在提交的时候,给 git commit
加上 -a
选项 git commit -a
,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add
步骤:
git commit -a -m ‘文字说明'
提交完成后,输出的日志如下:
查看一下工作区的状态,如下:
以上这些步骤就演示了将变更从工作区添加到版本库的过程;
6.4. 查看提交历史
我们可通过 log
命令来查看提交的历史;
git log
以 ASCII 图形的方式查看提交历史
git log --graph
最近的更新排在最上面。每次更新都有一个 SHA-1 校验和、作者的名字和电子邮件地址、提交时间,最后缩进一个段落显示提交说明。
有时候图形化工具更容易展示历史提交的变化,随 Git 一同发布的 gitk 就是这样一种工具。它是用 Tcl/Tk 写成的,基本上相当于 git log 命令的可视化版本,凡是 git log 可以用的选项也都能用在 gitk 上。在项目工作目录中执行 gitk
命令后,就会启动图 2-2 所示的界面。
上半个窗口显示的是历次提交的分支祖先图谱,下半个窗口显示当前点选的提交对应的具体差异。
6.5. 推送数据到远程仓库
目前,我们新提交的所有数据都只是存放在本地的版本库(.git
目录)中,远程仓库中还没有这些数据;我们可以查看一下远程仓库中,确定下;
Git 跟 Subversion 不同, Subversion 中只要一提交,数据就会被推到远程仓库中了;造成这些区别的原因是 Git 是布式的版本控制系统,而 Subversion 是集中式的版本控制系统;
通过 push
命令,可把本地仓库中的数据推送到远程仓库:
git push
此时,可以查看一下远程仓库中,看是否已经包含了我们的新提交;
6.6. 拉取远程仓库中的更新
如果有其他人往远程远程仓库上推送了新的提交,我们可以执行以下命令来获取新的提交:
git pull
6.7. 忽略某些文件
有时候我们可能想忽略一些文件,比如:node_mode
、.idea
等等,但是,在执行 status
或 add
命令时,总是显示这些文件,甚至一不小心就提交了这些文件;这时我们可以在工作区根目录下创建一个名为 .gitignore
的文件,在该文件中列出要忽略的文件模式;这样,Git 就不会在跟踪和显示这些文件了;
文件 .gitignore 的格式规范如下:
- 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。
- 在一行的末尾添加注释,会使该行被Git忽略,所以注释只能独占一行,不能添加在行的末尾;
- 可以使用标准的 glob 模式匹配。
- 匹配模式最后跟反斜杠(/)说明要忽略的是目录。
- 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。
.gitignore 文件的例子:
# 此为注释 – 将被 Git 忽略
# 忽略所有 .a 结尾的文件
*.a
# 但 lib.a 除外
!lib.a
# 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
/TODO
# 忽略 build/ 目录下的所有文件
build/
# 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
7. 分支
与 Subversion 不同 Git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针,它总是指向最后一次的提交对象。在创建仓库时,Git 会自动创建一个名叫 master
的默认分支;
7.1. 查看分支
git branch
被 *
标记的分支是当前所在的分支;
7.2. 创建分支
创建一个名叫 dev 的分支
git branch dev
再查看一下分支
你会发现多了一个 dev 分支;但当前仍处在 master 分支下;也就是说,用 branch 创建新分支时,并不会自动切换到新分支上;
7.3. 切换分支
我们可以用如下命令切换分支:
git checkout dev
验证一下是否切换过去
7.4. 创建并切换分支
创建分支,再切换过去,需要两步,如果想一步完成,也是可以的,只需要用带 -b
选项的 checkout
命令即可:
git checkout -b bug
验证一下
发现,已经创建了一个 bug 分支,并且也已经切换到 bug 分支上了;
7.5. 分支共用工作区
- 在 bug 分支下新增一个
file2.txt
文件,内容如下:
b
b
b
b
b
- 将该文件添加到暂存区,并提交;
git add -A
git commit -m "版本2"
- 切换到 master 分支
git checkout master
再查看一下工作区里的内容
你会发现,刚才建的那个文件 file2.txt
没有了,因为 master 下没有 file2.txt
文件,file2.txt
在 bug 分支下;
这也说明:
- 分支 是共用 工作区的;
- 切换分支时,Git 会自动将工作区里的内容置为当前分支的内容;
7.6. 查看所有分支的提交历史
git log
命令默认只能查看指定分支的提交历史,可视化命令 gitk
也是,如果想查看所有分支的提交历史,可以给 git log
或者 gitk
添加 --all
选项;如下:
git log --all
可视化界面查看
gitk --all
git log --all
的输出结果如下:
其中 HEAD -> master
表示当前在 master 分支下,HEAD
表示当前工作区对应的哪个分支 或 提交;
从输出结果中可以看到 master 和 dev 分支还指向同一个提交,而 bug 分支 指向另一个提交;这是因为创建 dev 和 bug 分支时,是处在 master 分支下,创建的新分支会自动 和 当时所在分支 指向同一提交;所以 master 和 dev 分支还指向同一个提交,而后来 bug 分支里单独提交一个版本,所以 bug 分支指向了另一个提交;
7.7. 分支只是一个指针并且共享共同的历史
如果没做切换,当前还是在 master
分支;
- 接下来我们在 master 分支里更改一下
file1.txt
的内容,将 第3行 的内容改成a3
,如下:
a
a
a3
a
a
- 暂存并提交这次更改,这次我们使用一个快捷的命令
git commit -a -m "版本3"
添加 -a
选项可以自动暂存 所有已跟踪的文件(被修改(modified)和 被删除(deleted)文件,但不包括新文件(new)),并直接提交;
- 查看一下全部分支的提交历史
git log --graph --all --oneline
,其中--oneline
选项是将提交信息放在一行显示;
从输出结果中可以看到,master 分支指向了刚才提交的新版本 6dad279 版本3
,此时 master、dev、bug 分支都指向了不同的提交,但是,它们的版本历史中都有 2a40918 版本1
,这是它们共享的提交对象;
并且从结果中也可以看到:
整个仓库的提交历史只有一个,但仓库中可以有多个分支(如:master、dev、bug ),而每个分支都会指向一个提交;所以,在 Git 中,分支只是一个指针,对提交的一个引用,不同分支间可以有共同的提交历史;
7.8. 合并分支
为了给大家演示一下冲突,我们先制造一些冲突;
- 切换到 bug 分支
git checkout bug
; - 将
file1.txt
文件的第3行改成a4
,内容如下:
a
a
a4
a
a
- 暂存并提交改动
git commit -a -m "版本4"
; - 将 master 分支的变更合并到 当前分支(bug分支):
合并分支用merge
命令,如下:
git merge master
从输出中,我们可以看到,合并失败了,因为 file1.txt
文件冲突了;如果没有冲突,合并就自动完成,并会弹出文本编辑器让你输出此次合并的提交信息;
为什么 file1.txt
文件会冲突了呢?
因为 我们在 master 和 bug 分支下都改了第3行的内容,所以冲突了;
什么情况下才会冲突?
两个分支修改了同一文件的同一位置(简单来说,就是修改的内容有交叉)就会导致合并时产生冲突,如果修改的是不同文件 或者 是同一文件的不同位置,也不会导致冲突;
7.9. 查看冲突内容
我们可以使用如下命令查看冲突的内容
git diff
输出中显示出了冲突的文件file1.txt
,和冲突的内容,其中 <<<<<<<
之上 和 >>>>>>>
之下的内容是共同的内容,非冲突的内容; <<<<<<<
和 =======
之间是当前分支中冲突的内容, =======
和 >>>>>>>
之间是其它分支中冲突的内容;
我们也可以直接在编辑器中查看冲突的文件内容:
7.10. 解决冲突
由于语义的复杂性,Git 目前还不会帮我们自动解决冲突,我们需要自己来解决;
如果此时我们想终止合并,可以使用如下命令:
git merge --abort
如果我们要继续合并,需要先解决冲突,解决冲突的方法如下:
- 根据需要决定如何保留和更改冲突的内容;
- 移除冲突的标记文行
<<<<<<<
、=======
、>>>>>>>
; - 使用
add
命令将冲突标记为已解决git add file1.txt
或者 直接标识所有git add .
- 提交变更
git commit
;
这会弹出文本编辑器让你输出此次合并的提交信息,里面默认有表达合并的操作的提交信息,使用默认的即可;
当冲突解决了并提交后,合并操作也就完成了;此时查看一下整个仓库的版本历史:
git log --all --graph
从输出结果中可以看到,合并会产生一个新的提交对象 ebb0d5b95a3e30127379a862de42ad96812d0720
,并且分支当前分支(bug分支)已经指向了这个新的合并对象;但 master 分支仍然指向的是原来的提交对象 9e32b1556d3259e9193b19942ef76756c7e6afd3 版本3
,因为我们是将 master 分支的内容 合并到 当前分支(bug分支),合并改变的是当前分支,并不会影响 master 分支;
7.11. 删除分支
如果我们想删除一个分支(比如 dev 分支),我们可以使用如下命令:
git branch -d dev
8. 获取帮助
想了解 Git 的各式工具该怎么用,可以阅读它们的使用帮助,方法有三:
$ git help [命令]
$ git [命令] --help
$ man git
比如,要学习 config 命令可以怎么用,运行:
$ git help config
帮助文档采用BNF语法格式描述规范描述命令行的语法,BNF语法格式的元字符及其含义如下:
[ ]
:可选内容;
< >
:必须给出内容;
{ }
:可重复0至无数次的内容;
a|b|c
:多选一;
…
:可以有多个;
备注:关于BNF的详细内容可参考《语法格式描述规范BNF和ABNF》
9. Git和Subversion的命令的对比
详情请看Git和Subversion的命令的对比
10. 相关文章
- Git并行工作流程规范
- Git基础教程
- Git命令大全
- Git技巧和问题解决方案
- Git中合并多个提交的各种方法
- Git并行工作流程规范设计记录
- 弃用SVN选择Git的理由
- Git和Subversion的命令的对比
- 分布式和集中式版本控制系统的区别
- Git的存储机制