【Git】Git 原理和使用

news2024/12/28 18:30:55

Git

  • 一、Git 本地仓库
    • 1. 本地仓库的创建
    • 2. 配置 Git
    • 3. 工作区、暂存区、版本库
    • 4. 添加文件
    • 5. 查看 .git 文件
    • 6. 修改文件
    • 7. 版本回退
    • 8. 撤销修改
    • 9. 删除文件
  • 二、分支管理
    • 1. 理解分支
    • 2. 创建分支
    • 3. 切换分支
    • 4. 合并分支
    • 5. 删除分支
    • 6. 合并冲突
    • 7. 分支管理策略
    • 8. bug 分支
    • 9. 强制删除临时分支
  • 三、远程仓库
    • 1. 克隆远程仓库
    • 2. 向远程仓库推送
    • 3. 拉取远程仓库
    • 4. 配置 Git
      • (1)忽略特殊文件
      • (2)给命令配置别名
    • 5. 标签管理
      • (1)创建标签
      • (2)操作标签

我们在Linux常用工具中学会了 git 的简单使用,下面我们进一步学习使用 git.

版本控制器:为了能够更⽅便我们管理一些不同版本的⽂件,便有了版本控制器。

所谓的版本控制器,就是能让你了解到⼀个⽂件的历史,以及它的发展过程的系统。通俗的讲就是⼀个可以记录⼯程的每⼀次改动和版本迭代的⼀个管理系统,同时也⽅便多⼈协同作业。⽬前最主流的版本控制器就是 Git.

Linux中,如果我们的平台是 centos,安装 git 相当简单,以 centos7.6 为例,只需要执行 sudo yum -y install git,查看 git 安装的版本:git --version.

如果我们的平台是 ubuntu,安装 git 的指令为: sudo apt-get install git -y;查看 git 安装的版本:git --version.

注意:使用 git 工具无论是 centos 还是 ubuntu 平台,都是一样的。

一、Git 本地仓库

1. 本地仓库的创建

仓库是进⾏版本控制的⼀个⽂件⽬录。我们要想对⽂件进⾏版本控制,就必须先创建⼀个仓库出来。

创建⼀个 Git 本地仓库对应的命令为 git init ,注意命令要在⽂件⽬录下执⾏,例如:

在这里插入图片描述

如上就在一个目录下建好了一个本地仓库,我们使用 ls -la 查看这个目录下的仓库:

在这里插入图片描述

我们发现,当前⽬录下多了⼀个 .git 的隐藏⽂件, .git ⽬录是 Git 来跟踪管理仓库的,我们不要⼿动修改这个⽬录⾥⾯的⽂件,不然改乱了,就把 Git 仓库给破坏了。

2. 配置 Git

当安装 Git 后⾸先要做的事情是设置你的用户名称e-mail 地址,这是⾮常重要的。

我们在 Linux 常用工具中也有所介绍,其配置指令为:

		git config [--global] user.name "Your Name" 
		git config [--global] user.email "email@example.com"

其中 –global 是⼀个可选项。如果使⽤了该选项,表⽰这台机器上所有的 Git 仓库都会使⽤这个配置。我们也推荐加上该选项;如果你希望在不同仓库中使⽤不同的 namee-mail ,可以不要 –global 选项,但要注意的是,执⾏命令时必须要在仓库⾥。

如果我们想修改配置,直接执行上面的指令即可,新增的配置会覆盖之前的配置。

我们配置好 Git 后,可以查看当前的配置:git config -l

如果我们想删除配置,删除配置的指令如下:

		git config [--global] --unset user.name
		git config [--global] --unset user.email

注意,如果我们在配置 Git 时加上了 –global 选项,在删除配置时也应该要加上 –global 选项。

3. 工作区、暂存区、版本库

首先我们先认识一下工作区、暂存区和版本库的概念:

  • 工作区:是在电脑上你要写代码或⽂件的⽬录
  • 暂存区:英⽂叫 stageindex。⼀般存放在 .git ⽬录下的 index ⽂件(.git/index)中,我们把暂存区有时也叫作索引(index)
  • 版本库:⼜名仓库,英⽂名 repository 。⼯作区有⼀个隐藏⽬录 .git ,它不算⼯作区,⽽是 Git版本库。这个版本库⾥⾯的所有⽂件都可以被 Git 管理起来,每个⽂件的修改、删除Git 都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“ 还原 ”。

其中,三者之间的关系如下图:

在这里插入图片描述

  • 图中左侧为⼯作区,右侧为版本库。Git 的版本库⾥存了很多东西,其中最重要的就是暂存区
  • 在创建 Git 版本库时,Git 会为我们⾃动创建⼀个唯⼀的 master 分⽀,以及指向 master 的⼀个指针叫 HEAD。(分⽀和HEAD的概念后面再介绍)
  • 当对⼯作区修改(或新增)的⽂件执⾏ git add 命令时,暂存区⽬录树的⽂件索引会被更新
  • 当执⾏提交操作 git commit 时,master 分⽀会做相应的更新,可以简单理解为暂存区的⽬录树才会被真正写到版本库中。

由上述描述我们便能得知:通过新建或粘贴进⽬录的⽂件,并不能称之为向仓库中新增⽂件,⽽只是在⼯作区新增了⽂件。必须要通过使⽤ git addgit commit 命令才能将⽂件添加到仓库中进⾏管理。

4. 添加文件

