Git - 1( 14000 字详解 )

news2025/5/16 20:54:22

一: Git 初识

1.1 提出问题

在工作或学习中,我们常常会面临文档管理的问题,尤其是在编写各种文档时。为了防止文档丢失或因更改失误而无法恢复,我们常常会创建多个版本的副本,例如:“报告-v1”、“报告-v2”、“报告-最终版”等等。虽然每个版本都有其独特的内容,最终我们只需要一份正式的报告,但大量副本的产生会导致我们很难记住每个版本的具体修改内容。

为了更有效地管理这些版本,版本控制器应运而生。版本控制器是一个系统,能够记录文件的历史及其演变过程。它不仅方便我们追踪每一次的改动,还能支持多人协同作业,使团队的协作更加高效。目前最主流的版本控制工具是 Git,它支持管理多种文件格式,包括文本文件、文档、电子表格等。对于开发人员来说,Git 最重要的作用在于帮助我们管理软件开发项目中的源代码文件。

但是需要注意,所有版本控制系统实际上只能有效跟踪文本文件的改动,它可以明确记录每次的改动,比如增加或删除了某些内容。然而对于图片和视频等二进制文件,版本控制系统虽然也能管理,但无法详细跟踪具体的变化。系统只能告知某个文件的大小变化,却无法显示文件内容的具体改动。

1.2 创建 Git 本地仓库

仓库是进行版本控制的一个文件目录,创建一个仓库是对文件进行版本控制的前提。在 Git 中,创建一个本地仓库的命令是 git init,但是要注意这个命令需在所需的文件目录下执行。

仓库创建好后会有一个 .git 目录,它是一个隐藏目录,专门用于 Git 跟踪和管理仓库。注意不要手动修改该目录中的文件,不然可能会因为错误更改而破坏 Git 仓库的结构和功能。

1.3 配置 Git

当安装 Git 后首先要做的事情是设置你的用户名称和 e-mail 地址,配置命令为:

git config [--global] user.name "Your Name"      # 将 "Your Name" 替换为你的昵称
git config [--global] user.email "email@example.com"  # 将 "email@example.com" 替换为你的邮箱地址(只需格式正确即可)

–global 是一个可选项。如果使用该选项,表示在这台机器上的所有 Git 仓库都将采用这个配置。如果你希望在不同的仓库中使用不同的用户名或邮箱,可以不添加 --global 选项,但请注意,执行此命令时必须在相应的仓库目录下。

1.4 认识工作区、暂存区、版本库

术语描述
工作区在电脑上编写代码或文档的目录。
暂存区英文称为 stage 或 index,通常存放在 .git 目录下的 index 文件(即 .git/index)。有时也称为索引。
版本库也称为仓库,英文名为 repository。工作区包含一个隐藏目录 .git,它不算作工作区,而是 Git 的版本库。版本库中的所有文件都可以被 Git 管理,记录每个文件的修改和删除,便于随时追踪历史或还原到某个时刻。

在这里插入图片描述

图中左侧为工作区,右侧为版本库。在 Git 的版本库中,存储了许多重要内容,其中最关键的是暂存区。当创建 Git 版本库时,Git 会自动生成一个唯一的 master 分支,以及一个指向 master 的指针称为 HEAD。当对工作区中的文件进行修改或新增后,执行 git add 命令时,暂存区的文件索引会被更新。随后,执行 git commit 命令时,master 分支会相应更新,这意味着暂存区的文件树会被写入版本库中。因此,仅仅通过新建或粘贴文件到目录并不能将其视为向仓库新增文件,必须使用 git add 和 git commit 命令才能将文件添加到仓库进行管理。

  1. add 命令的语法:
# 添加一个或多个文件到暂存区
git add [file1] [file2] ... [fileN]

# 添加指定目录到暂存区,包括子目录
git add [dir]

# 添加当前目录下的所有文件改动到暂存区
git add .
  1. commit 命令的语法:
# 提交暂存区全部内容到本地仓库中
git commit -m "message"

# 提交暂存区的指定文件到仓库中,message 需要用户自行填写,这是用来记录你这次提交的细节的,要好好写
git commit [file1] [file2] ... -m "message"
  1. 案例练习
hyb@139-159-150-152:~/gitcode$ vim ReadMe                # 打开 ReadMe 文件进行编辑
hyb@139-159-150-152:~/gitcode$ cat ReadMe                # 查看 ReadMe 内容
hello bit
hello bit
hyb@139-159-150-152:~/gitcode$ git add ReadMe            # 将 ReadMe 文件添加到暂存区
hyb@139-159-150-152:~/gitcode$ git commit -m "commit my first file"  # 提交文件到本地仓库

