git-flow分支模型:从原文到使用(建议收藏~)

本文先是对Vincent Driessen提出git-flow分支模型的原文逐句进行了翻译 ,然后提取文中有价值的信息;在此基础之上详细解释了git-flow的工作流程 ;最后举例说明了git-flow在开发过程中的使用。阅读本文,您可以收获:

  • Vincent Driessen提出git-flow模型时候的背景知识和他对于git的一些思考;
  • git-flow模型的原理和设计思路;
  • git-flow在实践中的应用;
  • 常见的git-flow命令。

翻译/创作不易,如果这篇文章对您有些许启示,欢迎在留言区讨论,谢谢!

一、 git-flow分支模型的提出

开始之前,让我们先拜读Vincent Driessen 在2010.01.05 发布的一篇文章。

原文地址为:nvie.com


原文开始


一个成功的Git分支模型 -- Vincent Driessen

2020年3月5日更新

这个模型是在 2010 年构思的,当时 Git 本身也刚出现不久,时光如梭,现在已经有 10 多年了。在这10年里,git-flow(指的是2010.01.05发布的文章中介绍的分支模型)在许多软件团队中变得非常流行,人们开始把它当作一种标准。但不幸的是,它也被当作一种教条或灵丹妙药。

在这些10年中,Git已经风靡全球,并且使用Git开发的最流行的软件正在向Web应用转变。Web应用通常是持续交付的,不会回滚,并且您不必支持在广泛应用中运行的多个软件版本

当我在10年前写这篇博文时,并不是指的这类(持续交付的)软件。如果你的团队正在进行持续交付类软件的开发,我建议采用更简单的工作流程(比如GitHub flow ),而不是试图将git-flow硬塞到你的团队中。

然而,如果你正在构建有明确版本 的软件,或者需要支持多个软件版本,那么git-flow可能仍然适合你的团队,就像在过去的10年里适合其他人一样。

总之,永远记住并不存在万灵药。要考虑自己的实际情况,不要盲目崇拜某种方法。

正文 -- 写于2010.01.05

在这篇文章中,我介绍了我大约一年前为我的一些项目(包括工作和私人项目)引入的开发模型,而这个模型已经被证明非常成功。我不会谈论任何项目的细节,只会讨论分支策略和发布管理 。下面这个全景图涵盖了本文关于分支模型讨论的所有方面。

1. 为什么是git?

关于Git相对于集中式源代码控制系统的优缺点 的讨论,请参考网络上的相关内容。作为一名开发者,我更喜欢Git,它真正改变了开发者对合并和分支 的思考方式。从我过去使用的经典CVS/Subversion角度来看,合并/分支相关的操作一直被认为有些可怕,而且是偶尔才会进行的操作。

但是在Git中,这些操作非常简单和廉价,并且它们被视为日常工作流程的核心部分之一 。例如,在CVS/Subversion相关的书籍中,分支和合并通常在后面的章节中讨论(供高级用户使用),而在每本Git的书籍中,它已经在第3章中涵盖了基础知识。

由于其简单性和重复性,分支和合并不再是令人害怕的事情。版本控制工具应该在分支/合并方面提供帮助,而不仅仅是其他方面。

关于使用哪种工具的讨论到此为止,我们继续进入开发模型。我在这里要介绍的模型实际上不过是一组团队成员必须遵循的流程,以建立一个受控的软件开发过程。

2. 分散但集中

我们使用的存储库设置与这个分支模型很好地配合,它是具有一个中央"真实"存储库的设置。请注意,这个存储库是假想的中央存储库(因为Git是一种分布式版本控制系统,在技术层面上没有中央存储库的概念)。我们将把这个存储库称为origin,因为这个名称对所有Git用户来说都很熟悉。

每个开发者都从origin进行拉取和推送操作。但除了集中化的推拉关系外,每个开发者还可以从其他同行那里拉取更改以形成子团队。例如,在将工作进展 推送到origin之前,与两个或更多的开发者一起合作完成一个大型新功能可能会很有用。在上面的图中,有Alice和Bob、Alice和David、Clair和David这些子团队(正如上图所示)。 (笔者注:这段话作者是在说,使用git的团队可以做到大型新功能的开发由多个团队合作完成) 从技术上讲,这意味着Alice在Git中定义了一个名为bob的远程库,指向Bob的存储库,反之亦然。

