Git——分支管理(2)

git · 浏览次数 : 153

小编点评

## Merge 操作概述 Merge 操作是一种合并两个分支的内容并将其整合到另一个分支中的过程。在本地分支和远程分支在同一个基点产生分歧时,需要执行 Merge 操作才能进行合并。 **合并过程步骤:** 1. 找到两个要整合的分支的共同祖先。 2. 取得当前所在分支的每次提交引入的变更。 3. 在远程分支上创建新的提交以保存这些变更。 4. 在当前分支上依次引入每个提交。 5. 在合并之前,对分支进行 rebase,将原始提交重新应用在远程分支的顶部。 6. 完成合并操作后,进行推送。 **Merge 操作的作用:** * 合并两个分支中的所有内容。 * 优化分支结构。 * 减少分支冲突。 * 提高代码维护性。 **示例:** 假设我们拥有两个分支:`main` 和 `test`,它们在同一个基点上。如果 `main` 和 `test` 的内容不同,我们需要执行 Merge 操作才能进行合并。 **合并后的结果:** * `main`分支包含了 `test`分支中的所有内容。 * `test`分支被合并到 `main`分支中。 * `main` 的 `test` 子分支被合并到 `main` 的 `test` 子分支中。

正文

Git——分支管理(2)

提示:图床在国外且动图比较多的情况下,需要时间加载。

目录:

[lab.magiconch.com][福音戰士標題生成器]-1695021721029

Git基础

关于Git的基础请参考上一篇基础的教程,这里主要是关于Git的分支管理的内容,在讲解完成之后会以实战的形式让各位更好的理解如何使用Git这一个强大的工具。

Git的分支与HEAD

Git的存储机制

当你发起提交的时候,Git存储的是提交对象,其中包含了指向暂存区快照的指针。

Git在仓库区一般会这样保存对象:

graph LR A("提交对象") --> C("Tree对象") -->B("Blob1对象") C-->D("Blob2对象")
  • 提交对象,一次提交包含着元数据以及指向项目根目录的树对象的指针,以便需要的时候重新创建这次快照。

    image.png
  • Blob 对象,只用于存储单个文件内容,一般都是二进制的数据文件,不包含任何其他文件信息,比如不包含文件名和其他元数据,可以同时有多个。

  • Tree 对象,对应文件系统的目录结构,里面主要有:子目录 (tree),文件列表 (blob),文件类型以及一些数据文件权限模型等。

Git将文件的快照存储为对象,每个对象都有一个唯一的哈希值。当文件发生变化时,Git会计算新文件的哈希值,并将其作为新对象存储在对象数据库中。当Git检测到两个文件版本相似时,它会计算差异(即两个版本之间的不同之处),并将这些差异作为一个新的对象存储。这个差异对象会引用原始文件的哈希值,以便可以重构原始文件的内容。

Git的分支指针

Git的分支只不过是一个指向某次提交的轻量级的可以移动指针,Git默认的分支名是master,当你发起提交的时候就有了一个指向最后一次提交的master分支。每次提交时他都会自己向前移动。

举个例子:

graph LR H("HEAD") -->G G("master") ==> Commit_C direction LR subgraph Commit_A direction TB A("提交对象A") --> B("文件对象A") end subgraph Commit_B direction TB C("提交对象B") --> D("文件对象B") end Commit_A --> Commit_B subgraph Commit_C direction TB E("提交对象C") --> F("文件对象C") end Commit_B --> Commit_C

也就是说分支其实就是指针,指针指向某一次提交。其中比较特殊的是HEAD指针,是用来指向当前分支指针的指针,表示当前在master分支上。

Git的远程仓库

远程分支是指远程仓库的分支指针,这些指针存在于本地且无法被移动,当你与服务器进行网络通信的时候,他会自动更新,也就是使用pull等命令的时候,远程分支有点像书签,会提示你上一次连接服务器时远程仓库中每个分支的位置。

