当前位置: 首页 > news >正文

【Git】Git 分支

Git 分支

1.分支简介

为了真正理解 Git 处理分支的方式,我们需要回顾一下 Git 是如何保存数据的。

或许你还记得 起步 的内容, Git 保存的不是文件的变化或者差异,而是一系列不同时刻的 快照

在进行提交操作时,Git 会保存一个提交对象(commit object)

该提交对象会包含一个指向暂存内容快照的指针。 但不仅仅是这样,该提交对象还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针。需要注意的是,首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象, 而由多个分支合并产生的提交对象有多个父对象!

为了能够更加形象地进行说明,假设现在在一个工作目录中,有三个文件,其结构如下:

-index
|
|---README
|---test.rb
|---LICENSE

我们需要暂存并提交这三个文件。

$ git add README test.rb LICENSE
$ git commit -m 'The initial commit of my project'

使用 git add 进行暂存操作时,会为每一个文件计算校验和(使用我们在 起步 中提到的 SHA-1 哈希算法),然后会把当前版本的文件快照保存到 Git 仓库中 (Git 使用 blob 对象来保存它们),最终将校验和加入到暂存区域等待提交。

下一步便是使用 git commit 进行提交,Git 会先计算每一个子目录(本例中只有项目根目录)的校验和, 然后在 Git 仓库中这些校验和保存为树对象

随后,Git 便会创建一个提交对象, 它除了包含上面提到的那些信息外,还包含指向这个树对象的指针(即指向项目的根目录)。 如此一来,Git 就可以在需要的时候重现此次保存的快照。

所以此时 Git 仓库中有5个对象:

  • 一个提交对象,其中包含着指向树对象的指针,以及所有的提交信息
  • 一个树对象,其中记录着项目的目录结构每一个 blob 对象的索引
  • 三个 blob 对象,其中保存了文件的快照(snapshot)

它们的结构如下:

在这里插入图片描述

可以看到,这5个对象之间通过指针进行连接,并将提交对象作为其根节点,共同构成了一次暂存提交操作的完整内容(也可以理解为一个版本)!

需要注意的是,上述是第一次提交时生成的提交对象!而如果我们后续再次进行修改,然后再次进行暂存和提交,同样也会生成对应的提交对象,而其中会包含一个指向上一个提交对象(也就是前面所说的父对象)的指针

多次执行修改、暂存以及提交操作后,在 Git 版本库中的 object 文件夹中,就会形成如下的结构:

在这里插入图片描述

这里的 Snapshot A、B、C 实际上就是前面说到的树对象。

了解了 Git 保存各版本数据的方式后,我们就可以进入对分支的学习了。

Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 master 分支会在每次提交时自动向前移动。

另外需要注意的是:Git 的 master 分支并不是一个特殊分支。 它就跟其它分支完全没有区别。 之所以几乎每一个仓库都有 master 分支,是因为 git init 命令默认创建它,并且大多数人都懒得去改动它。

如果我们将分支的概念加入上述的提交对象中,会得到以下结构:

在这里插入图片描述

可以看到,所谓的分支,只不过是指向某一个提交对象的指针!同时,我们可以看到其中有一个特殊的指针:HEAD,后续我们会对这个特殊的指针进行详细的介绍。

分支的创建

Git 是怎么创建新分支的呢? 很简单,它只是为你创建了一个可以移动的新的指针。 比如,创建一个 testing 分支, 你需要使用 git branch 命令:

$ git branch testing

这会在当前所在的提交对象上创建一个指针。注意是当前所在的提交对象上!一定要注意这一点,不然后续创建分支时很可能会出现分支起点不对而导致代码被污染的情况!

完成创建后的结构如下:

在这里插入图片描述

可以看到新创建的分支 testingmaster 指向同一个提交对象(提交历史)。

但是这里还有一个问题:Git 是如何知道当前在哪一个分支上的呢?这就要依靠前面提到过的那个特殊的指针 HEAD 了! 在 Git 中,它是一个指针,指向当前所在的本地分支(译注:将 HEAD 想象为当前分支的别名)。 在本例中,因为 git branch 命令仅仅 创建 一个新分支,并不会自动切换到新分支中去,所以此时 HEAD 指针仍指向 master 分支,即我们当前仍在 master 分支上。

在这里插入图片描述

当然,我们也可以使用特定的命令,查看各个分支指针所指向的提交对象:

$ git log --oneline --decorate

效果如下:

在这里插入图片描述

比较上下内容,可以发现它们实际上是一样的,只不过 Git Graph 插件通过具象化的形式将文字转为了图表!同时可以发现,HEAD 指向当前分支 test-VIFI01-v2

分支切换

要切换到一个已存在的分支,你需要使用 git checkout 命令。 我们现在切换到新创建的 testing 分支去:

$ git checkout testing

这样 HEAD 就指向 testing 分支了。

在这里插入图片描述

那么,这样的实现方式好在哪里?此时如果我们在 testing 分支上,再次修改、暂存、提交一次,那么提交历史就会变成这样:

