【Git】Git 分支

Git-提交时On branch master Your branch is up to date with Git-提交时On branch master Your branch is up to date with ‘origin/master’. nothing to commit, worki… 如图所示: On branch master Your branch is up to date with 'origin/master'. nothing to commit, working ... 阅读详情

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

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

完成创建后的结构如下:

在这里插入图片描述

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

但是这里还有一个问题: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 address
 1 file changed, 2 insertions(+)

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

在这里插入图片描述

合并分支 — 情况1

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

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

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
 index.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 会使用两个分支的末端所指的快照(C4 和 C5)以及这两个分支的公共祖先(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.html

no 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 env
 1 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】分支

Git 分支

qq_74897518的博客 1598

git commit 出现On branch master nothing to commit, working tree clean解决方法

回车后直接进入merge编辑信息页面,直接:wq退出。

weixin_52090716的博客 2万+

git创建分支

分支命名规范: master: master 分支就叫master 分支 develop: develop 分支就叫develop 分支 feature: feature 分支 咱们暂时可以按 feature_wechat_v2.0.1 这种命名规范来,后面有更好的命名规范咱们再改。v2.0.1 表示当前迭代的版本号,wechat 表示当前迭代的名称,这里我们是开发小程序迭代,就命名了 wechat release: release 分支的名称我们直接命名为这次需求的版本号,比如:2.0.1

King Saj 4万+

Git命令实战

基本的 Git 工作流程 在工作目录中修改文件 暂存文件,将文件的快照放入暂存区域 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录 git help帮助命令 'git help -a' and 'git help -g' list available subcommands and some concept guides. See 'git help &amp;lt;command...

bwangk的博客 613

Super4PCS文章阅读笔记

Super4PCS阅读笔记 Super4PCS阅读笔记 前言 前言 今天给大家分享一下点云配准四点法4PCS0的变种——Super4PCS。此算法的原文在:Super4PCS: Fast Global Pointcloud Registration via Smart Indexing。稍微我也会写一篇关于如何使用这篇文章的里所提供的代码进行点云粗配准。关于四点法...

Vodake的博客 4539

RK3588+TRL8367s 四网口千兆交换机配置与优化实战

本文详细介绍了基于RK3588高性能SoC与TRL8367s千兆交换芯片构建四网口交换机的完整实战流程。内容涵盖硬件连接、设备树配置、内核驱动加载、性能优化及常见问题排查,重点解析了RGMII时序调试、DSA架构配置等关键步骤,为嵌入式网络设备开发提供实用指南。

weixin_29266647的博客 672

git常用命令

由于git的命令有很多,在这里我们只去讲解常用的命令 第一个和第二个命令是设置用户签名(用户名,邮箱),只需要设置一次,并且必须要配置不然后面提交代码时候会报错,命令如下, 要看是否设置成功可以去C盘用户名为命令板上的目录下有一个.gitconfig文件,用文本打开,如下就配置成功: 签名的作用是区分不同的操作者身份 git init -----初始化本地库的 2.git status ----初始化本地库初始化git后需要看一下git的状态 可以发现有三行...

m0_57254953的博客 603

IAR9.20.4安装与注册全攻略:附资源及典型问题解决方案

本文提供IAR9.20.4的详细安装与注册指南,涵盖环境准备、安装步骤、权限设置及注册机使用技巧。针对典型问题如评估版残留、权限不足和杀毒软件拦截等,给出了具体解决方案,帮助用户顺利完成IAR开发环境的搭建与激活。

a2b3c4d5e的博客 296

[GIT]如何删除分支

git删除分支操作

weixin_43288065的博客 6万+

Excel数字变成了小数点+E+17?这些方法帮你解决!

本文介绍了三种解决Excel中数字变成小数点+E+17问题的方法:通过下拉箭头或右键菜单设置单元格格式为文本、使用TEXT函数将科学计数法转换为文本。这些方法各有优缺点,适用于不同的场景和需求。在实际应用中,我们可以根据具体情况选择合适的方法来解决问题。通过以上方法,我们可以轻松地从繁琐的小数点+E+17问题中解脱出来,更便捷地处理Excel中的数字。希望本文能够帮助到您,让您在使用Excel时更加得心应手!

nntxthml的博客 1245

Klipper-源码模块

Klippy上位机程序采用多线程架构,包含四个主要进程:主线程处理G代码命令、串口IO线程(C语言实现)、MCU响应处理线程(Python实现)和独立日志线程。代码结构分为三大模块:chelper(C语言辅助函数)、extras(扩展功能如温度控制)和kinematics(运动学模型实现)。核心功能模块包括串口通信(serialhdl.py)、步进电机控制(stepper.py)、运动学计算等,其中C语言实现的底层模块通过serialqueue.c处理高效IO。扩展模块支持热床、传感器等外设,运动学子模块提

weixin_44258581的博客 991

git查看分支、创建分支、合并分支

git branch 列出本地已经存在的分支,并且当前分支会用*标记 git branch -r 查看远程版本库的分支列表 git branch -a 查看所有分支列表(包括本地和远程,remotes/开头的表示远程分支) git branch -v 查看一个分支的最后一次提交 git branch --merged 查看哪些分支已经合并到当前分支 git branch --no-merged 查看所有未合并工作的分支

读书郎 1万+

C/C++基础讲解(四十三)之图形篇之绘制直线、圆、圆弧、 椭圆

程序主要是基于Visual studio 2019进行编译完成了,有兴趣的小伙伴可以自己安装下Visual studio 2019,网上有现成的教程,当然了,如果有问题,也可以和我联系,这里我们主要讲解些源码实例,不多说了,言归正传。 C语言,做为学习其他语言的基础语言,其重要性就不言而喻了.下面我将和大家一起来学习探讨C语言的相关奥秘。 实例1:绘制直线 实例2:绘制圆 实例2:绘制圆弧 实例2:绘制椭圆

hnjzfwy的博客 1234

Git之分支管理

本文介绍了Git的重要功能之一——分支。从分支的概念引入,介绍了管理分支的命令,通过举例的方式使其更为直观,更易理解。

一只小卷毛的博客 1737

yocto系列讲解[实战篇]54 - 添加Qt5和生成带Qt5的SDK

为了满足读者盆友想看yocto如何添加qt5的需求,今天就开始尝试添加meta-qt5

fulinux的博客 3870

仅使用 Python 创建的 Web 应用程序(前端版本)第03章Streamlit-多页面

接下来,我们将解释多页面切换。Streamlit 没有“多页面”或“页面路由”等功能。另一方面,通过根据用户动作切换要执行的功能,可以使其看起来好像存在“多个页面”。注意:我认为它类似于 SinglePageApplication (SPA)。然而,根据 React、Vue 等中使用的 URL 路径来更改页面的路由很困难。还有一个用于获取查询参数的实验性 API,但如果您确实需要这种功能,我认为认真尝试编写 React 或 Vue 是个好主意。我们来看一个通过按下按钮来切换页面的示例,如下所示。

xianyinsuifeng的博客 1327

Git之Git分支

语句解释git branch查看分支列表git branch 分支名称创建新分支git checkout 分支名称切换分支git checkout -b 分支名称分支的快速创建和切换git merge 要合并的分支名称合并分支。注意:假设要把 C 分支的代码合并到 A 分支,则必须先切换到 A 分支上,再运行 git merge 命令,来合并 C 分支!git branch -d 分支名称删除分支遇到冲突手动解决。

xrkhy的博客 1261

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Git拉分支及合并分支

拉分支: 比如我们像从master主干拉取一个新分支我们需要先切换到master分支,并且更新到最新然后创建分支并且关联远程仓库: git checkout master git pull git checkout -b dev1.0 //稍等一会会发现分支会自动切换到dev1.0 git push origin dev1.0 git push --set-upstream origin dev1.0 //修改了的东西要提交,不然你切回master的时候会发现,分支上修改的东西在master

天涯芳草 3844

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Git 分支篇之远程分支

本文转载自Pro Git(中文版)   远程分支(remote branch)是对远程仓库中的分支的索引。它们是一些无法移动的本地分支;只有在 Git 进行网络交互时才会更新。远程分支就像是书签,提醒着你上次连接远程仓库时上面各分支的位置。   我们用 远程仓库名/分支名 这样的形式表示远程分支。比如我们想看看上次和 origin 仓库进行通讯时 master 分支的样子,就应该查看 origin/master 分支。如果你和同伴一起修复某个问题,但他们先推送了一个 iss53 分支到远程仓库,虽然你可.

柚咖小窝 9112

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Git分支:什么是分支,如何管理分支?

一、前言 如果有人问你,当下最流行的“版本管理系统”(Version Control System)是什么,那你一定要毫不犹豫的告诉他,非Git莫属。 Git 相比同类软件,Git有很多优点。其中很显著的一点,就是版本的分支(branch)和合并(merge)十分方便。有些传统的版本管理软件,分支操作实际上会生成一份现有的代码的物理拷贝,而Git只生成一个指向当前版本(又称”快照“)的...

Smile yourlife 4993

git命令切换分支、更新分支

1、查看分支: 命令:git branch -a $ git branch -a master remotes/origin/20201228 remotes/origin/HEAD -> origin/master remotes/origin/develop remotes/origin/master 2、切换分支: 命令:git checkout -b 20201228 origin/20201228 第一个参数 - 20201228:是下载到本地的分支名称 第二个参数 -

GreatOneDay的博客 1万+

【Git】Git 分支创建分支、分支合并、分支删除

文章目录创建分支合并分支删除分支删除本地分支删除远程分支 创建分支 从master创建分支或者从分支上面建立一个分支是一样的: 想从master或者dev分支上面创建新的分支,先切换分支到master或者dev,以master为例: git checkout master 创建一个本地分支dev_1,并切换到该分支上 git checkout -b dev_1 创建一个对应的远程分支 ...

汪雯琦的博客 727

git 查看分支的源分支_Git必知必会之Git分支

一、什么是Git分支能够熟练使用Git 分支操作是掌握分布式版本控制系统的基础,当我们创建一个仓库并对仓库进行初始化之后,该仓库会就会创建一个默认的 master 分支,而这个 master 分支可以被当做是最开始的主分支。Git 分支的创建不限制于网络,具有本地特性,而且还可以根据我们的需求来创建多个分支,这些分支可以是为了修复程序中的某个 bug 而存在 ,或者是为了增加当前程序的一些新特性都...

weixin_32300981的博客 2975

Git分支

在版本回退⾥,每次提交,Git都把它们串成⼀条时间线,这条时间线就可以理解为是⼀个分⽀。截⽌到⽬前,只有⼀条时间线,在Git⾥,这个分⽀叫主分⽀,即master分⽀。再来理解一下HEAD,HEAD严格来说不是指向提交,而是指向master。每次提交,master分⽀都会向前移动⼀步,这样,随着你不断提交,master分⽀的线也越来越⻓,⽽ HEAD只要⼀直指向master分⽀即可指向当前分⽀。

KrisZhang10的博客 1369

管理Git的分支

一、

qq_53514756的博客 3882

Git查看本地分支、远程分支、所有分支

Git查看本地分支、远程分支、所有分支 查看本地分支 git branch 查看远程分支 git branch -r -r 表示 remote 查看所有分支 git branch -a ...

chunguang.yao的博客 16万+
上一篇: 【Git】Git 基础
下一篇: 【Git】Git 变基(rebase)以及rebase和merge之间的区别
cannotbecounted
博客等级 码龄7年 101粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值