Git

Git基本配置

Git安装好之后,需要通过如下两行命令做一个基本配置,配置的信息将展示在我们每一次提交的后面,所以不要使用不方便公开的信息,如果不配置以后每次提交的时候都会让你输入用户名和密码。

git config --global user.name "java"    
git config --global user.email "123456@qq.com"

这个配置会保存在当前用户目录下的.gitconfig文件中。

Git基本操作

工作区和暂存区

Git中引入了暂存区/缓存区(Stage/Index)的概念
在这里插入图片描述

  1. 工作区很好理解,就是本地的文件夹。
  2. 这些本地的文件我们要通过git add命令先将他们添加到暂存区中。
  3. git commit命令则可以将暂存区中的文件提交到本地仓库中去。

初始化仓库

仓库的初始化有两种方式:一种是直接从远程仓库克隆,另一种则是直接从当前目录初始化。

当前目录初始化

git init

执行完成后当前目录下会多出一个.git的隐藏文件夹,所有git需要的数据和资源都存放在该目录中。

查看仓库状态

通过git status命令来查看仓库中文件的状态。

git status

添加文件到暂存区

git add命令可以将一个文件添加到暂存区。

git add 01.txt

提交到本地仓库

当文件提交到暂存区之后,通过git commit命令将当前暂存区的文件提交到本地仓库。

注意,执行commit命令时,需要加上提交备注,即-m参数。

git commit -m "第一次提交代码"

提交成功之后,我们可以通过如下命令修改提交备注。

git commit --amend  

运行该命令,会自动打开vi编辑器,此时我们可以重新编辑上次提交的备注信息。

查看提交日志

通过git log命令我们可以查看以往仓库中提交的日志,比如提交的版本号、提交者、提交者邮箱、提交时间、提交备注等信息。

git log

有的时候我们要查看的命令并不用这么详细,可以在git log后面加上–pretty=short,这样显示出来的就只是简略信息了。

git log --pretty=short

如果只想查看某一个文件的提交日志,在git log后面加上文件名即可。

git log 01.txt

如果我还想查看提交时文件的变化,加上-p参数即可。

git log -p 01.txt

绿色的+表示新增的行,红色的-表示删除的行。

git log有一个局限性,就是不能查看已经删除的commit的日志。
举个例子:下班了,我发现今天下午提交的代码全都是有问题的,于是做了一个版本回退,回退到今天早上的状态,然后关机回家,第二天来了后我发现搞错了,其实那些代码都是OK的,于是我又想让仓库版本前进到昨天下午的状态,却发现git log命令查看不到昨天下午提交的版本号。

此时,我们可以使用git reflog命令来实现这一个请求,git reflog命令可以显示整个本地仓库的commit, 包括所有branch的commit, 甚至包括已经撤销的commit, 只要HEAD发生了变化, 就会在reflog里面看得到,而git log只显示当前分支的commit,并且不显示删除掉的commit。

git reflog

查看更改前后的差异

使用git diff命令我们可以查看工作区和暂存区的区别。

git diff

使用git diff HEAD命令我们可以查看工作区和本地仓库的差别。

git diff HEAD

Git中的各种后悔药

Git强大的撤销、版本回退功能,让我们在开发的过程中能够随意的回到任何一个时间点的状态。

工作区的代码想撤销

可以通过git checkout -- <file>命令来撤销工作区的代码修改。

git checkout 01.txt

add到暂存区的代码想撤销

  1. 将暂存区的代码撤销到工作区
  2. 将工作区的代码撤销(具体操作和’工作区的代码想撤销’一致)

将暂存区的代码撤销,可以使用git reset HEAD命令来实现。

git reset HEAD
git checkout 01.txt

提交到本地仓库的代码想撤销

提交到本地仓库的代码一样也可以撤销,可以利用git reset --hard <版本号>命令来实现版本回退,该命令中的版本号有几种不同的写法:

  1. 可以使用HEAD^ 来描述版本,一个^ 表示前一个版本,两个^^表示前两个版本,以此类推。
  2. 也可以使用数字来代替^,比如说前100个版本可以写作HEAD~100。
  3. 也可以直接写版本号,表示跳转到某一个版本处。我们每次提交成功后,都会生成一个哈希码作为版本号,所以这里我们也可以直接填版本号,哈希码很长,但是我们不用全部输入,只需要输入前面几个字符即可,就能识别出来。