在这里插入图片描述

可以看到,testing 分支向前移动了,但是 master 则没有,其仍然指向在其上最后一次提交所对应的提交对象!

若我们此时切换回 master 分支:

$ git checkout master

在这里插入图片描述

这条命令做了两件事。 一是使 HEAD 指回 master 分支,二是将工作目录恢复成 master 分支所指向的快照内容。 也就是说,你现在做修改的话,项目将始于一个较旧的版本。 本质上来讲,这就是忽略 testing 分支所做的修改,以便于向另一个方向进行开发。

需要注意的是,在切换分支时,工作目录中的内容会被改变,即恢复成目标分支所指向的快照内容,而当 Git 不能干净利落地完成这个工作时,它会禁止切换分支。(例如在某一分支上进行了一些修改,但并没有将其放入暂存区,此时就无法切换分支!)

此时,如果我们再在 master 分支上进行一些修改并将其暂存并提交,那么就会导致项目的提交历史产生分叉(参见 项目分叉历史):

在这里插入图片描述

当然提交历史的分叉也是可见的,不论是通过指令还是插件。

对于较为复杂的项目,还是推荐通过插件来查看提交历史的分叉情况:

在这里插入图片描述

由于 Git 的分支实质上仅是包含所指对象校验和(长度为 40 的 SHA-1 值字符串)的文件,所以它的创建和销毁都异常高效。 创建一个新分支就相当于往一个文件中写入 41 个字节(40 个字符和 1 个换行符),如此的简单能不快吗?

在 Git 中,任何规模的项目都能在瞬间创建新分支。 同时,由于每次提交都会记录父对象,所以寻找恰当的合并基础(译注:即共同祖先)也是同样的简单和高效。 这些高效的特性使得 Git 鼓励开发人员频繁地创建和使用分支。

接下来,让我们看看你为什么应该这样做。

2.分支的新建与合并

为了形象地描述这部分内容,我们会在一个场景中进行介绍:

你将经历如下步骤:

  1. 开发某个网站。
  2. 为实现某个新的用户需求,创建一个分支。
  3. 在这个分支上开展工作。

正在此时,你突然接到一个电话说有个很严重的问题需要紧急修补。 你将按照如下方式来处理:

  1. 切换到你的线上分支(production branch)。
  2. 为这个紧急任务新建一个分支,并在其中修复它。
  3. 在测试通过之后,切换回线上分支,然后合并这个修补分支,最后将改动推送到线上分支。
  4. 切换回你最初工作的分支上,继续工作。

新建分支

首先,初始的项目提交历史应该是下面这个样子的:

在这里插入图片描述

现在,你需要解决编号为 #53 的问题。 那么就需要新建一个分支并同时切换到那个分支上,你可以运行一个带有 -b 参数的 git checkout 命令:

$ git checkout -b iss53
Switched to a new branch "iss53"

此时你已经检出到该分支 (也就是说,你的 HEAD 指针指向了 iss53 分支)

然后你继续在 iss53 分支上工作,并且做了一些提交。 在此过程中,iss53 分支在不断的向前推进。

因此项目的提交历史变成了下面这样:

在这里插入图片描述

现在你接到那个电话,有个紧急问题等待你来解决。 有了 Git 的帮助,你不必把这个紧急问题和 iss53 的修改混在一起, 你也不需要花大力气来还原关于 53# 问题的修改,然后再添加关于这个紧急问题的修改,最后将这个修改提交到线上分支。 你所要做的仅仅是切换回 master 分支。

但是,在你这么做之前,要留意你的工作目录和暂存区里那些还没有被提交的修改, 它可能会和你即将检出的分支产生冲突从而阻止 Git 切换到该分支。

最好的方法是,在你切换分支之前,保持好一个干净的状态,并使用 git status 命令检查一下分支的状态。 有一些方法可以绕过这个问题(即,暂存 — stashing修补提交 — commit amending), 我们会在 贮藏与清理 中看到关于这两个命令的介绍。

现在,我们假设你已经把你的修改全部提交了,这时你可以切换回 master 分支了:

$ git checkout master
Switched to branch 'master'

这个时候,你的工作目录和你在开始 #53 问题之前一模一样,现在你可以专心修复紧急问题了。此时,需要新建一个 hotfix 分支,并在该分支上解决问题并提交:

$ git checkout -b hotfix
Switched to a new branch 'hotfix'...修复问题$ git commit -a -m 'fixed the broken email address'
[hotfix 1fb7853] fixed the broken email address1 file changed, 2 insertions(+)

此时,项目的提交历史如下:

在这里插入图片描述

合并分支 — 情况1

待测试人员测试完成,确保修复是正确的之后,此时需要hotfix 分支合并回 master 分支,从而将修复部署到线上。

你可以使用 git merge 命令来达到上述目的:

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forwardindex.html | 2 ++1 file changed, 2 insertions(+)

在合并的时候,你应该注意到了“快进(fast-forward)”这个词。 由于你想要合并的分支 hotfix 所指向的提交 C4 是你所在的提交 C2 的直接后继, 因此 Git 会直接将指针向前移动

