[Git] 01 - Git 首次配置和基础操作

1.1 - Git 入门

一、关于版本控制

版本控制是一套系统,该系统按时间顺序记录某一个或一系列文件的变更,让你可以查看其以前的特定版本。

版本控制系统:Version Control System (VCS)

(一)本地版本控制系统

  • 将文件复制到另一个文件目录下,加上时间戳,是最简单但也最容易出错的版本控制方式;
  • RCS:常用 VCS 工具,通过叠加保存在磁盘上的补丁集(patch set)使文件恢复到某个历史状态;

(二)集中式版本控制系统 CVCS

  • 有一个包含所有修订版本的单一服务器,多个客户端可以从这个中心位置检出文件;
  • 缺点:服务器如果宕机,任何人都无法协作或提交更改;如果磁盘受损,可能丢失历史记录。

(三)分布式版本控制系统 DVCS

  • 客户端对代码仓库(repository)进行完整镜像,而不仅是检出文件的快照;


二、关于 Git

(一)快照而非差异

  • Git 与其他 VCS 的最大区别是对待数据的方式。
  • Git 将数据视为一个微型文件系统的一组快照:
    • 每次提交或在 Git 中保存项目状态时,Git 会抓取一张所有文件当前状态的快照,然后存储一个指向该快照的引用;
    • 如果文件未发生变动,Git 则不会重新保存文件,而是留下一个指向先前已经保存过的相同文件的链接;

传统版本控制系统,存储对每个文件的基础版本做出的改动

Git 将数据存储为随时间变化的项目快照

(二)几乎所有操作都在本地执行

  • Git 的大部分操作只需要应用到本地文件和资源,使 Git 的速度惊人;
  • 可以在离线状态下继续大部分工作。

(三)Git 的完整性

  • Git 中所有的数据在存储前都会执行校验和计算,随后以校验和来引用对应的数据,意味着 Git 对所有文件/目录的更改都知情;
  • Git 采用 SHA-1 散列(一个由 40 个十六进制字符组成的字符串)进行校验。

(四)Git 通常只增加数据

  • Git 中基本所有的操作都只是向 Git 数据库中添加数据,很难让系统执行无法撤销的操作;
  • Git 中你有可能弄丢/弄乱未提交的变更,但一旦提交就基本不可能丢失。

(五)三种状态

  • 在 Git 中,文件可以处于以下三种状态之一:
    • 已提交(committed):数据被安全地存入本地数据库中;
    • 已修改(modified):已经改动了文件,但尚未提交;
    • 已暂存(staged):对已修改文件的当前版本做出了标识,并将其加入下一次要提交的快照中;

Git 项目的三个主要区域

  • Git 项目的三个主要区域:
    • Git 目录:最重要的部分,是 Git 保存项目元数据和对象数据库的地方,也是克隆仓库时要复制的内容;
    • 工作目录:项目某个版本的单次检出,从 Git 目录下的压缩数据库内被提取出,放置在磁盘上以供使用和修改;
    • 暂存区:单个文件,一般位于 Git 目录下,保存了下次所要提交内容的信息;
  • Git 的基本工作流:
    • 修改工作目录中的文件;
    • 暂存文件,将这些文件的快照加入暂存区;
    • 提交暂存区的文件,将快照永久保存在 Git 目录中;
  • 状态的判断:
    • 处在 Git 目录中的文件版本就被认为是 已提交 状态;
    • 如果该文件被修改,且处于暂存区,就处于 已暂存 状态;
    • 如果检出后发生了变更,但未被暂存,则处于 已修改 状态。

三、安装 Git


四、Git 的首次配置

Git 包含了名为 git config 的配置工具,可获取和设置配置变量。

配置变量存储的三个位置

  • [path]/etc/gitconfig 文件:
    • 包含系统中所有用户及其仓库的值;
    • --system 选项;
  • ~/.gitconfig or ~/.config/git/config 文件:
    • 针对你自己;
    • -- global 选项;
  • 当前仓库的 Git 目录(即 .git/config)中的 config 文件:
    • 针对单个仓库;
    • -- local 选项。