1.通过git log查看当前提交日志

git log

2.通过git reset HEAD^^向前回退两个版本

git reset HEAD^^

3.查看日志,发现最后一次提交的版本号是695ce1fe,利用git reset —hard 695ce1fe命令回到回退之前的状态

git reset —hard 695ce1fe

4.通过git reset —hard HEAD~1回到上一个版本

git reset —hard HEAD~1

Git分支管理

查看分支

可以通过git branch命令来查看当前仓库有哪些分支,而我们处于哪一个分支中。

git branch

分支创建和切换

可以利用git branch <分支名>命令来创建一个分支,然后利用git checkout <分支名>来切换分支

git branch fa
git checkout fa
git branch

也可以通过git checkout -b <分支名>来一步到位,创建并切换分支

git checkout -b fb
git branch

也可以通过git checkout -命令来切换回上一个分支

git checkout -

分支合并

想要合并分支,我们先切换到master分支上,然后执行git merge --no-ff fa命令即可完成分支合并

git merge --no-ff fa

以图表方式查看分支

可以通过git log --graph命令来直观的查看分支的创建和合并等操作

git log --graph

分支衍合

所谓的分支衍合其实也是分支合并的一种方式,下面我们就来看看这个分支衍合到底是什么样的。现在我的master分支的内容和fa分支的内容是保持一致的,fa是从master中创建出来的,如下图
在这里插入图片描述
现在我向fa和master中各自做一次提交,如下图
在这里插入图片描述
此时我们执行如下两条命令将两个分支合并

git checkout fa
git rebase master

rebase命令在执行的过程中会首先把fa中的每个commit取消,并且将之保存为临时patch,再将fa分支更新为最新的master分支,然后再把那些临时的patch应用到fa上,此时fa分支将指向新创建的commit上,那些老的commit将会被丢弃,这些被丢弃的commit在执行git gc命令时会被删除。合并后的分支如下图
在这里插入图片描述
上面的git rebase master命令在执行的过程中有可能会发生冲突,发生冲突时我们有两种方案,一种直接退回到之前的状态,另一种就是解决冲突继续提交。

  • 退回到之前的状态
git rebase --abort
  • 解决冲突
    不过大多数情况下我们都是要解决冲突的,解决之后继续提交。此时我们用编辑器打开冲突的文件,看到的内容可能是这样的
    在这里插入图片描述
    ======上面的是HEAD中的内容,下面的是要合并的内容,根据自己的需求编辑文件,编辑完成之后,通过如下两条命令继续完成合并:
git add 01.txt
git rebase --continue

冲突解决

前面提到了在分支衍合时出现冲突的解决方案,其实普通的合并也有可能出冲突,出现冲突很正常,解决就是了,git merge合并分支时如果出现冲突还是先重新编辑冲突文件,编辑完成之后,再执行git add 和git commit即可。

Git关联远程仓库

配置SSH KEY

SSH KEY的配置不是必须的,不配置的话我们就只能使用HTTPS协议,这样每次提交时要输入用户名密码,略麻烦,所以还是配置一下。配置SSH KEY的原理很简单,采用非对称加密方式生成公钥和私钥,公钥告诉GitHub,私钥留在自己电脑上(私钥不可泄露),当我们向GitHub上提交数据时,GitHub会用我们留给它的公钥加密一段消息返回给我们的电脑,如果我们能够用私钥解密成功,说明是合法的用户,这样就避免我们输入用户名密码了。大致的原理就是这样,现在很多免登录的系统都采用了这种方式,比如Hadoop免登录配置也是这样。

  1. 查看本地是否已有SSHKEY
    查看当前用户目录下是否有.ssh文件,如下
ls la ~/.ssh

如果查看之后有结果,则直接跳转到第四步,什么都没有就继续生成。

  1. 生成SSH指纹
    生成SSH指纹的命令很简单,如下:
ssh-keygen -t rsa -b 4096 -C "你的邮箱地址"