换句话说,当你试图合并两个分支时, 如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候, 只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧——这就叫做 “快进(fast-forward)”。

现在,最新的修改已经在 master 分支所指向的提交快照中,你可以着手发布该修复了。当前的项目提交历史如下:

在这里插入图片描述

而对于 hotfix 分支,此时已经不再需要它了,所以可以通过 git branch -d 来将其删除。

合并分支 — 情况2

现在你可以切换回你正在工作的分支继续你的工作,也就是针对 #53 问题的那个分支(iss53 分支)。

当你在 iss53 分支上继续工作并提交后,项目的提交历史会变成这样:

在这里插入图片描述

此时可以看到,我们先前在 hotfix 分支上所做的工作并没有包含到 iss53 分支中,此时你有两个选择:

  1. 拉取 master 分支,将最新的 master 分支合并到 iss53 分支上,从而保持 iss53 分支是领先于 master 的,待 iss53 分支完成其工作后,将其合并到 master 中。
  2. 不合并 master,待 iss53 分支完成其工作后,将其合并到 master 中。

第一种方式虽然繁琐,但相比于第二种方式的优势在于:如果是较为复杂的项目,如果你不保持开发分支始终领先于 master 分支,那么在最后将其合并入 master 分支时,可能会出现冲突

这里我们暂时只讨论第二种方式,后续会对合并时的冲突以及如何解决冲突进行详细的介绍。

假设你已经修正了 #53 问题,并且打算将你的工作合并入 master 分支。 为此,你需要合并 iss53 分支到 master 分支,这和之前你合并 hotfix 分支所做的工作差不多。 你只需要检出到你想合并入的分支,然后运行 git merge 命令:

$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html |    1 +
1 file changed, 1 insertion(+)

这和你之前合并 hotfix 分支的时候看起来有一点不一样。 在这种情况下,你的开发历史从一个更早的地方开始分叉开来(diverged)

因为,master 分支所在提交并不是 iss53 分支所在提交的直接祖先,Git 不得不做一些额外的工作。 出现这种情况的时候,Git 会使用两个分支的末端所指的快照(C4C5)以及这两个分支的公共祖先(C2),做一个简单的三方合并

在这里插入图片描述

合并后的结果如下:

在这里插入图片描述

和之前将分支指针向前推进所不同的是,Git 将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它。这个被称作一次合并提交,它的特别之处在于他有不止一个父提交

有冲突的分支合并

有时候合并操作不会如此顺利。

如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,Git 就没法干净的合并它们。 例如,如果你对 #53 问题的修改和有关 hotfix 分支的修改都涉及到同一个文件的同一处,在合并它们的时候就会产生合并冲突:

$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

此时 Git 做了合并,但是没有自动地创建一个新的合并提交

Git 会暂停下来,等待你去解决合并产生的冲突。 你可以在合并冲突后的任意时刻使用 git status 命令来查看那些因包含合并冲突而处于未合并(unmerged)状态的文件

$ git status
On branch master
You have unmerged paths.(fix conflicts and run "git commit")Unmerged paths:(use "git add <file>..." to mark resolution)both modified:      index.htmlno changes added to commit (use "git add" and/or "git commit -a")

任何因包含合并冲突而有待解决的文件,都会以**未合并状态(Unmerged)**标识出来。 Git 会在有冲突的文件中加入标准的冲突解决标记,这样你可以打开这些包含冲突的文件然后手动解决冲突。 出现冲突的文件会包含一些特殊区段,看起来像下面这个样子:

<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">please contact us at support@github.com
</div>
>>>>>>> iss53:index.html

这表示 HEAD 所指示的版本(也就是你的 master 分支所在的位置,因为你在运行 merge 命令的时候已经检出到了这个分支)在这个区段的上半部分(======= 的上半部分),而 iss53 分支所指示的版本在 ======= 的下半部分。 为了解决冲突,你必须选择使用由 ======= 分割的两部分中的一个,或者你也可以自行合并这些内容。 例如,你可以通过把这段内容换成下面的样子来解决冲突:

<div id="footer">
please contact us at email.support@github.com
</div>

上述的冲突解决方案仅保留了其中一个分支的修改,并且 <<<<<<< , ======= , 和 >>>>>>> 这些行被完全删除了。

在你解决了所有文件里的冲突之后,还需要进行两步操作来完成合并:

  1. 对每个文件使用 git add 命令来将其标记为冲突已解决。 一旦暂存这些原本有冲突的文件,Git 就会将它们标记为冲突已解决。

  2. 如果你对结果感到满意,并且确定之前有冲突的的文件都已经暂存了,这时你可以输入 git commit 来完成合并提交。 默认情况下提交信息看起来像下面这个样子:

    Merge branch 'iss53'Conflicts:index.html
    #
    # It looks like you may be committing a merge.
    # If this is not correct, please remove the file
    #	.git/MERGE_HEAD
    # and try again.# Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    # On branch master
    # All conflicts fixed but you are still merging.
    #
    # Changes to be committed:
    #	modified:   index.html
    #
    

    如果你觉得上述的信息不够充分,不能完全体现分支合并的过程,你可以修改上述信息, 添加一些细节给未来检视这个合并的读者一些帮助,告诉他们你是如何解决合并冲突的,以及理由是什么。

