Git & GitHub

First Post:

Last Update:

Git

Git 官网: https://git-scm.com

Git: 代码版本管理工具

  • 版本控制系统
  • 管理代码历史
  • 跟踪代码变化

通过时间控制和跟踪代码变化1


Git 的工作方式

工作目录: 使用的项目文件都将由 git 管理的目录

  1. 第一次 commit: 类似于快照, 将所有的文件保存下来
  2. 第二次commit: 只将有改动的文件内容保存下来, 而不是保存文件本身
  3. 当工作目录新增文件时
    第三次commit: 新增的文件将被保存

分支:
默认情况下, git 会将你的更改提交至 master 分支(main 分支)

当想要在主分支的基础上开发新的东西, 而不影响主分支的代码, 就需要用到分支
分支可以创建完全独立的工作目录, 是主分支的完整副本
分支可以合并至主分支

工作树:

1
2
3
4
5
flowchart TB
1[主分支] --> 分支1
1[主分支] --> 分支2
1[主分支] --> ...
分支1 --合并--> 2[主分支]

在 git 管理的目录下会有有个 .git 的隐藏目录, 这个目录被称为 git 仓库

git 仓库包含两个不同的区域:

  • 暂存区, 一个索引文件
    • 可以将其看作是草稿区, 用于暂存代码的改变
  • 对象文件夹, 包含不同的 commit
    • 保存实际的文件和跟踪的改变
1
2
3
4
graph LR

工作目录 --add--> 暂存区 --commit--> 对象文件夹


仓库初始化 和 提交 Commit

如果想要 git 管理工作目录, 需要初始化 git 仓库

1
2
3
4
5
# 查看git仓库信息
git status

# 仓库初始化
git init

将文件加入暂存区

1
2
3
4
git add <文件>

# 一个例子
git add ./

提交至 git 仓库

1
2
3
# -m 选项: 提交的信息
# -m (message)
git commit -m <备注的信息>

如果没有为 git 配置用户名和邮箱, commit 会报错

1
2
git config --global user.email <电子邮箱地址>
git config --global user.name <用户名>

查看提交信息

1
2
3
4
5
6
7
8
9
git log

# 示例:
# 输出的信息
commit 3e3ce608e2a283a807a208ed734bc1659a91d3e8 (HEAD -> master) # 提交id
Author: voilone <voilone@qq.com>
Date: Sun Jan 8 23:26:20 2023 +0800

first commit

如果有多个 commit, 而你想跳转到一个指定的 commit
先查看并复制 commit 的 id
然后:

1
2
git checkout <commit ID>

当跳转到指定的 commit
git log 指令将不会看到指定 commit 后的 commit
但这并不意味着后面的 commit 被删除了

1
2
3
4
# 跳回分支 master 最后的commit
git checkout master

# 会发现, git log 命令又恢复显示回所有的 commit 了

分支 Branches

创建的第一个分支, 默认名称为 master

1
2
# 查看现有分支
git branch

创建分支

1
2
3
4
5
6
7
# 分支名不允许有空格
git branch <分支名>
# 或
git checkout -b <分支名>

# 例:
git branch second-branch

切换至指定的分支

1
git checkout <分支名>

在新建的分支 2 下
git log 命令会显示与主分支一模一样的 commit 包括 commit id


合并分支

将分支合并至主分支

1
2
# 将指定分支合并至当前分支
git merge <指定的分支>

新命令

新命令主要是功能与命令相契合, 便于理解和使用

如果使用的 git 版本 >= 2.23
就可以使用这些新命令

1
2
# 查看 git 版本
git -v

切换和创建分支

1
2
3
4
5
# 切换分支
git switch <分支名>

# 创建分支
git switch -c <分支名>

使用 git log 我们会发现
在一些 commit 后面会有一个 (HEAD -> 分支1, 分支2, ...)

最后一次 commit 称之为 head, 这是一个默认行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
flowchart LR