graph LR G("master") ==> Commit_C direction LR subgraph Commit_A direction TB A("提交对象A") --> B("文件对象A") end subgraph Commit_B direction TB C("提交对象B") --> D("文件对象B") end Commit_A --> Commit_B subgraph Commit_C direction TB E("提交对象C") --> F("文件对象C") end Commit_B --> Commit_C H("remote") ==> Commit_C

remote指针同master指针一样,都是一个指针而已。

Git的远程分支管理

合并冲突

Fast-forward操作指的是当前分支所在位置是在已有要合并分支的后面,打个比方:

graph LR G("main") ==> Commit_B direction LR subgraph Commit_A direction TB A("提交对象A") --> B("文件对象A") end subgraph Commit_B direction TB C("提交对象B") --> D("文件对象B") end Commit_A --> Commit_B subgraph Commit_C direction TB E("提交对象C") --> F("文件对象C") end Commit_B --> Commit_C H("orgin/main") ==> Commit_C

main节点落后于服务器上的main(以后都称之为origin/main),此时执行Fast-forward操作就是把服务器的远程分支合并到main之上,此时main指针会向前走一个,这样的操作就是Fast-forward。

合并之后结果如下:

graph LR G("main") ==> Commit_C direction LR subgraph Commit_A direction TB A("提交对象A") --> B("文件对象A") end subgraph Commit_B direction TB C("提交对象B") --> D("文件对象B") end Commit_A --> Commit_B subgraph Commit_C direction TB E("提交对象C") --> F("文件对象C") end Commit_B --> Commit_C H("orgin/main") ==> Commit_C

merge操作指的是在本地分支和远程分支在同一个基点产生分歧的时候如下图所示:

graph LR G("main") ==> Commit_B direction LR subgraph Commit_A direction TB A("提交对象A") --> B("文件对象A") end subgraph Commit_B direction TB C("提交对象B") --> D("文件对象B") end Commit_A --> Commit_B subgraph Commit_C direction TB E("提交对象C") --> F("文件对象C") end Commit_A --> Commit_C H("orgin/main") ==> Commit_C

在你的第一次提交之后本地已有个第二次提交,远程也有一个基于第一次提交的远程提交,此时就需要merge将两次提交合并成新的提交:merge_commit,来进行合并。

graph LR direction LR subgraph Commit_A direction TB A("提交对象A") --> B("文件对象A") end subgraph Commit_B direction TB C("提交对象B") --> D("文件对象B") end subgraph Commit_C direction TB E("提交对象C") --> F("文件对象C") end subgraph merge_commit direction TB G("提交对象C") --> H("文件对象C") end Commit_A --> Commit_B Commit_A --> Commit_C Commit_C --> merge_commit Commit_B --> merge_commit merge_commit --> J("orgin/main") merge_commit --> I("main")

Rebase操作指的是在上述情况之上直接将某个分支之上所有提交的更改在另一个分支上重现一遍。

为了Rebase需要先找到两个要整合的分支的共同祖先,然后取得当前所在分支的每次提交引入的变更,并把这些变更保存成文件,这之后将当前分支重置为要整合到的分支,然后在该分支上依次引入之前保存的每个更改。

在合并之前分支已成这个样子:

graph LR G("main") ==> Commit_B direction LR subgraph Commit_A direction TB A("提交对象A") --> B("文件对象A") end subgraph Commit_B direction TB C("提交对象B") --> D("文件对象B") end Commit_A --> Commit_B subgraph Commit_C direction TB E("提交对象C") --> F("文件对象C") end Commit_A --> Commit_C H("orgin/main") ==> Commit_C

当我们想把远程分支的内容整合到main分支之上(就是将orgin/main rebase到 main)的话就会有如下情况,合并之后:

graph LR G("main") ==> Commit_B direction LR subgraph Commit_A direction TB A("提交对象A") --> B("文件对象A") end subgraph Commit_B direction TB C("提交对象B") --> D("文件对象B") end Commit_A --> Commit_B subgraph Commit_C+ direction TB E("提交对象C") --> F("文件对象C") end Commit_B --> Commit_C+ H("orgin/main") ==> Commit_C+

可以看到这里实际上变化成了Fast-forward所处理的情况,再次执行Fast-forward(merge)即可完成操作。

远程分支和本地仓库的冲突处理

查看当前分支情况

查看当前分支信息:

(base) neo@NeoNeuxs:~/git_test/Essays$ git branch
* main
  test

加上参数v可以显示当前每个分支的最新提交和其的提交信息,加上a则会包括当前的远程分支:

(base) neo@NeoNeuxs:~/git_test/Essays$ git branch -av
* main                dd0258f [ahead 3] Merge branch 'test'
  test                8eafb31 update git rm pycharm
  remotes/origin/HEAD -> origin/main
  remotes/origin/main e5d18d7 del copy

*代表了HEAD指针所处位置,也就是当前所在的分支。 update git rm pycharm就是对应的提交信息。e5d18d7就是提交对象的散列值。

如果要查看已并入当前的分支的所有分支信息可以使用:

(base) neo@NeoNeuxs:~/git_test/Essays$ git branch -av --merged
* main                dd0258f [ahead 3] Merge branch 'test'
  test                8eafb31 update git rm pycharm
  remotes/origin/HEAD -> origin/main
  remotes/origin/main e5d18d7 del copy

相反的,显示没有并入分支的命令可以使用:

(base) neo@NeoNeuxs:~/Desktop/Essays$ git branch -av --no-merged
  remotes/origin/HEAD -> origin/main
  remotes/origin/main e5d18d7 del copy

但是以上的方式都不够明显展示分支的变化及历史,所以推荐还是使用如下命令:

git log --graph --decorate --oneline --all

如图展示了两个本地的仓库,其中二者的远程仓库是保持一致的,也就是说二者都有一样的远程信息,但是本地却差别很大,我们的工作就是尽量合并二者的内容并优化分支结构。

image-20240506012058410

在看到二者的分支图的时候我们就能看到:

image-20240506012643030

简单来说我们的解决方案如下

首先rebase仓库A,将仓库A的main分支rebase到远程上然后提交到服务器。

然后将远程新的内容pull到仓库B,再进行一次rebase然后将内容上传到服务器。最终再pull仓库A、仓库B、服务器就可以实现同步。

(base) neo@NeoNeuxs:~/Desktop/Essays$ git rebase origin/main
Successfully rebased and updated refs/heads/main.

reabase之后:

image-20240506020430611

由于仓库B还有部分内容没有提交,这里就再提交一次:

(base) neo@NeoNeuxs:~/git_test/Essays$ git commit -a -m "finished git 1"
[main e2fdc30] finished git 1
 1 file changed, 61 insertions(+), 6 deletions(-)

提交之后分支如下,本次提交并不影响合并方案。

image-20240506020817574
git pull --rebase
# 等价于:
git fetch origin/main
git rebase origin/main
image-20240506023005761

其中的分支变化如下:

image-20240506032249539

关于rebase的变化的解释:

Git会将该合并提交的更改拆分成多个单独的提交,并将它们重新应用在远程分支的顶部。这意味着原始的合并提交(在这个例子中是 dd0258f)不再存在于变基后的分支历史中。

在git的变基过程遵循如下方式,在两个分支的共同祖先开始提取被变基分支(master)上的有效修改,然后将被变基分支的有效更改指向基分支(orgin/master)的最新提交。

245df5e提交和e5d18提交完全一致,并不是有效提交,所以被舍弃。

image-20240506025758663

需要注意的是,没有手动推送上图中test分支,服务器上实际上是没有245df5e,8eafb31的信息的。