3. main分支

这个开发模型受到了现有模型的很大启发。抽象出来的中央存储库origin包含两个持久化分支:

    1. master
    1. develop

origin/master分支对于每个Git用户来说应该是熟悉的。与master分支并行存在的另一个分支称为develop。两者的关系如下图所示:

我们认为origin/master是主分支,(原因是:)其中HEAD的源代码始终反映出一个可供生产使用的状态

我们认为origin/develop是主分支,(原因是:)其中HEAD的源代码始终反映出下一个发布的最新开发变更的状态。有些人将其称为"集成分支"。

当develop分支中的源代码达到稳定点并准备好发布时,所有的变更都应该以某种方式合并回master,并标记一个发布号。这一过程如何具体完成将在后面进一步讨论。

因此,每次将变更合并回master时,将会产生一个新的生产发布。这一点应该严格遵守。我们可以使用Git钩子脚本,在master上提交时自动构建和部署我们的软件到生产服务器。

4. Supporting分支

除了主分支master和develop外,我们的开发模型还使用了各种支持分支,以帮助团队成员进行并行开发 ,方便追踪功能为生产发布做准备 ,并在快速修复实 时生产问题时提供帮助。与主分支不同,这些分支总是有限的生命周期,因为它们最终将被删除。

这些supporting分支包括:

    1. feature(功能)分支
    1. release(发布)分支
    1. hotfix(热修复)分支

每个分支都有特定的目的,并受到严格的规则约束,规定了哪些分支可以作为其源分支,哪些分支必须作为其合并目标分支。接下来我们将逐一介绍它们。

4.1. Feature分支

  • 可以从以下分支创建:
    • develop
  • 必须合并回:
    • develop
  • 分支命名约定:
    • 除了master、develop、release-*或hotfix-*之外的任何名称

上述关系表示如下图:

功能分支(有时也称为主题分支)用于开发即将到来或遥远未来版本的新功能 。当开始开发一个功能时,此功能将被合并到哪个目标发布中可能还不清楚。功能分支的本质是它存在于功能开发期间,但最终将被合并 回develop(以确保新功能添加到即将发布的版本中)或被丢弃(在需求更改或者开发失败的情况下)。

功能分支通常只存在于开发者的存储库中,而不在origin中

4.1.1. 创建一个feature分支

开始开发一个新功能时,从develop分支创建一个新的分支。

bash 复制代码
$ git checkout -b myfeature develop # Switched to a new branch "myfeature"

在develop分支上合并一个已完成的功能。 已完成的功能可以合并到develop分支,以确保将它们添加到即将发布的版本中:

bash 复制代码
$ git checkout develop # Switched to branch 'develop'
$ git merge --no-ff myfeature 
# Updating ea1b82a..05e9557
# (Summary of changes)
$ git branch -d myfeature # Deleted branch myfeature (was 05e9557).
$ git push origin develop

使用--no-ff标志会导致合并始终创建一个新的提交记录。这样可以避免丢失有关功能分支历史存在的信息,并将一起添加功能的所有提交组合在一起。对比:

在后一种情况下,从Git历史中无法看出哪些提交记录共同实现了一个功能,您将不得不手动阅读所有的日志信息。在后一种情况下,撤销整个功能(即一组提交)会变得非常困难,而如果使用--no-ff标志,则可以轻松完成。

是的,它会创建更多(空的)提交记录,但是收益远大于成本

4.2. Release分支

  • 可以从以下分支创建:
    • develop
  • 必须合并回:
    • develop和master
  • 分支命名约定:
    • release-*

发布分支用于准备新的生产发布 。它们允许最后一刻的修补漏洞和完善细节。此外,它们还允许进行小的错误修复和为发布准备元数据(版本号、构建日期等)。通过在发布分支上完成所有这些工作,开发分支就可以为下一个重大发布接收新功能。

从develop分支创建一个新的发布分支的关键时刻是当develop(几乎)反映出新发布的期望状态时。至少此时应将所有目标为要构建的发布的功能合并到develop中。所有打算在未来版本中发布的功能都不可以被合并,它们必须等待发布分支创建后再合并。 (笔者注:release分支存在时,feature分支中的内容不可以再合并到develop分支中)

