目录

  1. 1. 前言
  2. 2. 引入
  3. 3. 安装配置
  4. 4. 工作流程
    1. 4.1. 工作区 Working Directory
    2. 4.2. 暂存区 Staging Area
    3. 4.3. 版本库 Repository
  5. 5. 创建仓库
    1. 5.1. .git 目录
  6. 6. 基本操作
    1. 6.1. 冲突解决
  7. 7. 分支管理
  8. 8. 提交历史
  9. 9. 标签
  10. 10. 注意事项
  11. 11. Git 服务
    1. 11.1. GitHub
    2. 11.2. GitLab
    3. 11.3. Gogs

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

Git

2023/2/5 Dev
  |     |   总文章阅读量:

前言

https://missing.csail.mit.edu/2020/version-control/

https://docs.github.com/zh/get-started/git-basics/set-up-git

https://www.runoob.com/git/git-tutorial.html

https://cloud.tencent.com/developer/article/2194434

https://juejin.cn/post/7272276908379799563

https://segmentfault.com/a/1190000017030384


引入

以 Minecraft 为例,我们设想一下这样一个场景:

  • 首先,本地游玩 Minecraft 一定需要创建一个存档,这个存档会记录下你的游戏状态(Repository)
  • 当你正在盖一个建筑,你想使用“结构方块”把这个建筑框起来,告诉系统我要把这部分存一下(Add)
  • 当你正常退出游戏,系统保存了你的存档,你还复制了这份存档生成了一个快照副本,方便以后的某个时刻不满意想直接回退使用它,然后你意识到你得在某个地方写一个注释用于记录这个快照副本此时的进度,方便下次打开这个快照副本的时候知道从哪开始干(Commit)
  • 你想大搞红石科技,但是你怕把原来的存档卡爆,于是你复制了一份同样的存档,原先的存档继续作为一个普通的建筑档,新复制的这个专门用于搞红石科技,这样即使新复制的这个炸档了也不会影响到原始的存档(Branch)
  • 你在这个用于“实验”的存档中成功造好了红石科技,想把它搬回原始存档(Merge)
  • 你玩的本地存档是单人模式,而你想玩服务器了!(Remote)
  • 你把本地存档的建筑照搬到了服务器里(Push)
  • 你把服务器的建筑照搬到了本地存档(Pull)
  • 你在本地存档里坐标 (X:100, Y:64, Z:100) 的地方放了一块钻石块,但是服务器里同一坐标 (X:100, Y:64, Z:100) 放了一块岩浆。你想把服务器这个坐标的内容照搬到本地,就会发生冲突,需要你自己手动介入(Conflict)

安装配置

Git 不仅仅是个版本控制系统,它也是个内容管理系统(CMS),工作管理系统等。

安装 git: https://git-scm.com/download/

然后 Windows 下就能使用 git bash 了

git config 命令:配置或读取相应的工作环境变量,这些环境变量,决定了 Git 在各个环节的具体工作方式和行为

这些变量可以存放在以下三个地方:

  • /etc/gitconfig 文件:系统中对所有用户都普遍适用的配置。若使用 git config 时用 --system 选项,读写的就是这个文件。
  • ~/.gitconfig 文件:用户目录下的配置文件只适用于该用户。若使用 git config 时用 --global 选项,读写的就是这个文件。
  • 当前项目的 Git 目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以 .git/config 里的配置会覆盖 /etc/gitconfig 中的同名变量。

配置个人的用户名称和电子邮件地址,用于每次提交代码时记录提交者的信息

git config --global user.name "C1oudfL0w0"
git config --global user.email test@cloud.com

检查已有的配置信息:

git config --list

有时候会看到重复的变量名,那就说明它们来自不同的配置文件(比如 /etc/gitconfig 和 ~/.gitconfig),不过最终 Git 实际采用的是最后一个

查看某个环境变量的配置:

git config user.name

工作流程

克隆仓库:

git clone https://github.com/username/repo.git

创建新分支:

git checkout -b new-feature

暂存文件:

git add filename
# 或者添加所有修改的文件
git add .

提交更改:

git commit -m "Add new feature"

拉取最新更改:

git pull origin main
# 或者如果在新的分支上工作
git pull origin new-feature

推送更改:

git push origin new-feature

合并更改:

git checkout main
git pull origin main
git merge new-feature

删除分支:

git branch -d new-feature

# 从远程仓库删除分支
git push origin --delete new-feature

工作区 Working Directory

工作区是你在本地计算机上的项目目录,你在这里进行文件的创建、修改和删除操作。工作区包含了当前项目的所有文件和子目录

  • 显示项目的当前状态。
  • 文件的修改在工作区中进行,但这些修改还没有被记录到版本控制中。

暂存区 Staging Area