【TIPS】首次配置:设置用户身份、个人编辑器,检查个人设置
  • 设置用户身份:

    • 设置用户名和电子邮件地址:
      $ git config --global user.name "Du Guiyu"
      $ git config --global user.email duhelan07@outlook.com
    • 只需要进行一次配置,Git 此后的每一次提交都使用这些信息,非常重要;
  • 设置个人编辑器:

    • 例如 Emacs:
      $ git config --global core.editor emacs
    • 例如在 Windows 系统中使用 Nodepad++:
      $ git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin" (路径后的选项是启动参数,是 Nodepad++ 自己定义并解析的命令行选项)
    • 当 Git 需要输入消息时会用到该编辑器,如果不配置编辑器,在 Git 发起编辑操作时可能会提前终止;
  • 检查个人设置:

    • 使用 git config --list 命令即可列出当前 Git 可找到的所有设置;
    • 使用 git config <key> 命令可查看 Git 配置中当前某个键的值。

五、获取帮助

使用以下三种方式可查看 Git 命令的帮助:

$ git help <verb>
$ git <verb> --help
$ man git-<verb>

例如 git help config


1.2 - Git 基本操作

一、获取 Git 仓库

建立 Git 项目的方法有两种:

  • 把现有的项目 / 目录导入 Git;
  • 从服务器上克隆现有的 Git 仓库。

(一)在现有目录中初始化 Git 仓库

进入项目目录并输入:git init ;

【TIPS】在 Windows 系统中快速打开 PowerShell / Git Bash 的方法

在 Windows 系统文件管理器中,打开项目文件夹,点击路径栏,输入 cmd / powershell 并回车,可快速在 cmd / powershell 中进入该目录

在目录右键菜单中选择“Open Git Bash here”,快速打开 Git Bash

(二)克隆现有仓库

进入项目目录并输入:git clone <url> ,该命令提供了许多可选项:

# 当前在 C:\projects
 
$ git clone https://github.com/user/repo.git
# 结果:C:\projects\repo\...
 
$ git clone https://github.com/user/repo.git myrepo
# 结果:C:\projects\myrepo\...
 
$ git clone https://github.com/user/repo.git .
# 结果:C:\projects\...(要求当前目录为空)
 
$ git clone https://github.com/user/repo.git path/to/dir
# 结果:C:\projects\path\to\dir\...(dir 目录必须为空)

二、在 Git 仓库中记录变更

工作目录下的每个文件都处于两种状态之一:

  • 已跟踪(tracked):上一次快照中包含的文件;
    • 又可分为:已修改;未修改;已暂存;
  • 未跟踪(untracked):除已跟踪外的所有文件,即 不在上一次快照中,也不在暂存区中的文件。

(一)查看当前文件状态

检查文件状态使用 git status 命令。

# 克隆仓库后,立即使用 git status 命令:
$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
 
nothing to commit, working tree clean

如果向项目中添加一个 README 文件,再使用命令。Git 不会主动添加新文件到下一次的提交范围,所以该文件会处于 未跟踪 状态:

# 初始化一个新仓库,并新建 README.md 文件并写入内容
$ echo 'hello, world' > README.md
$ git status
On branch master
 
No commits yet
 
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        README.md
 
nothing added to commit but untracked files present (use "git add" to track)

(二)跟踪新文件

使用 git add <file/path> 命令让 Git 跟踪新文件:

  • 如果参数为目录,则递归跟踪目录下的所有文件。
$ git add README.md
$ git status
On branch master
 
No commits yet
 
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   README.md

(三)暂存已修改的文件

git add 是多功能命令,其核心操作是把内容写入暂存区,所以既可用来跟踪新文件,也可用来暂存文件。

# 添加一些内容到 README.md 末尾
$ echo "Welcome to salmon-isle.com!" >> README.md
$ git status
On branch master
 
No commits yet
 
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   README.md
 
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.md
 
$ git add README.md
$ git status
On branch master
 
No commits yet
 
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   README.md