在包含 .git 的⽬录下新建⼀个 test ⽂件,我们可以使⽤ 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,由用户自己完成,这部分内容绝对不能省略,并要好好描述,是⽤来记录提交细节的。

例如:

在这里插入图片描述

git commit 命令执⾏成功后会告诉我们,1个⽂件被改动(就是我们新添加的 test ⽂件),插入了一⾏内容(test 中有一⾏内容)。

我们可以使⽤ git log 命令,来查看下历史提交记录,例如:

在这里插入图片描述

该命令显⽰从最近到最远的提交⽇志,并且可以看到我们 commit 时的⽇志消息。如果嫌输出信息太多,不好看的,可以加上 --pretty=oneline 参数:

在这里插入图片描述

需要说明的是,我们看到的⼀⼤串类似 7aad62bad5848c12ef8818df7e3c9cfb9c01fa17 的是每次提交的 commit id (版本号)Git 的 commit id 不是1,2,3……递增的数字,⽽是⼀个 SHA1 计算出来的⼀个非常大的数字,用十六进制表示。

5. 查看 .git 文件

我们可以使用 tree .git/ 指令查看自己的 .git/ 的目录结构,由于目录结构太长了,我们就截取重要的部分讲解。

  • index 就是我们的暂存区,add 后的内容都是添加到这⾥的:

在这里插入图片描述

  • HEAD 就是我们的默认指向 master 分⽀的指针

在这里插入图片描述

在这里插入图片描述

⽽默认的 master 分⽀,其实就是:

在这里插入图片描述

打印的 7aad62bad5848c12ef8818df7e3c9cfb9c01fa17 就是当前保存的最新的 commit id

在这里插入图片描述

  • objectsGit 的对象库,里面包含了创建的各种版本库对象及内容。当执⾏ git add 命令时,暂存区的⽬录树被更新,同时⼯作区修改(或新增)的⽂件内容被写⼊到对象库中的⼀个新的对象中,就位于 “.git/objects” ⽬录下,让我们来看看这些对象有何⽤处:

查找 object 时要将 commit id 分成两部分,其前两位是⽂件夹名称,后38位是⽂件名称。找到这个⽂件之后,⼀般不能直接看到⾥⾯是什么,该类⽂件是经过 sha (安全哈希算法)加密过的⽂件,但是我们可以使⽤ git cat-file -p + commit id 命令来查看版本库对象的内容:

在这里插入图片描述

以上就是我们最近⼀次的提交。

总结,在本地的 git 仓库中,有几个文件或者目录很特殊:

  • index: 暂存区, git add 后会更新该内容。
  • HEAD: 默认指向 master 分⽀的⼀个指针。
  • refs/heads/master: ⽂件⾥保存当前 master 分⽀的最新 commit id
  • objects: 包含了创建的各种版本库对象及内容,可以简单理解为放了 git 维护的所有修改。

6. 修改文件

Git 跟踪并管理的是修改,而非文件。什么是修改?比如我们新增了一行,这就是⼀个修改,删除了一行,也是⼀个修改,更改了某些字符,也是⼀个修改,删了⼀些⼜加了⼀些,也是⼀个修改,甚⾄创建⼀个新⽂件,也算⼀个修改。我们下面对 test 文件进行一次修改:

在这里插入图片描述

此时,仓库中的 test 和我们⼯作区的 test是不同的,如何查看当前仓库的状态呢? git status 命令用于查看在我们上次提交之后是否有对⽂件进⾏再次修改,例如:

在这里插入图片描述

上面的结果告诉我们,test 被修改过了,但还没有完成添加与提交。

我们先对文件进行添加,再查看仓库的状态:

在这里插入图片描述

如上图就说明 test 已经添加到暂存区了,但时还没有完成提交,随后我们提交即可。

最后,git diff [file] 命令可以⽤来显示暂存区和⼯作区⽂件的差异;也可以使用 git diff HEAD -- [file] 命令来查看版本库和⼯作区文件的区别。

例如我们再对 test 进行修改,修改后对比暂存区和工作区文件的差异:

在这里插入图片描述

如上结果,在最后一个 hello world!! 前面有一个 ’ - ’ 号,说明是减少了这一行,结果的确是这样的。

7. 版本回退

Git 能够管理⽂件的历史版本,这也是版本控制器重要的能⼒。如果有⼀天我们发现之前的⼯作做的出现了很大的问题,需要在某个特定的历史版本重新开始,这个时候,就需要版本回退的功能了。

执⾏ git reset 命令⽤于回退版本,可以指定退回某⼀次提交的版本。要解释⼀下 “回退” 本质是要将版本库中的内容进行回退,⼯作区或暂存区是否回退由命令参数决定:

	git reset 命令语法格式为: git reset [--soft | --mixed | --hard] [HEAD]
	
	--mixed 为默认选项,使⽤时可以不⽤带该参数。该参数将暂存区的内容退回为指定提交版本内容,⼯作区⽂件保持不变。
	--soft 参数对于⼯作区和暂存区的内容都不变,只是将版本库回退到某个指定版本。
	--hard 参数将暂存区与⼯作区都退回到指定版本。切记⼯作区有未提交的代码时不要⽤这个命令,因为⼯作区会回滚,你没有提交的代码就再也找不回了,所以使⽤该参数前⼀定要慎重。
	
	HEAD 说明:
	◦ 可直接写成 commit id,表⽰指定退回的版本
	◦ HEAD 表⽰当前版本
	◦ HEAD^ 上⼀个版本
	◦ HEAD^^ 上上⼀个版本
	◦ ...以此类推