3.多人协同开发

在学习多人协同开发之前,首先需要了解几个概念。

1.长期分支

因为 Git 使用简单的三方合并,所以就算在一段较长的时间内,反复把一个分支合并入另一个分支,也不是什么难事。 也就是说,在整个项目开发周期的不同阶段,你可以同时拥有多个开放的分支;你可以定期地把某些主题分支合并入其他分支中。

许多使用 Git 的开发者都喜欢使用这种方式来工作,比如只在 master 分支上保留完全稳定的代码——有可能仅仅是已经发布或即将发布的代码。 他们还有一些名为 develop 或者 next 的平行分支,被用来做后续开发或者测试稳定性——这些分支不必保持绝对稳定,但是一旦达到稳定状态,它们就可以被合并入 master 分支了。 这样,在确保这些已完成的主题分支(短期分支,比如之前的 iss53 分支)能够通过所有测试,并且不会引入更多 bug 之后,就可以合并入主干分支中,等待下一次的发布。

事实上我们刚才讨论的,是随着你的提交而不断右移的指针。 稳定分支的指针总是在提交历史中落后一大截,而前沿分支的指针往往比较靠前

在这里插入图片描述

通常把他们想象成**流水线(work silos)**可能更好理解一点,那些经过测试考验的提交会被遴选到更加稳定的流水线上去。如下:

在这里插入图片描述

你可以用这种方法维护不同层次的稳定性。再次强调一下,使用多个长期分支的方法并非必要,但是这么做通常很有帮助,尤其是当你在一个非常庞大或者复杂的项目中工作时。

2.远程分支

远程引用是对远程仓库的引用(指针),包括分支、标签等等。 你可以通过 git ls-remote <remote> 来显式地获得远程引用的完整列表, 或者通过 git remote show <remote> 获得远程分支的更多信息。 然而,一个更常见的做法是利用远程跟踪分支

远程跟踪分支是远程分支状态的引用。它们是你无法移动的本地引用。一旦你进行了网络通信, Git 就会为你移动它们以精确反映远程仓库的状态。请将它们看做书签, 这样可以提醒你该分支在远程仓库中的位置就是你最后一次连接到它们的位置。

它们以 <remote>/<branch> 的形式命名。 例如,如果你想要看你最后一次与远程仓库 origin 通信时 master 分支的状态,你可以查看 origin/master 分支。 你与同事合作解决一个问题并且他们推送了一个 iss53 分支,你可能有自己的本地 iss53 分支, 然而在服务器上的分支会以 origin/iss53 来表示。

这可能有一点儿难以理解,让我们来看一个例子。 假设你的网络里有一个在 git.ourcompany.com 的 Git 服务器。 如果你从这里克隆,Git 的 clone 命令会为你自动将其命名为 origin,拉取它的所有数据, 创建一个指向它的 master 分支的指针,并且在本地将其命名为 origin/master。 Git 也会给你一个与 origin 的 master 分支在指向同一个地方的本地 master 分支,这样你就有工作的基础。

需要注意的是,远程仓库名字 “origin” 与分支名字 “master” 一样,在 Git 中并没有任何特别的含义。 如果你运行 git clone -o booyah,那么你默认的远程分支名字将会是 booyah/master

在这里插入图片描述

上面就是进行一次克隆的结果,即拉取远程仓库的所有数据并在本地创建对远程分支的引用。

如果你在本地的 master 分支做了一些工作,在同一段时间内有其他人推送提交到 git.ourcompany.com 并且更新了它的 master 分支,这就是说你们的提交历史已走向不同的方向。 即便这样,只要你保持不与 origin 服务器连接(并拉取数据),你的 origin/master 指针就不会移动

在这里插入图片描述

可以看到本地对于远程分支的引用并不指向远程仓库中的最新位置,而是指向该分支在远程仓库中你最后一次连接到远程仓库时的位置

这就导致,本地的分支和远程的分支是可以分叉的!

假如此时运行 git fetch <remote> 命令(在本例中为 git fetch origin)。从中抓取本地没有的数据,并且更新本地数据库,移动 origin/master 指针到更新之后的位置。那么此时的提交历史如下:

在这里插入图片描述

这里需要注意,从远程仓库获取信息时,有两种方式:

  1. git fetch <remote> — 该命令的效果是抓取远程仓库的所有数据并更新本地仓库,但从上面的例子可以看到,它并不会将本地的某一分支与其对应的远程分支进行合并,例如在上面的例子中,执行 fetch 命令后,仅仅是更新了本地仓库,并没有将远程分支 origin/master 和本地分支 master 进行合并!
  2. git pull <remote> <branch> — 该命令会拉取指定远程分支的代码并合并到当前本地分支。