注意邮箱地址要替换。

  1. 添加ssh到ssh-agent中
    执行如下命令即可:
eval "$(ssh-agent -s)"

OK,做好这一切之后,我们当前用户目录下已经有了一个名为.ssh的隐藏文件夹了,打开这个目录,会发现有一个名为id_rsa.pub的文件,这就是我们一会要使用的公钥文件。

  1. 将公钥告诉GitHub
    登录GitHub,点击右上角的向下的箭头,选择Settings,在新打开的页面中左边侧栏选择SSH and GPG keys,如下
    在这里插入图片描述

完了之后点击最下面的Add SSH key按钮即可,如此之后,我们的SSH KEY就配置成功了。

创建远程仓库

接下来我们在GitHub上创建一个仓库,登录成功之后,直接点击右上角绿色的New repository按钮,如下
在这里插入图片描述
其实这里我们只需要填一个版本仓库的名字,我填了test,填好之后,点击Create repository就OK了。

关联远程仓库

创建成功之后,我们会看到仓库的地址,如下:git@github.com:lenve/test.git,然后我需要将我们之前的本地仓库和这个远程仓库进行关联,使用git remote add命令,如下:

$ git remote add origin git@github.com:lenve/test.git

在这条命令中,git会自动将远程仓库的名字设置为origin,方便我们的后续操作。

推送到远程仓库

  • 推送到master分支

假设我想将本地master分支上的内容推送到远程master分支上,方式如下:

$ git push -u origin master

-u参数可以在推送的同时,将origin 仓库的master 分支设置为本地仓库当前分支的upstream(上游)。添加了这个参数,将来运行git pull命令从远程仓库获取内容时,本地仓库的这个分支就可以直接从origin 的master 分支获取内容,省去了另外添加参数的麻烦。这个参数也只用在第一次push时加上,以后直接运行git push命令即可。

  • 推送到其他分支

如果想推送到其他分支,还是这条命令,修改一下分支的名字即可,比如我也想把我的fa分支推送到远程仓库中,执行如下命令:

git checkout fa
git push -u origin fa

先切换到fa分支,然后执行git push命令,参数含义和之前的一样,这里我们创建的远程仓库的分支名也为fa(当然我们可以取任何名字,但是为了不混淆,最好取一致的名字)。这两条命令执行成功之后,此时在网页中我们就可以看到已经有多个分支了,如下:
在这里插入图片描述

从远程仓库获取

  • 首次获取

刚刚是我们向远程仓库提交数据,有提交当然就有获取,我们可以通过git clone命令克隆一个远程仓库到本地,方式也简单,在本地创建一个空文件夹,执行如下命令:

git clone git@github.com:lenve/test.git

表示克隆文件到本地仓库。此时克隆的远程仓库的master分支到本地仓库,我们可以通过git branch -a来查看本地仓库和远程仓库的信息,-a参数可以同时显示本地仓库和远程仓库的信息,如下:
在这里插入图片描述
我们看到远程仓库中已经有了fa分支了,如果我们想把fa分支也克隆下来,执行如下命令:

git checkout -b fa origin/fa

表示根据远程仓库的fa分支创建一个本地仓库的fa分支

  • 从远程仓库更新

此时我们回到第一次最早的那个test本地仓库中,那个test仓库的fa分支现在和远程仓库不一致了,我们可以通过git pull命令来更新,如下:
在这里插入图片描述

Git工作区储藏

现在有一个master分支,master分支中有一个文件叫01.txt,该文件中只有一行数据,然后对01.txt执行add和commit,然后再从master分支中创建出一个新的分支fa,切换到fa分支上,然后向01.txt中再添加一行数据,添加成功之后,不做任何事情,再切换回master分支,此时用cat命令查看01.txt文件,发现竟然有两行数据,按理说master中的01.txt只有一行数据,而fa中的01.txt有两行数据,整个过程如下图:
在这里插入图片描述

  • 方案一

第一种解决方案就是在某一个分支修改文件之后,先add并且commit之后再去切换分支,这个操作就比较简单了,这里就不再演示了。

  • 方案二(储藏)

第二种解决方案就是储藏(Stashing),储藏适用在如下场景中:

当我在一个分支fa中修改了文件,但是还没有完全改好,此时我并不想add/commit,但是这个时候有一个更急迫的事情在另外一个分支fb上需要我去做,我必须要切换分支。
在这样一个场景中,如果我直接切换分支,会出现如下两个问题:

1.从fa切换到fb之后,工作区的代码还是fa的代码,不符合我的工作要求。
2.假设我不在乎问题1,在fb中直接修改工作区的代码,等我在fb中修改完后提交后再回到fa,会发现我之前的代码丢失了。

为了解决这个问题,Git给我们提供了储藏(Stashing)。

现在假设一开始master和fa分支中的文件内容都是一致的,而且两个分支的工作区都是干净的,即没有东西需要add/commit,此时,我在master中修改了文件,修改完成之后,执行git status命令我们看到master中有东西需要add/commit,此时我想切换到fa分支中去,但是并不想对master分支执行add/commit,这个时候我们可以执行如下命令,先将当前分支中的文件储藏起来:

git stash

OK,执行完git stash命令之后,再执行git status,我们发现此时master分支已经是干净的了,此时我们可以愉快的切换到fa分支中去了,切换到fa分支之后,我们发现master中的修改并没有干扰到fa分支,当我们完成了fa分支中的工作之后,再回到master分支,此时执行如下命令可以恢复刚刚储藏的数据:

git stash apply

上面这个命令执行完之后,master分支中的工作区中的文件就恢复了,此时执行git status就可以看到又有数据需要add/commit了。

我们也可将工作区储藏多次,这个时候我们可以执行如下命令来查看储藏:

git stash list

执行效果如下:
在这里插入图片描述
git stash apply表示恢复最近一次储藏,如果我们想恢复到之前的某一次储藏,可以加上储藏的名字,如下:

git stash apply stash@{1}

恢复储藏并出栈

git stash pop

执行效果和git stash apply一样,不同的是,这里执行完之后,会将栈顶的储藏移除。

删除某一个储藏

git stash drop stash@{4}

最后一个参数是指储藏的名字。

Git标签管理

我们可以针对某一次的提交打上一个标签,有点类似于给某次提交取个别名,比如1.0版本发布时打个标签叫v1.0,2.0版本发布时打个标签叫v2.0,因为每次版本提交的结果都是一连串的哈希码,不容易记忆,打上v1.0,v2.0这些具有某种含义的标签后,可以方便我们进行版本管理。

轻量级标签

轻量级标签就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。

首先我们可以通过如下命令来查看当前仓库中的所有标签:

git tag

打标签的方式很简单,直接通过git tag 来完成即可,如下命令:

git tag v1

表示创建了一个名为v1的tag,这个tag默认是创建在最新一次的commit上的,如下:
在这里插入图片描述
我们可以利用git show 来查看标签对应的版本信息,如下:
在这里插入图片描述
我们可以通过git tag -d 命令删除一个标签:

git tag -d v1

在这里插入图片描述
如果我想给历史上的某次commit打一个标签呢?我们可以通过如下命令git tag ,如下:

git tag v0.0 7d519

表示给commit的哈希码为7d519的那一次commit打上一个标签,如下图:
在这里插入图片描述

含附注的标签

而含附注标签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG) 来签署或验证。

打一个含附注的标签很简单,使用git tag -a -m 命令,如下:

git tag -a v0.0 -m "文件初次建立" 7d519

在这里插入图片描述
如果不加最后的版本号参数,表示给最新的一次commit打标签。

签署标签

说到签署标签我们得先介绍一下GPG:

GPG是加密软件,可以使用GPG生成的公钥在网上安全的传播你的文件、代码。为什么说安全的?以Google所开发的repo为例,repo即采用GPG验证的方式,每个里程碑tag都带有GPG加密验证,假如在里程碑v1.12.3处你想要做修改,修改完后将这个tag删除,然后又创建同名tag指向你的修改点,这必然是可以的。但是,在你再次clone你修改后的项目时,你会发现,你对此里程碑tag的改变不被认可,验证失败,导致你的修改在这里无法正常实现。这就是GPG验证的作用,这样就能够保证项目作者(私钥持有者)所制定的里程碑别人将无法修改。那么,就可以说,作者的代码是安全传播的。为什么会有这种需求?一个项目从开发到发布,再到后期的更新迭代,一定会存在若干的稳定版本与开发版本(存在不稳定因素)。作为项目发起者、持有者,有权定义他(们)所认可的稳定版本,这个稳定版本,将不允许其他开发者进行改动。还以Google的repo项目为例,项目所有者定义项目开发过程中的点A为稳定版v1.12.3,那么用户在下载v1.12.3版本后,使用的肯定是A点所生成的项目、产品,就算其他开发者能够在本地对v1.12.3进行重新指定,指定到他们修改后的B点,但是最终修改后的版本给用户用的时候,会出现GPG签名验证不通过的问题,也就是说这样的修改是不生效的。

——摘自<[带GPG签名的Git tag]>一文

使用签署标签我们先要生成GPG Key,生成命令如下:

gpg --gen-key

能默认的就直接按回车默认,不能默认的就根据提示输入相应的值,这里的都很简单,不再赘述。完了之后,就可以通过如下命令来打标签了:

git tag -s v0.0 -u "laowang" -m "文件初次建立" 7d519

就把上面的-a换成-s,然后添加-u参数,-u参数的值是我们在生成GPG Key的时候配置的name属性的值,注意-u参数不可以写错,否则标签会创建失败,如下:
在这里插入图片描述

标签推送到远程仓库

git push命令并不会把tag提交到远程仓库中去,需要我们手动提交,如下:

git push origin v0.0

表示将v0.0标签提交到远程仓库,也可以通过git push origin --tags提交所有的tag到远程仓库,如下:
在这里插入图片描述
此时别人调用git pull更新代码之后,就能看到我们的tag。如下
在这里插入图片描述

Git Subtree

Git Subtree 是 Git 官方给出的一个管理子项目的解决方案,在 Git Subtree 之前,官方给出的方案是 Git Submodule,但是从 Git1.5.2 开始,Git 新增并推荐使用这个功能来管理子项目,只要大家本地安装的 Git 版本大于等于 1.5.2,都可以直接使用 Git Subtree。

Git Subtree 虽然不具备依赖管理的功能,但是在处理快速代替的公共代码库时,却显得非常得心应手,而且它能够做到双向同步!

首先,假设我现在有一个项目叫做 vmall,vmall 是一个微服务项目,里边包含了很多微服务,同时也包含了一个在快速迭代的公共代码块 vmall-common(注意,vmall 和 vmall-common 分属两个不同的仓库)。

vmall-common 我已经提交在 GitHub 上了,地址是 https://github.com/lenve/vmall-common。

现在我想在 vmall 项目中引用 vmall-common,怎么做呢?在 vmall 仓库中执行如下代码即可:

git subtree add --prefix=vmall-common https://github.com/lenve/vmall-common.git master --squash

最后的 --squash 参数表示不拉取历史信息,而只生成一条 commit 信息,这是一个可选参数,可以不加。这行命令执行完成后,在 vmall 项目中,就可以看到 vmall-common 了,而且 vmall-common 将作为一个普通的文件夹存在,该怎么样还是怎么样。

假如说,我们在开发的过程中,修改了 vmall-common,这个时候,在 vmall 仓库中,我们可以通过如下命令将 vmall-common 提交到它自己的仓库中去(先将 vmall 中的变化提交到远程仓库,再执行如下代码):

git subtree push --prefix=vmall-common https://github.com/lenve/vmall-common.git master

当 vmall-common 中的代码发生变化了,其他微服务通过如下指令可以更新代码:

git subtree pull --prefix=vmall-common https://github.com/lenve/vmall-common.git master --squash

这三个指令基本上就能应付日常的大部分操作了,不过每次都要输入一个长长的地址很不方便,我们可以给地址取一个别名:

git remote add -f vmall-common https://github.com/lenve/vmall-common.git

这样,最上面介绍的三个命令就可以简化了:

git subtree add --prefix=vmall-common vmall-common master --squash
git subtree pull --prefix=vmall-common vmall-common master --squash
git subtree push --prefix=vmall-common vmall-common master

原文链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值