[master (root-commit) c614289] commit my first file       # 提交信息
1 file changed, 2 insertions(+)                            
create mode 100644 ReadMe                                 

执行 git commit 命令成功后,系统会反馈如下信息:1 个文件被修改,也就是我们新添加的 ReadMe 文件,并插入了两行内容,因为 ReadMe 文件中有两行内容。注意:commit 命令只会提交在缓存区中的数据!

hyb@139-159-150-152:~/gitcode$ touch file4 #1. 新增file4⽂件
hyb@139-159-150-152:~/gitcode$ git add file4 #2. 将file4添加到暂存区
hyb@139-159-150-152:~/gitcode$ touch file5 #3. 新增file5⽂件

hyb@139-159-150-152:~/gitcode$ git commit -m"add file" #4. 提交修改
[master 3d406c0] add file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file4
  1. 现在代码就提交到本地仓库了,我们可以使用 git log 命令来查看历史提交记录:
hyb@139-159-150-152:~/gitcode$ git log
commit 23807c536969cd886c4fb624b997ca575756eed6 (HEAD -> master)
Author: hyb91 <2689241679@qq.com>
Date:   Tue May 14 10:00:00 2025 +0800

	add 3 files

commit c61428926f3853d4ec6dde904415b0e6c1dabcc6
Author: hyb91 <2689241679@qq.com>
Date:   Tue May 14 09:55:00 2025 +0800

	commit my first file

该命令显示了从最近到最远的提交日志,并可以查看每次提交时的日志消息。如果觉得输出信息太多、难以阅读,可以尝试添加 --pretty=oneline 参数,以简化输出格式。

hyb@139-159-150-152:~/gitcode$ git log --pretty=oneline
23807c536969cd886c4fb624b997ca575756eed6 (HEAD -> master) add 3 files
c61428926f3853d4ec6dde904415b0e6c1dabcc6 commit my first file

我们看到的类似于 23807c536969cd886c4fb624b997ca575756eed6 的一串字符是每次提交的 commit ID,也就是版本号。Git 的 commit ID 并不是简单的递增数字,而是通过 SHA-1 算法计算得出的一个很大的数字,以十六进制表示。

1.5 认识 .git 文件

首先看看我们的 . git 文件的目录:

hyb@139-159-150-152:~/gitcode$ tree .git/
.git/
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
└── objects
    ├── 23
    │   └── 807c536969cd886c4fb624b997ca575756eed6
    ├── 83
    │   └── 0a8c9feefbdc098bbae2cdc25e5034ce1920d7
    ├── 8f
    │   └── add50161b6fafa53ce7e79d278dc490240c946
    ├── 9c
    │   └── 9e1f0f6bff3015df71a0963004476f5e6cfd54
    ├── c6
    │   └── 1428926f3853d4ec6dde904415b0e6c1dabcc6
    ├── e6
    │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
    ├── info
    └── pack
└── refs
    ├── heads
    │   └── master
    └── tags

18 directories, 27 files
组件描述
index暂存区,add 后的内容都是添加到这里的。
HEAD当前指向默认的 master 分支的指针。
refs/heads/master文件里保存当前 master 分支的最新 commit id。
objectsGit 的对象库,包含创建的各种版本库对象及其内容。当执行 git add 命令时,暂存区的目录树被更新,同时工作区中修改或新增的文件内容会写入到对象库中的一个新对象,存储在 .git/objects 目录下。

1.6 修改文件

Git 相较于其他版本控制系统设计得更加优秀,因为它跟踪和管理的是对文件的修改,而不仅仅是文件本身。那么,什么是修改呢?例如,新增一行、删除一行、修改某些字符、删掉一些内容再添加新的,甚至创建一个新文件,都是被视为修改。让我们对 ReadMe 文件进行一次修改,接着看看 Git 是如何跟踪和管理的。

hyb@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
hello world

此时仓库中的 ReadMe 文件与我们工作区中的 ReadMe 文件是不同的。要查看当前仓库的状态可以使用 git status 命令。该命令用于检查自上次提交以来,是否对文件进行了新的修改。

hyb@139-159-150-152:~/gitcode$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
  modified:   ReadMe

no changes added to commit (use "git add" and/or "git commit -a")

上述结果告诉我们 ReadMe 文件已经被修改,但尚未完成添加和提交。目前我们只知道文件被修改了,如果能具体了解哪些地方发生了变化那就更好了。虽然有同学可能会说自己刚刚的修改记得很清楚,但你是否还记得三天前写了什么代码,或者有没有写呢?

git diff [file] 命令用于显示暂存区和工作区文件之间的差异,输出格式采用的是 Unix 通用的 diff 格式。此外我们还可以使用 git diff HEAD – [file] 命令查看版本库与工作区文件之间的区别。了解对 ReadMe 文件所做的具体修改后,再将其提交到本地仓库,心里就踏实多了。