3.跟踪远程分支

当然,如果每次执行 git pull 时,都在后面加上指定的远程分支名,即麻烦也容易出错,因此我们可以为本地分支建立对某一远程分支的追踪关系

建立追踪关系有三种方式:

  1. 手动建立追踪关系

    $ git branch --set-upstream-to=<remote>/<branch> <本地分支名>
    
  2. push时建立追踪关系

    $ git push -u <远程主机名> <本地分支名>
    

    加上-u参数,这样push时,本地指定分支就和远程主机的同名分支建立追踪关系。

  3. 新建分支时建立追踪关系

    $ git checkout -b <本地分支名> <remote>/<branch>
    

    此时,新分支指针指向 <远程主机名>/<远程分支名> 所指的位置。具体位置可用 git log --oneline --graph 查看。

4.变基

详细介绍参考另一篇笔记:

5.分支策略

在 Git 中,常见的分支管理策略包括以下几个方面:

  1. 主分支主分支通常是最稳定的分支,用于发布生产版本。在 Git 中,主分支通常是 master 分支或者 main 分支。
  2. 开发分支:开发分支通常从主分支派生而来,在其上进行新功能或修复错误的开发。在 Git 中,通常使用 develop 分支作为开发分支。
  3. 特性分支:特性分支是为了开发单独的功能而创建的分支。这些分支通常从开发分支派生而来,并在实现目标后被合并回开发分支。在 Git 中,通常使用 feature/ 分支命名约定来表示特性分支。
  4. 发布分支/灰度分支:发布分支是用于准备发布版本的分支,也称为灰度分支,通常从主分支派生而来。这些分支应该包含与发布相关的所有更改,并且应该经过全面测试和审核后再合并回主分支。在 Git 中,通常使用 release/ 分支或 gray/ 分支命名约定来表示发布分支。
  5. 热修复分支:热修复分支通常用于快速修复紧急问题,例如安全漏洞或崩溃。这些分支通常从主分支派生而来,并且只包含必要的更改。在 Git 中,通常使用 hotfix/ 分支命名约定来表示热修复分支。
  6. 此外,还可能会有测试分支 test/等。

通过采用合适的 Git 分支管理策略,可以帮助团队更好地组织和管理代码,提高团队的协作能力和生产效率。除了上述常见的分支管理策略,还可以根据团队的具体需求和工作流程定制适合自己的分支管理策略。

6.多人协作

Git 是一个优秀的多人协作工具,以下是 Git 多人协作的一些最佳实践:

  1. 使用分支:使用分支可以帮助团队成员在不影响主分支的情况下进行开发和测试,避免代码冲突和错误。建议采用主分支、开发分支、特性分支、发布分支、热修复分支等分支管理策略
  2. 提交规范:每次提交代码时应该附加有意义的提交信息,描述本次提交的更改内容和目的。建议采用语义化版本号和提交信息模板等规范,以便更好地记录和追踪代码变更历史。
  3. 定期合并:团队成员应该定期将自己的分支合并回主分支或者开发分支。这可以避免较大的代码冲突和错误,并且保持代码库的整洁和可维护性。
  4. 代码审查:通过代码审查可以确保代码的质量和一致性,并且可以识别和纠正潜在的问题和错误。建议采用 pull request 和 code review 等工具和流程,以便团队成员对彼此的代码进行审查和反馈。
  5. 团队协作:团队成员之间应该保持及时和有效的沟通,共享技术和经验,并尽可能避免个人行为和偏见对项目和团队产生不良影响。

通过采用上述最佳实践,可以帮助团队高效协作、保证代码质量和稳定性,并提高团队的生产力和创造力。

7.多人协作时的冲突解决

当进行多人协作时,难免会出现代码存在冲突而导致推送失败的情况,此时我们就需要解决冲突。

下面用一个例子来模拟一下:

假设你和同事在同一个分支上工作,此时他已经完成了一些工作并将这些工作提交到了远程仓库的分支上。而恰巧你的工作中,对某些同样的文件进行了修改。此时,你尝试推送到远程:

$ git add env.txt$ git commit -m "add new xxx"
[dev 7bd91f1] add new env1 file changed, 1 insertion(+)create mode 100644 env.txt$ git push origin xxx
To github.com:michaelliao/learngit.git! [rejected]        xxx -> xxx (non-fast-forward)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

此时推送失败,因为你的同事的最新提交和你试图推送的提交有冲突。

解决办法也很简单,Git 已经提示我们,先用git pull把最新的提交从origin/master抓下来,然后,在本地合并,解决冲突,再推送

此时执行 git pull ,会提示有冲突,此时手动解决冲突即可(如何解决可以参考前面的内容)。

解决冲突后,再次提交,然后推送。

因此,多人协作的工作模式通常是这样:

  1. 首先,可以试图用 git push origin <branch-name> 推送自己的修改;

  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用 git pull 试图合并;

  3. 如果合并有冲突,则解决冲突,并在本地提交;

  4. 没有冲突或者解决掉冲突后,再用 git push origin <branch-name> 推送就能成功!