例如,我们重新对 test 文件写入内容:

在这里插入图片描述

然后对这里的内容进行添加和提交:

在这里插入图片描述

如上我们版本库中最新的提交是 “test reset”,此时我们将它进行版本回退,将暂存区版本库中的内容回退到上一个版本:

在这里插入图片描述

在这里插入图片描述

如上结果,仓库中提醒我们需要进行添加和提交操作,说明我们已经回退到上一个版本;除此之外,上面回退版本操作中,我们还可以使用 git reset + commit id 进行指定版本的回退;假设我们从最新的版本直接回退到最初的commit test的版本,如下:

当前是最新版本:

在这里插入图片描述

回退到最初版本,复制 最初的commit testcommit id 使用即可:

在这里插入图片描述

当前我们的暂存区版本库都已经回到 最初的commit test 的版本,但是工作区并没有回去,因为我们没有带选项,默认的选项 --mixed 只会回退暂存区和版本库中的内容;工作区中的内容依然如下:

在这里插入图片描述

但现在如果我后悔了,想再回到 test reset 的那一个版本怎么办?我们可以继续使⽤ git reset 命令回退版本,但我们必须要拿到test resetcommit id 去指定回退的版本。

但我们看到了 git log 并不能打印出上一次最新的 commit id ,运气好的话我们可以从终端上去找之前的记录,运⽓不好的话 commit id 已经被我们搞丢了。

但是 Git 还提供了⼀个 git reflog 命令能补救⼀下,该命令⽤来记录本地的每⼀次命令,如下:

在这里插入图片描述

我们观察到,这里的 commit id 只有前面的一部分,没错,Git 版本回退的时候,也可以使⽤部分 commit id 来代表目标版本,我们找到 test reset 的版本后,进行回退:

在这里插入图片描述

此时又回到了 test reset 的版本。

Git 的版本回退速度⾮常快,因为 Git 在内部有个指向当前分⽀(此处是master)的 HEAD 指针, refs/heads/master ⽂件⾥保存当前 master 分⽀的最新 commit id 。当我们在回退版本的时候,Git 仅仅是给 refs/heads/master 中存储⼀个特定的版本,可以简单理解成如下图:

在这里插入图片描述

在这里插入图片描述

8. 撤销修改

如果我们在我们的⼯作区写了很长时间代码,越写越写不下去,觉得自己写的实在是不好,想恢复到上⼀个版本;当然我们可以直接删除在工作区新增的代码,但是这样效率极低所以我们可以使用 git 指令完成;

我们可以使用 git checkout -- [file] 命令让⼯作区的文件回到最近⼀次 addcommit 时的状态。 要注意 git checkout -- [file] 命令中的 -- 很重要,切记不要省略,⼀旦省略,该命令就变为其他意思了,后面我们再介绍。

下面我们分几种情况讨论:

  • (1)对于工作区的代码,还没有 add

我们的 test 文件中有如下的句子:

在这里插入图片描述

下面我们在 test 文件中新增内容:

在这里插入图片描述

下面我们可以直接使用指令 git checkout -- test 即可将文件内容恢复到上一个 add 之前版本:

在这里插入图片描述

  • (2)已经 add,但没有 commit

让我们来回忆⼀下学过的 git reset 回退命令,该命令如果使⽤ --mixed 参数,可以将暂存区的内容退回为指定的版本内容,但工作区文件保持不变。那我们就可以回退暂存区的内容了,例如:

在这里插入图片描述

add 之后我们将暂存区的内容回退,执行 git reset HEAD test 指令:

在这里插入图片描述

我们发现,暂存区的内容回退了,但是工作区的内容还没有回退,此时我们已经回到情况一了,所以执行 git checkout -- test 即可:

在这里插入图片描述

  • (3)已经 add,也已经 commit

我们可以 git reset --hard HEAD^ 回退到上⼀个版本,不过,这是有条件的,就是你还没有把自己的本地版本库推送到远程仓库。

如下已经 addcommit

在这里插入图片描述

将工作区、暂存区、版本库中的内容全部回到上一版本:

在这里插入图片描述

9. 删除文件

Git 中,删除也是⼀个修改操作,如下,如果要删除 file3 ⽂件,怎么搞呢?

在这里插入图片描述

如果直接执行 rm file3 ,此时,工作区和版本库就不⼀致了,要删⽂件,目前除了要删⼯作区的⽂件,还要清除版本库的文件。

⼀般⾛到这⾥,有两种可能:

  • 确实要从版本库中删除该文件
  • 不小心删错了

对第⼆种情况,很明显误删,需要使⽤ git 来进行恢复,很简单,我们刚学过(删除也是修改):git checkout -- file3 即可;

对于第⼀种情况,很明显是没有删完,我们只删除了⼯作区的⽂件。这时就需要使用 git rm 将文件从暂存区和工作区中删除,并且 commit

在这里插入图片描述

二、分支管理

1. 理解分支

分⽀就好像科幻电影里面的平⾏宇宙,当你正在学习语文的时候,另⼀个你正在另⼀个平行宇宙里学习数学。如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了语文又学会了数学!

在版本回退里,我们已经知道,每次提交,Git 都把它们串成⼀条时间线,这条时间线就可以理解为是⼀个分支。截止到目前,只有⼀条时间线,在 Git ⾥,这个分支叫主分支,即 master 分支。

