From 7a2a62ca818e7b98e81a9273ef998c1ec8577c0a Mon Sep 17 00:00:00 2001 From: dichgrem Date: Sun, 30 Nov 2025 16:37:39 +0800 Subject: [PATCH] update:git --- content/about-git.md | 622 +++++++++++++------------------------------ 1 file changed, 188 insertions(+), 434 deletions(-) diff --git a/content/about-git.md b/content/about-git.md index a3010e3..55af858 100644 --- a/content/about-git.md +++ b/content/about-git.md @@ -6,203 +6,249 @@ date = 2023-12-15 tags = ["乱七八糟"] +++ - - 前言 Git,作为现代软件开发中不可或缺的版本控制工具,常常让初学者感到困惑。本文旨在介绍 Git 的全流程安装和基本使用,希望能够帮助新手更轻松地理解和掌握 Git 的基本概念和操作。 -## 安装git -- Windows:[Git-download](https://git-scm.com/download/) +我们以Github为例子过一遍Git的安装/配置/连接和第一次提交. -- Archlinux:`sudo pacman -S git` +## 1.安装Git -## 原理 +- Windows:官网下载[Git-download](https://git-scm.com/download/)或者使用Scoop/WinGet等等. -一个Git仓库的目录里面包括``工作目录``(即我们要追踪的代码)以及``.git``目录(Git 在这里存储自己的数据)。Git 维护了三棵“树”:第一个是你的 `工作目录`,它持有实际文件;第二个是 `暂存区(Index)`,它像个缓存区域,临时保存你的改动;最后是 `HEAD`,它指向你最后一次提交的结果。 +- Linux:Ubuntu:`sudo apt install git` / Arch:`sudo pacman -S git` +安装完成后可以在终端中检测版本: -![git-tree](http://marklodato.github.io/visual-git-guide/basic-usage.svg.png) - -## 创建新仓库 - -首先我们需要得到一个Git仓库,一般有两种方法: - -- 在本地初始化之后连接到远程; -- 在远程创建后”下载“到本地。 - -**方法一** -创建新文件夹,在你的项目目录中运行以下命令: -```bash -git init --initial-branch=main ``` -这里设置默认仓库主分支名称为 main,避免因为 main/master 名称不同导致的推送问题。 - -> Git目前默认的主分支为 master,和 github 默认分支 main 不同,这使得默认配置下 git 往往连接失败。除了创建的时候设定外还可以通过以下方法改变默认分支。 -```bash -git config --global init.defaultBranch main //将默认分支修改成main +❯ git -v +git version 2.51.2 ``` -**方法二** -克隆远端服务器上的仓库: +## 2.创建密钥 -- HTTPS方法:``git clone https://github.com/Dichgrem/script.git`` -- 或者使用SSH方法:``git clone git@github.com:Dichgrem/script.git`` +在推送代码到Github的时候,我们需要进行认证,有密码认证和密钥认证两种方法,现在推荐使用密钥认证。 ->建议使用SSH方法,如果你使用HTTPS方法,则提交代码时需要手动输入用户名/密码,使用SSH方法则只需要在``~/.ssh/config``中配置即可。 +- 首先生成一对公私钥,这里的邮箱可以随意填写: -## 配置 +```bash +ssh-keygen -t rsa -b 4096 -C "your_email@example.com" +``` +你会看到如下所示的提示,像我一样填写路径的时候就可以顺便给它改个名字,否则会使用默认名id_rsa: -Git的设置文件为.gitconfig,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)。 +``` +❯ ssh-keygen -t rsa -b 4096 -C "your_email@example.com" +Generating public/private rsa key pair. +Enter file in which to save the key (/home/dich/.ssh/id_rsa): /home/dich/.ssh/Github +``` +随后一直按回车即可. + +- 生成的这对公私钥位于``~/.ssh/config``路径下,在Windows中就是``C盘/User/你的用户名``下,带.pub后缀的文件为公钥,不带.pub后缀的为私钥,打开公钥复制全部内容,然后将公钥添加到Github的``Settings-SSH and GPG keys``中。 + +> 当你添加完毕后就无法在Github的设置中再次查看它了,确保了安全性. + +- 随后编辑 `~/.ssh/config` 文件,这个文件的作用是让Git知道主机对应的密钥,例如: + +```bash +# GitHub + +Host github + HostName github.com + User git + IdentityFile ~/.ssh/Github + +# Gitee + +Host gitee + HostName gitee.com + User git + IdentityFile ~/.ssh/Gitee +``` + +> 这边的IdentityFile是你的私钥位置,即为不带pub后缀的文件。如果你不想将私钥放在~/.ssh/下,可以查看我的另一篇[博客](https://blog.dich.bid/network-ssh/) + +- 设置好上面这些后就可以测试连接到Github,如果成功则显示successfully. + +```bash +❯ ssh -T git@github.com + +Hi Dichgrem! You've successfully authenticated, but GitHub does not provide shell access. +``` + +## 3.配置Git + +在正式连接到仓库前,我们还需要让Git知道我们的用户名和邮箱地址。 - 显示当前的Git配置 ```bash git config --list ``` -- 编辑Git配置文件 -```bash -git config -e [--global] -``` -- 设置提交代码时的用户信息 + +- 设置提交代码时的用户信息,这里的name推荐和你的GitHub用户名一致,邮箱可以不为真实邮箱,比如``no-reply@github.com`` ```bash git config [--global] user.name "[name]" git config [--global] user.email "[email address]" ``` -- 设置大小写敏感(windows不区分大小写的解决办法) + +> 注意!如果你填写了你的真实邮箱,同时这个仓库又是Public的,那么其他人可以看到你的邮箱! + +- 配置默认主分支为Main + ```bash -git config core.ignorecase false +git config --global init.defaultBranch main ``` -- 配置git默认使用的编辑器 -```bash -git config --global core.editor "nvim" +这里的设置是因为Git目前默认的主分支名为 master ,而 Github 默认分支名为 main ,这样可以保持一致。 + +## 4.创建仓库 + +配置完Git之后我们就可以连接到远程的仓库了。首先创建一个Git仓库,一般有两种方法: + +- 方法一(推荐)在远程创建后下载到本地 + +我们在Github中的``repositories``下New一个仓库,然后在绿色的Code按钮中复制链接,克隆远端服务器上的仓库; + +``` +git clone git@github.com:Dichgrem/script.git ``` -## 连接远程仓库 +>如果你前面没有配置密钥,就会发现无法使用这个命令克隆仓库。那么什么时候使用HTTPS的克隆呢?比如其他人的仓库,你没有权限,又不想fork一份的情况下,就可以使用HTTPS. -连接到远程仓库并推送需要证明你有权写入仓库。早期Github可以使用密码认证,现在则使用密钥认证。 +- 方法二:在本地初始化之后连接到远程 + +创建一个新文件夹,然后在那个文件夹下运行以下命令: -- 生成密钥: ```bash -ssh-keygen -t rsa -b 4096 -C "your_email@example.com" -``` -- 生成的文件位于``~/.ssh/config``路径下,带.pub后缀的文件为公钥,不带.pub后缀的为私钥,使用``cat ~/.ssh/id_rsa.pub``将公钥添加到github/gitee的设置-SSH中。 - -- 随后使用 `ssh-add` 命令将生成的密钥添加到 SSH 代理中。 -```bash -ssh-add ~/.ssh/github_key -ssh-add ~/.ssh/gitee_key -``` -- 在 `~/.ssh/config` 文件中配置不同的主机别名以及相应的密钥文件。编辑该文件并添加内容,例如: -```bash -# GitHub repository 1 - -Host github1 - - HostName github.com - - User git - - IdentityFile ~/.ssh/github_key - -# GitHub repository 2 - -Host github2 - - HostName gitee.com - - User git - - IdentityFile ~/.ssh/gitee_key +git init --initial-branch=main ``` -- 连接到github: -```bash -ssh -T git@github.com -``` -- 添加远程仓库: +- 在Github上创建一个同名仓库,随后添加远程链接: + ```bash git remote add origin - -# 例如:git remote add origin git@github.com:Dichgrem/dichos.git ``` + > 如果你运行``git remote -v``发现URL为HTTP格式则可以用下面的命令改为Git格式: ```bash # 例如:git remote set-url origin git@github.com:Dichgrem/dichos.git ``` -## 创建分支 -```bash -git branch main -``` -这将创建一个名为 main 的分支。 +## 4.推送代码 -- 删除分支 -```bash -git branch -d master -``` -- 使用大写强制删除 -```bash -git branch -D master -``` +- 添加 - -## 添加和提交 - -你可以提出更改(把它们添加到暂存区),使用如下命令: +在Git仓库中新建或修改文件后,使用如下命令把它们添加到暂存区: ```bash -git add git add * ``` -这是 git 基本工作流程的第一步;使用如下命令以实际提交改动: -```bash + +- 提交 + +随后使用如下命令提交改动: +```bash git commit -m "代码提交信息" -# 例如:git commit -m "Initial commit" +# 例如:git commit -m "update:mycode" ``` 现在,你的改动已经提交到了 **HEAD**,但是还没到你的远端仓库。 -- 添加指定文件到暂存区 -```bash -git add [file1] [file2] ... -``` -- 添加指定目录到暂存区,包括子目录 -```bash -git add [dir] -``` -- 添加当前目录的所有文件到暂存区 -```bash -git add . -``` -添加每个变化前,都会要求确认 -- 对于同一个文件的多处变化,可以实现分次提交 -```bash -git add -p -``` -- 删除工作区文件,并且将这次删除放入暂存区 -```bash -git rm [file1] [file2] ... -``` -- 停止追踪指定文件,但该文件会保留在工作区 -```bash -git rm --cached [file] -``` -- 改名文件,并且将这个改名放入暂存区 -```bash -git mv [file-original] [file-renamed] -``` -## 推送改动 +- 推送改动 + +执行如下命令以将这些改动提交到远端仓库,随后即可在GitHub上查看; -你的改动现在已经在本地仓库的 **HEAD** 中了。执行如下命令以将这些改动提交到远端仓库: ```bash git push origin main ``` -可以把 **main** 换成你想要推送的任何分支,如**master**或者**test** -如果你的远程仓库是最新的,可以使用以下命令更新本地仓库: -```bash -git pull +> 想学习更多Git操作,可以使用这个[Git练习网站](https://learngitbranching.js.org/?locale=zh_CN) + +## 5.Commit规范 + +- 提交信息的基本格式,例如 + +``` +feat:add_highlight ``` -> Verified +- 常见的 Commit 类型 + +```bash +- feat:新功能的添加 + +- fix:修复 Bug + +- docs:文档相关的修改 + +- style:代码格式、排版等不影响代码逻辑的调整 + +- refactor:代码重构,不涉及新功能或 Bug 修复 + +- perf:性能优化 + +- test:添加或修改测试代码 + +- build:构建相关的变更,如依赖管理、构建脚本等 + +- ci:持续集成相关的修改 + +- chore:其他杂项维护,不涉及源代码或测试文件的修改 + +- revert:回滚到上一个版本的提交 +``` + +## 6.Git原理 + +- 三棵树 + +一个Git仓库的目录里面包括``工作目录``(即我们要追踪的代码)以及``.git``目录(Git 在这里存储自己的数据)。Git 维护了三棵“树”:第一个是你的 `工作目录`,它持有实际文件;第二个是 `暂存区(Index)`,它像个缓存区域,临时保存你的改动;最后是 `HEAD`,它指向你最后一次提交的结果。 + +![git-tree](http://marklodato.github.io/visual-git-guide/basic-usage.svg.png) + +- `.git` 目录结构 + +```bash +.git/ +├── HEAD +├── config +├── description +├── hooks/ +├── index +├── info/ +│ └── exclude +├── logs/ +│ ├── HEAD +│ └── refs/ +├── objects/ +│ ├── info/ +│ └── pack/ +├── refs/ +│ ├── heads/ +│ ├── remotes/ +│ └── tags/ +``` + +* objects:存储 Git 的所有对象,包括: + * blob:文件内容 + * tree:目录结构 + * commit:提交对象,记录提交信息和指向的树对象 + * tag:标签对象 + 这些对象以 SHA-1 哈希命名,前两位作为子目录,其余作为文件名 +* refs:存储所有引用,包括: + * heads:本地分支 + * remotes:远程分支 + * tags:标签 +* HEAD:指向当前检出的分支或提交。例如,`ref: refs/heads/main` 表示当前位于 `main` 分支 +* config:仓库级别的配置文件,包含用户名、邮箱、远程仓库等信息 +* description:用于描述仓库,仅供 GitWeb 等工具使用 +* hooks:存放 Git 钩子脚本的目录,可用于在特定操作前后执行自定义脚本,如 `pre-commit`、`post-merge` 等 +* index:暂存区(staging area)的索引文件,记录了即将提交的文件信息 +* info:包含辅助信息,如 `exclude` 文件用于定义仓库级别的忽略规则 +* logs:记录了引用(如分支、标签)的更新历史,有助于追踪操作记录 + +--- + +## 7.Tips + + +### Verified 在 GitHub 的 commit 历史中看到的 “Verified” 标记,表示该提交是经过 签名验证(signed commit) 的,也就是 GitHub 能确认这个 commit 的确是由声明的提交者(你)签名并发布的。可以通过GPG或者SSH配置: @@ -245,184 +291,7 @@ git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers Good "git" signature for test@mail.com with ED25519 key SHA256:ssh-ed25519 AAAABBBBBBBBBBBBBBBBBBBBB ``` -## 合并分支 - -分支是用来将特性开发绝缘开来的。比如你在本地的test分支新增了一个功能,想要合并到主分支中。 - -创建一个叫做“test”的分支,并切换过去: -```bash -git checkout -b test -``` -新增某些功能后切换回主分支: -```bash -git checkout master -``` -在主分支上执行合并操作,将 test 分支的改动合并到主分支: -```bash -git merge test -``` -推送完成后可以把新建的分支删掉: -```bash -git branch -d test -``` - -### 分支常用操作 -```bash -- 列出所有本地分支 -git branch - -- 列出所有远程分支 -git branch -r - -- 列出所有本地分支和远程分支 -git branch -a - -- 列出所有本地分支,并展示没有分支最后一次提交的信息 -git branch -v - -- 列出所有本地分支,并展示没有分支最后一次提交的信息和远程分支的追踪情况 -git branch -vv - -- 列出所有已经合并到当前分支的分支 -git branch --merged - -- 列出所有还没有合并到当前分支的分支 -git branch --no-merged - -- 新建一个分支,但依然停留在当前分支 -git branch [branch-name] - -- 新建一个分支,并切换到该分支 -git checkout -b [branch] - -- 新建一个与远程分支同名的分支,并切换到该分支 -git checkout --track [branch-name] - -- 新建一个分支,指向指定commit -git branch [branch] [commit] - -- 新建一个分支,与指定的远程分支建立追踪关系 -git branch --track [branch] [remote-branch] - -- 切换到指定分支,并更新工作区 -git checkout [branch-name] - -- 切换到上一个分支 -git checkout - - -- 建立追踪关系,在现有分支与指定的远程分支之间 -git branch --set-upstream-to=[remote-branch] -git branch --set-upstream [branch] [remote-branch] - 已被弃用 - -- 合并指定分支到当前分支 -git merge [branch] - -- 中断此次合并(你可能不想处理冲突) -git merge --abort - -- 选择一个commit,合并进当前分支 -git cherry-pick [commit] - -- 删除分支 -git branch -d [branch-name] - -#新增远程分支 远程分支需先在本地创建,再进行推送 -git push origin [branch-name] - -- 删除远程分支 -git push origin --delete [branch-name] -git branch -dr [remote/branch] -``` - -## 标签 - -Git 的 tag 功能主要用于``给仓库历史中的某个特定提交打上“标签”``,通常用于标记版本发布点(例如 v1.0、v2.0 等),以``便于后续的版本定位、回溯和发布管理``。 - -### 标签类型 - -Git 提供两种类型的标签: - -- 附注标签(Annotated Tag)会创建成一个完整的 Git 对象,存储打标签者的名字、邮箱、日期和标签说明,还可采用 GPG 进行签名。推荐用于正式发布,因为包含更多元数据和安全信息。 - -- 轻量标签(Lightweight Tag)实际上只是对某个提交的引用,不保存额外信息,类似一个固定的分支。适用于临时标记或非正式用途。 - -### 创建标签 - -- 创建附注标签 - -使用 -a 参数表示“annotated”,并用 -m 提供标签说明。例如,给当前提交创建一个名为 v1.0 的附注标签: -```bash -git tag -a v1.0 -m "发布版本 v1.0" -``` -这会在 Git 数据库中生成一个完整的标签对象,可通过 git show v1.0 查看标签信息和对应的提交详情。 - -如果需要给旧提交贴标签,可以在命令末尾指定提交的 SHA 值(部分 SHA 也可): -```bash -git tag -a v1.0 -m "发布版本 v1.0" -``` - -- 创建轻量标签 - -直接指定标签名即可,不加任何参数: -```bash -git tag v1.0-light -``` -轻量标签仅仅是一个提交引用,因此查看时不会显示附加信息。 - -### 列出标签 -- 列出所有标签 -```bash -git tag -``` -- 还可以使用通配符过滤: -```bash -git tag -l "v1.*" -``` -这样便于管理和筛选大量标签。 -- 查看标签详细信息 -```bash -git show v1.0 -``` -这会显示标签对象的元数据以及对应的提交记录。 - -### 推送标签 -``默认情况下,git push 不会将本地标签推送到远程仓库。推送标签有两种方式:`` -- 推送单个标签 -```bash -git push origin v1.0 -``` -- 一次性推送所有标签 -```bash -git push origin --tags -``` -### 删除标签 -- 删除本地标签 -```bash -git tag -d v1.0 -``` -- 删除远程标签 -```bash -git push origin --delete v1.0 -``` -## 日志 - -如果你想了解本地仓库的历史记录,最简单的命令就是使用: -```bash -git log -``` -- 只看某一个人的提交记录: -```bash -git log --author=bob -``` -- 一个压缩后的每一条提交记录只占一行的输出: -```bash -git log --pretty=oneline -``` -- 看看哪些文件改变了: -```bash -git log --name-status -``` -## 生成补丁 +### 生成补丁 比如你修改了项目中的``fs/proc/base.c``,然后 @@ -433,7 +302,8 @@ git format-patch origin/16.0 ``` 即可在目录下生成补丁``0001-fix-base.patch``. -## 删除前一个提交记录 + +### 删除前一个提交记录 有时候手滑或者不想使用一个commit说明,可以用以下命令撤销上一个 commit: ```bash git reset --soft HEAD~1 @@ -444,122 +314,6 @@ git reset --soft HEAD~1 ```bash git reset --hard HEAD~1 ``` -> 注意:--hard 会清除未提交的更改,无法恢复。 -## `.git` 目录中主要文件和子目录的结构及其作用 - -### 📁 `.git` 目录结构概览 - -```bash -.git/ -├── HEAD -├── config -├── description -├── hooks/ -├── index -├── info/ -│ └── exclude -├── logs/ -│ ├── HEAD -│ └── refs/ -├── objects/ -│ ├── info/ -│ └── pack/ -├── refs/ -│ ├── heads/ -│ ├── remotes/ -│ └── tags/ -``` - -### 🗂️ 核心文件和目录说明 - -* **HEAD**:指向当前检出的分支或提交。例如,`ref: refs/heads/main` 表示当前位于 `main` 分支。 - -* **config**:仓库级别的配置文件,包含用户名、邮箱、远程仓库等信息. - -* **description**:用于描述仓库,仅供 GitWeb 等工具使用。 - -* **hooks/**:存放 Git 钩子脚本的目录,可用于在特定操作前后执行自定义脚本,如 `pre-commit`、`post-merge` 等. - -* **index**:暂存区(staging area)的索引文件,记录了即将提交的文件信息。 - -* **info/**:包含辅助信息,如 `exclude` 文件用于定义仓库级别的忽略规则。 - -* **logs/**:记录了引用(如分支、标签)的更新历史,有助于追踪操作记录。 - -* **objects/**:存储 Git 的所有对象,包括: - - * **blob**:文件内容。 - * **tree**:目录结构。 - * **commit**:提交对象,记录提交信息和指向的树对象。 - * **tag**:标签对象。 - 这些对象以 SHA-1 哈希命名,前两位作为子目录,其余作为文件名。 - -* **refs/**:存储所有引用,包括: - - * **heads/**:本地分支。 - * **remotes/**:远程分支。 - * **tags/**:标签。 - -## Commit规范 - -### 提交信息的基本格式 - -- Header(头部) -格式: -``` -[可选的 scope]: <简短描述> -``` - -type 表示提交类型,如:feat(新功能)、fix(修复bug)等。 -scope 是可选的,用于指出变更影响的模块或范围。 -简短描述 用于概述本次提交的核心内容,通常使用祈使语气。 - -- Body(正文) -用于详细说明变更的动机、方法以及可能的影响,建议每行不超过 72 个字符。 - -- Footer(脚注) -可选部分,用来引用相关 issue、任务或说明破坏性变更(例如:BREAKING CHANGE: ...)。例如: - -``` -Fixes #123 -``` -这可以在提交后自动关闭相关问题。 - -### 常见的 Commit 类型 -```bash -- feat:新功能的添加 - 示例:feat(user): 添加用户注册功能 - -- fix:修复 Bug - 示例:fix(parser): 修复解析错误导致程序崩溃 - -- docs:文档相关的修改 - 示例:docs(readme): 更新使用说明 - -- style:代码格式、排版等不影响代码逻辑的调整 - 示例:style: 优化代码缩进和空格 - -- refactor:代码重构,不涉及新功能或 Bug 修复 - 示例:refactor: 优化数据处理逻辑 - -- perf:性能优化 - 示例:perf: 提升数据查询速度 - -- test:添加或修改测试代码 - 示例:test: 补充用户登录单元测试 - -- build:构建相关的变更,如依赖管理、构建脚本等 - 示例:build: 更新 webpack 配置 - -- ci:持续集成相关的修改 - 示例:ci: 调整 GitHub Actions 配置 - -- chore:其他杂项维护,不涉及源代码或测试文件的修改 - 示例:chore: 更新项目依赖 - -- revert:回滚到上一个版本的提交 - 示例:revert: 撤销上次提交 -``` --- **Done.**