为什么第一次的 git status 中 README.md 同时出现在了已暂存和未暂存列表中?

  • 暂存文件时,Git 保存该文件在 git add 时的样子;
  • 如果现在执行 git commit,则会提交该文件上次 git add 时的版本,而不是当前工作目录中的版本;
  • 所以,若暂存区中文件发生修改,需再执行一次 git add;

(四)显示更简洁的状态信息

执行 git status -s 或 git status --short 显示更简洁的状态信息:

$ git status -s
 M README
MM Rakefile
A  lib/git.rb
M  lib/simplegit.rb
?? LICENSE.txt
字母含义
Mmodified,已修改
Aadded,新增并已暂存
Ddeleted,已删除
Rrenamed,重命名
Ccopied,复制
Uupdated but unmerged,冲突未解决
??untracked,未跟踪
!!ignored,被忽略

(五)忽略文件

如果不希望某类文件被 Git 自动添加 / 出现在 Untracked 列表中(如日志文件、构建文件),可创建 .gitignore 文件,列出带匹配文件的模式(pattern):

  • 空行 / 以 # 开头的行会被忽略;
  • 支持标准 glob 模式(一种简介的模式匹配语法);
  • 正斜杠(/)开头的模式,禁止递归匹配。
  • 正斜杠(/)结束的模式,表示目录。
  • 感叹号(!)开头的模式,表示取反。
*.a            # 忽略所有 .a 文件
!lib.a         # 但跟踪 lib.a,即使上面忽略了 .a 文件
/TODO          # 只忽略当前目录下的 TODO 文件,而不是 subdir/TODO
build/         # 忽略任何名为 build 的目录中的所有文件
doc/*.txt      # 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/**/*.pdf   # 忽略 doc/ 目录及其所有子目录中的所有 .pdf 文件

参考资料:

GitHub 官方 .gitignore 模版库,涵盖了百余种不同项目和语言
https://github.com/github/gitignore

(六)查看已暂存和未暂存的变更

使用 git diff 命令能得到具体添加 / 删除了哪些行(即补丁, patch)。

  • diff 解决了:哪些变更还没有被暂存?哪些已暂存的变更正待提交?
命令比较对象
git diff工作区 vs 暂存区(index)
git diff --staged(或 --cached)暂存区 vs 最新提交(HEAD)
git diff HEAD工作区 vs 最新提交
git diff <commit1> <commit2>两个提交之间
git diff <branch1> <branch2>两个分支的顶端
例子(git diff 输出的逐行解释)

poem.md 文件已经在暂存区中,又在间隔较大的两处新增了两行。

文件头:

  • diff --git a/poem.md b/poem.md:比较的是旧版 a/poem.md 和新版 b/poem.md ;
  • index 8dbc764..5bae051 100644:旧 blob 哈希 8dbc764,新 blob 哈希 5bae051,100644 是普通文件权限;
  • --- a/poem.md / +++ b/poem.md:旧侧、新侧文件。

块(hunk):

  • @@ -10,6 +10,8 @@ And sorry I could not travel both 是 块头(hunk header):
    • -10,6 +10,8 指:旧文件从第 10 行开始数 6 行、新文件从第 10 行开始数 8 行;
    • And sorry I could not travel both 是 section heading,由 Git 就近抓取作,辅助开发者定位;
  • Git 默认显示变化的行上、下相邻的三行上下文。

(七)提交变更

执行 $ git commit 命令,将提交暂存区中的所有文件。

执行命令后,会打开指定的文本编辑器(git config --global core.editor):

  • 默认的提交信息会包含被注释掉的 git status 命令的最新输出结果,最上方是一行空行;
  • 既可以删掉这些注释,也可以保留,使用 git commit -v 会让这些信息更详细;
  • 在退出编辑器时,Git 将移除注释内容,将剩下的提交信息记录到本次提交。

使用 git commit -m <message> 可以直接在命令行键入提交信息。

$ git commit -m "Story 182: fix benchmarks for speed"
[master 463dc4f] Story 182: fix benchmarks for speed
 2 files changed, 2 insertions(+)
 create mode 100644 README