在这里插入图片描述

再来理解⼀下 HEADHEAD 严格来说不是指向提交,而是指向mastermaster 才是指向提交的,所以,HEAD 指向的就是当前分支。

每次提交,master 分支都会向前移动⼀步,这样,随着我们不断提交,master 分支的线也越来越⻓,而 HEAD 只要⼀直指向 master 分支即可指向当前分支。

通过查看当前的版本库,我们也能看出当前 master 分支指向的最新提交的 commit id

在这里插入图片描述

2. 创建分支

Git ⽀持我们查看或创建其他分支,对应的命令为:git branch;在这⾥我们来创建第⼀个自己的分支 dev ,对应的命令为:git branch dev;创建好后我们再看看我们的分支:

在这里插入图片描述

当我们创建新的分支后,Git 新建了⼀个分支叫 devmaster 前面的 * 表示当前 HEAD 指向的分支是 master 分支。另外,可以通过目录结构发现,新的 dev 分支:

在这里插入图片描述

发现目前 devmaster 指向同⼀个修改。目前的状态如下图:

在这里插入图片描述

3. 切换分支

如何切换到 dev 分支下进行开发呢?使用 git checkout 命令即可完成切换,如下:

在这里插入图片描述

我们发现 HEAD 已经指向了 dev,就表示我们已经成功的切换到了 dev 上。

我们现在在 dev 分支上对 test 文件进行一次修改并提交:

在这里插入图片描述

如上我们对文件添加了一行内容,接下来我们进行添加和提交:

在这里插入图片描述

然后我们切换回 master 分支上查看 test 文件:

在这里插入图片描述

此时我们发现,我们在 master 分支上的 test 并没有新增的那一行内容;我们来看看 dev 分支和 master 分支指向,发现两者指向的 commit id 是不⼀样:

在这里插入图片描述

因为我们是在 dev 分支上提交的,而 master 分支此刻的提交点并没有变,此时的状态如图如下:

在这里插入图片描述

当切换到 master 分支时,HEAD 就指向了 master,所以看不到提交了。

4. 合并分支

为了在 master 主分支上能看到最新的提交,就需要将 dev 分支合并到 master 分支,此时合并分支需要用到指令:git merge,如下:

此时如果我们在 dev 分支上,我们先需要切换到 master 分支上再进行合并:

在这里插入图片描述

合并分支:

在这里插入图片描述

git merge 命令用于合并指定分支到当前分支。合并后,master 就能看到 dev 分支提交的内容了。此时的状态如图如下:

在这里插入图片描述

此时的合并模式Fast-forward 模式, 代表 “快进模式” ,也就是直接把 master 指向 dev 的当前提交,所以合并速度非常快。当然,也不是每次合并都能 Fast-forward,我们后面会介绍其他的合并模式。

5. 删除分支

合并完成后,dev 分支对于我们来说就没用了, 那么 dev 分支就可以被删除掉,注意如果当前正处于某分支下,就不能删除当前分支;而可以在其他分支下删除那个分支,删除分支的指令为 git branch -d + 分支名称,如下:

在这里插入图片描述

因为创建、合并和删除分支非常快,所以 Git 推荐我们使用分支完成某个任务,合并后再删掉分⽀,这和直接在 master 分支上工作效果是⼀样的,但过程更安全。

6. 合并冲突

在实际分支合并的时候,并不是想合并就能合并成功的,有时候可能会遇到代码冲突的问题。

首先,我们先创建⼀个新的分支 dev1 ,并切换至目标分支,我们可以使⽤ git checkout -b dev1 ,一步完成创建并切换的动作,如下:

在这里插入图片描述

我们在 dev1 分支上修改 test 文件并进行添加提交,如下:

在这里插入图片描述

此时我们切换回 master 分支上,观察 test 中的内容,并没有改变,这是正常的现象,我们前面也已经解释过:

在这里插入图片描述

如今我们在 master 分支上的 test 文件进行修改,并进行添加提交:

在这里插入图片描述

现在 master 分支和 dev1 分支各自都分别有新的提交,变成了如下图状态:

在这里插入图片描述

这种情况下,Git 只能试图把各自的修改合并起来,但这种合并就可能会有冲突,如下所示:

在这里插入图片描述

上面提示我们合并有冲突,我们查看仓库此时的状态:

在这里插入图片描述

发现 test 文件有冲突后,可以直接查看⽂件内容,注意, Git 会⽤ <<<<<<<,=======,>>>>>>> 来标记出不同分支的冲突内容,如下图:

在这里插入图片描述

此时我们必须要手动调整冲突代码并需要再次提交修正后的结果,要么保留 master 分支上的内容,要么保留 dev1 分支上的内容;再次提交很重要,切勿忘记,如下:

在这里插入图片描述

到这里冲突就解决完成,此时的状态变成了下图:

在这里插入图片描述

用带参数的 git log 也可以看到分支的合并情况,例如指令:git log --graph --pretty=oneline --abbrev-commit,如下所示:

在这里插入图片描述

此时我们就可以把 dev1 分支删除了。

7. 分支管理策略

通常合并分支时,如果可能,Git 会采用 Fast forward 模式,我们上面也简单介绍过这个模式,就是直接将 dev 分支合并到 master 分支上,在这种 Fast forward 模式下,删除分支后,查看分支历史时,会丢掉分支信息,看不出来最新提交到底是 merge 进来的还是正常提交的。

在这里插入图片描述