这就是多人协作的工作模式,一旦熟悉了,就非常简单。

相关文章:

【Git】Git 分支

Git 分支 1.分支简介 为了真正理解 Git 处理分支的方式&#xff0c;我们需要回顾一下 Git 是如何保存数据的。 或许你还记得 起步 的内容&#xff0c; Git 保存的不是文件的变化或者差异&#xff0c;而是一系列不同时刻的 快照 。 在进行提交操作时&#xff0c;Git 会保存一…...

.NET Upgrade Assistant 升级 .NET MAUI

.NET Upgrade Assistant 是一种可帮助您将应用程序升级到最新的 .NET版本 的工具&#xff0c;并且您可以使用这个工具将您的应用程序从旧平台&#xff08;例如 Xamarin Forms 和 UWP&#xff09;迁移到新的平台。此外&#xff0c;这个新版本的工具&#xff0c;可以让您在不更改…...

记一次诡异的Cannot find declaration to go to,Cannot resolve method

记一次诡异的 Cannot find declaration to go to&#xff0c; Cannot resolve method getOnExpressions in Join 对于项目中通常问题&#xff0c;清除缓存&#xff0c;重启idea&#xff0c;或者仔细检查语法通常都能解决问题&#xff0c;但是这次却失效了&#xff0c;以下是原…...

智慧园区:AI边缘计算技术与视频监控汇聚平台打造智慧园区解决方案

一、行业趋势与背景 智慧园区是现代城市发展的重要组成部分&#xff0c;通过智能化技术提高园区的运营效率、降低成本、增强环境可持续性等具有重要作用。在智慧园区中&#xff0c;人工智能和视频汇聚技术是重要的前置技术。人工智能技术可以实现对数据的智能化处理和分析&…...

SpringCloud(17~21章):Alibaba入门简介、Nacos服务注册和配置中心、Sentinel实现熔断与限流、Seata处理分布式事务

17 SpringCloud Alibaba入门简介 17.1 why会出现SpringCloud alibaba Spring Cloud Netflix项目进入维护模式 https://spring.io/blog/2018/12/12/spring-cloud-greenwich-rc1-available-now 说明 Spring Cloud Netflix Projects Entering Maintenance Mode 什么是维护模…...

Jmeter安装与测试

目录 一&#xff1a;JMeter简介&#xff1a; 二&#xff1a;JMeter安装与配置 三&#xff1a;JMeter主要原件 一&#xff1a;JMeter简介&#xff1a; JMeter&#xff0c;一个100&#xff05;的纯Java桌面应用&#xff0c;由Apache组织的开放源代码项目&#xff0c;它是功能 …...

java开发环境从0开始 【汇总版】

java开发环境从零开始 第一步&#xff1a;jdk第二步&#xff1a;安装 mysql第三步:安装maven第四步&#xff1a;idea最新免费安装第五步&#xff1a;安装navicate第六步 &#xff1a;安装git&#xff0c; 第一步&#xff1a;jdk 第一步当然是最先安装java开发环境啦。 看这个链…...

线性代数的本质(九)——二次型与合同

文章目录 二次型与合同二次型与标准型二次型的分类度量矩阵与合同 二次型与合同 二次型与标准型 Grant&#xff1a;二次型研究的是二次曲面在不同基下的坐标变换 由解析几何的知识&#xff0c;我们了解到二次函数的一次项和常数项只是对函数图像进行平移&#xff0c;并不会改变…...

STM32WB55开发(4)----配置串口打印Debug调试信息

STM32WB55开发----4.配置串口打印Debug调试信息 概述硬件准备视频教学样品申请选择芯片型号配置时钟源配置时钟树RTC时钟配置查看开启STM32_WPAN条件配置HSEM配置IPCC配置RTC启动RF开启蓝牙开启串口调试配置蓝牙参数设置工程信息工程文件设置Keil工程配置代码配置结果演示 概述…...

云原生服务无状态(Stateless)特性的实现

文章目录 为何要使用无状态服务&#xff1f;无状态服务的实现方法1. 会话状态外部化2. 负载均衡3. 自动伸缩4. 容器编排5. 数据存储6. 安全性 示例&#xff1a;使用Spring Boot实现无状态服务结论 &#x1f389;欢迎来到云计算技术应用专栏~云原生服务无状态&#xff08;Statel…...

zookeeper最基础教程

文章目录 一、简介1、工作机制2、特点3、数据结构4、应用场景5、选举机制 二、软件安装1、单机版安装2、集群安装3、配置参数解读(zoo.cfg)4、ZK集群启动脚本 三、命令行操作1、语法2、使用3、节点相关4、监听器原理5、节点删除与查看 三、写数据流程 一、简介 1、工作机制 官…...

又一重磅利好来袭!Zebec Payroll 集成至 Nautilus Chain 主网