暂存区是一个临时存储区域,它包含了即将被提交到版本库中的文件快照,在提交之前,你可以选择性地将工作区中的修改添加到暂存区。

  • 暂存区保存了将被包括在下一个提交中的更改。
  • 你可以多次使用 git add 命令来将文件添加到暂存区,直到你准备好提交所有更改。
git add filename       # 将单个文件添加到暂存区
git add .              # 将工作区中的所有修改添加到暂存区
git status             # 查看哪些文件在暂存区中

版本库 Repository

版本库包含项目的所有版本历史记录。

每次提交都会在版本库中创建一个新的快照,这些快照是不可变的,确保了项目的完整历史记录。

  • 版本库分为本地版本库和远程版本库。这里主要指本地版本库。
  • 本地版本库存储在 .git 目录中,它包含了所有提交的对象和引用。
git commit -m "Commit message"   # 将暂存区的更改提交到本地版本库
git log                          # 查看提交历史
git diff                         # 查看工作区和暂存区之间的差异
git diff --cached                # 查看暂存区和最后一次提交之间的差异

完整的操作:

# 本地修改文件后
git add file.txt
git commit -m "Update file.txt"
git push origin main # 推送到远程仓库

创建仓库

git init <repo_path> # 默认为当前目录,执行后创建 .git 目录
git addgit commit -m '初始化项目版本'

注: 在 Linux 系统中,commit 信息使用单引号 ',Windows 系统,commit 信息使用双引号 "。所以在 git bash 中 git commit -m '提交说明' 这样是可以的,在 Windows 命令行中就要使用双引号 git commit -m "提交说明"

.git 目录

./git
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── index
├── info
│   └── exclude
├── logs
│   └── HEAD
├── objects
│   ├── 00
│   │   └── fa871f7c774c8a2f3c8204e3546e80daabe365
│   ├── 1d
│   │   └── 6f7af91f6b8b8ac903bd77ea9ee7531ab59a9f
│   ├── 46
│   │   └── fc026da73f9cdb62f72506f0146f5ad22ca4c8
│   ├── 5b
│   │   └── 58bd121fd2c29b36d2f5dd7dfd450bde15f4c1
│   ├── 8c
│   │   └── bb1da21438cf0907cda9bb85ddcf065fa43bf3
│   ├── af
│   │   └── 74f3306302ad59fc71670c229f16a1fa606849
│   ├── b4
│   │   └── cfa0242cf57a9373c7c7c73397414ff7b8f530
│   ├── bc
│   │   └── 7b276cb5dee2c2fcb62641047d7b79c74783b9
│   ├── ce
│   │   └── a0b8cbf9737b4f438e56fb23b7b12e03ecde96
│   ├── dc
│   │   └── dbd0b338ad13627f452ab48bdbc5df67ab576c
│   ├── e6
│   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│   └── ff
│       └── 13a25b35fda25c5fc977cb4e2009a97d50f4d1
└── refs
    └── heads
        └── master

COMMIT_EDITMSG:保存着最近一次的提交信息,git 不会用到这个文件,只是给用户一个参考

flag commit

config:存储了项目级别的 Git 配置信息,包括用户名、邮箱、远程仓库等。