在release分支被创建之后,会给下一次的master分配一个版本号;这个版本号必须是在release分支被创建之后才决定的,develop分支对于这个版本号是无感的,也不应该参与到版本号的确定过程中来。也就是说,release分支完全决定了下一次master的版本号。

4.2.1 创建一个Release分支

发布分支是从develop分支创建的。例如,假设版本1.1.5是当前的生产发布,而我们即将发布一个重大版本。develop分支的状态已准备好用于"下一个发布",我们已经决定这将成为1.2版本(而不是1.1.6或2.0)。因此,我们创建一个发布分支,并给它一个反映新版本号的名称:

bash 复制代码
$ git checkout -b release-1.2 develop # Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2 # Files modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
# [release-1.2 74d9424] Bumped version number to 1.2
# 1 files changed, 1 insertions(+), 1 deletions(-)

创建一个新分支并切换到它后,我们会升级版本号。在这里,bump-version.sh是一个虚构的shell脚本,用来改变记录软件版本号的文件。然后,提交commit后的版本号。

这个release分支可能会存在一段时间,直到可以正式发布该版本(指的是合并到master分支上去)。在此期间,可以在此分支上应用错误修复 (而不是在develop分支上)。严格禁止在此处添加大型新功能它们在生命周期结束之前必须合并到develop分支,因此需要等待下一个重大发布

4.2.2 Release分支的结束

当release中的bug被修改完毕,正式发布之前需要做如下工作:

    1. 首先,将发布分支合并到master(因为每个在master上的提交都是一个新的发布,根据定义来说)。
    1. 接下来,在master上的那个提交必须被标记,以便将来可以轻松地参考这个历史版本。
    1. 最后,需要将在发布分支上进行的更改合并回develop,以便将来的发布也包含了这些错误修复。 (笔者注:简单来说就是合并到master和develop分支上去,并在合并到master分支之后打上tag)

Git操作如下:

bash 复制代码
$ git checkout master # Switched to branch 'master'
$ git merge --no-ff release-1.2
# Merge made by recursive.
# (Summary of changes)
$ git tag -a 1.2

现在发布已完成,并为将来的参考进行了标记。

为了保留在发布分支上进行的更改,我们需要将其合并回develop分支。在Git中执行如下操作:

bash 复制代码
$ git checkout develop
# Switched to branch 'develop'
$ git merge --no-ff release-1.2
# Merge made by recursive.
# (Summary of changes)

这一步可能会导致合并冲突(尤其是因为我们更改了版本号)。如果发生冲突,请解决冲突并提交。

现在我们真正完成了,发布分支可以被删除,因为我们不再需要它:

bash 复制代码
$ git branch -d release-1.2
# Deleted branch release-1.2 (was ff452fe).

4.3. Hotfix分支

  • 可以从以下分支创建:
    • master
  • 必须合并回:
    • develop和master
  • 分支命名约定:
    • hotfix-*

上述关系表示如下:

热修复分支与发布分支非常类似 ,它们都是为了准备新的生产发布,尽管是非计划性的 。 (笔者注:理想情况下,master在运行过程中不应该有bug,可是难免会出现意想不到的问题,这个时候并没有打算发布一个新版本的计划,所以需要使用hotfix分支紧急处理此bug) 热修复分支的存在是为了立即处理生产版本中不希望出现的问题。当需要立即解决生产版本中的关键错误时,可以从标记了生产版本的master分支上创建一个热修复分支

hotfix处理的问题是:在团队成员在develop分支上继续开发新功能的同时,另一个人可能正在处理紧急的线上bug。

4.3.1 创建Hotfix分支

热修复分支是从master分支创建的。例如,假设版本1.2是当前正在运行并由于严重错误而引起麻烦的生产发布版本。但是develop上的更改尚不稳定。然后,我们可以创建一个热修复分支并开始解决问题:

bash 复制代码
$ git checkout -b hotfix-1.2.1 master # Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1 # Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
# [hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
# 1 files changed, 1 insertions(+), 1 deletions(-)

不要忘记在创建分支后升级版本号!

然后,修复bug并将修复内容提交为一个或多个单独的提交。

bash 复制代码
$ git commit -m "Fixed severe production problem"
# [hotfix-1.2.1 abbe5d6] Fixed severe production problem
# 5 files changed, 32 insertions(+), 17 deletions(-)