other --- co1

h2(HEAD) --> co3

subgraph commits2

co1("commit1") --> co2("commit2") --> co3("commit3")

end



master --- commit1

h1(HEAD) --> commit3

subgraph commits
commit1("commit1") --> commit2("commit2") --> commit3("commit3")
end

分离 HEAD

HEAD 不关心分支, 只关心 commit 的 id

当一个 commit 不独属于一个分支时
checkout 指定的 commit id, 会引起 HEAD 分离, 即 detached HEAD 状态2

1
2
3
git checkout <commit id>

# 这样会可能进入 分离 HEAD 状态

删除与撤销

删除跟踪的文件

从工作目录中删除跟踪的文件

1
2
3
4
5
# 查看哪些文件属于暂存区
git ls-files

# 将指定文件从暂存区删除
git rm <文件名>

撤消操作

当文件做出更改时, 你想将指定文件回到最后一次 commit 状态

1
2
3
4
5
6
7
8
9
10
# 将指定文件回归到最后一次 commit 的状态
# --代表没有指定分支
git checkout -- <文件名>

# 简写
git checkout <文件名>

# 例:
# 将当前文件夹恢复至最后一次提交的状态
git checkout -- ./

新命令

等价于 git checkout -- <文件名>:

1
git restore <文件名>

删除未跟踪的文件

1
2
3
4
5
6
7
8
9
10
11
12
# 删除指定未跟踪的文件
git clean <文件>

# 列出将要删除的文件
git clean -dn

# 删除所有未跟踪的文件
git clean -d

# 忽略提醒并删除
# -f 强制
git clean -df

撤销提交到暂存区的文件

在将文件提交到暂存区后, HEAD 会指向暂存区
如果使用 git checkout 命令进行撤销, 将不会起作用

git reset 将文件的最新 commit 存放到暂存区

1
2
3
4
git reset <文件名>

# 然后再进行撤销
git checkout <文件名>

新命令

git reset 命令等价于:

1
git restore --staged <文件名>

Git Stash

基础使用

当你想保存当前代码进度而又不想提交或创建新分支时
你可以用到 git stash

git stash 的基本运用:

1
2
3
4
5
6
7
# 执行这条命令后, 工作目录会跳回到最新的提交
git stash


# 执行这条命令后
# 工作目录恢复到 执行 git stash 前的状态
git stash apply

更多用法

列出多个 stash:

1
2
3
4
5
6
7
git stash list

# 输出
stash@{0}: WIP on master: 8adf4dd file1 added

# 应用指定下标的 stash
git stash apply {0}

创建 stash 时还可添加备注

1
git stash push -m "这是备注"

如果想将 stash 中的内容加入到暂存区, 需要将其弹出

1
git stash pop [stash_下标]

删除某个 stash:

1
2
3
4
git stash drop  [stash_下标]

# 想删除所有 stash
git stash clear

Git Reflog

如果误删一个提交或一个分支, 可使用 git reflog 恢复
需要注意, 恢复的有效期只有 30 天

1
2
# 删除的提交会恢复
git reflog

恢复分支

1
2
3
4
5
6
7
8
# 先从该命令的输出中查找你要恢复的分支哈希值
git reflog

# 先分离 HEAD
git checkout [哈希值]

# 然后再创建分支
git switch -c [分支名]

合并分支

分支合并感觉稍微有点复杂, 使用使用时还需复习下

合并类型:

  • 快进合并 (Fast Forward)
  • 非快进合并 (Non Fast Forward)
  • 递归合并
  • . . .

快进合并

主分支不改动(即没有任何新的提交), 分支提交改变.
在这种情况下合并分支就被称为快进合并

1
2
3
4
git switch master

# 快速合并
git merge [分支名]

这样的合并不会创建新的提交, 也就意味着 HEAD 会同时指向主分支和改变的分支

1
2
3
4
5
6
7
# 进入主分支
git switch master