参考:精通Git(第二版)

与Git——分支管理(2)相似的内容:

Git——分支管理(2)

Git——分支管理(2) 提示:图床在国外且动图比较多的情况下,需要时间加载。 目录: 目录Git——分支管理(2)提示:图床在国外且动图比较多的情况下,需要时间加载。目录:Git基础Git的分支与HEADGit的存储机制Git的分支指针Git的远程仓库Git的远程分支管理远程分支和本地仓库的冲突处

Git分支管理

前言 从22年10月到24年1月,一直忙于项目建设,终于顺利投产,截止现在,项目需求、项目缺陷持续推进,越发感觉到代码分支管理的重要性,从项目投产最初,一直试图通过查询各种资料,想找到一种合适的策略进行分支管理,奈何可能是资料过于繁杂未能发现有实际落地价值的资料,通过诸多资料,仅知道了有git工作流

【规范】Git分支管理,看看我司是咋整的

制定Git分支管理规范旨在加速团队协作,确保代码质量和主分支稳定性,支持敏捷开发流程。主要涉及分支包括:主分支(master/main)确保生产环境稳定;开发分支(develop)用于集成日常开发成果;特性分支(feature)支持单独功能开发;修复分支(hotfix)快速修复线上问题。规范流程涵盖...

Git 代码分支管理

Git 代码分支的命名规范以及管理方式对项目的版本发布至关重要,为了解决实际开发过程中版本发布时代码管理混乱、冲突等比较头疼的问题,我们将在文中阐述如何更好的管理代码分支。

如何使用 Terraform 和 Git 分支有效管理多环境?

> 作者|Sumeet Ninawe > 翻译|Seal软件 > 链接|https://spacelift.io/blog/terraform-environments 通常我们使用 Terraform 将我们的基础设施定义为代码,然后用 Terraform CLI 在我们选择的云平台中创建制定的基

团队如何选择合适的Git分支策略?

现代软件开发过程中要实现高效的团队协作,需要使用代码分支管理工具实现代码的共享、追溯、回滚及维护等功能。目前流行的代码管理工具,包括CVS,SVN,Git,Mercurial等。 相比CVS和SVN的集中管理,Git具有非常明显的优势,**例如:去中心化的代码管理方式减少了开发者对中心服务器的依赖,

【.NET项目分享】免费开源的静态博客生成工具EasyBlog,5分钟拥有自己的博客

EasyBlog 说明 本博客系统通过构建工具生成纯静态的博客网站,借助GitHub Pages,你可以在5分钟内免费拥有个人博客。 它具有以下特点 生成纯静态网站,访问速度极快 使用markdown格式来编写博客内容 基于git代码管理来存储你的博客 使用CI工具来自动化部署你的博客站点 效果展示

git clone开启云上AI开发

摘要:相比于传统的软件开发,AI开发存在以下4个痛点:算法繁多;训练时间长;算力需求大;模型需手动管理,我们可以使用云上AI开发的方式来缓解以上4个痛点。 本文分享自华为云社区《git clone开启云上AI开发》,作者:ModelArts开发者。 已发布地址:https://developer.h

Git Cherry-pick使用

## 概述 无论项目大小,当你和一群程序员一起工作时,处理多个 Git 分支之间的变更都会变得很困难。有时,与其把整个 Git 分支合并到另一个分支,不如选择并移动几个特定的提交。这个过程被称为 "挑拣", 即 Cherry-pick。 本文将介绍 "Cherry-pick" 的内容、原因和方法。

保姆教程系列:Git 实用命令详解

!!!是的没错,胖友们,保姆教程系列又更新了!!! @目录前言1.将本地项目推送到远程仓库2. Idea Git回退到某个历史版本3. 修改项目关联远程地址方法4. Git 修改分支的名称5. Git 删除分支6. master分支代码复制到新的分支7. Git迁移项目到其他代码仓库,且保留分支与提