4.3.2 结束Hotfix分支

当完成修复后,需要将bug修复合并回master分支,并且还需要将其合并回develop分支,以确保该bug修复也包含在下一个发布中。这与完成发布分支的方式完全相似。

首先,更新master分支并为发布做标记。

bash 复制代码
$ git checkout master # Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
# Merge made by recursive.
# (Summary of changes)
$ git tag -a 1.2.1

接下来,也要将bug修复包含在develop分支中:

bash 复制代码
$ git checkout develop
# Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
# Merge made by recursive.
# (Summary of changes)

这里的一个例外是,如果当前存在发布分支,那么热修复的更改需要合并到该发布分支中,而不是develop分支。将bug修复向后合并到发布分支最终会导致在发布分支完成时将bug修复合并到develop分支中。(如果develop分支中的工作立即需要此bug修复,并且不能等待发布分支完成,您也可以安全地将bug修复现在就合并到develop分支中。) (笔者注:这里作者在讲如果release分支存在的时候,线上出现了紧急bug,该如何做?给出的解决办法仍然是使用hotfix分支,当紧急bug解决之后hotfix无疑是要合并到master中去的,并且也要合并到release分支中,但是要不要合并到develop中去要视情况而定,情况一:此紧急bug如果影响到了develop的工作,那就将其合并到develop中;情况二:此紧急bug不影响现在develop的工作,那就可以将其合并到release中,反正release在销毁之前也要合并到develop中,无非是时间上靠后一些)

最后,删除临时分支:

bash 复制代码
$ git branch -d hotfix-1.2.1
# Deleted branch hotfix-1.2.1 (was abbe5d6).

5. 总结

虽然这个分支模型没有什么特别新颖的地方,但它构建了一个优雅的心智模型,易于理解,并让团队成员形成对分支和发布过程的共同理解。


原文结束


二、 原文重点信息摘要

从原文中摘取出来的一些有用的信息,与git-flow相关或者无关,但是对于提升对git的认识十分有帮助的:

  1. git-flow分支模型发布十年之后,作者建议:如果开发的软件有明确的版本,则推荐使用git-flow这种分支模型;如果软件是持续交付的则使用GitHub flow分支模型。强调了不要教条。
  2. 作者对git-flow有着清晰的定义:它是一种分支和发布管理的策略(或者模型),用来约束软件开发过程。
  3. git-flow模型将分支划分成两种:无限生命周期的分支(master, develop)和有限生命周期的分支(feature, release, hotfix);前者又被称为main(主)分支 ,后者被称为supporting(辅助)分支
  4. master分支作为主分支的原因是:master分支始终代表的是最新的生产环境 中的代码;而develop分支作为主分支的原因是:develop分支始终待变的是最新的开发环境下的代码。
  5. 有限生命周期分支的一个特点就是:最终会被删除。
  6. feature分支必须基于develop分支创建,生命周期结束之前必须合并回develop分支,或者被丢弃。
  7. 作者推荐在使用git merge的时候带上--no-ff,因为这样做可以保留更多的提交信息,但是代价是会多一次空的提交记录。
  8. release分支必须基于develop分支创建,并且在生命周期结束之前必须合并回develop和master分支,注意这里是"和"不是"或"。
  9. hotfix分支必须基于【标记了生产版本的】master分支创建,并且在生命周期结束之前必须合并回develop和master分支,注意这里是"和"不是"或"。
  10. master分支线上运行的时候,develop分支上可能已经有了不稳定的新功能,所以无法通过develop创建新的release分支。hotfix分支存在的意义在于修复master分支上的紧急问题。
  11. 在整个过程中,只有master分支需要被tag,往mater分支上打tag的时机有两个,一个是release合并到master时,此时master应该增加一个大版本号 ,另外一个是hotfix合并到master时,这个时候master应该增加一个小版本号
  12. 解决master上的bug使用的永远都是hotfix分支,当在hotfix分支上修复线上bug,修复完成之后将hotfix合并到master分支上,并tag;然后,如果此时release分支存在,就将hotfix合并到release分支上,如果release分支不存在,就将hotfix合并到develop上;如果release存在,并且develop因为此紧急bug无法继续开发,那就将hotfix同时合并到release和develop分支上。