流支付协议 Zebec Protocol 正在积极的拓展自身生态&#xff0c;随着此前其全新路线图的发布&#xff0c;揭示了该生态从 Web3 世界向 Web2 世界跨越的决心。根据其最新路线图&#xff0c;Zebec Protocol 正在从最初构建在 Solana 上的流支付协议&#xff0c;拓展为囊括模块化公…...

NLP模型的tokenize方法中return_tensors参数

NLP模型的tokenize方法中return_tensors参数 在许多NLP模型的tokenize方法中,return_tensors参数可以指定tokenize之后返回的张量类型,常见的可选值包括: ‘tf’: 返回TensorFlow的张量对象Tensor。 ‘pt’: 返回PyTorch的张量对象torch.Tensor。 ‘np’: 返回NumPy的ndarray对…...

模方新建工程时,显示空三与模型坐标系不一致怎么解决

答:检查空三xml与模型的metadata.xml的坐标系是否一致&#xff0c;metadata文件是否有在data目录外面。 模方是一款针对实景三维模型的冗余碎片、水面残缺、道路不平、标牌破损、纹理拉伸模糊等共性问题研发的实景三维模型修复编辑软件。模方4.0新增单体化建模模块&#xff0c;…...

氧化锌避雷器绝缘电阻测试

氧化锌避雷器 绝缘电阻测试 试验目的 避雷器绝缘电阻包括本体绝缘电阻和底座绝缘电阻, 主要目的在于初步检查避雷 器内部是否受潮; 有并联电阻者可检查其通、 断、 接触和老化等情况。 试验设备 高压绝缘电阻测试仪 厂家&#xff1a; 湖北众拓高试 试验方法 本体绝缘电阻试验…...

链动2+1系统开发

什么是链动21模式&#xff1f; 链动21主要是一个集团队搭设、快速提升产品销量&#xff0c;与消费者做到合作共赢的一个商业模式&#xff0c;让用户在享受购物折扣的同时&#xff0c;也能获得相对收益&#xff0c;同时公司也能达到产品快速销售这样的一个目的&#xff0c;而链…...

AIGC(生成式AI)试用 4 -- 从模糊到精确

从模糊到精确&#xff0c;也许差异在于 更多的描述&#xff0c;更多的信息更具像的描述&#xff0c;更多的数据&#xff0c;更有效的信息主题明确和目标清晰层次感与条理性更简洁清晰的逻辑 “说清楚点&#xff0c;不太明白&#xff0c;提供更多的信息也许能知道要做什么。” …...

Linux中使用Docker安装ElasticSearch7.10.x集群

使用Docker安装ElasticSearch7.10.x单节点请访问这里 一、集群环境说明 服务器IP地址192.168.137.1&#xff0c;192.168.137.2&#xff0c;192.168.137.3 二、前期准备 1. 拉取镜像 docker pull elasticsearch:7.10.12. 首先需要创建一个用于生成秘钥的初始容器&#xff0…...

electron 左上角图标 dev(开发环境)可显示 build(打包)后无法显示

先说解决方法&#xff0c;用于作为图标的ico文件需要富集多种尺寸&#xff0c;必须包含256*256&#xff0c;且同时应当包含其他更小的尺寸。 例如&#xff1a; 接下来解释一下这么做的原因 ico是Iconfile的缩写&#xff0c;是Windows计算机中的一种图标文件格式&#xff0c;…...

全球与中国BGO晶体市场:增长趋势、竞争格局与前景展望

BGO晶体&#xff0c;全名为Bismuth Germanate Scintillation Crystal&#xff08;铋锗酸盐闪烁晶体&#xff09;&#xff0c;是一种用于探测放射性粒子和射线的闪烁晶体材料。它的主要成分是铋氧化物&#xff08;Bi4Ge3O12&#xff09;&#xff0c;其中铋和锗的特性使得这种晶体…...

华三路由交换技术基础——计算机网络基础

计算机网络&#xff1a; 定义&#xff1a;一组具有自治权的计算机互联的集合 作用&#xff1a; 1.共享信息资源 2.分解式处理信息 4.负载均衡 5.综合信息服务 它是计算机技术与通信技术的两个领域的结合 一&#xff0c;计算机网络中的基本概念&#xff1a; 局域网&#xff…...

Docker搭建RK3568开发环境

推荐&#xff1a;Ubuntu 20.04 版本 Docker加速 # 编辑 Docker 配置文件 $ sudo vim /etc/docker/daemon.json# 加入以下配置项 {"registry-mirrors": ["https://dockerproxy.com","https://hub-mirror.c.163.com","https://mirror.baidu…...

【GAMES202】Real-Time Ray Tracing 1—实时光线追踪1

一、前言 这篇我们开始新的话题—Real-Time Ray Tracing简称RTRT&#xff0c;也就是实时光线追踪&#xff0c;关于光线追踪&#xff0c;我们已经不止一次提到过它的优点&#xff0c;无论是软阴影还是全局光照&#xff0c;光线追踪都很容易做&#xff0c;唯一的缺点就是速度太慢…...

Linux修复损坏的文件系统