hyb@139-159-150-152:~/gitcode$ git diff ReadMe
diff --git a/ReadMe b/ReadMe
index 9c9e1f0..4a97140 100644
--- a/ReadMe
+++ b/ReadMe
@@ -1,2 +1,3 @@
hello bit
-hello bit
+hello git
+hello world

1.7 版本回退

我们之前提到过,Git 能够管理文件的历史版本,这是版本控制系统的重要功能。如果某一天我们发现之前的工作出现了重大问题,需要从某个特定的历史版本重新开始,这时就可以使用版本回退的功能。

要进行版本回退,可以使用 git reset 命令,该命令允许我们指定退回到某次提交的版本。但是要注意:回退的本质是将版本库中的内容进行还原,而工作区或暂存区是否也回退则由命令参数来决定。git reset 命令的语法格式为:git reset [–soft | --mixed | --hard] [HEAD]。

参数描述
–mixed默认选项,使用时可以不带该参数。将暂存区的内容退回为指定提交版本的内容,工作区文件保持不变。
–soft对工作区和暂存区的内容都不变,仅将版本库回退到某个指定版本。
–hard将暂存区与工作区都退回到指定版本。切记工作区有未提交的代码时不要使用此命令,使用前务必慎重。
HEAD可直接写成 commit id,表示指定退回的版本。HEAD 表示当前版本,HEAD^ 表示上一个版本,HEAD^^ 表示上上一个版本,同时还可以使用 ~ 数字表示:HEAD~0 表示当前版本,HEAD~1 表示上一个版本,HEAD~2 表示上上一个版本。
git reset --hard 14c12c32464d6ead7159f5c24e786ce450c899dd
git reset --hard d95c13f

d95c13f 是 version 3 的提交 ID 的一部分。在 Git 中,进行版本回退时,也可以使用部分提交 ID 来代表目标版本。这种方式使得回退操作更加灵活和便捷。

Git 的版本回退速度非常快,它在内部维护一个指向当前分支的 HEAD 指针,此处是 master。该指针指向 refs/heads/master 文件中保存的最新提交 ID。当我们执行版本回退时,Git 只需在 refs/heads/master 中更新为特定的提交 ID。这可以简单理解为将指针重新指向某个特定的版本。

在这里插入图片描述

1.8 撤销修改

如果我们在工作区代码编写了很长时间,感觉自己写的代码不尽如人意,想要恢复到上一个版本,此时该怎么做呢?下面我们将分三种情况进行讲解。

1.8.1 还没有 add

我们当然可以通过 Vim 等文本编辑器手动删除工作区新增的代码,但这种方法仅适合短时间内少量代码的情况。如果我们已经写了三天的代码且没有进行任何提交,直接删除将变得困难,甚至可能根本不记得自己增加了哪些内容。有同学可能会提到使用 git diff 来查看差异,但这样也会需要耗费大量时间,且在这个过程中容易修改出 bug。时间一周过去了,你又该如何向老板交代呢?

实际上,Git 为我们提供了更好的解决方案。我们可以使用 git checkout – [file] 命令将工作区的文件恢复到最近一次 add 或 commit 时的状态。请注意,命令中的 – 非常重要,切勿省略;否则,该命令的含义就会改变。我们将在后面的内容中详细讨论这一点。

# 向 ReadMe 文件中新增一行代码
hyb@139-159-150-152:~/gitcode$ vim ReadMe
hyb@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3
This piece of code is like shit  # 这是我们新增的代码

# 恢复到上一次 add 或 commit
hyb@139-159-150-152:~/gitcode$ git checkout -- ReadMe
hyb@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3

1.8.2 已经 add 但没有 commit

此时已经保存到暂存区了,该怎么撤销呢?让我们回顾一下之前学过的 git reset 回退命令。如果使用 --mixed 参数,该命令可以将暂存区的内容回退到指定的版本,而工作区的文件保持不变。这使我们能够轻松地回退暂存区的内容!

1.8.3 已经 add 并且 commit

不用担心,我们可以使用 git reset --hard HEAD^ 命令回退到上一个版本!不过,这个操作是有条件的:你必须确保还没有将本地版本库的更改推送到远程。还记得 Git 是一个分布式版本控制系统吗?后续我们会讨论远程版本库的内容。一旦你将更改推送到远程版本库,后果可能就会非常严重……

1.9 删除文件

在 Git 中,删除操作也是一种修改。如果需要删除 file5 文件,直接使用命令 rm file5 是不够的,这样会导致工作区和版本库不一致,反而增加了麻烦。在这种情况下,通常有两种可能性:第一,你确实想从版本库中删除该文件;第二,你不小心删除了错误的文件。如果出现第二种情况,误删文件后可以通过 Git 进行恢复。这一点我们之前已经学习过,因为在 Git 中,删除操作同样被视为修改。