三、git-flow设计目标

  • 并行开发:允许多个团队成员同时进行独立的功能开发,而不会造成混乱和代码冲突。
  • 版本控制:提供清晰的版本控制机制,使得每个发布版本都能够被标记和追踪。
  • Bug修复和紧急处理:允许团队快速响应Bug修复和紧急处理的需求,并确保这些修复能够顺利地集成到主要分支中。
  • 长期维护:支持对已发布版本的长期维护和修复,以满足用户需求。

四、git-flow全景图详细分析

如果您看原文译文比较吃力(很大一部分原因是我翻译的不好),那么在这个小节,我将通过多个维度详细分析文章中给出的git-flow分支模型的全景图,力求将该模型的工作流程解释清楚。

1. 从左向右理解全景图

  1. 上图从左往右的各个分支分别为feature, develop, release, hotfixes, master,其中红色框住的有feature,release,hotfixes,它们统称为support分支,特点是有限的生命周期 ,即使用完之后会被删除掉。蓝色框住的是develop和master,它们俩又称为main分支,特点是无限生命周期 ,又称为持久化分支
  2. 在五个框顶部都各有一行小字,表示这个分支与bug 的关系。在feature和develop分支上标注no bug ,意思是对于这两个分支来说不存在bug一说,因为这个时候准确的叫法是不稳定的新功能 。在release分支上的小字是release bug ,用这样的记号是为了区别后面的urgent bug,release bug只存在于release分支上,并且由release分支负责fix,fix之后有三种处理方式:①修改只停留在release上;②修改被合并到develop上;③修改被合并到develop和release上,如下图所示:
  • 第一种情况适用的场景:开发根本就没好好加班,release上的bug实在是太多了,光是小徐就分到了100个bug要改,今天上午才改了1个,这个时候将修改合并到develop上去没有意义,不说了,小徐要在release上修改剩下的99个了。
  • 第二种情况对应的场景:release上爆出来一个bug,这个bug非常的致命,已经影响到了后续新功能的开发,需要优先解决,所以被解决之后立马会合并到develop分支中;或者,虽然小徐还有99个bug没改,但是小徐一向谨慎认真,为了尽量不影响其他同事,所以小徐每改一个就将代码合并到develop中一次,他不怕麻烦。
  • 第三种情况对应的场景:小徐加了一周班,终于把100个bug解决了,可以从预上线release分支正式上线到master了,这个时候需要将release上修改的内容合并到master和develop上,保证master在tag的时候develop和master上的代码是相同的。
  • 显然,第三种情况要慎之又慎,因为一旦release合并到master,release就会消失。
  1. 在master分支上的小字是urgent bug ,含义是紧急bug ,紧急bug的修复和release bug的修复方式不同,紧急bug只能通过新建分支的方式进行合并,原因是master分支上的内容必须通过merge进行修改,并且每次merge之后版本号都要发生变化 ,也就是说master的内容不可能和release分支上一样可以直接在本分支上修改。用来修改紧急bug的分支就是hotfix 分支,在hotfix分支上修改完之后会合并到develop和master分支上,并且改变master分支的小版本号,如下图所示:

遗憾的是,Vincent Driessen的文章中,对hotfix分支修改线上bug分两种情况进行了讨论,但是他给出的全景图只展示了一种。为了弥补这个遗憾,我将在下一个维度看这幅全景图的时候补上这种情况

  1. 最后来看看feature和develop的关系。显然,feature只和develop有关系,和其他三个分支都没有关系,因为feature分支从develop分支来,又回到develop分支去。但是事实果真如此吗?

2. 从上到下理解全景图

根据release分支的存在与否,可以将全景图分成三个部分:①release分支创建之前;②release分支存在时;③release分支销毁后。

2.1 release分支创建之前

下图是release分支创建之前的部分:

这个时候,强调两件事情:

  1. 只有release创建之前的feature会进入到下一个版本,下图中的feature1就会进入1.0版本,而feature2就不会。
  1. release创建之前的hotfix只需要无脑合并到develop和master中就可以了。

2.2 release分支创建存在时

这个时候的情况表示为:

这个时候,develop专心于解决bug,强调两件事:

  1. feature不可以在release存在的时候合并到develop上去。
  1. 如果此时有urgent bug, 虽然还是创建hotfix分支解决,但是又和release出现之前有所不同,会出现两种情况,如下图所示: 情况一:hotfix的修改不会影响到目前develop分支的开发,所以先合并到release上,等release销毁前再同其他内容一起合并到develop上。

