身为一名程序员,我们除了自己单人开发项目,更多的情况需要多人协同开发。如果你使用硬盘拷贝或者发送压缩包之类的方式(虽然我们公司常用),那肯定是不如 版本控制系统
来的安全与高效。不考虑硬盘丢失或文件损坏等意外情况,拷贝的代码合并就很令人头疼,本文就来带大家快速上手 分布式版本控制系统Git
。
集中式版本控制系统的版本库是集中存放在“中央服务器”的,所有操作都需要联网,局域网或互联网。比如你修改了某个bug,但是你的电脑无法联网或者“中央服务器”宕机了,此时你就无法提交到“中央服务器”,就会影响到你 版本管理
。代表工具:SVN
。
分布式版本控制是没有“中央服务器”的,每一台电脑都有完整的版本库,你可以在本地分支上提交代码、合并分支、解决冲突等操作。多人协作时只需要把各自的修改推送给对方,就能看到对方的操作记录了。代表工具:Git
。
Git是一个 开源的分布式版本控制系统
,可以有效、高速地处理从很小到非常大的项目版本管理。也是 Linus Torvalds
为了帮助管理 Linux
内核开发而开发的一个开放源码的版本控制软件。先看下面的示意图:
Git有本地仓库和远程仓库,它们俩都有完整的版本库,远程仓库的作用是方便开发人员之间代码的推送与拉取。
- clone(克隆):从远程仓库中克隆代码到本地仓库
- checkout(检出):从本地仓库中检出一个仓库分支然后进行修订
- add(添加):在提交前先将代码保存到暂存区
- commit(提交):提交到本地仓库
- fetch(抓取):从远程仓库更新版本库到本地仓库,不进行合并
- pull(拉取):从远程仓库更新版本库到本地仓库,并自动进行合并
- push(推送):将本地仓库的修改内容推送到远程仓库
官网:Git官网
当前最新版是2.37.3,下载后运行程序,全部默认即可。安装完成后,在桌面或任何文件夹内右键,出现下面两个则表示成功:
Git GUI:Git提供的图形界面工具
Git Bash:Git提供的命令行工具
本文只介绍 Git Bash
中的命令,了解了命令后界面工具也很容易上手。
安装完成后首先 必须
要设置用户信息,因为Git每次提交版本时都会使用该用户
git config --global user.name '你的用户名'
git config --global user.email '你的邮箱'
git config --global user.name
git config --global user.email
命令形式:
git init
新建一个文件夹 git_test
,进入目录后打开 Git Bash
,输入上述命令,出现以下内容则表示初始化成功
此时在目录中会生成一个隐藏的 .git
文件夹,里面就是你的版本库信息,含 .git
文件夹的目录称为 工作目录
。
在工作目录中所有文件都有状态,新建文件是未跟踪(untracked),修改已有文件是未暂存(unstaged),添加到暂存区是已暂存(staged),提交到仓库是已提交(committed)。
命令形式:
git status
输入以上命令,可以查看仓库当前状态
命令行提示说:在master分支上没有任何内容可以提交(创建或复制文件,然后使用“git add”命令来跟踪)
命令形式:
git add 文件名|通配符
上述命令可以将工作区一个或多个文件添加到暂存区
添加单个文件:git add 文件名或目录名
添加所有修改的文件:git add .
举例说明:
在我们的工作目录 git_test
中新建一个txt文件叫file01(可以鼠标右键新建,也可以使用命令 touch file01.txt
),此时再执行 git status
命令会得到另一种提示:
命令行提示说:file01.txt是未被跟踪的文件,使用“git add 文件名
”来包含要提交的内容 。
那我们这里就执行 git add file01.txt
命令,然后再执行 git status
命令,可以发现它的状态发生了改变:
命令行提示:file01.txt文件等待提交,使用“git rm --cached ” 可以退回未暂存状态。
上面的操作是新增一个文件,如果修改已提交的文件,则会更改状态为未暂存(unstaged)。假设你已完成 5.1.4 提交到仓库 的操作,然后修改 file01.txt
内容,添加 count=1
,然后再执行 git status
命令:
命令行提示:你的修改还没有暂存,不能提交!可以使用"git add "来更新要提交的内容,或者使用“git restore ”来丢弃工作目录中的更改。
那我们这里可以执行 git add file01.txt
或者 git add .
命令,然后再执行 git status
命令,可以发现它的状态发生了改变:
可以看到修改后的 file01.txt
文件被成功添加
命令形式:
git commit[ -m "注释内容"]
通过该命令可以将已暂存的文件提交到本地仓库,[]
中的部分表示可选,推荐必填
。因为 注释内容
本身是必须的,如果在此处不填,下一步会打开其他编辑器(比如vim编辑器或其他)让你填写。
此时再执行 git status
查看状态
可以看到已经成功提交了,之前的 No commits yet
也消失了。注意:提交步骤需要先添加到暂存区再提交
,下文说的提交到仓库指的这连续两步。
命令形式:
git log[option]
选项:
通过该命令可以查看仓库的所以操作记录
此处 commit
后面的一长串字符串是版本号(commitID),后面括号内的 HEAD
表示 当前所在分支
,这里的意思是当前分支是master分支。Author表示作者,Date则表示提交时间,add file01就是我们填写的 提交信息
。
我们可以把上面几个常用选项全部加上,同时输出不加选项的日志进行比较:
commitID缩短了,用户信息和日期被省略了,只留下了关键的分支和注释,这样我们看日志会更加清楚明了。同时,缩略的commitID使用时效果是一样的,因为它是唯一的。
命令形式:
git reset --hard commitID
比如上面已经提交过两次,第一次新建file01文件,第二次在file01文件修改内容,所以有两次提交记录,执行上述命令后当前版本就会重置到第一次提交记录上
此时你在日志中已经查看不到第二次提交的记录了,那我们是否可以通过本条命令重置当前版本到第二次提交记录上?答案是可以的,我们可以通过上面第二次提交的commitID来执行命令。
可以看到日志中又出现了第二次提交的记录,但是如果我们清除了命令行工具的内容拿不到commitID,那还能重置回去吗?答案是可以的,这里需要使用另一条命令: git reflog
。这条命令可以理解为 显示所有引用日志
,它可以查看所有的版本操作记录,包含提交与重置,而 git log
只显示当前版本(HEAD指针
)及其之前的版本信息。
这里我们对比一下两条命令的输出,在 git log
下面只有两次的提交记录,而在 git reflog
下面有四条记录,从上到下是最新到最旧的记录,分别是:1. 重置到第二次提交,2. 重置到第一次提交,3. 提交更新文件file01.txt,4. 提交新建文件file01.txt。所以我们可以在这拿到想要的commitID。
我们新增了一个 file02.txt
文件,但是我们不想提交它,同时又希望使用 git add .
来一键全部提交,此时可以新建一个 .gitignore
文件,在里面写上 file02.txt
保存,下面我在保存前后分别执行 git status
查看了文件的状态
可以看到保存前未跟踪的文件里包含 file02.txt
文件,保存后则被忽略了。
有些命令加上选项会很长,但是又经常使用,比如 git log --oneline --graph
,此时我们可以给它配置别名。
.bashrc
文件.bashrc
文件。部分windows系统不支持创建点开头的文件,可以打开 Git Bash
执行 touch ~/.bashrc
。.bashrc
文件中输入以下内容alias git-log='git log --all --oneline --graph'
这样别名就设置成功了,我们可以执行 git-log
试试效果
发现确实和执行 git log --oneline --graph
是一样的,注意,.bashrc
的内容修改后 Git Bash
需要重启才会生效。
顾名思义,分支就是从主体上分出去的一部分。分支可以把开发环境和生产环境分离开来,避免开发影响到生产环境。最常用的分支有两个:master(生产)分支
和dev(开发)分支
。其他更细致的分支可以自行百度,这里举个例子, 比如leader让你开发一个新功能,应该在dev分支
上创建一个新的分支feature/xxx
,等到功能完成并且测试通过后先合并到dev分支
上,然后leader审核通过后再合并到master分支
上,这样可以在开发新功能的同时保证生产环境的稳定与安全。
命令形式:
git branch
初始化仓库时默认创建 master
分支,可以看到当前只有 master分支
,并且 当前所在分支
就是 master分支
(颜色标绿且前面带有星号)
命令形式:
git branch 分支名
可以看到已经成功创建了 dev分支
,但是 当前所在分支
还是 master分支
。
命令形式:
git checkout[ -b] 分支名
不加参数 -b
只能切换已创建的分支,添加参数 -b
可以在分支不存在时创建并切换。
一个分支上的提交可以合并到另一个分支。比如前面提到的,master作为 生产分支
,我们新增功能模块是不该在上面开发的,可以新建一个dev分支,开发完成后再合并到master分支。
命令形式:
git merge 分支名
举例说明:继续使用前面的例子,我们切换到 dev分支
然后创建一个file03.txt文件,按顺序执行 git add .
,git commit -m 'add file03'
,git-log
。
此时可以看到最新的版本记录,分支是dev(HEAD指针指向的就是当前分支),注释内容是 add file03
,正是我们刚刚提交的。然后切换回master分支
可以看到master分支的版本记录只到 update count=1
这一步,这时我们想把 dev分支
的改动合并到 master分支
上来,就可以执行 git merge dev
。注意,我们要合并到master分支那就要切换到master分支,不能在dev分支上执行,那就没有效果了。
可以看到,dev分支
上的改动已经成功合并到master分支
上。
命令形式:
git branch -d 分支名 // 通常情况使用
git branch -D 分支名 // 强制删除,在被删除分支比当前分支的版本更新时使用,比如dev比master多了一次提交,想要删除dev就必须使用该命令
当我们在两个分支上改动同一个文件,就会产生冲突。比如上面的例子,master
和dev
都有file01.txt
文件,内容都是 count=1
,我们切换到dev分支
,把内容改为 count=2
然后提交,再切换到master分支
,把内容改为 count=3
然后提交,然后我们把dev合并到master上,
此时命令行提示:自动合并file01.txt失败,需要解决冲突然后提交结果。我们可以使用记事本打开file01.txt:
两条分支都修改了同一个文件的同一行,合并时Git不知如何取舍,所以干脆交给执行合并命令的人处理。从HEAD到虚线的是当前分支的内容,从虚线到dev的就是dev分支的内容。解决冲突很简单也很暴力,那就是留下你需要提交的内容
,比如这里我要留下 count=3
那就删掉其他内容,
然后再重新提交一遍就行了
前面我们讲的都是本地仓库的操作命令,只有将远程仓库关联进来才是完整的Git工作流程
。那么我们如何搭建Git远程仓库呢?其实可以通过互联网上提供的一些代码托管服务来实现,比如Github,码云(Gitee)等等。Github因为某些原因需要科学上网,我们这边就选择码云。
码云是国内的一个代码托管平台,想要使用它的服务自然要先注册账号,注册流程直接略过。
在码云右上角有个加号,展开后点击【新建仓库】
然后填写仓库名称,系统会自动填充路径
其他都可以不用改动,然后立即创建
创建后的样子如上图所示
现在远程仓库已经创建好了,我们想要把本地仓库推送到远程仓库,远程仓库需要验证我们的身份,有两种方式,一种是输入Git的账号和密码,一种是SSH公钥,推荐使用第二种。
首先打开 Git Bash
执行以下命令来生成公钥:
ssh-keygen -t rsa
然后一直回车即可,如果公钥已经存在,则会自动覆盖。已经生成过的公钥,可以执行以下命令来查看:
cat ~/.ssh/id_rsa.pub
这样我们就拿到需要的公钥了,然后要把它填到哪呢?打开码云,展开右上角头像菜单
根据上图点击【设置】,然后左侧菜单栏点击【SSH公钥】,把拿到的公钥填到公钥一栏里
标题一栏有时会自动填充,你也可以随便改,点击确定就添加成功了。那么如何验证公钥生效了呢?打开 Git Bash
执行 ssh -T [email protected]
,出现以下内容则表示成功
注意:如果你是第一次访问它,会询问你是否继续访问,这里输入 yes 然后回车,然后就能看到上图的内容了。
命令形式:
git remote add 远端名称 仓库路径
我们打开码云上新建的仓库,从上面获取仓库的SSH地址
然后就能在 Git Bash
中执行命令
命令形式:
git remote
命令形式:
git push[ -u][ <远程主机名> <本地分支名>[:<远程分支名>]]
如果直接执行 git push
,会提示当前分支和远程分支没有关联,需要我们推送当前分支并绑定关联。
方法有两种,第一种是:
git push origin master
origin是通用的远程主机名,本地分支名和远程分支名相同时可省略,所以可以只有一个master。这种写法有一个弊端,就是每次都要写全。第二种方法是:
git push -u origin master
参数 -u
是 --set-upstream
的缩写,作用是将当前本地分支(即master)和远程分支(也叫master)建立关联,之后的推送可以直接执行 git push
。
此时就成功推送到了远程仓库,并且创建了master分支,origin/master
就是远程分支。我们打开码云上的仓库,可以看到文件全都推送成功了,历史提交的版本也都能查看。
我们也可以执行 git branch -vv
来查看本地分支和远程分支的关联关系,下图看到 master
后面跟着 origin/master
就说明关联成功了。
其他:git push
命令除了 -u
还有其他参数,此处不做展开,有兴趣的可以执行 git push -h
查看自行研究。
回滚远程仓库:git push
到远程仓库,正常推送会被拒绝,需要使用强制命令 git push -f
到远程仓库,完成回滚。
我们已经成功将本地仓库推送到远程仓库,假如我们的同事要协同开发,他就可以从远程仓库进行克隆。
命令形式:
git clone[ 远程仓库路径][ 本地目录名称]
远程仓库路径
就是仓库的url,可以使SSH或其他,如下图
这样就成功克隆了仓库。
本地目录名称
作用是修改本地项目名称
,如果不加,本地项目的目录名称就是远程仓库的名称。比如上面,远程仓库名是 git_test
,Cloning into 'git_test'
就表示在当前目录下创建了一个 git_test
目录,把远程仓库的内容克隆到该目录,我们可以加上 git_testf_01
,那么目录名就自动变了。
这里我们可以执行 ls
命令,它可以查看当前目录下所有文件
可以看到,确实是创建了 git_test_01
目录
抓取
命令形式:
git fetch[ <远程仓库名> [ <分支名>]]
提示:如果不指定远程仓库名和分支名,则抓取对应的分支。
继续使用上面的例子,在 git_test
目录下新增 file04.txt
文件并提交到仓库,然后推送到远程仓库。打开 git_test_01
目录,执行抓取命令
执行 git-log
可以看到最新的版本库是 origin/master
远程分支,但是本地 master
分支并不是最新版本库,因此需要执行 git merge origin/master
合并分支
此时本地 master
分支也是最新版本库了
拉取命令形式:
git pull[ <远程仓库名> [ <分支名>]]
提示:如果不指定远程仓库名和分支名,则抓取对应的分支。
抓取和拉取的区别就在于,抓取不会自动合并,而拉取会在抓取后执行合并。我们可以在 git_test
目录下新增 file05.txt
文件并提交到仓库,然后推送到远程仓库。打开 git_test_01
目录,执行拉取命令
可以看到,拉取成功后本地 master
分支就是最新版本库了。
**本地仓库更改后,在推送到远程仓库前,应该先执行抓取,再执行推送。**假如用户A修改了file01文件并且推送到了远程仓库,用户B也在本地修改了file01文件,此时他想推送到远程仓库就会失败。
提示说远程仓库有你本地没有的工作,建议你先集成远程仓库的更改。这就是先执行抓取的原因。我们执行抓取后(通常执行拉取,此处抓取是为了),输出日志查看。
远程更改了count为8,本地更改了count为9,此时执行合并分支
就会产生冲突。
如果觉得 抓取+合并
太麻烦,你也可以直接执行拉取(pull),效果是一样的。
图中HEAD表示本地,最后面的版本号表示远程。
出现冲突不用怕,解决冲突和前面本地仓库是一样的,就是把 需要提交的内容留下
,其余删除,然后提交到本地,再推送到远程。这里我们就把这段内容删除,留下count=10,然后提交。
这样我们就解决了冲突,最后一步就是把解决冲突后的文件推送到远程仓库。
远程仓库新增一条分支,本地可以通过 fetch
命令同步分支
git fetch
然后就能通过 checkout
命令切换到新的分支上
git checkout 分支名
到这里,Git的入门知识就讲完了,希望这篇文章能对入门的伙伴有一点帮助。