[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true

description:对于空的 Git 仓库,此文件内容为空。对于非空的 Git 仓库,内容为描述该项目的文本。

Unnamed repository; edit this file 'description' to name the repository.

HEAD:指向当前所在的分支(或者是一个特定的提交)

ref: refs/heads/master

index:包含了暂存区(stage)的内容,记录了即将提交的文件和相关元数据

❯ hexdump -C index
00000000  44 49 52 43 00 00 00 02  00 00 00 01 67 b6 df ac  |DIRC........g...|
00000010  06 6f f3 00 67 b6 df ac  06 6f f3 00 00 00 fd 00  |.o..g....o......|
00000020  06 34 25 e8 00 00 81 a4  00 00 00 00 00 00 00 00  |.4%.............|
00000030  00 00 00 09 dc db d0 b3  38 ad 13 62 7f 45 2a b4  |........8..b.E*.|
00000040  8b db c5 df 67 ab 57 6c  00 08 66 6c 61 67 2e 70  |....g.Wl..flag.p|
00000050  68 70 00 00 a8 d5 ca b5  11 ba 3b d8 66 2b 79 6c  |hp........;.f+yl|
00000060  ee 90 25 78 0e e7 c0 17                           |..%x....|
00000068

info:包含一些辅助性的信息

logs:存储了每个引用(分支、标签等)的修改历史

cat logs/HEAD
0000000000000000000000000000000000000000 ff13a25b35fda25c5fc977cb4e2009a97d50f4d1 ryan <ryan@work.com> 1740033342 +0800 commit (initial): first file
ff13a25b35fda25c5fc977cb4e2009a97d50f4d1 af74f3306302ad59fc71670c229f16a1fa606849 ryan <ryan@work.com> 1740033420 +0800 commit: second file
af74f3306302ad59fc71670c229f16a1fa606849 af74f3306302ad59fc71670c229f16a1fa606849 ryan <ryan@work.com> 1740033512 +0800 checkout: moving from master to flag
af74f3306302ad59fc71670c229f16a1fa606849 1d6f7af91f6b8b8ac903bd77ea9ee7531ab59a9f ryan <ryan@work.com> 1740033731 +0800 commit: flag file
1d6f7af91f6b8b8ac903bd77ea9ee7531ab59a9f af74f3306302ad59fc71670c229f16a1fa606849 ryan <ryan@work.com> 1740034654 +0800 checkout: moving from flag to master
af74f3306302ad59fc71670c229f16a1fa606849 1d6f7af91f6b8b8ac903bd77ea9ee7531ab59a9f ryan <ryan@work.com> 1740036538 +0800 checkout: moving from master to flag
1d6f7af91f6b8b8ac903bd77ea9ee7531ab59a9f 5b58bd121fd2c29b36d2f5dd7dfd450bde15f4c1 ryan <ryan@work.com> 1740038030 +0800 commit: flag commit
5b58bd121fd2c29b36d2f5dd7dfd450bde15f4c1 af74f3306302ad59fc71670c229f16a1fa606849 ryan <ryan@work.com> 1740038060 +0800 checkout: moving from flag to master

objects:存储了Git仓库的对象(commits、trees和blobs),其中的命名规则为 refs 前两位作为文件夹,refs 剩下的部分作为文件名,如 ff13a25b35fda25c5fc977cb4e2009a97d50f4d1 的结构为 ff/13a25b35fda25c5fc977cb4e2009a97d50f4d1,文件中的内容是 zlib 压缩后的 commit,解压后内容如下:

commit 151\x00tree cea0b8cbf9737b4f438e56fb23b7b12e03ecde96
author ryan <ryan@work.com> 1740033342 +0800
committer ryan <ryan@work.com> 1740033342 +0800

first file

refs:存储了所有的引用(分支、标签等)

cat refs/heads/master
af74f3306302ad59fc71670c229f16a1fa606849

基本操作

git init
git clone	# 拷贝一份远程仓库,包括被clone仓库的版本变化

git add
git status
git diff	# 比较文件的不同,即暂存区和工作区的差异
git difftool
git range-diff	# 比较两个提交范围之间的差异
git commit
git reset	# 回退版本
git rm	# 将文件从暂存区和工作区中删除
git mv	# 移动或重命名工作区文件
git notes	# 添加注释
git checkout	# 分支切换
git switch	# 更清晰的分支切换
git restore	# 恢复或撤销文件的更改
git show	# 显示git对象的详细信息

git log
git blame <file>
git shortlog
git describe

git remote
git fetch	# 从远处获取代码库,将本地已有的远程仓库更新到最新状态,仅拉取更改不会合并分支
git pull	# 拉取远程分支更新到本地仓库,自动合并与更改
git push
git submodule	# 管理包含其他 Git 仓库的项目

冲突解决

当我们尝试 git pull 更新本地仓库时,有时会遇到 error: Your local changes to the following files would be overwritten by merge... Please commit your changes or stash them before you merge.

这是因为本地修改了文件,而远程仓库更新的代码恰好也要覆盖这些文件

解决方法,分多种情况:

  • 放弃本地修改,直接用远程最新代码
git reset --hard HEAD
git pull
  • 保留本地修改,与最新代码合并
# 1. 将本地修改暂时“藏”起来
git stash

# 2. 重新拉取最新代码(此时会成功)
git pull

# 3. 将刚刚“藏”起来的修改恢复到代码中,如果你的修改和原作者的修改冲突了,Git 会提示你手动解决冲突(Merge Conflict)
git stash pop
  • 保存本地修改
# 1. 提交你的本地修改
git add .
git commit -m "保存我的本地修改"

# 2. 重新拉取并合并
git pull

分支管理


提交历史


标签

Git 标签(Tag)用于给仓库中的特定提交点加上标记,通常用于发布版本(如 v1.0, v2.0)


注意事项

  • Windows (^M)和 Linux/Mac 的换行符不一样,如果一个仓库的代码在 Windows 下打开过,系统会自动把文件的换行符替换成 Windows 格式。此时在 Mac 下 git pull 会导致冲突,可以强制拉取最新代码,也可以使用此命令让 git 自动处理换行符问题
git config --global core.autocrlf true

(设置完之后,Git 在拉取时会自动转换换行符,提交时也会自动转回去,就不会再报这种错误了)


Git 服务

GitHub


GitLab


Gogs

Gogs(Go Git Service)是一个用 Go 语言编写的轻量级、自托管的 Git 服务解决方案