必备技能——Git

76 阅读13分钟

为什么学Git

在现在的真实企业开发中,项目一般是由很多程序员一起协同开发的,而协同开发所使用的工具一般就是Git。使用Git进行协同开发有很多好处:代码备份代码还原协同开发追责透明等。并且大部分开源项目都是通过Git进行管理的,学习Git还可以参与一些开源项目的维护。总而言之,Git操作是程序员必备的技能!

Git是什么

版本控制

代码的每一次修改(提交)都定义一个版本。通过控制版本从而管理代码。

集中式版本控制

集中式版本控制工具,版本库是集中存放在中央服务器的,开发人员需要开发时,从中央服务器下载代码,修改代码后提交到中央版本库,此时就在中央版本库中产生了一个新的版本。这个过程是需要联网的。集中版本控制存在一些问题:

依赖网络连接:开发人员必须时刻保持与中央服务器的连接才能进行提交、更新等操作。一旦网络出现问题,就无法继续工作或同步最新的代码变更。

单点故障风险:所有的版本都在中央服务器中,假如该服务器出现故障,可能会导致版本信息损坏或者丢失

性能问题:假如项目扩大,频繁从中央服务器获取最新版本代码或者推送更改都会导致性能下降,影响效率

代表性的集中式版本控制工具是SVNCVS,但这两个工具早已过时。

分布式版本控制

分布式版本控制系统没有“中央服务器”,每个人的电脑都是一个完整的版本库,这样工作时就无需联网了,版本库就在本地电脑上。多人协作只需要将各自的修改推送给对方,就可以互相看到对方的修改了。(但是这种方式使用较少,还是通过共享版本库进行的协作开发。

Git是一个分布式版本控制工具,也是最具代表性、应用最广泛的分布式版本控制工具,开发者是Linux系统开发团队,此处不做过多介绍。

Git工作流程

image.png

clone(克隆):从远程仓库中克隆代码到本地仓库

checkout(检出):从本地仓库中检出一个仓库分支然后进行修订(切换使用的分支)。

add(添加):从工作区提交代码到本地仓库时,先将代码提交到暂存区(Index)

commit(提交):从暂存区提交代码到本地仓库。本地仓库中也可以保存修改的各个历史版本。

fetch(抓取):从远程仓库抓取代码到本地仓库,不会进行任何版本合并,使用较少(一般是直接使用pull)

pull(拉取):从远程仓库直接将代码拉取到本地仓库,并进行自动合并(merge),然后将其放在工作区(虽然pull操作可以直接将代码放在工作区,但并非是直接到工作区的)。

push(推送):修改完成之后,需要和团队成员共享代码,需要将代码推送到远程仓库,然后团队其他开发者可以从远程仓库中pull最新的代码,从而协作开发。

这些差不多就是在实际开发中Git的工作流程了,下面会详细介绍Git的使用。

GitBash操作Git

Windows系统的电脑一般是使用GitBash操作Git的,所以说本文也是根据GitBash进行讲解的。GitBash就像一个小的Linux操作系统,可以理解为一个用来操作Git的Linux,在使用GitBash的时候会用到部分Linux操作命令

准备工作

下载安装本文就不讲解了,可以去这个地址下载:Git - Downloads建议选择默认安装。安装成功后单击鼠标右键就可以看到:

image.png

说明安装Git成功,然后点击Open Git Bash here,就可以打开GitBash进行git操作。

基本配置

用户信息

安装好Git之后,首先需要做的事情是设置用户名和Email地址,这是非常重要的,每次Git提交都会使用到该用户信息,这也是为什么Git能够方便追责的原因。需要在GitBash中输入:

git config --global user.name “your username”

git config --global user.email “your email”

25b32d3be307d84e1452cd1799c3986.png

如图所示,成功配置了用户名和Email地址,可以通过以下命令查看配置的结果:

git config --global user.name 

git config --global user.email

为常用指令配置别名

上文提到,使用GitBash和Linux有很多相通之处。在GitBash中有很多常用指令,这些指令有很多参数,每次使用这些指令都需要输入大量参数,这是很麻烦的,所以说可以使用别名

1.在Windows的用户目录中创建.bashrc文件,推荐在GitBash中使用touch命令创建:

image.png

2.在.bashrc文件中输入以下内容

#用于输出git提交日志 
alias git-log='git log --pretty=oneline --all --graph --abbrev-commit' 
#用于输出当前目录所有文件及基本信息 
alias ll='ls -al'

3.添加到环境变量中:打开GitBash,执行source ~/.bashrc命令。

image.png

GitBash还可以配置一些其他设置,此处就不做扩展。

获取本地仓库

要使用Git对我们的代码进行版本控制,首先需要获得本地仓库。可以在电脑中的任意位置创建一个空目录作为Git的本地仓库(建议是空目录,不是空目录也可以);然后在GitBash中执行命令git init,这个命令就是将这个目录初始化为一个git本地仓库,执行成功后就可以在本地看到隐藏的.git目录,这就是git本地仓库:

image.png

Git本地操作

Git在本地操作的过程如图所示:

image.png

当前的目录就是工作区,当我们在工作区中新建一个文件时,该文件就属于untracked(未跟踪)状态。此时Git知道有这个文件的存在,但是并未对其进行版本管理

image.png

如图所示,使用git status命令查询文件修改的状态,可以看见新建的file01.txt文件处于Untracked状态,此时我们可以通过git add命令将其添加到暂存区:

image.png

在实际开发中,我们一般会将工作区中所有文件都提交到本地仓库交给Git管理(无需Git管理的文件可以在.gitignore文件中列出),所以说可以直接使用git add .通配符进行添加。

在暂存区中的文件可以使用git commit命令将其提交到本地仓库,-m选项可以为其添加注释(不使用该选项也会让你输入注释的):

image.png

提交后我们可以使用git-log(这是刚才在.bashrc中配置的别名)查看提交记录:

image.png

可见我们成功将file01.txt文件提交到了master分支中(分支下文会讲解),成功将file01.txt文件交给了Git进行管理。

当我们对一个已经跟踪后的文件修改,那么该文件就会变成unstaged(未暂存)状态,此时仍然需要我们使用git add将其添加到暂存区:

此时修改file01的内容:

image.png

该文件已经是跟踪后,所以说此时是未暂存状态:

image.png

使用git add将其加入暂存区:

image.png

发现file01此时已经是待提交状态了,表明已经暂存了。(那个警告的内容是因为我在Windows系统上使用了vi编辑器,目前阶段可以忽略这个问题)。

此时我们再次使用git commit将其提交到本地仓库:

image.png

发现提交日志中,已经有了两个版本了(一个是commit,一个是update),说明Git可以帮助我们管理不同版本!,既然Git可以帮助我们管理版本,我们自然可以使用版本回退进行版本切换。通过git reset --hard commitID可以将版本切换到对应的commitID的那个版本commitID就是git-log提交日志的前面那一串哈希值):