但在合并冲突部分,我们也看到通过解决冲突问题,会再进⾏⼀次新的提交,得到的最终状态为:

在这里插入图片描述

那么这就不是 Fast forward 模式了,这样的好处是,从分支历史上就可以看出分支信息。例如我们现在已经删除了在合并冲突部分创建的 dev 分支,但依旧能看到 master 其实是由其他分支合并得到:

在这里插入图片描述

Git 也推荐我们强制禁用 Fast forward 模式,那么就会在 merge 时生成⼀个新的 commit ,这样,从分支历史上就可以看出分支信息。

下面我们使用 --no-ff 方式的 git merge 实践一下禁用 Fast forward 模式 进行合并。首先,创建新的分支 dev ,并切换至新的分支,在新的分支上修改文件并添加提交:

在这里插入图片描述

然后切回 master 分支开始合并:

在这里插入图片描述

此时我们执行的指令为:git merge --no-ff -m "test git merge --no-ff" dev;注意 --no-ff 参数,表示禁用 Fast forward 模式。禁用 Fast forward 模式 后合并会创建⼀个新的 commit ,所以加上 -m 参数,把描述写进去。

此时我们可以查看合并的历史情况:

在这里插入图片描述

可以看到,不使用 Fast forward 模式merge 后就像这样:

在这里插入图片描述

所以在合并分支时,加上 --no-ff 参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,⽽ fast forward 合并就看不出来曾经做过合并。

8. bug 分支

假如我们现在正在 dev 分支上进行开发,开发到⼀半,突然发现 master 分支上面有 bug,需要解决。在 Git 中,每个 bug 都可以通过⼀个新的临时分支来修复,修复后,合并分支,然后将临时分支
删除。

假设我们现在主分支的 test 如下:

在这里插入图片描述

我们现在要去 dev 分支上开发:

在这里插入图片描述

突然发现 master 分支上的 test 中少写了一个 hello, world!,即出现了 bug,此时我们切换到 master 分支上查看 test 中的内容:

在这里插入图片描述

我们看到,我们在 dev 分支上的 test 没有添加并提交时,修改 test 文件会影响 master 分支上的 test 文件,此时我们不想在 master 分支的 test 中看到 dev 分支上的 test 修改的内容,所以,Git 提供了 git stash 命令,可以将当前的⼯作区信息进⾏储藏,被储藏的内容可以在将来某个时间恢复出来,如下,在 dev 分支上使用该命令:

在这里插入图片描述

我们用 git status 查看⼯作区,就是干净的(除非有没有被 Git 管理的⽂件),因此可以放心地创建分支来修复bug。

储藏 dev ⼯作区之后,由于我们要基于 master 分支修复 bug,所以需要切回 master 分支,再新建临时分支来修复 bug,如下:

在这里插入图片描述

此时我们已经创建并进入 fix_bug 分支,我们开始修 bug,由于我们少写了一个 hello, world!,所以我们加上后添加并提交:

在这里插入图片描述

然后再切换回 master 分支进行合并,最后删除 fix_bug 分支:

在这里插入图片描述

此时,bug 的修复⼯作已经做完了,我们还要继续回到 dev 分支进行开发。切换回 dev 分支:

在这里插入图片描述

此时我们的工作区还是干净的,我们需要恢复我们开发的代码,使用 git stash list 可以查看我们存储区:

在这里插入图片描述

工作现场还在,Gitstash 内容存在某个地方了,但是需要恢复⼀下,如何恢复现场呢?我们可以使用 git stash pop 命令,恢复的同时会把 stash 也删了,如下:

在这里插入图片描述

在这里插入图片描述

如上,我们开发时的代码就找回来了,此时我们继续可以开发;但是修复 bug 的内容,并没有在 dev 上显示,此时的状态图为:

在这里插入图片描述

我们的最终目的是要让 master 合并 dev 分支的,那么正常情况下我们切回 master 分支直接合并即可,但这样其实是有⼀定风险的。是因为在合并分支时可能会有冲突,而代码冲突需要我们⼿动解决(在 master 上解决)。我们无法保证对于冲突问题可以正确地⼀次性解决掉,解决的过程中难免手误出错,导致错误的代码被合并到 master 上。如果在 master 分支上直接合并 dev 分支,此时的状态为:

在这里插入图片描述

此时我们有另外一种解决方案,在 dev 分支上合并 master ,再让 master 去合并 dev ,这样做的目的是有冲突可以在 dev 分支解决并进行测试,而不影响 master 。此时的状态为:

在这里插入图片描述

在这里插入图片描述

下面我们开始代码演示,先在 dev 上合并 master

在这里插入图片描述

发现冲突,然后解决冲突:

在这里插入图片描述

然后添加并提交:

在这里插入图片描述

切换回 master,进行合并 dev

在这里插入图片描述

此时合并完成,删除 dev 分支即可。

9. 强制删除临时分支

如果我们在日常开发中在一个开发分支上开发代码,突然被叫停了,需要把这个分支删除,如下为新的分支上开发的代码:

在这里插入图片描述

并进行添加提交:

在这里插入图片描述

如果切换回 master 分支上按照常规方式删除,会出现以下问题:

在这里插入图片描述

我们可以使用指令:git branch -D temp 强制删除:

在这里插入图片描述

三、远程仓库

创建一个仓库我们在 Linux常用工具(下) 中已经介绍过,这里不再做介绍。

1. 克隆远程仓库