首次提交就完成了,命令输出中包含了提交到了哪个分支、SHA-1 校验和、改动的文件数量等等。

(八)跳过暂存区

使用 git commit -a 命令,Git 将自动把所有已跟踪的文件加入暂存区,然后提交。

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
 
    modified:   CONTRIBUTING.md
 
no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m 'Add new benchmarks'
[master 83e38c7] Add new benchmarks
 1 file changed, 5 insertions(+), 0 deletions(-)

(九)移除文件

使用 git rm <file> 移除文件,git rm -r <path> 递归移除目录,支持 glob 模式。

git rm 命令实际上做的事:

  • 先从暂存区中移除,即停止跟踪;
  • 再从工作目录中移除(使用 git rm --cached 可只停止跟踪,不从工作目录中删除)。

如果一个文件与上次一提交时不一致,就必须加上 -f 选项强制删除。

(十)移动文件

使用 git mv file_from file_to 可移动 / 重命名文件。

git mv 命令实际上做的事:

mv old new          # 1. 在文件系统里移动 / 重命名文件
git rm old          # 2. 从索引中删除旧路径
git add new         # 3. 把新路径加入索引

三、查看提交历史

使用 git log 命令可查看仓库的提交历史。

git log                    # 看提交历史
 
git log --oneline          # 一行一条
git log --oneline --graph  # 图形化分支合并结构(只从当前 HEAD 往回走)
git log --all --oneline --graph   # 看全部
 
git log -5                 # 只看最近 5 条
git log --stat             # 查看简要统计信息
git log -p                 # 看具体 diff(相当于 --patch)
git log <file>             # 看某个文件的修改历史
git log --follow <file>    # 追踪文件重命名后的历史
 
git log --author="张三"    # 按作者筛选
git log --since="2 weeks ago"   # 按时间筛选(近两周)
git log -S "functionName"  # 找哪次提交引入/删除了某字符串(pickaxe)
git log --grep="fix bug"   # 按提交信息筛选

对 git log 命令其他选项和参数的详细介绍
https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History


四、补充和撤销操作

(一)补充提交文件

使用 git commit --amend 命令:

$ git commit -m 'Initial commit'
$ git add forgotten_file
$ git commit --amend

被 --amend 提交覆盖的文件是可恢复的,它实际上创建了新提交,并使原提交进入“游离状态”。

(二)撤销已暂存的修改 / 对文件的修改

Git 2.23 引入了 git restore 命令,专门用于撤销操作,用于替代 git reset 和 git checkout 中关于文件操作的部分。

命令作用结果
git restore <file>丢弃工作区的修改用暂存区的内容覆盖工作区。如果没 add 过,则用 HEAD 内容覆盖。
git restore --staged <file>把文件从暂存区撤出用 HEAD 的内容重置暂存区,但工作区修改原封不动。
git restore --staged --worktree <file>彻底重置两个区域用 HEAD 的内容同时覆盖暂存区和工作区,等于彻底放弃该文件的所有未提交修改。

如果仍想保留修改,却需要将它暂时隐藏一会,可使用储藏和分支机制(下一章介绍)。

【旧命令介绍】git reset <commit> <file>(不再推荐使用)

使用 **git reset <commit> <file>** 命令,将指定提交中该文件的版本恢复到暂存区,不改变工作区。

省略提交参数时,默认使用 HEAD。

该操作通常用于取消暂存,但最终文件状态取决于工作区、暂存区和 HEAD 三者之间的差异。

【旧命令介绍】git checkout -- <file>(不再推荐使用)

使用 git checkout -- <file> 命令撤销对文件的更改(这是一条危险命令,永久丢弃未暂存的修改):

......
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
 
    modified:   CONTRIBUTING.md
 
$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
 
    renamed:    README.md -> README

五、使用远程仓库

(一)显示远程仓库

使用 git remote 命令查看已设置的远程仓库

  • 克隆一个仓库后,Git 给克隆源服务器的默认名称是 origin;
  • 使用 git remote -v 可显示远程仓库对应 URL。