hyb@139-159-150-152:~/gitcode$ git checkout -- file5
hyb@139-159-150-152:~/gitcode$ ls
file1  file2  file3  file4  file5  ReadMe

对于第一种情况,如果你确实想从版本库中删除该文件,那么仅仅删除工作区的文件是不够的。这时,你需要使用 git rm 命令,将文件同时从暂存区和工作区中删除,并随后进行提交。

hyb@139-159-150-152:~/gitcode$ git rm file5
rm 'file5'

hyb@139-159-150-152:~/gitcode$ git status
On branch master
Changes to be committed:
	(use "git restore --staged <file>..." to unstage)
		deleted:    file5
		
hyb@139-159-150-152:~/gitcode$ git commit -m"deleted file5"

二: 分支管理

2.1 理解分支

接下来将开始介绍 Git 的强大功能之一:分支。分支可以比作科幻电影中的平行宇宙。当你在电脑前努力学习 C++ 时,另一个你在平行宇宙中专心学习 Java。如果这两个平行宇宙互不干扰,那么对你来说没有任何影响。但是如果他们在某个时刻合并了,这样一来你不仅学会了 C++ 还掌握了 Java!

在这里插入图片描述

在版本回退的过程中,你已经了解到,每次提交时,Git 会将这些提交串成一条时间线,这条时间线可以被视为一个分支。目前只有一条时间线,在 Git 中,这个分支被称为主分支,即 master 分支。

在这里插入图片描述

接下来我们来理解一下 HEAD。严格来说 HEAD 并不是直接指向提交,而是指向 master 分支,只有 master 才实际指向具体的提交。因此,HEAD 指向的就是当前分支。每次提交时,master 分支都会向前移动一步,随着你不断提交,master 分支的线也会变得越来越长,而 HEAD 始终指向 master 分支,从而保持对当前分支的指向。

2.2 创建分支

Git 支持我们查看或创建其他分支。在这里我们创建第一个自己的分支 dev,对应的命令如下:

hyb@139-159-150-152:~/gitcode$ git branch         #查看当前本地所有分⽀
* master
hyb@139-159-150-152:~/gitcode$ git branch dev     #新建分⽀dev
hyb@139-159-150-152:~/gitcode$ git branch
  dev
* master

当我们创建新的分支后,Git 会新建一个指针,命名为 dev。* 符号表示当前 HEAD 指向的分支是 master。此外还可以发现新的 dev 分支与 master 分支指向的是相同的提交。我们也可以确认,当前 HEAD 仍然指向 master 分支。

在这里插入图片描述

2.3 切换分支

那如何切换到 dev 分支下进行开发呢?使⽤ git checkout 命令即可完成切换,示例如下:

hyb@139-159-150-152:~/gitcode$ git checkout dev
Switched to branch 'dev'
hyb@139-159-150-152:~/gitcode$ git branch
* dev
  master
hyb@139-159-150-152:~/gitcode$ cat .git/HEAD
ref: refs/heads/dev

在这里插入图片描述

我们发现 HEAD 已经指向了 dev,这表示我们成功切换到了 dev 分支!接下来,在 dev 分支下修改 ReadMe 文件,新增一行内容,并进行一次提交操作:

hyb@139-159-150-152:~/gitcode$ vim ReadMe
hyb@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3
write aaa for new branch # 新写的

hyb@139-159-150-152:~/gitcode$ git add .
hyb@139-159-150-152:~/gitcode$ git commit -m"modify ReadMe"
[dev 3740dce] modify ReadMe
 1 file changed, 1 insertion(+)

现在 dev 分支的工作完成,我们可以切换回 master 分支。但是切换回 master 分支后,我们会发现 ReadMe 文件中新增的内容消失了!但是这些内容在 dev 分支中仍然存在。为什么会出现这种情况呢?通过查看 dev 分支和 master 分支的指向,我们会发现它们指向的提交是不同的。

hyb@139-159-150-152:~/gitcode$ cat .git/refs/heads/dev
bdaf528ffbb8e05aee34d37685408f0e315e31a4
hyb@139-159-150-152:~/gitcode$ cat .git/refs/heads/master
5476bdeb12510f7cd72ac4766db7988925ebd302

在这里我们就能明白了,因为我们是在 dev 分支上进行提交的,而此时 master 分支的提交点并没有发生变化。此时的状态如下图所示,当切换到 master 分支之时,HEAD 就指向了 master,所以就看不到提交了!

在这里插入图片描述

2.4 合并分支