克隆/下载远端仓库到本地,需要使⽤ git clone 命令,后⾯跟上我们的远端仓库的链接,远端仓库的链接可以从仓库中找到:选择 “克隆/下载” 获取远程仓库链接:

在这里插入图片描述

SSH 协议和 HTTPS 协议是 Git 最常使⽤的两种数据传输协议。SSH 协议使⽤了公钥加密和公钥登陆机制,体现了其实⽤性和安全性,使⽤此协议需要将我们的公钥放上服务器,由 Git 服务器进⾏管理。使
HTTPS 方式时,没有要求,可以直接克隆下来。

HTTPS 的方式我们之前也介绍过,直接将仓库地址复制到 git clone 后即可,这里着重介绍 SSH 的方式。

如果我们按照上面的方式克隆,由于我们没有添加公钥到远端库中,服务器拒绝了我们的 clone 链接:

在这里插入图片描述

需要我们设置一下:

  1. 创建 SSH Key。在用户主⽬录下,看看有没有 .ssh 目录,如果有,再看看这个目录下有没有 id_rsaid_rsa.pub 这两个文件,如果已经有了,可直接跳到下⼀步。如果没有,需要创建 SSH Key

像这种情况,在 .ssh 里没有 id_rsaid_rsa.pub,我们就要直接创建 SSH Key
在这里插入图片描述

此时就需要我们输入指令:ssh-keygen -t rsa -C "你的邮箱" ,然后一路按回车即可:

在这里插入图片描述

随后我们的 .ssh 目录下就有这两个文件了,其中这两个就是 SSH Key 的秘钥对, id_rsa 是私钥,不能泄露出去, id_rsa.pub公钥,可以放心告诉任何人:

在这里插入图片描述

  1. 添加自己的公钥到远端仓库

我们回到自己的远程仓库找到设置:

在这里插入图片描述

点击 ssh公钥 选项:

在这里插入图片描述

进入后我们先随意给公钥命名,然后复制公钥到以下地方:

在这里插入图片描述

其中复制公钥,我们 cat 一下公钥的文件即可,然后复制公钥:

在这里插入图片描述

我们做好上面的工作后,点击确认即可,随后输入自己账号的密码即可。

随后我们就可以创建 SSH 仓库了,新建一个目录然后 git clone + 仓库地址 即可。

如果有多个人协作开发,GitHub/Gitee 允许添加多个公钥,只要把每个人的电脑上的 Key 都添加到 GitHub/Gitee,就可以在每台电脑上往GitHub/Gitee 上提交推送了。

当我们从远程仓库克隆后,实际上 Git 会自动把本地的 master 分支和远程的 master 分支对应起来,并且,远程仓库的默认名称是 origin 。在本地我们可以使⽤ git remote 命令,来查看远程库的信息,如:

在这里插入图片描述

或者,用 git remote -v 显示更详细的信息:

在这里插入图片描述

上面显示了可以抓取和推送的 origin 的地址。如果没有推送权限,就看不到 push 的地址。

2. 向远程仓库推送

本地已经 clone 成功远程仓库后,我们便可以向仓库中提交内容,例如新增一些文件后提交上去:

在这里插入图片描述

到这里我们已经将内容提交至本地仓库中,如何将本地仓库的内容推送至远程仓库呢,需要使用 git push 命令,该命令用于将本地的分支版本上传到远程并合并,命令格式如下:

		git push <远程主机名> <本地分支名>:<远程分支名>
		#如果本地分支名与远程分支名相同,则可以省略冒号:
		git push <远程主机名> <本地分支名>

此时我们要将本地的 master 分支推送到 origin 主机的 master 分支,则可以执行:git push origin master

在这里插入图片描述

这里可以直接使用 git push,因为我们在克隆的时候本地的 master 分支和远端的 master 分支已经对应起来。

由于我们使用的是 HTTPS 协议,所以每次 push 都要输入用户名和密码,如果是使用 SSH 协议则不需要。

如下,三个文件都被推送至远程仓库了:

在这里插入图片描述

3. 拉取远程仓库

假设我们在远程仓库中修改 file1 文件,如下,点击编辑进行修改:

在这里插入图片描述

如下,我们修改了 file1:

在这里插入图片描述

此时,远程仓库是要领先于本地仓库⼀个版本,为了使本地仓库保持最新的版本,我们需要拉取远端代码,并合并到本地。Git 提供了 git pull 命令,该命令用于从远程获取代码并合并本地的版本。格式如下:

		git pull <远程主机名> <远程分支名>:<本地分支名>
		
		# 如果远程分支是与当前分支合并,则冒号后⾯的部分可以省略。
		git pull <远程主机名> <远程分支名>

我们使用一下:

在这里插入图片描述

这里可以直接使用 git pull,因为我们在克隆的时候本地的 master 分支和远端的 master 分支已经对应起来。

4. 配置 Git

(1)忽略特殊文件

在⽇常开发中,我们有些文件不想或者不应该提交到远端,比如保存了数据库密码的配置⽂件,那怎么让 Git 知道呢?在 Git ⼯作区的根目录下创建⼀个特殊的 .gitignore ⽂件,然后把要忽略的⽂件名填进去,Git 就会自动忽略这些文件了。

不需要从头写 .gitignore ⽂件,gitee 在创建仓库时就可以为我们生成,不过需要我们主动勾选⼀下:

在这里插入图片描述

