1. 初识 Git
1.1 Git 是什么?
Git 是一个开源的分布式版本控制系统,用于高效地跟踪和管理项目代码的变更历史(不仅仅是代码,还有其它格式也是可以的~)
1.2 为什么要有 Git
在学习或者是工作的时候,比如编写各种文档,为了防止文档丢失,更改失误,我们不得不复制出一个副本,保留历史记录,方便找回历史记录,比如:
“设计文档-v1”
“设计文档-v2”
“设计文档-v3”
“设计文档-确定版”
“设计文档-最终版”
每个版本有各自的内容,但最终会只有⼀份文档是需要被使用的,在此之前的⼯作都需要这些不同版本的报告,于是每次都是复制粘贴副本,文件就越来越多,不仅文件多,更重要的是,随着版本数量的不断增多,我们可能记不太清每一个版本具体修改的哪些内容,文档如此,我们编写的项目代码也如此!
那么,如何解决呢?
答:版本控制器 ,记录每次修改以及版本迭代的一个管理系统,目前,最主流的版本控制器就是 Git,可以控制电脑上所有格式的文件
为了能够更方便管理这些不同版本的⽂件,便有了版本控制器! 所谓的版本控制器,就是能让你了解到⼀个文件的历史,以及它的发展过程的系统。通俗的讲就是⼀个可以记录⼯程的每⼀次改动和版本迭代的⼀个管理系统,同时也方便多人协同作业,目前最主流的版本控制器就是 Git,Git 可以控制电脑上所有格式的文件,例如doc、excel、dwg、dgn、rvt等等,对于我们开发⼈员来说,Git 最重要的就是可以帮助我们管理软件开发项目中的源代码文件!
【注意事项】
所有的版本控制系统,Git也不例外,其实只能跟踪文本文件的改动,比如 txt文件,网页,所有的程序代码等等,版本控制系统可以告诉你每次的改动,比如在第10行加了"name",在第12行删除了一个"Windows",而图片、视频等这些二进制文件,虽然也能由版本控制系统管理,但没办法跟踪文件的变化,只能把⼆进制文件每次改动串起来,即只知道图片从90KB改成了100KB,但到底改了啥,版本控制系统无法记录,所有并不知道,也没法知道~
2. 安装 Git
接下来,我们来进行实操!安装 Git ~
Git 是开放源代码的代码托管工具,最早是在 Linux 下开发的,当然,最开始也只能应用于 Linux 平台,后面慢慢的被移植到 Windows下,现在 Git 可以在 Linux、Unix、Mac 和 Windows 这几大平台上正常运行了~
2.1 Linux-Ubuntu 安装 Git
这里介绍 Ubuntu 下的安装(因为 Centos 现在不维护了~,因此,本文不作过多介绍)
在 Ubuntu 安装 git 相当简单~ 一起来看看!
- 首先查看系统有没有安装过 Git,输入命令:
git --version
- 如果出现 git 版本号已经安装:
- 如果出现这类提示,则没安装
Command 'git' not found, but can be installed with:
sudo apt install git
- 没有则进行安装,输入安装命令:
sudo apt-get install git -y
(在安装过程中,出现了图形化界面,回车即可~)
再次输入git --version
,就可以看到 git 版本号啦!此时,安装完成!(是不是非常简单!)
2.2 Windows 安装 Git
Git 官网直接下载:Git 下载官网
- 选择 Windows 操作系统
- 根据自己的电脑选择相应的下载
下载完成后,找到下载到的文件,进行双击进行安装
-
接着,按照指示,一步步安装~
非常简单的~ 按照指示点下一步就好啦(勇敢牛牛,不怕困难!)
- 检测是否安装好 Git,打开 Git Bash
- 检测是否安装好 Git,打开 Git Bash
输入:git -- verison
,出现对应安装的 git 版本号,就是安装成功啦!!!
3. Git 初始化与配置
Git 的安装是很简单的,现在我们来看看 Git 的初始化与配置~
3.1 创建 Git 本地仓库
可以将仓库理解成是进行版本控制的一个文件目录,如果我们想要对文件进行版本控制,就必须先创建一个仓库出来!
创建⼀个 Git 本地仓库对应的命令为 git init
,注意命令要在文件目录下执行,例如:
3.2 配置 Git
当安装 Git 后首先要做的事情就是设置你的用户名称和 e-mail 地址,这是非常非常重要的,配置命令为:
git config [--global] user.name "Your Name"
git config [--global] user.email "email@example.com" # 把 Your Name 改成你的用户名
# 把 email@example.com 改成你的邮箱的格式,只要格式正确即可
注意 --global
是⼀个可选项,如果使用了该选项,就表示这台机器上所有的 Git 仓库都会使用这个配置,如果你希望在不同仓库中使用不同的 name 或 e-mail ,即可以不要 --global
选项,但需要注意的是,执行命令时必须要在仓库里面~
查看配置命令为:
git config -l
删除对应的配置命令为:
git config [--global] --unset user.name
git config [--global] --unset user.email
4. Git 工作流程 - 认识工作区、暂存区、版本库
-
工作区:是在电脑上要写的代码或者是文件的目录
-
暂存区(stage/index):一般存放在 .git 目录下的 index 文件(.git/index)中,把暂存区有时也叫作索引(index)
-
版本库(repository):也叫仓库,工作区有⼀个隐藏目录 .git ,它不算工作区,而是 Git 的版本库,这个版本库里面的所有文件都可以被 Git管理起来,每个文件的修改、删除,Git 都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以"还原"
- 左侧为工作区,右侧为版本库,Git 的版本库里存放了很多东西,其中最重要的是暂存区
- 在创建版本库的时候, Git 会自动为我们自动创建一个唯一的 master 的分支,以及指向 master 的一个指针 HEAD (分支与HAED后续介绍)
- 当对工作区修改或者是新增的文件,执行
git add
命令,暂存区目录树的文件索引会被更新 - 当执行提交操作
git commit
时,master 分支会做相应的更新,可以简单理解为暂存区的目录树才会被真正写到版本库中
由上述描述我们便能得知:通过新建或粘贴进⽬录的⽂件,并不能称之为向仓库中新增⽂件,⽽只是在⼯作区新增了⽂件。必须要通过使⽤ git add 和 git commit 命令才能将⽂件添加到仓库中进⾏管理!!!
添加文件
在包含 .git 的⽬录下新建⼀个 ReadMe ⽂件,我们可以使⽤ git add 命令可以将⽂件添加到暂存
区:
• 添加⼀个或多个⽂件到暂存区: git add [file1] [file2] ...
• 添加指定⽬录到暂存区,包括⼦⽬录: git add [dir]
• 添加当前⽬录下的所有⽂件改动到暂存区: git add .
再使⽤ git commit 命令将暂存区内容添加到本地仓库中:
• 提交暂存区全部内容到本地仓库中: git commit -m "message"
• 提交暂存区的指定⽂件到仓库区: git commit [file1] [file2] ... -m "message"
注意 :git commit 后⾯的 -m 选项,要跟上描述本次提交的 message,由⽤⼾⾃⼰完成,这部分内容绝对不能省略,并要好好描述,是⽤来记录你的提交细节,是给我们⼈看的。
例如:
我们还可以多次 add 不同的⽂件,⽽只 commit ⼀次便可以提交所有⽂件,是因为需要提交的⽂件是通通被 add 到暂存区中,然后⼀次性 commit 暂存区的所有修改.如:
Git 工作流程:
- 工作区:开发者实际编辑代码的目录
- 暂存区:通过
git add
将修改添加到暂存区,准备提交 - 本地仓库(Local Repository):通过
git commit
将暂存区的修改保存到本地仓库,生成一个提交记录(上述介绍的是本地仓库) - 远程仓库(Remote Repository):通过
git push
将本地提交推送到远程仓库,如Gitee、GitHub(后续介绍如何连远程仓库)
截⾄⽬前为⽌,我们已经更够将代码直接提交⾄本地仓库了。我们可以使⽤ git log 命令,来查看
下历史提交记录:
该命令显⽰从最近到最远的提交⽇志,并且可以看到我们 commit 时的⽇志消息。
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上 --pretty=oneline 参数:
需要说明的是,我们看到的⼀⼤串类似 5a250e...2111e0 的是每次提交的 commit id (版本
号),Git 的 commit id 不是1,2,3……递增的数字,⽽是⼀个 SHA1 计算出来的⼀个⾮常⼤的数字,⽤⼗六进制表示.
查看.git 文件
先来看看我们的 .git 的⽬录结构:
1.index 就是我们的暂存区,add 后的内容都是添加到这⾥的。
2.HEAD 就是我们的默认指向 master 分⽀的指针。
⽽默认的 master 分⽀,其实就是:
打印的 5a250e9e1895753939dfcf9cba0719ee6d2111e0是什么东西呢?保存的就是当前最新
的 commit id 。
3. objects 为 Git 的对象库,⾥⾯包含了创建的各种版本库对象及内容。当执⾏ git add 命令
时,暂存区的⽬录树被更新,同时⼯作区修改(或新增)的⽂件内容被写⼊到对象库中的⼀个新的
对象中,就位于 ".git/objects" ⽬录下,让我们来看看这些对象有何⽤处:
查找 object 时要将 commit id 分成2部分,其前2位是⽂件夹名称,后38位是⽂件名称。
找到这个⽂件之后,⼀般不能直接看到⾥⾯是什么,该类⽂件是经过 sha (安全哈希算法)加密过的⽂件,好在我们可以使⽤ git cat-file 命令来查看版本库对象的内容:
其中,还有⼀⾏ tree c9b796e175c00c170f3e2b54ce4e2dd73cf43af9 ,我们使⽤同样的⽅
法,看看结果:
再看 ReadMe 对应的 a0423896973644771497bdc03eb99d5281615b51 :
总结⼀下,在本地的 git 仓库中,有⼏个⽂件或者⽬录很特殊
• index: 暂存区, git add 后会更新该内容。
• HEAD: 默认指向 master 分⽀的⼀个指针。
• refs/heads/master: ⽂件⾥保存当前 master 分⽀的最新 commit id 。
• objects: 包含了创建的各种版本库对象及内容,可以简单理解为放了 git 维护的所有修改。
修改文件
Git ⽐其他版本控制系统设计得优秀,因为 Git 跟踪并管理的是修改,⽽⾮⽂件。
什么是修改?⽐如你新增了⼀⾏,这就是⼀个修改,删除了⼀⾏,也是⼀个修改,更改了某些字符,也是⼀个修改,删了⼀些⼜加了⼀些,也是⼀个修改,甚⾄创建⼀个新⽂件,也算⼀个修改。
让我们将 ReadMe ⽂件进⾏⼀次修改:
此时,仓库中的 ReadMe 和我们⼯作区的 ReadMe 是不同的,如何查看当前仓库的状态呢? git
status 命令⽤于查看在你上次提交之后是否有对⽂件进⾏再次修改。
上⾯的结果告诉我们,ReadMe 被修改过了,但还没有完成添加与提交。
⽬前,我们只知道⽂件被修改了,如果能知道具体哪些地⽅被修改了,就更好了。有人会说,我刚改的我知道呀!可是,你还记得你三天前写了什么代码吗?或者没写?
git diff [file] 命令⽤来显⽰暂存区和⼯作区⽂件的差异,显⽰的格式正是Unix通⽤的diff格
式。也可以使⽤ git diff HEAD -- [file] 命令来查看版本库和⼯作区⽂件的区别。
知道了对 ReadMe 做了什么修改后,再把它提交到本地仓库就放⼼多了。
git add 之后,就没有看到上⾯ no changes added to commit (use "git add" and/or "git commit -a") 的消息了。接下来让我们继续 git commit 即可:
版本回退
执⾏ git reset 命令⽤于回退版本,可以指定退回某⼀次提交的版本。要解释⼀下“回退”本质是
要将版本库中的内容进⾏回退,⼯作区或暂存区是否回退由命令参数决定:
git reset 命令语法格式为: git reset [--soft | --mixed | --hard] [HEAD]
• HEAD 说明:
◦ 可直接写成 commit id,表⽰指定退回的版本
◦ HEAD 表⽰当前版本
◦ HEAD^ 上⼀个版本
◦ HEAD^^ 上上⼀个版本
◦ 以此类推...
• 可以使⽤ 〜数字表⽰:
◦ HEAD~0 表⽰当前版本
◦ HEAD~1 上⼀个版本
◦ HEAD^2 上上⼀个版本
◦ 以此类推...
值得说的是,Git 的版本回退速度⾮常快,因为 Git 在内部有个指向当前分⽀(此处是master)的
HEAD 指针, refs/heads/master ⽂件⾥保存当前 master 分⽀的最新 commit id 。当我们
在回退版本的时候,Git 仅仅是给 refs/heads/master 中存储⼀个特定的version,可以简单理解
成如下⽰意图:
【操作一】提交 version3 后,发现 version3 编写有误,想回退到 version2,重新基于 version2 开始写,这里希望工作区的内容也回退到 version2 版本,因此需要 --hard
参数,如下:
可以看到 Read 文件的内容,已经回退到 version2 了,使用 git log
查看提交⽇志,也发现 HEAD 指向了 version2
【操作二】后悔回退到 version2,想再回到 version3
可以继续使用 git reset 命令,回退到 version3 版本,but 我们必须要拿到 version3 的 commit id 去指定回退的版本,从上图中,看到 git log 并不能打印出 version3 的 commit id ,如果运气好的话,可以在终端找之前的记录,运气不好的话,commit id 已经被我们搞丢啦,不过不用担心!Git 还提供了⼀个 git reflog 命令,可以补救⼀下,该命令用来记录本地的每⼀次命令!!!
【操作三】在实际开发中,由于长时间开发,导致 commit id 早就找不到了,但是又想回到 version3,貌似现在不可能~
我们要知道 Git 版本回退速度非常快,因为 Git 在内部有个指向当前分支,这里是 HEAD 指针默认指向 master 分支,在.git 隐藏文件中refs/heads/master 文件里面保存了当前 master 分支的最新 commit id,当我们在回退版本的时候, Git 仅仅是给 refs/heads/master 中存储⼀个特定的 version,可以简单理解为下图:
可以查看 refs/heads/master 文件内容,保存了最新的 commit id,如下:
如果是操作二,回退到 version3 版本,则保存的 commit id 为 version3 的
撤销修改
情况⼀:对于⼯作区的代码,还没有 add
万幸!才写了一行内容,就发现需要删除了,万一写了很多,一直都没有提交,可能都忘记自己新增的哪些内容了,那如何删除呢?
Git 为我们提供了更好的方式!!!
我们可以使⽤ git checkout -- [file] 命令让⼯作区的
⽂件回到最近⼀次 add 或 commit 时的状态。 要注意 git checkout -- [file] 命令中的
-- 很重要,切记不要省略,⼀旦省略,该命令就变为其他意思了
情况⼆:已经 add ,但没有 commit
add 后还是保存到了暂存区呢?怎么撤销呢?
让我们来回忆⼀下学过的 git reset 回退命令,该命令如果使⽤ --mixed 参数,可以将暂存区
的内容退回为指定的版本内容,但⼯作区⽂件保持不变。那我们就可以回退下暂存区的内容了!!
我们可以讲版本回退到当前版本库版本
git reset --mixed HEAD File
git reset --hard HEAD File
情况三:已经 add ,并且也 commit 了
不要担⼼,我们可以 git reset --hard HEAD^ 回退到上⼀个版本!不过,这是有条件的,就是
你还没有把⾃⼰的本地版本库推送到远程。
删除本地仓库中的文件
在 Git 中,删除也是一个修改操作
下面演示删除 file4 文件:
使用 rm file4
?
这样直接删除是没有用的,此时只是删除了工作区的 file4,git status 会告诉你哪些文件被删除了,但是,这个时候,工作区和版本库就不一致了,要删除文件,除了要删除工作区的文件,还要清除版本库的文件
到这里,有两种情况:
【情况一】确实需要从版本库删除该文件
使用 git rm [文件名]
,将文件从工作区和暂存区中删除,并且 commit ~
【情况二】删错了
使用 git checkout -- file4
来恢复, 删除也是修改哦,这是刚刚学过的命令~
5.Git分支管理
在版本回退⾥,每次提交,Git都把它们串成⼀条时间线,这条时间线就可以理解为是⼀个分⽀。截⽌到⽬前,只有⼀条时间线,在Git⾥,这个分⽀叫主分⽀,即 master 分⽀。
再来理解⼀下HEAD,HEAD 严格来说不是指向提交,⽽是指向master,master才是指向提交的,所以,HEAD 指向的就是当前分⽀。
每次提交,master分⽀都会向前移动⼀步,这样,随着你不断提交,master分⽀的线也越来越⻓,⽽HEAD只要⼀直指向master分⽀即可指向当前分⽀。
通过查看当前的版本库,我们也能清晰的理出思路:
cat .git/HEAD
---》ref: refs/heads/master
cat .git/refs/heads/master
----》5476bdeb12510f7cd72ac4766db7988925ebd302
创建分支
Git ⽀持我们查看或创建其他分⽀,在这⾥我们来创建第⼀个⾃⼰的分⽀ dev ,对应的命令为:
git branch #查看当前本地所有分⽀
----》* master
git branch dev #新建分⽀dev
git branch
---》dev
---》* master
当我们创建新的分⽀后,Git 新建了⼀个指针叫 dev, * 表⽰当前 HEAD 指向的分⽀是 master 分
⽀。另外,可以通过⽬录结构发现,新的 dev 分⽀:
ls .git/refs/heads/
---》dev master
cat .git/refs/heads/*
-》5476bdeb12510f7cd72ac4766db7988925ebd302
-》5476bdeb12510f7cd72ac4766db7988925ebd302
发现⽬前 dev 和 master 指向同⼀个修改。并且也可以验证下 HEAD ⽬前是指向 master 的。
cat .git/HEAD
---》ref: refs/heads/master
切换分支
那如何切换到 dev 分⽀下进⾏开发呢?使⽤ git checkout 命令即可完成切换,⽰例如下:
git checkout dev
-》Switched to branch 'dev'
git branch
-》* dev
-》master
cat .git/HEAD
-》ref: refs/heads/dev
我们发现 HEAD 已经指向了 dev,就表⽰我们已经成功的切换到了 dev 上!
接下来,在 dev 分⽀下修改 ReadMe ⽂件,新增⼀⾏内容,并进⾏⼀次提交操作:
vim ReadMecat ReadMe
-》hello bit
-》write aaa for new branchgit add .git commit -m"modify ReadMe"
-》[dev 3740dce] modify ReadMe
-》1 file changed, 1 insertion(+)
现在,dev 分⽀的⼯作完成,我们就可以切换回 master 分⽀:
git checkout master
-》Switched to branch 'master'
cat ReadMe
-》hello bit
切换回 master 分⽀后,发现ReadMe⽂件中新增的内容不⻅了!!
但是在 dev 分⽀上,内容还在。为什么会出现这个现象呢?我们来看看 dev 分⽀和 master 分⽀指向,发现两者指向的提交是不⼀样的:
因为我们是在dev分⽀上提交的,⽽master分⽀此刻的提交点并没有变,此时的状态如图如下所示:
当切换到 master 分⽀之时,HEAD 就指向了 master,当然看不到提交了!
合并分支
为了在 master 主分⽀上能看到新的提交,就需要将 dev 分⽀合并到 master 分⽀,⽰例如下:
git branch
-》* dev
-》mastergit checkout master # 切换到 master 上进⾏合并
-》Switched to branch 'master'
git merge dev # 合并 dev 分⽀
-》Updating 16623e1..3740dce
-》Fast-forward
-》ReadMe | 1 +
-》1 file changed, 1 insertion(+)
cat ReadMe
-》hello bit
-》write aaa for new branch
git merge 命令⽤于合并指定分⽀到当前分⽀。合并后,master 就能看到 dev 分⽀提交的内容
了。此时的状态如图如下所⽰。
Fast-forward 代表“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度⾮常快。
当然,也不是每次合并都能 Fast-forward。
删除分支
合并完成后, dev 分⽀对于我们来说就没⽤了, 那么dev分⽀就可以被删除掉,注意如果当前正处于某分⽀下,就不能删除当前分⽀,如:
git branch
-》* dev
-》master
git branch -d dev
-》error: Cannot delete branch 'dev' checked out at '/home/hyb/gitcode'
⽽可以在其他分⽀下删除当前分⽀,如
git checkout master
Switched to branch 'master'
git branch -d dev
Deleted branch dev (was bdaf528).
因为创建、合并和删除分⽀⾮常快,所以Git⿎励你使⽤分⽀完成某个任务,合并后再删掉分⽀,这和直接在master分⽀上⼯作效果是⼀样的,但过程更安全.
合并冲突
可是,在实际分⽀合并的时候,并不是想合并就能合并成功的,有时候可能会遇到代码冲突的问题。为了演⽰这问题,创建⼀个新的分⽀ dev1 ,并切换⾄⽬标分⽀,我们可以使⽤ git checkout -
b dev1 ⼀步完成创建并切换的动作,⽰例如下
git checkout -b dev1
Switched to a new branch 'dev1'git branch
* dev1
master
在 dev1 分⽀下修改 ReadMe ⽂件,更改⽂件内容如下,并进⾏⼀次提交,如:
cat ReadMe
hello bit
write bbb for new branch # 将 aaa 该为 bbbgit add .git commit -m"modify ReadMe"
[dev1 0854245] modify ReadMe
1 file changed, 1 insertion(+), 1 deletion(-)
切换⾄ master 分⽀,观察 ReadMe ⽂件内容:
git checkout master
Switched to branch 'master'
cat ReadMe
hello bit
write aaa for new branch
我们发现,切回来之后,⽂件内容由变成了⽼的版本,这种现象很正常,我们现在也完全能理解。
此时在 master 分⽀上,我们对 ReadMe ⽂件再进⾏⼀次修改,并进⾏提交,如下:
[wmh@hcss-ecs-1036 gitcode]$ git branch
dev1
* master
[wmh@hcss-ecs-1036 gitcode]$ vim ReadMe
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
write ccc for new branch
[wmh@hcss-ecs-1036 gitcode]$ git add .
[wmh@hcss-ecs-1036 gitcode]$ git commit -m"modify ReadMe"
[master c10f6d0] modify ReadMe
1 file changed, 1 insertion(+), 1 deletion(-)
现在, master 分⽀和 dev1 分⽀各⾃都分别有新的提交,变成了这样:
这种情况下,Git 只能试图把各⾃的修改合并起来,但这种合并就可能会有冲突,如下所⽰:
[wmh@hcss-ecs-1036 gitcode]$ git merge dev1
Auto-merging ReadMe
CONFLICT (content): Merge conflict in ReadMe
Automatic merge failed; fix conflicts and then commit the result.
[wmh@hcss-ecs-1036 gitcode]$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: ReadMe
no changes added to commit (use "git add" and/or "git commit -a")
发现 ReadMe ⽂件有冲突后,可以直接查看⽂件内容,要说的是 Git 会⽤ <<<<<<<,=======,
>>>>>>> 来标记出不同分⽀的冲突内容,如下所⽰:
此时我们必须要⼿动调整冲突代码,并需要再次提交修正后的结果!!(再次提交很重要,切勿忘
记)
到这⾥冲突就解决完成,此时的状态变成了:
分支管理策略
通常合并分⽀时,如果可能,Git 会采⽤ Fast forward 模式。还记得如果我们采⽤ Fast
forward 模式之后,形成的合并结果是什么呢?
在这种 Fast forward 模式下,删除分⽀后,查看分⽀历史时,会丢掉分⽀信息,看不出来最新提
交到底是 merge 进来的还是正常提交的。
但在合并冲突部分,我们也看到通过解决冲突问题,会再进⾏⼀次新的提交,得到的最终状态为:
那么这就不是 Fast forward 模式了,这样的好处是,从分⽀历史上就可以看出分⽀信息。例如我
们现在已经删除了在合并冲突部分创建的 dev1 分⽀,但依旧能看到 master 其实是由其他分⽀合并得到
Git ⽀持我们强制禁⽤ Fast forward 模式,那么就会在 merge 时⽣成⼀个新的 commit ,这样,
从分⽀历史上就可以看出分⽀信息
git merge --no-ff -m "msg" branch_name
bug分支
假如我们现在正在 dev2 分⽀上进⾏开发,开发到⼀半,突然发现 master 分⽀上⾯有 bug,需要
解决。在Git中,每个 bug 都可以通过⼀个新的临时分⽀来修复,修复后,合并分⽀,然后将临时分⽀删除。
可现在 dev2 的代码在⼯作区中开发了⼀半,还⽆法提交,怎么办?
Git 提供了 git stash 命令,可以将当前的⼯作区信息进⾏储藏,被储藏的内容可以在将来某个时
间恢复出来。
[wmh@hcss-ecs-1036 gitcode]$ git stash
Saved working directory and index state WIP on dev2: 41b082f modify ReadMe
[wmh@hcss-ecs-1036 gitcode]$ git status
On branch dev2
nothing to commit, working tree clean
⽤ git status 查看⼯作区,就是⼲净的(除⾮有没有被 Git 管理的⽂件),因此可以放⼼地创建分
⽀来修复bug。
储藏 dev2 ⼯作区之后,由于我们要基于master分⽀修复 bug,所以需要切回 master 分⽀,再新
建临时分⽀来修复 bug,⽰例如下:
[wmh@hcss-ecs-1036 gitcode]$ git checkout master # 切回master
Switched to branch 'master'
[wmh@hcss-ecs-1036 gitcode]$ git checkout -b fix_bug # 新建并切换到 fix_bug 分⽀
Switched to a new branch 'fix_bug'
[wmh@hcss-ecs-1036 gitcode]$ vim ReadMe
[wmh@hcss-ecs-1036 gitcode]$ cat ReadMe
hello bit
write bbb for new branch
a,b,c,d,e # 修复bug--忘记写e
[wmh@hcss-ecs-1036 gitcode]$ git add ReadMe # 重新add,commit
[wmh@hcss-ecs-1036 gitcode]$ git commit -m"fix bug"
[fix_bug 4bbc0c4] fix bug
1 file changed, 1 insertion(+), 1 deletion(-)
修复完成后,切换到 master 分⽀,并完成合并,最后删除 fix_bug 分⽀。
⾄此,bug 的修复⼯作已经做完了,我们还要继续回到 dev2 分⽀进⾏开发。切换回 dev2 分⽀
[wmh@hcss-ecs-1036 gitcode]$ git checkout dev2
Switched to branch 'dev2'
[wmh@hcss-ecs-1036 gitcode]$ git status
On branch dev2
nothing to commit, working tree clean
⼯作区是⼲净的,刚才的⼯作现场存到哪去了?⽤ git stash list 命令看看
[wmh@hcss-ecs-1036 gitcode]$ git stash list
stash@{0}: WIP on dev2: 41b082f modify ReadMe
⼯作现场还在,Git 把 stash 内容存在某个地⽅了,但是需要恢复⼀下,如何恢复现场呢?我们可以使⽤ git stash pop 命令,恢复的同时会把 stash 也删了,⽰例如下:
[wmh@hcss-ecs-1036 gitcode]$ git stash pop
On branch dev2
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: ReadMe
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (4f873250b3503687b5efd26196776aee7e3724c2)
再次查看的时候,我们已经发现已经没有现场可以恢复了。
但我们注意到了,修复 bug 的内容,并没有在 dev2 上显⽰。此时的状态图为:
Master 分⽀⽬前最新的提交,是要领先于新建 dev2 时基于的 master 分⽀的提交的,所以我们
在 dev2 中当然看不⻅修复 bug 的相关代码。
我们的最终⽬的是要让 master 合并 dev2 分⽀的,那么正常情况下我们切回 master 分⽀直接合
并即可,但这样其实是有⼀定⻛险的。
是因为在合并分⽀时可能会有冲突,⽽代码冲突需要我们⼿动解决(在 master 上解决)。我们⽆法保证对于冲突问题可以正确地⼀次性解决掉,因为在实际的项⽬中,代码冲突不只⼀两⾏那么简单,有可能⼏⼗上百⾏,甚⾄更多,解决的过程中难免⼿误出错,导致错误的代码被合并到 master 上。 此时的状态为:
解决这个问题的⼀个好的建议就是:最好在⾃⼰的分⽀上合并下 master ,再让 master 去合并
dev ,这样做的⽬的是有冲突可以在本地分⽀解决并进⾏测试,⽽不影响 master 。此时的状态
为:.
6.Git远程操作
下面演示在gitee上创建远程仓库
创建远程仓库
上面的.gitignore是为了在上传时过滤掉不重要的文件,分支模型选单分支模型就够用了,或者选生产/开发模型。
当然,如果创建仓库的时候没有添加.gitignore文件,可以在本地仓库创建.gitignore文件
将远程仓库克隆到本地
下面仅介绍两种方式:HTTPS,SSH
SSH
然后查看是否有 id_rsa 和 id_rsa.pub这两个文件
如果没有的话,需要创建ssh.key
ssh-keygen -t rsa -C "your_email@example.com"
注意:上面的邮箱要和gitee上绑定的邮箱一致
如果有的话,打开看一下
将上面的内容全部复制下来,然后再打开gitee的设置
配置SSH公钥
三板斧
git add
git commit -m "XXX"
git push
当我们从远程仓库克隆后,实际上 Git 会⾃动把本地的 master 分⽀和远程的 master 分⽀对应起来,并且,远程仓库的默认名称是 origin 。在本地我们可以使⽤ git remote 命令,来查看远程库的
信息,如:
git remote
或者,⽤ git remote -v 显⽰更详细的信息:
git remote -v origin
提交时要注意,如果我们之前设置过全局的 name 和 e-mail,这两项配置需要和 gitee 上配置的用户名和邮箱⼀致,否则会出错。或者从来没有设置过全局的 name 和 e-mail,那么我们第⼀次提交时也 会报错。这就需要我们重新配置下了,同样要注意需要和 gitee 上配置的⽤⼾名和邮箱⼀致。如何配置 已讲过,在这⾥就不再赘述。
到这⾥我们已经将内容提交⾄本地仓库中,如何将本地仓库的内容推送⾄远程仓库呢,需要使⽤ git push 命令,该命令⽤于将本地的分⽀版本上传到远程并合并,命令格式如下:
拉取远程仓库内容
给命令配置起别名
在我们使⽤ Git 期间,有些命令敲的时候着实让⼈头疼(太⻓了。。),幸运的是,git⽀持对命令进⾏简化!
举个例⼦,将 git status 简化为 git st ,对应的命令为:
git config --global alias .st status
--global 参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有⽤。如果不加,那只
针对当前的仓库起作⽤。
标签管理
标签 tag ,可以简单的理解为是对某次 commit 的⼀个标识,相当于起了⼀个别名。例如,在项⽬
发布某个版本的时候,针对最后⼀次 commit 起⼀个 v1.0 这样的标签来标识⾥程碑的意义。
这有什么⽤呢?相较于难以记住的 commit id , tag 很好的解决这个问题,因为 tag ⼀定要给⼀
个让⼈容易记住,且有意义的名字。当我们需要回退到某个重要版本时,直接使⽤标签就能很快定位到。
创建标签
在Git中打标签⾮常简单,⾸先,切换到需要打标签的分⽀上
然后,敲命令 git tag [name] 就可以打⼀个新标签
可以⽤命令 git tag 查看所有标签
可以⽤ git show [tagname] 查看标签信息。
当然,并非只能给最新的提交打标签,使用如下命令查看commit id,然后在git tag [版本] [commit id]
Git 还提供可以创建带有说明的标签,⽤-a指定标签名,-m指定说明⽂字,格式为:
git tag -a [name] -m "XXX" [commit_id]
删除标签
因为创建的标签都只存储在本地,不会⾃动推送到远程。所以,打错的标签可以在本地安全删除。
推送标签
如果要推送某个标签到远程,使⽤命令
git push origin <tagname>
当然,如果你本地有很多标签,也可以⼀次性的全部推送到远端:
git push origin --tags
本地删除远程标签
git push origin --delete <标签名>
7.多人协作一
目标:远程 master 分支下 file.txt 文件新增代码 “aaa”,“bbb”
实现:由开发者1新增aaa,开发者2新增bbb
条件:在一个分支下协作完成
我们创建一个分支 dev,在分支 dev 上完成这些操作
git branch
查看本地分支,只有一个 master ;git branch -r
查看远程分支,我们可以看到远程里面也只有 master,没有新创建的 dev
将 dev 分支从远程拉取下来
在 windows 上面模拟开发者2,首先需要将仓库克隆到 windows 下,随便选取一个目录,shift + 右键
此时我们准备工作完成,接下来我们让开发者1新增 aaa,开发者2新增 bbb
我们可以分别用Linux机器和Windows机器来模拟开发者1和开发者2,依旧是采用我们上面已经创建的仓库 remote-gitcode
。
1. 开发者1 创建一个分支dev
开发者1 创建一个分支 dev
,然后开发者1和开发者2都同时在这个分支上进行操作。
👉 你在哪个分支上工作,就从那个分支 push 自己:
2. 开发者2 拉取远程仓库
打开 bash 进行 clone 远程仓库:
当 clone 的时候,本地仓库就只有 master
分支,那么就要获取 dev
分支。如果本地还没有 dev
,Git 会自动从远程的 origin/dev
创建一个对应的本地分支,并自动追踪它。
git checkout -b dev origin/dev
将本地 dev
分支和远程的 dev
分支进行建立链接,开发者2的本地也具有 dev
分支了。
3. 开发者1 对远程仓库进行推送
切换到开发者2中,可以看到正常的进行对 file.txt
文件进行修改,可是 push 的时候却发生错误,提示当前的本地与远程仓库有区别!
我们应该先进行 pull 来更新本地仓库!
git pull origin dev
再次 push 又会发现失败,出现合并冲突问题,需要手动进行解决!!!
解决完冲突后,这里要特别注意,要重新进行 add .
和 commit -m
来重新进行推送,再次进行 push 就可以上传成功,开发者2 新添加的 bbb
内容成功推送。
此时可以在远程的 dev
分支上看到我们想要得到的结果:file.txt
文件内有开发者1添加的“aaa”,有开发者2添加的 bbb
。
接下来就可以用 master
来合并 dev
分支!!!
可以看到 master
分支上没有这两行代码!
4. 将内容合并至 master
4.1 提交 Pull Request
开发者1 和开发者2 在远程仓库创建一个 Pull Request,提交合并请求。
4.2 本地操作:
- 在
dev
分支和master
分支上,执行如下命令:
git checkout master
git merge dev
git push origin master
由于在 master
上进行 merge dev
,可能会导致冲突,因此应该在本地的 dev
上进行 merge master
。这样就算有冲突,也可以在本地解决。解决完冲突后,再用 master
来 merge dev
,就不会有问题。
步骤如下:
这样就可以看到 master
分支上的 file.txt
被同步更新了。
完成后,可以同时让开发者1和开发者2对 dev
分支进行删除。
8.多人协作二
1. 本地创建分支
要保证本地的 master
是最新的,先 pull
操作,然后再次创建 dev
分支。
开发者1 操作
开发者2 操作
可以看到每次开发都是自己创建的分支,然后进行 push,每次都能成功,不会遇到冲突的问题。因为我们是在最新的 master
上创建的分支,然后自己创建的分支只有自己开发的时候能够用上,所以不会出现 push 冲突的问题。
2. 拉取远程的 feature-2 分支
突然,开发者2生病了,开发者1需要担起开发 feature-2
分支的重任!这时需要从远程拉取 feature-2
分支进行开发。此时,我们又回到了多人开发一中的情形,开发者1和开发者2在同一个分支开发。
拉取远程分支内容
使用如下命令拉取远程 feature-2
分支的内容:
git pull origin feature-2
拉取到远程的 origin/feature-2
分支后,本地没有这个分支,所以需要创建并切换至 feature-2
分支。
git checkout -b feature-2 origin/feature-2
此时,开发者1就能够在 feature-2
分支上继续开发
3. 合并 feature-1 和 feature-2 至 master
现在就是又遇到了合并feature-1的问题,为了避免冲突 我们就还是再feature-1分支上来合并master
每次feature-1合并master之前 就要先保证master是最新的,所以要切换到master进行pull再用master进行合并merge
当我们merge master的时候跳转到当前页面就说明没用任何问题,没用产生冲突,ctrl + x 就会退出该页面!
最后,开发者1和开发者2将各自的 feature-1
和 feature-2
分支合并到 master
分支上。
4. 删除远程分支
删除远程分支后,本地仍然可以看到已删除的远程分支。此时,可以使用以下命令移除远程已删除的分支记录:
git remote prune origin
以上就是Git企业常用的内容了,需要我们勤加联系!!!!