$ git clone https://github.com/schacon/ticgit
Cloning into 'ticgit'...
remote: Reusing existing pack: 1857, done.
remote: Total 1857 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done.
Resolving deltas: 100% (772/772), done.
Checking connectivity... done.
$ cd ticgit
$ git remote
origin
 
# 可能有不止一个远程仓库
$ cd grit
$ git remote -v
bakkdoor  https://github.com/bakkdoor/grit (fetch)
bakkdoor  https://github.com/bakkdoor/grit (push)
cho45     https://github.com/cho45/grit (fetch)
cho45     https://github.com/cho45/grit (push)
defunkt   https://github.com/defunkt/grit (fetch)
defunkt   https://github.com/defunkt/grit (push)
koke      git://github.com/koke/grit.git (fetch)
koke      git://github.com/koke/grit.git (push)
origin    git@github.com:mojombo/grit.git (fetch)
origin    git@github.com:mojombo/grit.git (push)

上面的远程仓库地址使用了几种不同协议,将在补充链接阐述。

(二)添加远程仓库

运行 git remote add <shortname> <url> 命令可添加一个远程仓库,并起一个简短名称方便引用

$ git remote
origin
$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin	https://github.com/schacon/ticgit (fetch)
origin	https://github.com/schacon/ticgit (push)
pb	https://github.com/paulboone/ticgit (fetch)
pb	https://github.com/paulboone/ticgit (push)

(三)拉取数据

执行 git fetch <remote> 命令,从远程拉取数据

  • git fetch 只拉取数据到本地,而不自动合并;
  • 如果某个本地分支一直在跟踪远程分支,git pull 命令可在拉取数据后,尝试自动合并(即 git fetch + git merge ,将在下一章介绍);

(四)推送数据

执行 git push <remote> <branch> 命令,把变更推送到远程仓库

要令推送正常工作,必须满足:

  • 拥有克隆下来的仓库的写权限;
  • 克隆后没有其他人向远程仓库推送过数据,否则必须先拉取变更,再合并,才能推送。
$ git push origin feature/login
Enumerating objects: 12, done.
Counting objects: 100% (12/12), done.
Delta compression using up to 8 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 1.25 KiB | 1.25 MiB/s, done.
Total 7 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (3/3), done.
To https://github.com/user/repo.git
 * [new branch]      feature/login -> feature/login

如果当前分支已经设置了上游(upstream),那么可以直接执行 git push(下一章会讲到)

(五)检查远程仓库

执行 git remote show <remote> 命令查看远程仓库的详细信息

$ git remote show origin
* remote origin
  URL: https://github.com/my-org/complex-project
  Fetch URL: https://github.com/my-org/complex-project
  Push  URL: https://github.com/my-org/complex-project
  HEAD branch: master
  Remote branches:
    master                           tracked
    dev-branch                       tracked
    markdown-strip                   tracked
    issue-43                         new (next fetch will store in remotes/origin)
    issue-45                         new (next fetch will store in remotes/origin)
    refs/remotes/origin/issue-11     stale (use 'git remote prune' to remove)
  Local branches configured for 'git pull':
    dev-branch merges with remote dev-branch
    master     merges with remote master
  Local refs configured for 'git push':
    dev-branch                     pushes to dev-branch                     (up to date)
    markdown-strip                 pushes to markdown-strip                 (up to date)
    master                         pushes to master                         (up to date)

输出分析:

远程分支信息

状态含义
tracked本地已经有一个对应的远程跟踪分支(如 origin/master),并且它和远程保持同步跟踪。
new远程有这个分支,但本地还没有对应的远程跟踪引用。下次执行 git fetch 时,会在本地创建 remotes/origin/issue-43、remotes/origin/issue-45。
stale本地存在 remotes/origin/issue-11 这个远程跟踪引用,但远程仓库上这个分支已经被删除了。可以用 git remote prune origin 清理掉这个过时的引用。