想要在 master 主分支上看到新的提交,需要将 dev 分支合并到 master 分支。使用 git merge 命令可以将指定分支合并到当前分支。合并后,master 就能够看到 dev 分支提交的内容。Fast-forward 模式指的是将 master 直接指向 dev 当前的提交,因此合并过程非常快速。然而,并非每次合并都能使用 Fast-forward 模式,后面我们会介绍其他类型的合并方式。

hyb@139-159-150-152:~/gitcode$ git branch
* dev
  master

hyb@139-159-150-152:~/gitcode$ git checkout master  # 切换到 master 分支以进行合并
Switched to branch 'master'

hyb@139-159-150-152:~/gitcode$ git merge dev  # 合并 dev 分支
Updating 16623e1..3740dce
Fast-forward
ReadMe | 1 +
1 file changed, 1 insertion(+)

hyb@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3
write aaa for new branch

在这里插入图片描述

2.5 删除分支

合并完成后,dev 分支对我们来说就不再需要了,因此可以安全地删除它。但是需要注意,如果当前正处于 dev 分支下,是无法直接删除该分支的。不过,你可以在切换到除 dev 以外的分支后删除 dev 分支。

由于创建、合并和删除分支的速度非常快,Git 鼓励用户通过分支来完成特定任务。完成合并后再删除分支,这样做的效果与直接在 master 分支上工作是一样的,但整个过程更加安全。

hyb@139-159-150-152:~/gitcode$ git checkout master
Switched to branch 'master'
hyb@139-159-150-152:~/gitcode$ git branch -d dev # 删除 dev 分支
Deleted branch dev (was bdaf528).
hyb@139-159-150-152:~/gitcode$ git branch
* master

在这里插入图片描述

2.6 合并冲突

可是,在实际的分支合并过程中并不是每次都能顺利合并,有时会遇到代码冲突的问题。例如,假设我们在 dev1 分支中进行了修改并提交了,同时在 master 分支中也进行了不同的修改并提交了。在这种情况下,master 分支和 dev1 分支各自都有新的提交,Git 只能尝试将这些修改合并在一起,但这可能会导致冲突,如下所示:

在这里插入图片描述

发现 ReadMe 文件有冲突后,可以直接查看文件内容,要说的是 Git 会⽤ <,=,> 来标记不同分支的冲突内容:

hyb@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3
<<<<<<< HEAD
write ccc for new branch 
=======
write bbb for new branch
>>>>>>> dev1

此时需要我们手动调整代码冲突,并再次提交修正后的结果。到这里冲突就解决完成了。此时的状态将更新为:

在这里插入图片描述

2.7 分支管理策略

在合并分支时,如果条件允许,Git 通常会采用 Fast forward 模式。在 Fast forward 模式下,合并的结果是什么呢?在这种模式下,删除分支后查看分支历史时,分支信息会丢失,因此无法区分最新的提交是通过合并而来,还是正常的提交。

在这里插入图片描述

但是在处理合并冲突时,我们需要手动解决冲突问题,这会导致产生一次新的提交。因此,最终的状态会包含合并后的提交记录。

在这里插入图片描述

这样一来,合并就是 Fast forward 模式了。在这种情况下,分支历史中仍然保留了分支信息。即使我们已经删除了在解决合并冲突时创建的 dev1 分支,仍然可以看到 master 分支是由其他分支合并而来的。此外,Git 还支持强制禁用 Fast forward 模式,这样在合并时就会生成一个新的提交,从而可以在分支历史中清楚地显示出分支信息。

hyb@139-159-150-152:~/gitcode$ git log --graph --pretty=oneline --abbrev-commit
*   2976afc (HEAD -> master) merge ReadMe
|\
| * c594fd1 modify ReadMe
* | c10f6d0 modify ReadMe
|/

我们可以在合并分支的时候加上一个参数来禁止 Fast forward 模式。

git merge --no-ff -m "merge with no-ff" dev2

–no-ff 参数用于禁用 Fast forward 模式。在禁用该模式后,合并操作会创建一个新的提交,因此需要加上 -m 参数来添加合并提交的描述。合并完成后,可以查看分支历史:

hyb@139-159-150-152:~/gitcode$ git log --graph --pretty=oneline --abbrev-commit
*   5bd16b4 (HEAD -> master) merge with no-ff
|\
| * 41b082f (dev2) modify ReadMe
|/

可以看到,如果不使用 Fast forward 模式,merge 后就像这样:

在这里插入图片描述

因此,在合并分支时,使用 --no-ff 参数可以执行普通模式的合并,这样合并后的历史将保留分支信息,清楚地显示曾经进行过的合并。而使用 Fast forward 模式则无法显示历史中曾经的合并记录。

2.8 分支策略

