总言
主要内容:主要介绍Git中常用的指令。
PS:多人协作与企业开发模型使用,此部分内容不作博文总结。
文章目录
- 总言
- 1、初识Git
- 1.1、版本控制器
- 1.2、git安装
- 2、基本操作
- 2.1、Git本地仓库
- 2.1.1、创建Git本地仓库:git init
- 2.1.2、配置Git本地仓库:git config
- 2.3、认识工作区、暂存区、版本库
- 2.4、文件修改(新增、修改、删除)
- 2.4.1、添加文件:演示 git add、git commit、git log、git cat-file
- 2.4.2、修改文件:演示 git status、git diff
- 2.4.3、版本回退:演示 git reset、git reflog
- 2.4.4、撤销修改
- 2.4.4.1、基础说明
- 2.4.4.2、撤销情况一:尚未 add 的代码(只存在工作区)
- 2.4.4.3、撤销情况二:已经 add ,但没有 commit 的代码(存在于工作区、暂存区)
- 2.4.4.4、撤销情况三:已经 add ,并且commit 的代码(存在于工作区、暂存区、版本库)
- 2.4.5、删除文件
- 3、分支管理
- 3.1、理解分支:git branch
- 3.2、分支基本操作
- 3.2.1、创建分支:git branch new-branch
- 3.2.2、切换分支:git checkout/git switch new-branch 、git checkout -b
- 3.2.3、合并分支与合并冲突:git merge、 git log --graph
- 3.2.4、删除分支:git branch -d
- 3.2.5、选择分支合并模式:- - no - ff
- 3.3、分支管理策略
- 3.3.1、分支策略
- 3.3.2、bug分支:git stash、git stash list、git stash pop等
- 3.3.2.1、准备工作与如何使用bug分支
- 3.3.2.2、master分支bug修复后,后续dev操作
- 4、远程操作
- 4.1、分布式版本控制系统
- 4.2、远程仓库
- 4.2.1、新建远程仓库
- 4.2.2、克隆远程仓库:git clone
- 4.2.3、查看远程库信息:git remote
- 4.2.4、向远程仓库推送:git push
- 4.2.5、拉取远程仓库:git pull
- 4.2.6、配置Git:忽略特殊文件(.gitignore)
- 5、标签管理
- 5.1、理解标签
- 5.2、标签相关操作
- 5.2.1、创建与查看标签:git tag、git show
- 5.2.2、推送标签到远端:git push
- 5.2.3、删除标签:git tag -d、git push --delete
- Fin、共勉。
1、初识Git
1.1、版本控制器
1)、理解版本控制器
所谓的版本控制器,就是能让你了解到一个文件的历史,以及它的发展过程的系统。通俗的讲就是一个可以记录⼯程的每一次改动和版本迭代的一个管理系统,同时也⽅便多⼈协同作业。
2)、Git
目前最主流的版本控制器就是 Git 。Git 可以控制电脑上所有格式的⽂件,例如 doc、excel、dwg、dgn、rvt等等。而对于开发⼈员来说,Git 最重要的就是可以帮助我们管理软件开发项目中的源代码文件。
1.2、git安装
1)、基础说明
Git 是开放源代码的代码托管⼯具,最早是在Linux下开发的。开始也只能应应用Linux平台,后面慢慢的被移植到windows下,现在,Git可以在Linux、Unix、Mac和Windows这几大平台上正常运运行。
2)、安装操作
略。这里可根据平台需求自行搜索了解。
2、基本操作
2.1、Git本地仓库
2.1.1、创建Git本地仓库:git init
1)、Git本地仓库
说明:仓库是进行版本控制的⼀个文件目录。我们要想对文件进行版本控制,就需要创建一个仓库出来。在Git中,你可以有一个或多个本地仓库(repository),每个仓库都包含项目的所有文件和版本历史。
2)、如何创建本地仓库?
git init
:在指定目录中初始化一个新的 Git 仓库。当运行该命令时,Git 会在当前目录下创建一个名为 .git
的子目录,这个子目录包含了仓库的所有必要元数据,如对象数据库、引用、钩子(hooks)、配置信息等。
3)、 .git
目录
.git
目录是 Git 仓库的核心组成部分,它包含了仓库的所有元数据和对象数据库,通常是一个隐藏目录,可供 Git 用于跟踪管理仓库。一般情况下,不要手动修改这个目录里的文件,改乱极有可能会破坏 Git 仓库。
注意事项:
1、如果 .git
目录已经存在(即该目录已经是一个 Git 仓库),再次运行 git init
命令将不会有任何效果。
2、可以使用 git init --bare
命令创建一个裸仓库(bare repository)。裸仓库不包含工作目录,通常用于在服务器上存储共享的 Git 仓库。
3、在初始化 Git 仓库之前,确保你的目录是干净的,不包含与项目无关的文件或目录。这些文件或目录将不会被 Git 跟踪,但它们的存在可能会干扰你的工作。
2.1.2、配置Git本地仓库:git config
1)、添加两个配置项:name、email
当安装 Git 后首先要做的事情是设置你的 用户名称 和 e-mail 地址。
// 新增配置
git config [--global] user.name "Your Name"
git config [--global] user.email "email@example.com"
--global
是⼀个可选项。由于一个本地服务器可以存在多个本地仓库,因此,若使用该选项,则表示这台机器上所有的 Git 仓库都会使用当前设置的配置。
如果需要在不同仓库中使用不同的 name 或 e-mail ,可以不加 --global
选项。(PS:执行这些命令时,必须要在仓库里)
相关演示如下:
2)、查看配置和删除配置的相关指令
-l
是 --list
的缩写,表示列出所有设置。这个命令用于列出当前 Git 仓库的所有配置设置(包括全局设置和本地仓库设置)。
git config -l
--unset
选项表示要删除一个设置。user.name
和 user.email
是要删除的配置项,可根据需求修改为其它待删除配置项。
git config [--global] --unset user.name
git config [--global] --unset user.email
若加上 --global
选项,那么命令会删除全局配置中的相关设置。全局配置通常位于你的用户家目录下的 .gitconfig
文件中。
若不加 --global
选项,该命令会删除当前 Git 仓库的 .git/config
文件中的相关设置。
演示如下:
Git默认的输出是单一颜色的,不容易阅读,但其支持用多种颜色来显示其输出的信息,运行以下命令来开启多颜色输出:
git config --global color.status auto
git config --global color.diff auto
git config --global color.branch auto
git config --global color.interactive auto
git config --global color.ui "auto"
,也可以一次性设置。如果要删除也使用--unset
指令。
2.3、认识工作区、暂存区、版本库
工作区: 你在本地计算机上直接进行项目开发和文件编辑的区域。它通常是一个目录,其中包含了项目的所有文件和子目录。
暂存区: (stage或index)。一般存放在. git
目录下的index文件(.git/index) 中,我们把暂存区有时也叫作索引(index)
版本库: 又名仓库(repository)。 工作区有一个隐藏目录.git
, 它不算工作区,而是Git的版本库。这个版本库里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
在Git中,工作区、暂存区和版本库之间的交互是通过Git命令来完成的。(一般不允许手动修改.git
下的目录文件)
2.4、文件修改(新增、修改、删除)
2.4.1、添加文件:演示 git add、git commit、git log、git cat-file
1)、相关操作及指令学习
git add
命令可以将⽂件添加到暂存区中:
git add [file1] [file2] ... #添加⼀个或多个⽂件到暂存区
git add [dir] #添加指定⽬录到暂存区,包括⼦⽬录
git add . #添加当前⽬录下的所有⽂件改动到暂存区
git commit
命令将暂存区内容添加到本地仓库中:
git commit -m "message" #提交暂存区全部内容到本地仓库中
git commit [file1] [file2] ... -m "message" # 提交暂存区的指定⽂件到仓库区
-m
选项后跟上本次提交需要描述的信息,一般由用户自己设置。这部分内容是对这些文件的细节解释,因此不能省略,且要好好描述。
git log
命令,查看下历史提交记录。该命令显示从最近到最远的提交日志,每个提交都包含其哈希值、作者信息、提交日期和提交消息。(其可跟随一些选项,可看需求了解学习)
2)、上述操作,对于工作区、暂存区、版本库有何变化?
总览变化:
先来简单了解一下HEAD
指针:
如何看这里的commit id
?分成2部分,其前2位是文件夹名称,后38位是文件名称。
找到这个文件后,⼀般不能直接看到里面是什么,该类文件是经过 sha (安全哈希算法)加密过的文件。可以使用 git cat-file
命令来查看版本库对象的内容。
由上述内容可以看出,Git实际管理的并不是文件,而上文件中的修改变动。
对于 commit 对象,它会显示提交信息;
对于 tree 对象,它会显示目录树的内容;
对于 blob 对象,它会显示文件的内容。
2.4.2、修改文件:演示 git status、git diff
1)、总述
git status
和 git diff
是 Git 版本控制系统中两个常用的命令,用于查看仓库的当前状态以及比较工作目录、暂存区(staging area)和提交之间的差异。
2)、git status指令介绍
git status
命令:用于显示工作区和暂存区的状态。它告诉你有哪些更改已经被暂存(staged),哪些更改还没有被暂存(unstaged),以及哪些文件在仓库中但是被删除了。
运行 git status
时,会看到以下几种输出:
Changes to be committed:这部分列出了你已经暂存(git add)的更改。
Changes not staged for commit:这部分列出了你已经修改但还没有暂存的更改。
Untracked files:这部分列出了你新创建的文件,但还没有被 Git 跟踪。
3)、git diff指令介绍
git diff 命令用于比较文件或目录的差异。它有多种用法,但最基本的用法是显示工作区中的更改与暂存区之间的差异。
git diff [file]
:显示工作目录中的更改与暂存区之间的差异。显示的格式正是Unix通用的diff格式。
git diff --cached
或 git diff --staged
:显示暂存区与上一次提交之间的差异。
git diff HEAD [file]
:显示工作目录中的更改与上一次提交之间(版本库中)的差异(与 git diff 相似,但更明确)。
2.4.3、版本回退:演示 git reset、git reflog
1)、相关指令学习
之前提到过,Git 能够管理文件的历史版本,这也是版本控制器重要能力体现。如何做到?
git reset
命令:用于回退版本,可以指定退回某⼀次提交的版本。这里的 “回退”主要是将版本库中的内容进行回退,工作区或暂存区是否回退,由命令参数决定。
git reset [--soft | --mixed | --hard] [HEAD]
--soft
参数对于工作区和暂存区的内容都不变,只是将版本库回退到某个指定版本。
--mixed
为默认选项,使用时可以不用带该参数(git reset [HEAD]
)。该参数将暂存区和版本库的内容退回为指定提交版本内容,工作区文件保持不变。
--hard
参数将暂存区、工作区与版本库都退回到指定版本。切记工作区有未提交的代码时不要用这个命令,因为工作区的回滚会导致没有提交的代码也一起被回退(结果就是容易找不回来),所以使用 该参数前一定要慎重。
具体解释: 这三个参数均会对版本库做回退(本来该指令就是用来回退版本库的,变是必然,其它是附带需求。)
--soft
重置位置的同时,保留 working Tree工作目录 和 index暂存区的内容,只让repository中的内容和 reset 目标节点保持一致,因此原节点和reset节点之间的【差异变更集】会放入index暂存区中(Staged files)。所以效果看起来就是工作目录的内容不变,暂存区原有的内容也不变,只是原节点和Reset节点之间的所有差异都会放到暂存区中。
--mixed(默认)
重置位置的同时,只保留 Working Tree工作目录的內容,但会将 Index暂存区 和 Repository 中的內容更改和reset目标节点一致,因此原节点和Reset节点之间的【差异变更集】会放入Working Tree工作目录中。所以效果看起来就是原节点和Reset节点之间的所有差异都会放到工作目录中。
--hard
:重置位置的同时,直接将 working Tree工作目录、 index 暂存区及 repository 都重置成目标Reset节点的內容,所以效果看起来等同于清空暂存区和工作区。
HEAD
参数说明:
1、可直接写 commit id
,表示指定退回的版本
2、可以使用 ^
表示:HEAD
指当前版本,HEAD^
上⼀个版本,HEAD^^
上上⼀个版本,以此类推。(PS:直接使用git reset HEAD
,表示将工作区和暂存区回退到与当前版本库相同)
3、可以使用 ~
数字表示:HEAD~0
指当前版本,HEAD~1
上一个版本,HEAD^2
指上上⼀个版本,HEAD^3
指上上上一个版本,以此类推。
代码演示:
Git 中还提供了一个命令git reflog
,可以对此补救一下。该命令显示了你仓库中引用(通常是 HEAD、分支和远程分支)的更改记录。这些记录包括了你何时创建或删除了分支、何时移动了 HEAD(例如,通过 git checkout、git merge、git reset 等命令),以及何时执行了其他影响引用的操作。
但这并不代表可以高枕无忧,实际开发中由于周期时间长,极有可能会导致 commit id
等早已经分辨不清找不到。因此才有之前所说,慎用--hard
选项。
2)、原理简述
reset 的本质: Git 的版本回退速度非常快,这是因为 Git 在内部有个指向当前分分支(此处是master)的HEAD 指针。实际执行该指令时,是移动 HEAD ,并且「捎带」上 HEAD 所指向的 branch(如果有的话)。
2.4.4、撤销修改
2.4.4.1、基础说明
在Git中,撤销修改操作需要根据不同需求而定。
工作区 | 暂存区 | 版本库 | 方法 |
---|---|---|---|
√ | ×(未 add ) | ×(未commit) | ①git diff对比,手动删除(不推荐)②git checkout – [file] |
√ | √(已 add) | ×(未commit) | git reset – hard、git rest – mixted(回到情况一) |
√ | √(已 add) | √(已 commit) | git reset --hard HEAD^ |
2.4.4.2、撤销情况一:尚未 add 的代码(只存在工作区)
如果我们在工作目录中做了一些修改,但还没有暂存(即还没有使用git add命令),此时想要撤销修改,可以使用git checkout -- <file>
命令。这会丢弃工作目录中该文件的所有修改,使其与HEAD(最后一次提交)中的版本保持一致。
git checkout -- filename
2.4.4.3、撤销情况二:已经 add ,但没有 commit 的代码(存在于工作区、暂存区)
如果我们已经使用git add命令暂存了修改,但还没有使用commit提交,此时,可以使用git reset
命令来撤销暂存。这会将修改从暂存区中移除,但保留在工作目录中。
git reset HEAD filename # 若需要继续撤销工作区内容,可以使用 git checkout -- filename,即回到了上述情况一。
git reset --mixed HEAD filenmame # 情况同上,--mixed 是默认参数,使⽤时可以省略
git reset --hard HEAD filename # 也可以使用该选项直接回退工作区和暂存库
2.4.4.4、撤销情况三:已经 add ,并且commit 的代码(存在于工作区、暂存区、版本库)
如果你已经提交了修改,并希望撤销这次提交,你可以使用git revert命令或git reset命令。使用git reset:这会重写历史,将HEAD指针移回到之前的提交。
git reset --hard HEAD~1
git reset --hard HEAD^
git reset --hard [commit ID]
条件限制:使用上述指令回退是有条件的。根据我们很久之前学习的git 三板斧,git push会将本地仓库的代码推送到远程仓库中。如果我们想要使用上述指令撤销文件,需要在还没有把本地版本库推送到远程前,即尚未使用git push操作前,才能有效撤销。
2.4.5、删除文件
在 Git 中,删除也是⼀个修改操作。可以通过如下两种方式完成:
1、使用文件系统的 rm 命令删除文件:
rm [filename]
#filename,要删除的文件名以及路径。如果你正在当前目录中删除文件,则可以只输入文件名。
使用文件系统的删除命令,此时 Git 并不会立即知道这个文件已经被删除。当我们尝试提交更改时,Git 会告诉你有一个未跟踪的文件被删除了(除非之前已经暂存了这个文件的删除)。为了将文件的删除操作提交到 Git 仓库,需要先告诉 Git 文件已经被删除:可以通过 git add 命令的 --all
或 -A
选项来实现,它会添加所有修改(包括新文件、修改的文件和删除的文件)。
git add --all
git add -A
git commit -m "XXX"
#即,rm删除后,需要再次 git add、git commit
相关演示:
2、使用 Git 的 git rm 命令删除文件:git rm [filename]
命令会删除文件系统中的文件,并将这个删除操作添加到暂存区。这意味着我们可以直接提交(commit)这个更改,而无需再次使用 git add 命令。
相关演示:
3、分支管理
3.1、理解分支:git branch
1)、概念理解
在Git中,分支(Branch)是一个指向提交对象的指针,它代表了一个独立的工作流或开发线。Git中的分支允许开发者在开发过程中进行并行工作,而不会相互干扰。
这就类似于你生活在一个多元宇宙中,其中存在无数个平行世界,每个世界都基于某个初始点(即“大爆炸”或起源)发展而来,但它们各自有着独特的历史、事件和生命轨迹。
在这个多元宇宙中,每个平行世界都可以看作是Git中的一个分支。每个分支都是从主世界(即Git中的主分支或master分支,尽管现在很多团队更倾向于使用main分支作为默认分支)的一个时间点(即某个提交)分叉出来的。
2)、如何查看分支(相关指令介绍)
我们如何查看当前本地的所有分支?可以使用如下指令:
git branch
执行 git branch
命令而不带任何参数时,它会列出仓库中所有的本地分支。 当前活动的分支前面会有一个星号(*
)标记。
在之前我们介绍过,HEAD 是一个特殊的指针,默认指向master分支。实则这种表述方式不太严谨。
HEAD 指针可以指向其他分支,被指向的分支就是当前正在工作的分支,该分支指向最新一次提交。 即,严格意义上 HEAD 实际上是指向该分支的引用,而不是直接指向提交。
例如,如果你检出了 master 分支,那么 HEAD 就会指向 master 分支,而 master 分支又指向最新的提交(如下图)。这意味着你可以通过 HEAD 来访问当前分支的最新提交。
通过查看当前的版本库,我们也能清晰的理出思路:
3.2、分支基本操作
3.2.1、创建分支:git branch new-branch
1)、相关指令介绍
Git支持我们查看或创建其他分支:
git branch new-branch
# new-branch 是新创建的分支的名字
演示如下:
如上图,我们演示了如何用git branch创建一个新分支,但同时,我们也发现所创建出来的新分支dev和master指向同一个修改。这是为什么?
2)、如何理解创建的新分支?
git branch 创建一个新的分支时,这个新分支默认会指向当前 HEAD 所指向的提交。换句话说,新分支将会基于你当前所在的分支或提交来创建。例如:例如,如果你在 master 分支上执行 git branch feature-branch,那么 feature-branch 将会指向 master 分支的最新提交。
3.2.2、切换分支:git checkout/git switch new-branch 、git checkout -b
1)、相关指令介绍
那么,如何切换到其它分支下进行开发呢?可以使用 git checkout
命令来切换分支。此外,从 Git 2.23 版本开始,也可以使用 git switch
命令来切换分支。
# new-branch 是分支名
# 使用 git checkout 切换分支
git checkout new-branch
# 使用 git switch 切换分支(Git 2.23+)
git switch new-branch
演示如下:
补充: 此外,我们还可以使用 git checkout -b
指令,创建一个新的分支并立即切换到该分支。
2)、演示在新分支下开发
现在,让我们在新分支下进行文件操作并提交到版本库中,看看会发生什么?
结论: 当我们在某个分支中对文件进行修改并提交这些更改时,该分支的引用(或者说指针)将会更新为指向这次提交所创建的新提交对象。 这种机制使得 Git 能够跟踪每个分支的历史和进度。每个分支都有自己的提交历史,而 HEAD 指针则能够帮助我们了解当前正在哪个分支上工作,以及该分支的最新状态是什么。
3.2.3、合并分支与合并冲突:git merge、 git log --graph
1)、演示合并分支
为了在master主分支上能看到新的提交,就需要将dev分支合并到master分支。在 Git 中通常使用 git merge
命令来完成。
git merge new-branch
# 表示将指定分⽀new-branch合并到当前分支中。
注意: 这里若要将dev分支合并到master分支中,我们需要在master分支中来使用这个指令。
演示分支合并(不存在冲突的情况):
PS:不是每次合并都能 Fast-forward,后续会介绍到其他方式的合并。
2)、演示分支合并冲突
使用git merge
指令后,Git 会尝试自动合并两个分支之间的差异。如果两个分支修改了同一个文件的同一部分,Git 会尝试合并这些更改。如果合并过程中出现冲突,Git 会停下来并提示你手动解决这些冲突。
解决合并冲突的方案: 如果合并过程中出现冲突,Git 会在合并后的文件中标记出冲突的部分。这时需要我们手动编辑这些文件,解决冲突,然后再次提交更改。 解决冲突后,需要再次使用 git add 命令将文件标记为已解决,并使用 git commit 命令来提交合并结果。
注意:根据上述演示可知,合并操作是单向的。 git merge主要是将一个分支(通常称为“源分支”或“要合并的分支”)的更改集成到另一个分支(通常称为“目标分支”或“当前分支”)中,而这个过程不会改变源分支的指向或其历史记录。
以下为上述合并的基本流程:
- 1、我们有一个目标分支(比如 main 或 master),这是希望将更改合并到的分支。此外,我们还有一个源分支(比如 feature-branch),这个分支包含了想要合并到目标分支的更改。
- 2、执行合并操作,需要切换到目标分支(使用 git checkout 或 git switch)。运行 git merge命令来合并源分支的更改到目标分支。Git 会尝试将这些更改集成到目标分支,如果过程中出现冲突,Git 会提示手动解决。
- 一旦合并完成(包括任何手动冲突解决),目标分支就会包含源分支的更改,并且这些更改会被添加到目标分支的提交历史中。但是,源分支(feature-branch)的指向和内容不会改变。它仍然指向它之前的最后一次提交,包含它之前的所有更改。
3)、其它补充
关于上述合并的分支情况,用带参数的git log也可以看到。
git log --graph --pretty=oneline --abbrev-commit
--graph
:显示一个 ASCII 图形表示,以便可以看到分支和合并历史。
--pretty=oneline
:以一行格式显示每个提交,包括提交哈希和提交消息的第一行。
--abbrev-commit
:使用缩写的提交哈希值,通常显示前几位字符(默认为 7 位,但可以通过 --abbrev= 指定其他长度)。
如果dev分支使用完毕后不再需要,可以将该分支删除。
3.2.4、删除分支:git branch -d
要删除一个分支,可以使用 git branch -d
命令(或者 -D
强制删除一个未合并的分支)。
# 删除已合并的分支
git branch -d old-branch
# 强制删除未合并的分支
git branch -D old-branch
演示与细节理解:
3.2.5、选择分支合并模式:- - no - ff
1)、前情回顾与问题描述
在之前使用git merge
合并分支时,我们简单提到过Git 会采用 Fast forward
模式合并分支。这通常会执行一个快进合并,意味着Git只是简单地移动master分支的指针到dev的最后一个提交,而不是创建一个新的合并提交。
在这种Fast forward
模式下,如果在合并后删除了源分支(dev),目标分支(master)不会记录源分支的任何历史信息丢失。那么,当我们在目的分支(master)中使用git log查看历史分支信息时,会导致我们无法辨别某次提交到底是由merge合并进来的,还是在当前分支正常提交的?
2)、非Fast forward模式合并
针对上述问题,我们只需在使用git merge合并时增加一个选项即可:git merge --no-ff
--no-ff
选项用于强制Git在合并时创建一个新的合并提交。这有助于保持一个更清晰的提交历史,因为每个特性分支的合并都会有一个与之关联的合并提交。
优势说明:
1、合并历史更加清晰:使用--no-ff选项可以清晰地看到哪些提交是来自于哪个分支的,以及这些分支是如何合并的。
2、便于回滚和审查:由于有明确的合并提交,所以在需要回滚或审查合并内容时,可以更容易地找到相关的提交。
3、保留分支信息:即使删除了合并的分支,由于合并提交的存在,仍然可以保留该分支的历史信息。
相关演示如下:
3.3、分支管理策略
3.3.1、分支策略
在软件开发的项目管理中,分支策略扮演着至关重要的角色。为了确保项目的顺利进行和版本的稳定发布,一般会按照以下基本原则进行分支管理:
首先,master
分支应保持高度的稳定性。这意味着该分支主要用于发布最新稳定的版本,且在日常开发中应避免直接在其上进行修改或提交代码。 它代表了项目的最新稳定状态,并作为所有其他分支的基准。
那么,日常的开发工作应该在哪里进行呢?答案是 dev
分支。dev
分支作为主要的开发分支,用于承载开发过程中的不稳定代码。团队成员在此分支上进行日常的开发、测试和修复工作。 当项目达到某个重要里程碑,如准备发布1.0版本时,我们会将 dev
分支上的代码合并到 master
分支,并通过 master
分支发布新版本。
在团队协作中,每个团队成员都应在自己的独立分支上进行工作。这些分支可以基于 dev
分支创建,允许个人自由地进行代码修改和测试。 个人的工作完成并经过验证后,可以将自己的分支合并到 dev
分支,以便与其他团队成员的工作进行集成。这种工作方式既保证了代码的隔离性,又促进了团队成员之间的协作和代码共享。
因此,团队合作的分⽀看起来就像这样:
3.3.2、bug分支:git stash、git stash list、git stash pop等
3.3.2.1、准备工作与如何使用bug分支
问题描述:假如我们现在正在dev2分支上进行开发,开发过程中发现master分支上有待解决的紧急bug。然而dev2的代码在工作区中已经开发了一半,尚未完全无法提交,此时该如何做?
回答:可以建立一个新的临时分支来修复bug。 但在此之前,要先保存dev2分支的工作区代码:
git stash
git stash list
Git提供了git stash
命令,这会保存当前工作目录和暂存区的所有更改,并返回到一个干净的工作状态。被储藏的内容可以在将来某个时间恢复出来。
此外, git stash list
命令,可以列出所有被 git stash
保存的暂存变更(stash entries)。每个 entry 都有一个唯一的名称(通常是基于时间戳和随机数的组合)。
储藏dev2工作区之后,由于我们要基于master分支修复bug,所以需要切回master分支,再新建临时分支来修复bug。
待修复完成后,切换到master分支,合并fix_ bug修复到master,最后删除用于fix_ bug分支(其使命已经完成)。
3.3.2.2、master分支bug修复后,后续dev操作
现在,让我们回到dev2分支中并恢复工作。
若之前使用了git stash
来保存暂存变更(stash entries),可以使用下述指令恢复工作:
# 重新将暂存恢复
git stash pop # 恢复entry并将其从 stash 列表中移除
git stash apply # 恢复但不会从 stash 列表中移除该 entry
# 删除暂存
git stash drop
# 显示
git stash list
git stash show
这些命令的用法:
- 若有一些未提交的变更,可运行
git stash
来保存这些变更。 - 查看所有保存的暂存变更:
git stash list
- 若决定重新应用其中一个
stash entry
:git stash apply stash@{0}
(其中 stash@{0} 是待想要重新应用的 stash entry 的名称)。也可以使用git stash drop
。 - 若决定删除一个
stash entry
:git stash drop stash@{1}
(其中 stash@{1} 是你想要删除的 stash entry 的名称) - 如果
git stash pop
、git stash apply
、git stash drop
、后面没有跟随具体的 stash entry 名称直接使用,那么 Git 默认会使用最近的一个 stash entry(通常是列表中的第一个:stash@{0}
)。
一个问题:dev2分支完成开发提交后,是否能直接合并到master上?
回答:
1、在先前的bug修复中,fix_bug是在dev2之后创建的,其在mster分支中合并后,master分支目前最新的提交是要领先于新建dev2时基于的master分支的提交的。这就意味着我们在dev2中是看不见修复bug的相关代码的。
2、如果直接合并dev2到master上,那么正常情况下,我们切回master分支进行合并即可,但这样其实是有一定风险的。这是因为在合并分支时可能会有冲突,而代码冲突需要我们手动解决,这意味着我们需要在master分支上解决冲突。由于在实际的项目中,代码冲突并非一两行那么简单,有可能几十上百行甚至更多,我们无法保证对于冲突问题可以正确地一次性解决掉,甚至在解决的过程中手误出错,导致错误的代码被合并到master上。
3、因此,这里我们建议:最好在自己的分支上合并下master,再让master去合并dev。这样做的目的是有冲突可以在本地分支解决并进行测试,而不影响master。
这里我们演示[建议]中的做法:
4、远程操作
4.1、分布式版本控制系统
1)、理解分布式版本控制系统
我们目前所介绍到的Git内容(工作区,暂存区,版本库等等), 都是在当前本地主机上的上。然而, Git 其实是一个分布式版本控制系统(Distributed Version Control System, DVCS)。它允许开发者在本地存储所有的版本历史、分支和标签,而不是依赖于一个中央服务器。每个开发者的本地仓库都包含完整的项目历史 ,因此他们可以在没有网络连接的情况下进行工作,并且可以随时与其他开发者同步更改。
2)、理解远程仓库
Git 这种分布式版本控制系统,其核心特性在于同一个 Git 仓库可以分散部署在不同的机器上。
在最初时通常只有一台机器拥有一个原始版本库,但此后,其他机器可以通过“克隆”操作获取该原始版本库的完整副本。而且每台机器上的版本库都是相同的,没有主从之分,它们各自拥有完整的项目历史记录和版本信息。
对于仅拥有一台电脑的用户而言,虽然理论上可以在同一台电脑上克隆多个版本库(只要这些库位于不同的目录),但在实际场景中,这样做并无太大意义,因为这样不仅不能充分利用分布式版本控制系统的优势,反而增加了数据丢失的风险(例如硬盘故障可能导致所有库同时受损)。
在实际应用中,通常的做法是选择一台机器作为服务器,该服务器保持24小时开机状态,并作为中心仓库。其他开发者从该“服务器”仓库克隆代码到自己的电脑上进行开发,完成开发后,再将各自的提交推送到服务器仓库,并从服务器仓库中拉取其他开发者的提交,以保持代码同步。
搭建自己的 Git 服务器固然可行,但对于初学者而言,这可能会增加学习难度。幸运的是,存在许多提供 Git 仓库托管服务的平台,如 GitHub、码云(Gitee)等代码托管平台。
这里主要介绍如何使用码云远程仓库进行版本控制操作。
4.2、远程仓库
4.2.1、新建远程仓库
略。
以前博文介绍过:相关链接。
4.2.2、克隆远程仓库:git clone
1)、基本介绍
克隆/下载远端仓库到本地,需要使用git clone
命令,后面跟上我们的远端仓库的链接。远端仓库的链接可以从仓库中找到:选择“克隆/下载”获取远程仓库链接。
SSH协议和HTTPS协议是Git最常使用的两种数据传输协议。 SSH 协议使用了公钥加密和公钥登陆机制,体现了其实用性和安全性,使用此协议需要将我们的公钥放上服务器,由Git服务器进行管理。使
用HTTPS方式时,没有要求,可以直接克隆下来。
2)、实操
HTTPS方式:之前博文介绍过。(实际打开克隆界面也会有提示,按照要求来即可)
SSH方式:此处略,详细操作步骤可自行搜索了解。这里只做一些简单说明。
1、使用SSH方式克隆仓库,若没有添加公钥到远端库中,服务器会拒绝我们的clone链接。
2、对此需要设置一下(创建SSH Key):在用户主目录下,看看有没有.ssh
目录,如果有,再看看这个目录下有没有id_ rsa
和id_ rsa.pub
这两个文件,如果已经有了,可直接跳到下一步。如果没有,需要创建SSH Key:
ssh-keygen -t rsa -C "1234578@123.com" #这里输入的邮箱和你远程仓库处用户邮箱相同
上述指令顺利完成,我们可以在用户主目录里找到.ssh
目录,里面有id_ rsa
和id_ rsa.pub
两个文件。它们个就是SSH Key的秘钥对,id_ rsa
是私钥,不能泄露出去,id_ rsa. pub
是公钥,可以公开。
3、如果有多个人协作开发,GitHub/Gitee 允许添加多个公钥,只要把每个人的电脑上的Key都添加到GitHub/Gitee,就可以在每台电脑上往GitHub/Gitee上提交推送了。
4.2.3、查看远程库信息:git remote
1)、origin远程仓库名
使用 git clone
命令克隆一个远程仓库时,Git 会自动将这个远程仓库命名为 origin
,并且会将 origin
设置为默认远程仓库。这个名称 只是一个约定俗成的名字,用于表示我们克隆的原始仓库,可以根据需要将其重命名或添加其他远程仓库。
如果需要重命名 origin 或添加其他远程仓库,可以使用以下命令:
git remote rename origin newname
:将默认的 origin 远程仓库重命名为 newname。
git remote add newname <url>
:添加一个新的远程仓库,并命名为 newname。这里的 是远程仓库的 URL。
2)、git remote命令
git remote
命令:可以查看所有已配置的远程仓库引用(默认为 origin,但你可以添加更多)。
git remote -v
命令:(-v
代表 --verbose
,即详细信息)可以查看每个远程仓库引用的 URL 和与之关联的别名。
如下图,我们只有 origin 远程仓库分别用于 fetch(拉取)和 push(推送)的 URL(通常这两个 URL 是一样的)。
4.2.4、向远程仓库推送:git push
1)、相关指令介绍
在Git中,当我们完成了一些本地更改(例如,添加了一些文件、修改了代码等)并想要将这些更改推送到远程仓库时,可以使用git push
命令,该命令用于将本地的分支版本上传到远程并合并,命令格式如下:
git push <远程主机名> <本地分⽀名>:<远程分⽀名>
# 如果本地分⽀名与远程分⽀名相同,则可以省略冒号:
git push <远程主机名> <本地分⽀名>
例如,我们本地仓库名称为origin,修改的内容在master分支中,此时要将其推送远程仓库master分支中,则有:git push origin master:master
,由于这里本地分支名与远程分支名相同,也可以写成:git push origin master
2)、注意事项
1、这里需要注意,如果我们之前设置过全局的 user.email
和user.name
,这两项配置需要和 gitee 上配置的用户名和邮箱⼀致,否则会出错。或者从来没有设置过全局的 name 和 e-mail,那么我们第⼀次提交时也会报错。这时就需要我们配置一下,相关操作见2.1.1章节。
2、直接使用 git push:若只输入 git push(并且没有指定任何参数)时,Git 会尝试推送当前所在的分支到其追踪的远程分支(如果设置了的话)。这通常是在我们已经设置了上游(upstream)分支的情况下使用的,例如,当我们克隆了一个远程仓库或者首次向远程仓库推送分支时,Git 会自动设置本地分支以追踪相应的远程分支。
4.2.5、拉取远程仓库:git pull
当远程仓库是要领先于本地仓库一个版本时,为了使本地仓库保持最新的版本,我们需要拉取远端代码并合并到本地。Git 提供了git pull
命令,该命令用于从远程拉取(fetch) 代码并 合并(merge) 本地的版本。格式如下:
git pull <远程主机名> <远程分⽀名>:<本地分⽀名>
# 如果远程分⽀是与当前分⽀合并,则冒号后⾯的部分可以省略。
git pull <远程主机名> <远程分⽀名>
演示如下:
4.2.6、配置Git:忽略特殊文件(.gitignore)
在日常开发中,有些文件我们不想或者不应该提交到远端,(如日志文件、编译生成的中间文件、配置文件中的敏感信息等)。对于此情况,Git在工作区的根目录下创建一个特殊的. gitignore
文件,用于指定不希望被Git追踪的文件或目录。
创建.gitignore
文件: 如果我们已经有一个.gitignore
文件,可以直接编辑它。
实际我们不需要从头写. gitignore
文件, gitee在创建仓库时就可以为我们生成,需要我们主动勾选。(当然,也可以自行创建,但要注意创建的目录必须在工作区的根目录下。)
指定要忽略的文件或目录 :在.gitignore
文件中,我们可以添加一行来指定一个要忽略的文件或目录。每行一个条目。 我们可以使用通配符和模式来设置 .gitignore文件例如:
*.a 忽略所有以.a结尾的文件。
!lib.a 但不忽略lib.a文件(注意前面的!表示取反)。
/todo.txt 只忽略仓库根目录下的todo.txt文件,而不忽略子目录中的todo.txt文件。
build/ 忽略build/目录及其所有内容。
doc/*.txt 忽略doc/目录下所有.txt文件。
其它详细内容见链接:gitignore
5、标签管理
5.1、理解标签
1)、是什么?
在Git中,标签(tags)是一种非常重要的引用类型,它们指向某个特定的提交,通常用于标记发布点(如v1.0、v2.5等)。与分支(branches)不同,标签通常不会随着新的提交而移动,它们被设计为指向代码库中的一个固定点。
2)、有何用?
那么,标签有什么用呢?(简述,感性认识)
可读性: 相较于难以记住的commit id
(一串长而复杂的哈希值),tag
通常是一个简短的、有意义的名称,如“v1.0”或“release-candidate”,这使得它们更易于理解和记忆。
标记重要版本: 通常,标签用于标记项目中的重要版本,如发布版本、里程碑或修复了关键问题的版本。这些标签使得团队成员和其他利益相关者能够轻松地找到和引用这些特定的版本。
历史追踪: 此外,随着项目的不断发展,会有多个版本发布**。通过为每个版本设置标签,可以轻松地追踪和识别不同的版本。** 这对于了解项目的历史、比较不同版本之间的差异以及回滚到以前的版本都非常有用。
5.2、标签相关操作
5.2.1、创建与查看标签:git tag、git show
1)、标签分类
Git中有两种类型的标签:轻量标签(Lightweight Tag) 和附注标签(Annotated Tag) 。
轻量标签(Lightweight Tag) : 轻量标签只是指向特定提交的引用。它们是最简单的标签形式,只是一个指针,没有额外的信息。创建轻量标签时,只需指定标签名称和目标提交即可。
附注标签(Annotated Tag) : 附注标签是包含额外信息的对象,其中包括标签的作者、创建日期、标签消息等。创建附注标签时,会创建一个独立的Git对象,存储标签的信息,并将其与特定提交关联。
2)、创建标签(本地)
创建轻量级标签:
git tag <tag_name> [<commit_hash>]
#<tag_name>(必须):指定创建的标签名称。
#<commit_hash>(可选):指定为某次提交创建标签,不指定则默认为最近一次提交。
创建附注标签:
git tag -a <tag_name> -m "<tag_message>" [<commit_hash>]
#<tag_name>(必须):指定创建的标签名称。
#"<tag_message>"(必须):指定附注标签的消息。
#<commit_hash>(可选):指定为某次提交创建标签,不指定则默认为最近一次提交
2)、查看标签
查看本地仓库的标签列表:
git tag [-l "<search_rule>"]
# -l "<search_rule>"(可选):用于列出匹配特定模式的标签。
# 例如,git tag -l "v1.*"将列出所有以"v1."开头的标签。
查看远程仓库的标签列表:
git ls-remote --tags <remote_repo>
# <remote_repo>(必须):指定远程仓库,一般为origin。
查看标签详情内容:
git show <tag_name>
# <tag_name>(必须):指定需要查看详情的标签名称。
5.2.2、推送标签到远端:git push
在本地创建的标签不会自动推送到远程。如果要推送某个标签到远程,可使用下述命令:
git push <remote_repo> <tag_name>
# <remote_repo>(必须):指定远程仓库,一般为origin。
# <tag_name>(必须):指定需要同步到远程仓库的标签名称。
如果本地有很多标签,也可以一次性的全部推送到远端:
git push origin --tags
5.2.3、删除标签:git tag -d、git push --delete
删除本地仓库标签:
git tag -d <tag_name>
# <tag_name>(必须):指定需要删除的标签名称。
删除远程仓库标签:
使用--delete
选项删除:
git push <remote_repo> --delete <tag_name>
# <remote_repo>(必须):指定远程仓库,一般为origin。
# <tag_name>(必须):指定需要删除的标签名称
使用冒号(:
)语法删除,这条命令与 --delete 选项等效:
git push <remote_repo> :refs/tags/<tag_name>
# <remote_repo>(必须):指定远程仓库,一般为origin。
# <tag_name>(必须):指定需要删除的标签名称