image.png

image.png

此时file01.txt被切换到了修改前,里面是没有内容的,说明我们通过Git切换版本成功。

我们也可以通过版本切换将版本切换到修改后,首先需要通过git-log查询修改操作那一次的commitID,但是我们再次查询提交日志,发现更新操作的那一次提交也无法查询到了:

image.png

无法知道commitID,自然也就无法切换版本了,但是可以使用git reflog指令,查看到已经删除的提交记录:

image.png

通过git reflog指令,我们查询到update操作的commitID是409a4ff,所以说我们就可以根据这个ID,将版本切换到update之后了:

image.png

image.png

如图所示,版本切换成功,可见Git的能力超乎想象!

.gitignore文件

我们总会有些文件无需纳入Git的管理,也不希望它们总出现在未跟踪文件列表。通常这些文件都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以在工作目录中创建一个名为.gitignore的文件(文件名称固定,必须是.gitignore,否则无效),列出要忽略的文件模式。下面是一个示例:

# no .a files 
*.a 
# but do track lib.a, even though you're ignoring .a files above
!lib.a 
# only ignore the TODO file in the current directory, not subdir/TODO
/TODO 
# ignore all files in the build/ directory 
build/ 
# ignore doc/notes.txt, but not doc/server/arch.txt 
doc/*.txt 
# ignore all .pdf files in the doc/ directory 
doc/**/*.pdf

.gitignore文件内容相对固定,忽略的内容也基本一致,一般都是提供好的。

分支