# 将分支的改变加入到主分支的暂存区
git merge --squash [分支名]

git commit -m "..."

非快进合并(递归合并)

主分支有额外提交, 同时其他分支也有额外提交,
这个时候会用到非快速合并

使用非快速合并, 两个分支将会被合并为一个分支, 并添加至主分支

1
2
# --no-ff 非快速合并
git merage --no-ff [分支]

Git Rebase

rebase 不是移动提交, 而是创建新的提交

注意: 不要在你的本地仓库外 rebase 提交

1
2
3
git branch 其他分支

git rebase 主分支

rebase 通过检测两个分支的同一个起点, 然后基于同一个起点,
将其他分支的进度创建至主分支


合并冲突

有很多潜在的合并冲突, 最容易想到的是不同分支的同一个文件的同一个位置被同时修改导致的合并冲突

当发生合并冲突时, 发生冲突的文件会显示冲突的细节
如果使用 VS Code, VS Code 会给出四个选项来处理冲突:

  • 不接受合并改变 (Accept Current Changes)
  • 接受合并后的改变 (Accept Incoming Changes)
  • 接受两个改变 (AcceptBoth Changes)
  • 比较变化 (Compare Changes)

当然, 也可以手动删除你不想要的冲突, 然后将文件添加到暂存区,然后提交(合并)

1
2
3
4
5
6
7
8
9
10
11
# 查看冲突状态
git status

# 查看具体的冲突
git diff

# 终止合并
git merge --abort

# 可以查看到两个将要合并的提交
git log --merge

要解决冲突, 就是手动删除你不想要的冲突, 然后 add ./, 然后 commit


合并, Rebase, Cherry Pick 的比较

git_3merges.jpg

Cherry Pick

假设这么一种情况, 如果你的主分支出现一些代码上的拼写错误, 而你在分支上修复了它
现在, 你只想将修复了的提交合并至主分支,而不是分支上的所有修改, 这个时候就可以用到 cherry-pick

1
2
3
4
5
6
7
8
9
10
# 假设分支上有两个提交
# 现在我们只想合并 commit 1 至主分支

commit 2 (HEAT -> git-branch)
...
new-feture

commit 1
...
fixed typo

cherry-pick 复制提交, 并生成一个新的提交 ID

1
2
3
4
5
6
7
8
9
10
# 回到主分支
git switch master

# 合并指定分支
git cherry-pick 分支提交ID

# 例:
# 将上面分支的 commit 1 合并到主分支
git switch master
git cherry-pick 1

总结

git_summery.jpg


Git 标签 (git tag)

假设我们的 Git 仓库有很多提交, 其中有些提交是一些代码的最终版本(比如版本 1.0, 版本 2.0 …)
我们可以通过添加 Git 标签来快速定位到这些提交

标签类型:

  • 轻量标签
  • 注释标签 (完整的 tag 对象)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 显示所有的标签
git tag

# 添加轻量标签
git tag 标签名 提交ID

# 添加注释标签
git tag -a 标签名 '注释信息'

# 显示Git 标签
git show 标签名

# 删除轻量标签
git tag -d 标签名

进入标签标记的提交

1
git checkout 标签名

GitHub

GitHub 官网: https://github.com

GitHub:

  • 最大的开发平台
  • 云托管与云协作的服务商
  • Git 存储库的托管服务商

概念

  • 本地仓库 git
  • 远程仓库 GitHub

远程仓库可以是 GitHub 或其他代码托管平台(比如 Gitea, Gitlab….)

1
2
3
# 添加远程仓库
# 这里的 origin 指的是远程仓库的别名
git remote add origin 远程仓库地址
1
2
3
4
5
# 将本地信息上传至远程仓库
git push

# 本地仓库与远程仓库同步
git pull

git_github.jpg



  1. 1.不仅仅是代码, 也可以是其它类型的文件
  2. 2.放心, 这样没有任何问题