情况二:这个urgent bug非常关键,不仅影响到了master,还使develop目前的工作无法继续开展,所以需要将修改内容立刻合并到develop上去。

这种情况的分析见上文原文重点信息摘要12条。

2.3 release分支销毁之后

此时的情况如下图所示:

此时,强调三件事:①feature可以向develop中合并了;②develop和master中的内容再release销毁之后是相同的;③master的大版本号改变了。

3. 理解全景图中的环路

全景图中存在有6个环路,从左到右,从上到下依次来看:

  1. 红色:这个环路从develop出发,到feature,最后汇入develop,表示的含义是跨版本的新功能开发的过程。
  2. 蓝色:这个环路从develop出发,到feature,最后汇入develop,表示的含义是新版本中要包含的新功能的开发过程。
  3. 草绿色:这个环路从develop出发,到feature,最后汇入develop,但是创建的时候release分支也存在,实际上表示的含义是基于release中已经修改了bug之后的develop进行新功能的开发。
  4. 橘色:这个环路从develop出发,到release,最后汇入develop,表示的含义是release中修复了影响下个新功能开发的bug。
  5. 灰色:这个环路从develop出发,到release,最后汇入develop,表示的含义是融入新功能之后的软件版本升级。
  6. 黄色:这个环路从master出发,到release,最后汇入master,表示的含义是线上bug紧急修复。

五、使用git-flow

要使用Gitflow工作流程,需要先安装并配置git-flow插件。以下是安装和使用git-flow的一般步骤:

  1. 安装git-flow插件 :在vscode插件商城中搜索gitflow并进行安装。
  2. 初始化仓库 :进入项目目录,并使用以下命令初始化Git仓库:git init
  3. 启用git-flow :在项目目录中执行以下命令以启用git-flowgit flow initgitflow插件将引导您进行一些基本配置选择,如选择主分支名和临时分支名的前缀等。
  4. 开始开发新功能 :执行git flow feature start <feature-name>命令以从develop分支创建一个新的功能分支。
  5. 完成功能开发 :在功能分支上进行代码编写、测试和提交。完成后,使用git flow feature finish <feature-name>命令将功能分支合并回develop分支。
  6. 发布新版本 :执行git flow release start <release-version>命令以从develop分支创建一个新的发布分支。在发布分支上进行测试、Bug修复等操作。完成后,使用git flow release finish <release-version>命令将发布分支合并回developmaster分支,并打上版本标签。
  7. 紧急修复 :如果在已发布版本中发现紧急Bug,可以使用git flow hotfix start <hotfix-name>命令创建一个紧急修复分支。在修复分支上进行修复,并使用git flow hotfix finish <hotfix-name>命令将其合并回developmaster分支。

六、git-flow相关指令

  • git flow feature publish <feature-name>:将功能分支推送到远程仓库。
  • git flow feature track <feature-name>:从远程仓库跟踪某个功能分支。
  • git flow feature pull <remote> <feature-name>:从远程仓库拉取某个功能分支。
  • git flow hotfix publish <hotfix-name>:将修复分支推送到远程仓库。
  • git flow hotfix track <hotfix-name>:从远程仓库跟踪某个修复分支。
  • git flow hotfix pull <remote> <hotfix-name>:从远程仓库拉取某个修复分支。
相关推荐
DN金猿2 小时前
git命令恢复/还原某个文件、删除远程仓库中的文件
git
DWei_GaGa5 小时前
Git:查看分支、创建分支、合并分支
git
涵信7 小时前
Windows11 安装 Ubuntu-20.04,同时安装配置 zsh shell,配置 git 别名(alias),大大提高开发效率
linux·git·ubuntu·bash
喝鸡汤10 小时前
一起学Git【第五节:git版本回退】
git
web Rookie11 小时前
Git的简介
git
苏三有春16 小时前
五分钟学会如何在GitHub上自动化部署个人博客(hugo框架 + stack主题)
git·go·github
high20111 天前
【Git】-- 版本说明
git
kaixin_learn_qt_ing1 天前
git clone
git
sin22011 天前
git stash
git
喝鸡汤1 天前
一起学Git【第二节:创建版本库】
git