如何判断文件系统是否损坏 当文件系统受损时&#xff0c;将会出现一些明显的迹象。例如&#xff0c;文件或文件夹无法访问、文件大小异常、系统启动慢或无法启动等。此外&#xff0c;系统也可能发出一些错误信息&#xff0c;如"Input/output error"、"Filesyst…...

三分钟学会一个新技能——使用Java操作Redis

目录 1、前置准备操作 1.1、为什么要进行前置准备操作 1.2、本地如何访问到云服务上Redis的6379端口号 1.3、配置步骤&#xff1a; 2、配置后本地主机如何操作 3、常用命令举例 3.1、通用命令举例 3.2、string相关命令举例 3.3、hash相关命令举例 3.4、list相关命令…...

Java学习笔记------内部类

内部类的定义&#xff1a; 在一个类的里面再定义一个类 内部类的使用场景&#xff1a; 内部类表示的事物是外部类的一部分&#xff08;B类表示的事物是A类的一部分&#xff0c;且B单独存在没有意义&#xff09;内部类单独出现没有任何意义 内部类的访问特点 内部类可以直接…...

面试题:问js的forEach和map的区别

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 【国庆头像】- 国庆爱国 程序员头像&#xff01;总有一款适合你&#xff01; 前言 为什么要写这么一篇文章&#xff0c;原因是今天下午水群的时候&…...

Hadoop设置固定ip无效的解决办法

今天配置Hadoop的时候&#xff0c;执行vi /etc/sysconfig/network-scripts/ifcfg-ens33修改网络配置文件后&#xff0c;一切正常&#xff0c;但重启后IP改变了&#xff0c;并且在修改以及重启网络连接数次后&#xff0c;IP依旧不按照我在ifcfg-ens33中配置的那样&#xff0c;检…...

论文解读 | 用于3D对象检测的PV-RCNN网络原创

原创 | 文 BFT机器人 01 背景 本文的背景涉及到3D物体检测&#xff0c;这是一个在自动驾驶和机器人等领域应用广泛的重要问题。在这些领域&#xff0c;LiDAR传感器被广泛用于捕捉3D场景信息&#xff0c;生成不规则且稀疏的点云数据。这些点云数据提供了理解和感知3D场景的关键…...

kali安装volatility及插件mimikatz

1.准备工作 kali安装pip2 wget https://bootstrap.pypa.io/pip/2.7/get-pip.py python2 get-pip.py 查看pip2版本 python2 -m pip -v pip2安装升级 pip2 install --upgrade setuptools 安装2个库 pip2 install construct2.10.54 pip2 install pycryptodome 下载文件d…...

郑州seo网站有优化/每日重大军事新闻

目录1. 矩阵元素的运算1.1 矩阵的加减运算1.2 矩阵的乘法运算1.2.0 数与矩阵的乘法1.2.1 矩阵与矩阵的乘法1.3 矩阵的除法运算1.4 矩阵的幂运算1.5 矩阵元素的查找1.6 矩阵元素的排序1.7 矩阵元素的求和1.8 矩阵元素的求积1.9 矩阵元素的差分1. 矩阵元素的运算 1.1 矩阵的加减…...

企事业网站建设的毕业论文/搜狗站长

Spring Cloud 是一系列框架的有序集合。它利用 Spring Boot 的开发便利性&#xff0c;巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务注册、服务发现、配置中心、消息总线、负载均衡、断路器、数据监控等&#xff0c;这些都可以用 Spring Boot 的开发风格做到一键启动…...

手机微网站制作/免费优化

哎&#xff0c;曾几何时 想当年&#xff0c;其实我也特别钟情于 if/else连环写法&#xff0c;上来就是一顿SAO操作&#xff0c;比如举个好理解的简单栗子&#xff1a;一般来说我们正常的后台管理系统都有所谓的角色的概念&#xff0c;不同管理员权限不一样&#xff0c;能够行使…...

气泡做网站上方代码/发稿软文公司

测试用例基础 describe块称为"测试套件"&#xff08;test suite&#xff09;&#xff0c;表示一组相关的测试。它是一个函数&#xff0c;第一个参数是测试套件的名称&#xff08;"加法函数的测试"&#xff09;&#xff0c;第二个参数是一个实际执行的函数。…...

湛江网站建设外包/东莞全网推广

再次的说到Linux&#xff0c;其实Linux就是一个Kernel&#xff0c;其他的都是一个个的源码工具&#xff1a;1、elinks&#xff1a;一种基于文本的web客户端工具&#xff0c;也可将其理解为浏览器格式&#xff1a;elink [OPTTION] [URL]参数&#xff1a;-dump&#xff1a;在显示…...

海淀高端网站建设/河南网站定制

1、打开毕业论文&#xff0c;找到一个表格这里我随便写了一个表格&#xff0c;进行练习使用&#xff0c;数据本身没有参考价值2、点击一下表格&#xff0c;点击表设计&#xff0c;点击下面那个箭头3、选择新建表格样式4、首先&#xff0c;我们给这个模板命名为三线表&#xff0…...