在实际开发中,我们应遵循几个基本原则进行分支管理。首先,master 分支应该保持高度稳定,仅用于发布新版本,因此平时不应在上面进行开发。开发工作应在 dev 分支上进行,该分支相对不稳定。当开发完成后,例如在发布 1.0 版本时,再将 dev 分支合并到 master 分支,以便进行版本发布。

在团队合作中,每个成员都可以在 dev 分支上进行开发,同时每个人可以拥有自己的分支,适时地将代码合并到 dev 分支上。这种合作模式使得团队的分支结构保持清晰有序。

在这里插入图片描述

2.9 bug 分支

当我们在 dev2 分支上进行开发并且尚未提交代码时,如果突然发现 master 分支上有一个 bug 需要修复,可以通过创建临时分支来进行修复。但是如果直接使用 git checkout master 切换分支,Git 会拒绝该操作,因为未提交的修改会“跟随”你转到新的分支,这可能导致代码污染。

为了解决这个问题,Git 提供了 git stash 命令,允许我们将当前工作区的未提交修改暂时储藏。通过这种方式,你可以安全地切换到 master 分支进行 bug 修复,待修复完成后再恢复之前的工作,继续在 dev2 分支上开发。

hyb@139-159-150-152:~/gitcode$ git stash
Saved working directory and index state WIP on dev2: 41b082f modify ReadMe
hyb@139-159-150-152:~/gitcode$ git status
On branch dev2
nothing to commit, working tree clean

使用 git status 命令查看工作区时,如果状态显示干净就可以安全地创建分支来修复 bug。储藏 dev2 的工作区后,我们需要切换回 master 分支,并在该分支上创建一个新的临时分支,以便进行 bug 修复,修复完成后切换到 master 分支并完成合并,最后删除这个分支,然后就继续回到 dev2 分支进行开发

hyb@139-159-150-152:~/gitcode$ git checkout dev2
Switched to branch 'dev2'
hyb@139-159-150-152:~/gitcode$ git status
On branch dev2
nothing to commit, working tree clean

此时工作区是干净的,之前的工作现场已经通过 git stash 暂存起来了,并保存在 Git 的某个地方。要恢复这个工作现场,可以使用 git stash pop 命令,这样不仅会将暂存的内容恢复到工作区,还会将对应的 stash 项目删除。以下是示例用法:

hyb@139-159-150-152:~/gitcode$ git stash pop
On branch dev2
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
modified:   ReadMe

no changes added to commit (use "git add" and/or "git commit -a")

Dropped refs/stash@{0} (4f873250b3503687b5efd26196776aee7e3724c2)

此时再次查看的时候,我们已经发现已经没有现场可以恢复了:

hyb@139-159-150-152:~/gitcode$ git stash list
hyb@139-159-150-152:~/gitcode$

另外,还可以使用 git stash apply 命令来恢复暂存的工作现场,但此操作不会删除 stash 内容,如果需要删除,则需使用 git stash drop 命令。你可以多次执行 git stash,在恢复时可以先使用 git stash list 查看所有暂存项,然后通过 git stash apply stash@{0} 命令恢复指定的 stash。恢复代码后,我们就可以继续开发,并在开发完成后进行提交,但是要注意,修复 bug 的内容,并没有在 dev2 上显示。此时的状态图为:

在这里插入图片描述

在创建 dev2 分支时,master 分支上最新的提交已领先于 dev2 的基础提交,因此在 dev2 中看不到修复 bug 的相关代码。我们的最终目标是将 dev2 分支合并回 master。通常情况下,我们可以简单地切换回 master 并进行合并,但这种方法存在一定风险。

合并分支时可能会产生代码冲突,而解决这些冲突通常需要手动处理。由于冲突可能涉及的代码行数较多,有时甚至达到几十上百行,因此难以保证在一次性解决时避免错误。在实际项目中,错误的合并代码可能会被引入到 master 中,导致潜在问题。因此,在进行合并前,需要谨慎考虑冲突的处理。

在这里插入图片描述

解决这个问题的一个好建议是,最好先在自己的分支上合并 master,再将 dev2 合并回 master。这样做的目的是在本地分支上解决冲突并进行测试,以避免对 master 分支造成影响。通过这种办法,可以更安全地处理潜在的代码冲突。

在这里插入图片描述
在这里插入图片描述

2.10 删除临时分支

在软件开发过程中,我们总是需要不断添加新的功能。为了避免实验性质的代码影响主分支的稳定性,每次添加新功能时,最好新建一个分支,称为 feature。在这个分支上进行开发,完成后再合并回主分支,最后可以删除该功能分支以保持项目的整洁。

然而,有时在功能分支上开发到一半时,可能会收到产品经理的通知,要求暂停新功能的开发。尽管开发工作无法继续,仍然需要对这个功能分支进行销毁。此时,使用传统的 git branch -d 命令可能无法满足需求,因为功能分支中可能还有未提交的更改,此时就要按照下面这种方式进行删除:

hyb@139-159-150-152:~/gitcode$ git branch -D dev3
Deleted branch dev3 (was cd2f149).
hyb@139-159-150-152:~/gitcode$ git branch
* master

2.11 小结

分支在实际开发中具有重要的作用。假设你准备开发一个新功能,但需要两周才能完成。在第一周,你编写了50% 的代码,如果立刻提交,由于代码不完整,可能会导致其他团队成员无法正常开展工作。而如果等到代码全部完成再提交,则会面临每天进度丢失的风险。这时,创建一个属于你自己的分支就显得尤为重要。其他人不会看到这个分支,而你可以在上面自由地进行开发,随时提交你的进度,直到最终完成后再将代码合并回主分支,这样既安全又不会影响其他人的工作。

此外,使用 Git 创建、切换和删除分支都非常高效,无论版本库中有多少文件,这些操作通常都能在一秒钟内完成。无论你的版本库是一个文件还是一万个文件,Git 都能迅速处理,让开发者可以更专注于编写和测试代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2377129.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TCPIP详解 卷1协议 九 广播和本地组播(IGMP 和 MLD)

9.1——广播和本地组播&#xff08;IGMP 和 MLD&#xff09; IPv4可以使用4种IP地址&#xff1a;单播&#xff08;unicast&#xff09;、任播&#xff08;anycast&#xff09;、组播&#xff08;multicast&#xff09;和广播&#xff08;broadcast&#xff09;。 IPv6可以使用…

16.1 - VDMA视频转发实验之TPG

文章目录 1 实验任务2 系统框图3 硬件设计3.1 IP核配置3.2 注意事项 4 软件设计4.1 注意事项4.2 工程源码4.2.1 main.c文件 1 实验任务 基于14.1&#xff0c;使用Xilinx TPG&#xff08;Test Pattern Generator&#xff09; IP提供视频源&#xff0c;将视频数据通过VDMA写入PS…

cocos creator 3.8 下的 2D 改动

在B站找到的系统性cocos视频教程,纯2D开发入门,链接如下: zzehz黑马程序员6天实战游戏开发微信小程序&#xff08;Cocos2d的升级版 CocosCreator JavaScript&#xff09;_哔哩哔哩_bilibili黑马程序员6天实战游戏开发微信小程序&#xff08;Cocos2d的升级版 CocosCreator Ja…

Unity光照笔记

问题 在做项目中遇到了播放中切换场景后地面阴影是纯黑的问题&#xff0c;不得不研究一下光照。先放出官方文档。 Lighting 窗口 - Unity 手册 播放中切换场景后地面阴影是纯黑 只有投到地面的阴影是纯黑的。且跳转到使用相同Terrain的场景没有问题。 相关文章&#xff1a…

嵌入式学习的第二十天-数据结构-调试+链表的一般操作

一、调试 1.一般调试 2.找段错误 二、链表的一般操作 1.单链表的修改 int ModifyLinkList(LinkList*ll,char*name,DATATYPE*data) {DATATYPE * tmp FindLinkList(ll, name);if(NULL tmp){return 1;}memcpy(tmp,data,sizeof(DATATYPE));return 0; } 2.单链表的销毁 int D…

家具制造行业的现状 质检LIMS如何赋能家具制造企业质检升级

在家具制造行业&#xff0c;从原木切割到成品出厂&#xff0c;质检环节贯穿始终 —— 木材含水率是否达标、板材甲醛释放量是否合规、涂层耐磨性能否通过标准…… 这些看似琐碎的检测项目&#xff0c;实则是企业把控产品品质、规避市场风险的核心关卡。传统人工质检模式在效率、…

idea整合maven环境配置

idea整合maven 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是springboot的使用。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性。【帮帮志系列文章】&#xff1a;每个知识点&#xff0c;都是写出代码…

无偿帮写毕业论文(看不懂的可以私信博主)

以下教程教你如何利用相关网站和AI免费帮你写一个毕业论文。毕竟毕业论文只要过就行&#xff0c;脱产学习这么多年&#xff0c;终于熬出头了&#xff0c;完成毕设后有空就去多看看亲人好友&#xff0c;祝好&#xff01; 一、找一个论文模板 废话不多说&#xff0c;先上干货Ov…

小白成长之路-vim编辑

文章目录 Vim一、命令模式二、插入模式3.a:进入插入模式&#xff0c;在当前光标的后一个字符插入![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fd293c3832ed49e2974abfbb63eeb5bb.png)4.o: 在当前光标的下一行插入5.i:在当前光标所在字符插入&#xff0c;返回命令模…