如果当时没有选择这个选择,在⼯作区创建⼀个也是可以的。无论哪种方式,最终都可以得到⼀个完整的 .gitignore 文件,例如我们想忽略以 .so.ini 结尾所有⽂件, .gitignore 的内容如下:

		*.ini
		*.so

.gitignore 文件中也可以指定某个确定的文件。最后⼀步就是把 .gitignore 也提交到远端,就完成了。

(2)给命令配置别名

在我们使用 Git 期间,有些命令敲的时候着实让⼈头疼(太长了),幸运的是,git 支持对命令进行简化!

例如,将 git status 简化为 git st ,对应的命令为:

		git config --global alias.st status

效果如下:

在这里插入图片描述

5. 标签管理

(1)创建标签

标签 tag ,可以简单的理解为是对某次 commit 的⼀个标识,相当于起了⼀个别名。例如,在项⽬发布某个版本的时候,针对最后⼀次 commit 起⼀个 v1.0 这样的标签来标识里程碑的意义。

这有什么用呢?相较于难以记住的 commit idtag 很好的解决这个问题,因为 tag ⼀定要给⼀个让人容易记住,且有意义的名字。当我们需要回退到某个重要版本时,直接使用标签就能很快定位到。

Git 中打标签非常简单,首先,切换到需要打标签的分支上:

在这里插入图片描述

然后,使用命令 git tag [tag name] 就可以打⼀个新标签:

在这里插入图片描述

可以用命令 git tag 查看所有标签:

在这里插入图片描述

默认标签是打在最新提交的 commit 上的。那如何在指定的 commit 上打标签呢?⽅法是找到历史提交的 commit id,然后打上就可以了,示例如下:

先查看历史提交的记录:

在这里插入图片描述

再对某一次提交打标签,将它的 commit id 跟在 git tag [tag name] 后即可;假设我们给 fix bug 的那一次提交打标签,并起标签名为 v0.9:

在这里插入图片描述

如上,标签就已经打好了;注意,标签不是按时间顺序列出,而是按字母排序的。我们可以用 git show [tag name] 查看标签信息:

在这里插入图片描述

最后,Git 还提供可以创建带有说明的标签,⽤ -a 指定标签名,-m 指定说明文字,格式为:

		git tag -a [tag name] -m "XXX" [commit id]

例如:

在这里插入图片描述

再查看标签,就可以看见我们的指定说明文字了:

在这里插入图片描述

(2)操作标签

如果标签打错了,也可以删除,指令为:

		git tag -d v1.0

如下所示:

在这里插入图片描述

其实我们的远程仓库也有标签,因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。

在这里插入图片描述

如果要推送某个标签到远程,使用命令: git push origin <tag name> 即可,如下:

在这里插入图片描述

此时我们查看远程仓库中的标签,确实推送到了远程:

在这里插入图片描述

在这里插入图片描述

当然,如果我们的本地有很多标签,也可以⼀次性的全部推送到远端,其指令为:git push origin --tags;这里就不做演示了。

如果标签已经推送到远程,要删除远程标签就麻烦⼀点,先从本地删除:

在这里插入图片描述

然后,从远程删除,删除命令也是 push,指令为:git push origin :[tag name],如下:

在这里插入图片描述

我们查看远程仓库的情况:

在这里插入图片描述

远程仓库的标签也确实删除了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1054065.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java的厨艺交流平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

JavaScript Web APIs第三天笔记

Web APIs - 第3天 进一步学习 事件进阶&#xff0c;实现更多交互的网页特效&#xff0c;结合事件流的特征优化事件执行的效率 掌握阻止事件冒泡的方法理解事件委托的实现原理 事件流 事件流是对事件执行过程的描述&#xff0c;了解事件的执行过程有助于加深对事件的理解&…

数据结构刷题(三十三):完全背包最小值情况。322. 零钱兑换、279. 完全平方数

题目一&#xff1a; 322. 零钱兑换https://leetcode.cn/problems/coin-change/ 思路&#xff1a;完全背包问题&#xff0c;求解最小组合数。dp[j]&#xff1a;凑足总额为j所需钱币的最少个数为dp[j]。同时需要确保凑足总金额为0所需钱币的个数一定是0&#xff0c;那么dp[0] 0…

如果只是用php纯做api的话,给移动端做数据接口,是否需要用php框架?

API接口对接是现代软件开发中不可或缺的一部分&#xff0c;它允许不同的应用程序之间进行数据交换和服务调用。在PHP中&#xff0c;可以使用多种方式实现API接口的对接&#xff0c;包括基于HTTP协议的传统方法以及现代的API客户端库客户端库客户端库等。 一、实现API接口的对接…

Web开发-登录页面设计流程

目录 确定页面设计样式创建js文件jquery.min.jsbootstrap.min.js 创建css文件bootstrap.min.cssmaterialdesignicons.min.cssstyle.min.css 创建ftl文件header.ftlfooter.ftllogin.ftlcss部分html部分 确定页面设计样式 可以自己用“画图”等软件进行设计&#xff0c;也可以打…

步进电机只响不转

我出现问题的原因是相位线接错。 我使用的滑台上示17H的步进电机&#xff0c;之前用的是57的步进电机。 57步进电机的相位线是A黑、A-绿、B红、B-蓝。 17步进电机的相位线是A红、A-绿、B黑、B-蓝。 这两天被一个问题困扰了好久&#xff0c;在调试步进电机开发板的时候电机发生…

ubuntu安装ROS