几乎所有的版本控制系统都以某种形式支持分支 使用分支意味着我们可以将个人的工作从开发主线上分离,比如从开发主线中分离Bug修改新功能开发等,可以不影响开发主线。分支是Git中相当重要的内容!

查看本地分支

使用git branch命令查看本地分支:

image.png

当前本地只有master分支,master分支是主分支。

创建本地分支

使用git branch 分支名可以创建一个新的本地分支:

image.png

切换分支

使用git checkout 分支名可以切换当前使用的分支:

image.png

成功从master主分支切换到了刚才创建的develop01分支(命令行括号中显示的就是当前分支)。

还可以使用git checkout -b 分支名创建一个不存在的分支(相当于创建一个新分支):

image.png

合并分支

在一个分支上的提交可以合并到另一个分支,这就是Git可以协作开发的最重要的原因,在当前分支中使用git merge 需要合并的分支就可以将该分支合并到当前分支上:

在develop01分支上修改file01.txt内容

image.png

提交更改:

image.png

如图所示,还未更改的develop02分支和master主分支还处于上一个版本;而更改后的develop01分支已经领先于它们一个版本(在提交日志中的版本越靠前越领先),此时我们切换到master分支,将develop01分支合并上来:

image.png

image.png

如图所示,成功将develop01分支合并到了master上。

(此处触发了Fast-forward快速合并机制:Fast-forward 是 Git 在合并分支时采用的一种简化方式,当目标分支(通常是 mainmaster)是源分支(例如 feature-branch)的直接祖先时发生。在这种情况下,Git 不需要创建一个新的合并提交,而是简单地将目标分支的指针向前移动到源分支的最新提交位置。)

删除分支

删除分支时,不能删除当前正在使用的分支,只能删除未使用的其他分支git branch -d 分支名,当删除分支时,需要进行各种检查(比如说当前分支还没有合并,就会删除失败);git branch -D 分支名,删除时不做任何检查,强制删除:

当前使用develop02分支,则无法删除

image.png

使用git branch -D强制删除也无法删除

image.png

只能删除未使用的分支

image.png

Git本地冲突

当多分支对文件进行修改时,可能会存在冲突,最常见于两个分支同时修改了同一个文件的同一个位置,此时就需要手动解决冲突:

master分支修改file01

image.png

image.png

develop01分支也修改file01的同一处位置

image.png

image.png

此时将develop01分支合并到master分支上:

image.png

如图所示:合并失败,出现了合并冲突,此时需要我们手动去解决冲突。解决冲突的方式非常简单,我们只需要将冲突的文件修改为希望合并的样子

因为有合并冲突,所以说file01文件中的内容是这样,此时我们只需要将其修改为我们希望合并后的样子即可解决冲突:

image.png

image.png

再次提交之后即可完成合并:

image.png

image.png

这样我们就解决了本地冲突。解决本地冲突的步骤可以概括为:出现冲突后,需要修改冲突文件的内容,将其修改为希望合并后的样子;修改完成后使用git addgit commit可以完成合并,成功处理冲突。

分支使用原则与流程

分支在开发中使用十分广泛,一般有以下使用原则与流程

mater(生产)分支

master分支是线上分支、主分支;还是一些中小规模的项目作为线上运行时的分支。在开发中,我们一般不会直接操作主分支

develop(开发)分支

develop分支是开发分支,是从master分支中创建的分支。一般作为开发部门的主要开发分支,如果没有其他并行开发不同期上线要求,都可以在此版本进行开发,阶段开发完成后,需要是合并到master分支,准备上线

feature分支

feature分支是develop分支中创建的分支,一般是同期并行开发,但不同期上线时创建的分支,分支上的研发任务完成后合并到develop分支

hotfix分支

hotfix分支是master分支中派生的分支,一般是作为线上修复bug使用的分支,将bug修复完成后,将该分支合并到mastertestdevelop分支。

还有一些其他分支,在此不再详述,例如test分支(用于代码测试)pre分支(预上线分支)等。

总结

从上文可以看出,Git是一个极其强大的分布式版本管理工具,其性能强悍、功能完善。本文主要是介绍了Git的本地仓库,但是Git是存在两种类型的仓库的——本地仓库远程仓库。我们可以通过互联网中一些代码托管平台来实现,这能更好的帮助我们协作开发