【常用算法:排序篇】7.算法魔法与面试秘籍:从趣味排序到实战通关

一、趣味排序算法&#xff1a;突破常规的思维火花 1. 睡眠排序&#xff08;Sleep Sort&#xff09;—— 时间维度的魔法 核心思想&#xff1a;利用多线程休眠时间模拟数值大小&#xff0c;自然输出有序结果。Python示例&#xff1a;import threading import timedef sleep_so…

Android | IOS — Solox性能测试

文章目录 Solox性能测试1. 前置条件2. 软件图片 Solox性能测试 1. 前置条件 安装Python:3.10.0以上版本&#xff1a; Windows&#xff1a;Python官网 安装 SoloX python -m solox2. 软件图片 软件图片 报告分析&#xff1a;

Midjourney 最佳创作思路与实战技巧深度解析【附提示词与学习资料包下载】

引言 在人工智能图像生成领域&#xff0c;Midjourney 凭借其强大的艺术表现力和灵活的创作模式&#xff0c;已成为设计师、艺术家和创意工作者的核心工具。作为 CSDN 博主 “小正太浩二”&#xff0c;我将结合多年实战经验&#xff0c;系统分享 Midjourney 的创作方法论&#x…

工具篇-扣子空间MCP,一键做游戏,一键成曲

一、登陆扣子空间 地址如下&#xff1a; 扣子空间 打开&#xff0c;然后登陆扣子 登陆之后快速开始&#xff1a; 二、生成游戏 小试牛刀&#xff0c;我们让它做一个打地鼠的游戏&#xff1a; 已经开始设计制作&#xff1a; 制作完成&#xff1a; 三、制作音乐 新…

5.6 - 5.9 MySQL

数据库&#xff1a;存储和管理数据的仓库DB。 数据库管理系统&#xff1a;操纵和管理数据库的大型软件DBMS。 关系型数据库 一个数据库内可以创建多张表&#xff0c;在一个表内能存放多个数据。 SQL语句&#xff1a; DDL&#xff1a; 存储字符串用varchar。&#xff08;类似于…

C# WinForm 如何高效地将大量数据从 CSV 文件导入 DataGridView

如果你有非常多的csv文件&#xff0c;每个文件包含N多行与M多列&#xff0c;如&#xff1a;18000 行和 27 列。现在&#xff0c;想制作一个 Windows 窗体应用程序&#xff0c;导入它们并在 datagridview 中显示&#xff0c;然后进行一些数学运算。可是&#xff0c;发现数据导入…

SQLPub:一个提供AI助手的免费MySQL数据库服务

给大家介绍一个免费的 MySQL 在线数据库环境&#xff1a;SQLPub。它提供了最新版本的 MySQL 服务器测试服务&#xff0c;可以方便开发者和测试人员验证数据库功能&#xff0c;也可以用于学习 MySQL。 免费申请 在浏览器中输入以下网址&#xff1a; https://sqlpub.com/ SQLP…

URP相机如何将场景渲染定帧模糊绘制

1&#xff09;URP相机如何将场景渲染定帧模糊绘制 2&#xff09;为什么Virtual Machine会随着游戏时间变大 3&#xff09;出海项目&#xff0c;打包时需要勾选ARMv7吗 4&#xff09;Unity是手动还是自动调用GC.Collect 这是第431篇UWA技术知识分享的推送&#xff0c;精选了UWA社…

WeakAuras Lua Script ICC (BarneyICC)

WeakAuras Lua Script ICC &#xff08;BarneyICC&#xff09; https://wago.io/BarneyICC/69 全量英文字符串&#xff1a; !WA:2!S33c4TXX5bQv0kobjnnMowYw2YAnDKmPnjnb4ljzl7sqcscl(YaG6HvCbxaSG7AcU76Dxis6uLlHNBIAtBtRCVM00Rnj8Y1M426ZH9XDxstsRDR)UMVCTt0DTzVhTjNASIDAU…

FramePack - 开源 AI 视频生成工具

&#x1f3ac; 项目简介 由开发者 lllyasviel 创建的一个轻量级动画帧处理工具库&#xff0c;专门用于游戏开发、动画制作和视频处理中的帧序列打包与管理。该项目采用高效的算法实现&#xff0c;能够显著提升动画资源的处理效率。 此 AI 视频生成项目&#xff0c;旨在通过低显…

Vuetify框架使用(一)之v-snackbar 组件封装及全局使用

说明&#xff1a;v-snackbar 组件适用于统一管理消息提示框(操作反馈的提示) 看效果&#xff1a; 1、在状态管理中创建文件&#xff0c;统一管理 // stores/snackbar.js /*** 统一管理消息提示框(操作反馈的提示)*/import { defineStore } from pinia; // 消息类型 export co…