进官网&#xff0c;选版本&#xff0c;操作系统 ROS: Home 开始安装&#xff1a; noetic/Installation/Ubuntu - ROS Wiki Installation Configure your Ubuntu repositories Configure your Ubuntu repositories to allow "restricted," "universe,"…

银行金融科技岗笔试题资料大总结

程序员进银行科技岗——简单总结_银行程序员 无水印&#xff0c;可直接打印使用。 中国银行 通用资料 视频资料

IPV6(IPV6,RIPng的配置以及手工配置IPV4隧道)

目录 实验一&#xff1a;IPv6的基本配置 实验二&#xff1a;RIPng基本配置 RIPng RIPng的工作机制 实验三&#xff1a;手工配置IPV4隧道 实验一&#xff1a;IPv6的基本配置 案例如下&#xff1a; 各部分配置如下 配置路由器RTA <Huawei>sys Enter system view, …

【论文笔记】DiffusionTrack: Diffusion Model For Multi-Object Tracking

原文链接&#xff1a;https://arxiv.org/abs/2308.09905 1. 引言 多目标跟踪通常分为两阶段的检测后跟踪&#xff08;TBD&#xff09;和一阶段的联合检测跟踪&#xff08;JDT&#xff09;。TBD对单帧进行目标检测后&#xff0c;使用跟踪器跨帧关联相同物体。使用的跟踪器包括使…

【STM32基础 CubeMX】外部中断

文章目录 前言一、中断是什么二、使用CubeMX配置你的第一个中断三、代码分析CubeMX四、中断函数按键中断点灯示例代码总结 前言 当涉及到STM32基础的外部中断时&#xff0c;我们进入了一个引人入胜的领域&#xff0c;它允许微控制器与外部世界进行互动并实时响应各种事件。外部…

【论文阅读】通过3D和2D网络的交叉示教实现稀疏标注的3D医学图像分割(CVPR2023)

目录 前言方法标注3D-2D Cross Teaching伪标签选择Hard-Soft Confidence Threshold Consistent Prediction Fusion 结论 论文&#xff1a;3D Medical Image Segmentation with Sparse Annotation via Cross-Teaching between 3D and 2D Networks 代码&#xff1a;https://githu…

2023年中国艺术涂料市场发展历程及趋势分析:艺术涂料市场规模将进一步扩大[图]

艺术涂料是一种用于绘画和装饰&#xff0c;具有各种纹理或通过涂装手段后具有高装饰性的新型涂料。由于具有高度饱和的颜色、良好的遮盖力和可塑性&#xff0c;呈现立体装饰效果好、色彩搭配适当、风格独具特色的特点&#xff0c;而使得涂装出的饰面自然贴合、更加美观漂亮&…

Centos7环境下安装MySQL8详细教程

目录 一、Xftp7下载二、MySQL8安装包的下载三、将MySQL8安装包上传至服务器四、解压mysql8安装包五、rpm包的安装六、依次安装下列文件七、对MySQL进行初始化和授权八、查看数据库初始密码九、启动MySQL服务十、使用初始密码登录MySQL关于MySQL的卸载 一、Xftp7下载 关于Xftp7…

力扣 -- 718. 最长重复子数组

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:int findLength(vector<int>& nums1, vector<int>& nums2) {int m nums1.size();int n nums2.size();//多开一行&#xff0c;多开一列vector<vector<int>> dp(m 1, ve…

华为云云耀云服务器L实例评测 | 搭建企业级 Registry 服务器 Harbor

文章目录 您需要了解Harbor介绍Harbor特性和优势系统设置关闭防火墙安装Docker安装Docker Compose配置镜像加速器 Habor安装传包并解压配置Harbor安装Horbor登录Harbor 测试创建项目推送镜像拉取镜像 您需要了解 本次搭建采用 华为云耀云服务器 &#xff0c;一键部署、快速搭建…

Visual Studio 代码显示空格等空白符

1.VS2010: 快捷键&#xff1a;CtrlR,W 2.VS2017、VS2019、VS2022&#xff1a; 工具 -> 选项 -> 文本编辑器 -> 显示 -> 勾选查看空白

RWA分析通过10个问题。不要让数字和视觉欺骗您!(文章很长,请仔细阅读)

已经有30个小伙伴加入我们的星球了&#xff0c;如果你不介意的话&#xff0c;可以加入 我的知识星球主要分享 1. 分享区块链各种有价值的内容 2. 一起攻读一些有用的书籍 3. 财富密码&#xff08;不敢保证&#xff09; 4. 一些自我的感悟 1.什么是现实世界资产&#xff08;RWA&…

【Flutter】Flutter Web 开发 如何从 URL 中获取参数值

【Flutter】Flutter Web 开发 如何从 URL 中获取参数值 文章目录 一、前言二、Flutter Web 中的 URL 处理三、如何从 URL 中获取参数四、实际业务中的用法五、完整示例六、总结 一、前言 大家好&#xff01;我是小雨青年&#xff0c;今天我想和大家分享一下在 Flutter Web 开发…

【C++历险记】国庆专辑---探索多态迷宫的代码之旅!

本篇目录 一、什么是多态&#xff1f;二、多态的定义及其实现2.1多态构成的条件2.2虚函数2.3虚函数的重写2.3.1析构函数的重写 2.4C11 override 和 final2.5重载、覆盖(重写)、隐藏(重定义)的对比2.6为什么不能是子类的指针或者引用呢&#xff1f;2.7为什么不能是父类对象呢&am…