此外它还会告诉你 pull 能获取到的所有引用、push 会推送到哪里。

(五)删除和重命名

执行 git remote rename <old> <new> 命令重命名远程仓库;执行 git remote rm 删除远程仓库。

重命名远程仓库也会导致远程分支的名称改变。


六、标记

Git 可以给某个特定提交打上有意义的标签(Tag),通常用来标记版本。

标签的本质是引用,存储在 refs/tags/ 命名空间下,可以指向任意对象(基本是 commit)。

(一)列举标签

使用 git tag 按字母顺序输出所有标签;使用 git tag -l "v1.8.5*" 列出特定标签。

$ git tag
v1.0
v2.0
 
$ git tag -l "v1.8.5*"
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5.1
v1.8.5.2

(二)创建和删除标签

Git 标签有两个类型:

轻量标签(Lightweight):指向某个 commit 的引用,没有额外信息:

  • 创建:git tag v1.4-lw ;

附注标签(Annotated):一个完整对象(Git tag object),包含打标签者的名字、邮箱、日期、标签说明等信息:

  • 创建:git tag -a v1.4 -m "my version 1.4" ;
  • 如果不加 -m,和 commit 一样 Git 会打开默认文本编辑器让你输入。
# 附注标签
$ git show v1.4
tag v1.4
Tagger: Ben Straub <ben@straub.cc>
Date:   Sat May 3 20:19:12 2014 -0700
 
my version 1.4
 
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700
 
    Change version number
 
# 轻量标签
$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw

使用 git tag -d <tag> 可以删除本地仓库的某个标签。
从远程仓库中删除标签要使用 git push origin --delete <tagname>。

(三)补加标签

Git 支持给曾经的 commit 补加标签,使用 git tag -a <tag> <commit> -m <message>。

# 先找到目标 commit 的 hash
$ git log --pretty=oneline
4682c3261057305bdd616e23b64b0857d832627b Add todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a Create write support
9fceb02d0ae598e95dc970b74767f19372d61af8 Update rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc Commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a Update readme
 
# 给指定 commit 打附注标签(可使用短 hash,即 hash 前缀,Git 将自动匹配)
$ git tag -a v1.2.0 9fceb02 -m "补打 1.2.0 版本标签"
 
# 推送到远程
$ git push origin v1.2.0

(四)共享标签

推送标签使用 git push origin <tag> 命令,填入 --tags 可推送全部

$ git push origin v1.5
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done.
Total 14 (delta 3), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new tag]         v1.5 -> v1.5
 
$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new tag]         v1.4 -> v1.4
 * [new tag]         v1.4-lw -> v1.4-lw

git push 推送的是引用(ref),分支和标签都属于引用,所以推送引用也使用 git push。

(五)检出标签

如果想查看某个标签对应的指向的版本,可以使用 git checkout <tag> 命令。但这会使仓库处于“分离 HEAD(detached HEAD)”状态。

因为标签作为一个引用,指向某次具体的提交,所以检出(checkout)会使 HEAD 指向那次具体的提交,而不再指向任何分支。

AI 生成,仅供参考

在“分离 HEAD”的状态下,如果创建提交:

  • 标签将保持不变;
  • 新的提交将不属于任何分支,如果 HEAD 离开了该提交,此后除了通过精确 hash 外无法访问;
  • 并且该提交可能被 Git 的垃圾回收机制清除,丢失。

因此,如果需要在旧版本基础上进行更改,要创建新分支:

# 以标签 v2.0.0 指向的提交为起点,创建一个名为 version2 的新分支,并切换到这个分支
$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2'

七、Git 别名

Git 支持为命令创建别名,例如用 git ci 替代 git commit。


1.3 - 总结

本章从“什么是版本控制”这个问题开始引入了 Git,并介绍了 Git 的特点和首次配置方法,然后全面地介绍了 Git 的基本操作,包括创建或克隆仓库、进行更改、暂存和提交这些更改、查看仓库的所有更改历史记录、远程仓库的使用等等。

下一章将介绍 Git 的分支模型,这是 Git 的核心功能。