
🔥keyipatience:个人主页
🎬作者简介:C/C++后端开发学习者
🌟专栏传送门:《c++》《linux》《c++高阶数据结构》《c++数据结构与算法》《前端学习》
《Git》
⭐️patience is key in life

Git 分布式版本控制系统
Git 是分布式 的,和 SVN 这种集中式不一样:每一台开发者电脑上,都保存一份完整的版本库(工作区、暂存区、所有历史提交记录全都有)。
集中式:只有中央服务器存完整仓库,本地只拿文件,断网基本没法提交、看历史。
分布式:本机就是完整仓库,断网也能正常 commit、查看历史、分支操作。
多人协作原理
每个人本地都有全套版本库:
- 你在自己电脑修改文件、提交;同事在他电脑也修改同一份文件、提交;
- 你们之间可以互相推送(push)、拉取(pull)对方的提交,同步修改;
优点:安全性高
每个人手里都有完整副本。 如果某一台电脑硬盘损坏、数据丢了,可以从其他任何人的仓库里复制一份完整版本库恢复,不怕单点故障
实际开发里的 "中央服务器
Git 本身分布式,不是必须要有中央服务器;但是实际工作几乎都会搭一个(比如 GitHub、Gitee、公司 GitLab)。大家都往这个公共仓库推代码、从这里拉代码,统一协作入口。

新建远程仓库


归属(下拉框)
选仓库属于谁:
- 选自己账号:私人仓库
- 如果你加入了 Gitee 组织,也可以选组织(团队共用)
仓库名称【必填】
只能英文、数字、横杠 -、下划线 _,不能中文、空格 ,就是仓库地址里的名字。 例:cpp-demo,仓库地址最后一段就是它。
仓库介绍(选填)
简单写这个项目是干嘛的,展示在仓库主页。
是否开源
- 公开:所有人都能看、克隆你的代码;你可以设置别人能不能提 PR
- 私有:只有你自己、你添加的成员可以访问,外网看不到
使用 Readme 文件初始化这个仓库
勾选:Gitee 自动帮你生成一个 README.md(项目说明文档) 勾选之后:远程仓库自带一个提交记录。后面本地上传代码的时候,就必须先 pull,不然 push 冲突。 不勾选:远程是空仓库,里面啥文件都没有,没有任何提交记录。本地代码直接 push 上去,不用 pull。
添加 .gitignore
.gitignore 的作用:告诉 git 哪些文件不要提交(编译产物、缓存、IDE 配置、日志等) 下拉选择对应模板:
许可证(开源仓库才需要关心,私有仓库随便选)
只有你选【公开】仓库时这个才有意义:
- MIT:很宽松,别人可以拿你的代码改、商用,保留版权声明就行(最常用)
- GPL:别人修改、基于你的项目发布,也必须开源
- 私有仓库:许可证选不选无所谓,一般选【不添加许可证】
分支模型
Gitee 新建页这个下拉:
- 标准模型(master /main 单主分支) 只有一条主分支,新版 Gitee 默认主分支名字是
main,老仓库叫master。个人学习、课程作业、自己写项目,无脑选这个。 - GitFlow 分支模型 自动创建:
main、develop、feature/、release/、hotfix/* 分支一套体系 适用:正规团队长期迭代项目,版本发布、bug 修复分开管理 不适合:个人小项目,太麻烦,分支太多用不上
其他小选项
- 允许 Issue:开启后别人可以给你提问题、反馈 bug,私有仓库也可以关掉
- 允许 Pull Request:别人可以提交代码修改请求,个人项目无所谓
组合方案两套
方案 1:你本地已经有仓库(推荐搭配)
网页填写配置:
-
归属:自己账号
-
仓库名:xxx
-
是否开源:私有
-
【不要勾选 Readme 初始化】
-
.gitignore:选 C++(按需)
-
许可证:不添加
-
分支模型:标准模型 创建之后,本地命令
//给这个本地仓库绑定一个远程地址,远程的别名固定叫
origin
git remote add origin https://gitee.com/xxx/xxx.git
//把本地的提交记录,推送到远程 origin 对应的仓库的master分支
git push -u origin main//手滑勾选了 Readme(远程有 README),上面 push 会报错,换成:
git remote add origin https://gitee.com/你的名字/仓库名.git
//专门用来解决:本地和远程各有第一条提交、历史互不关联的报错
git pull origin main --allow-unrelated-histories//
git push -u origin main
方案 2:本地是空的,打算新建一个全新仓库克隆下来再写代码(推荐搭配)
网页填写配置:
-
归属:自己账号
-
仓库名:xxx
-
是否开源:私有
-
勾选 Readme 初始化
-
.gitignore:选 C++
-
许可证:不添加
-
分支模型:标准模型 创建之后,本地只需要:
git clone https://gitee.com/xxx/xxx.git
//git clone干的事:
- 创建名为
xxx的文件夹 - 进入文件夹,执行
git init,生成.git,把这个文件夹变成本地 Git 仓库 - 执行
git remote add origin https://gitee.com/xxx/xxx.git,绑定远程地址 - 拉取远程仓库所有提交记录(
git fetch) - 检出默认分支(main/master),把所有文件放到本地文件夹
- 创建名为
Gitee 克隆仓库的两种方式:HTTPS 和 SSH
1、HTTPS(简单)
git clone https://gitee.com/hyb91/git_teaching.git
- 优点:不用额外配置,复制链接直接克隆
- 缺点:每次 push /pull 的时候,都要输入你的 Gitee 账号密码
2、SSH(配置完之后免密码,长期写代码推荐)
git clone git@gitee.com:hyb91/git_teaching.git
- 直接跑这条命令大概率报错:
Permission denied (publickey),因为现在服务器不认你,没有密钥 - 原理:SSH 靠一对密钥验证身份(公钥 + 私钥),不用输账号密码
SSH 完整配置步骤
1.生成密钥对
ssh-keygen -t rsa -C "你的gitee绑定邮箱"
一路回车,不要设置密码。 生成两个文件,在 ~/.ssh/ 文件夹:
id_rsa:私钥!自己收好,绝对不能发给别人id_rsa.pub:公钥,这个要复制内容放到 Gitee 上
2.把公钥上传到 Gitee Gitee 右上角头像 → 设置 → SSH 公钥 标题随便写,把 id_rsa.pub 里面全部文本粘贴进去,保存,验证账号密码。
3.配置完成后,再用 ssh 链接 clone。
详细剖析:
git remote
列出所有远程仓库的别名 输出只有 origin,代表:这个本地仓库绑定了一个远程仓库,名字就叫 origin(就是我们之前说的默认远程别名)
其实当我们从远程仓库克隆后,实际上 Git 会自动把本地的 master 分支和远程的 master 分支对应起来,并且,远程仓库的默认名称是 origin
怎么理解:
origin 只是远程仓库的别名 ,就是一个简短代号,代替长长的仓库地址。 git clone 执行的时候,Git 自动执行了 git remote add origin 仓库地址( 给当前这个本地 Git 仓库,登记一个远程仓库,代号叫 origin)。 之后写 origin 就代表这个 Gitee 仓库,不用每次粘贴一长串链接。
用 git remote -v 就能看到 origin 绑定的真实地址。
git remote -v
origin git@gitee.com:hyb91/git_teaching.git (fetch)
origin git@gitee.com:hyb91/git_teaching.git (push)
//- `(fetch)`:拉取地址,用来 `pull / fetch`(下载远程代码到本地)
//- `(push)`:推送地址,用来 `push`(把本地代码上传到远程)
本地 master 和远程 master 对应起来"(跟踪关系 / 上游关联)
克隆完成,本地会生成 master 分支,Git 自动设置: 本地 master 的上游(跟踪分支) = origin/master。相当于 Git 记住了你这个本地分支默认要推送到 origin 的 master 分支
这个绑定带来的效果: 你直接敲
git push
等价于
git push origin master:master
直接敲
git pull
等价于
git pull origin master:master
一句话:因为有这个跟踪绑定,命令可以简写,不用每次都写
origin master
对比另外一种路线 (git init + git remote add origin)
如果你是自己 git init 新建本地仓库、手动 remote add origin: 不会自动建立分支跟踪关系 所以第一次 push 必须加 -u:
git push -u origin master
-u 的作用就是:手动建立这个跟踪绑定 ,绑定成功之后,后面也可以直接 git push。
向远程仓库推送
# 1. ls 查看当前里面已有文件
ls
# 输出:README.en.md README.md(clone下来自带的)
# 2. vim 新建并编辑 file.txt
vim file.txt
# 里面写入:hello git
# 3. cat file.txt 查看文件内容,确认写进去了
cat file.txt
# 4. git add .
git add .
# 5. git commit -m "create file.txt"
git commit -m "create file.txt"
commit 时的身份要求
提交时要注意,如果我们之前设置过全局的 name 和 e-mail,这两项配置需要和 gitee 上配置的用户名和邮箱一致,否则会出错。(Git和gitee配置要一样)
user.name/user.email(commit 作者信息) 是标记:这个代码是谁写的,commit 的时候就写进版本记录。 如果和 Gitee 账号里的邮箱不匹配:Gitee 识别不出是你提交的,头像不显示、贡献统计不算绿点,严格仓库会直接报错。
设置命令:
# 全局(所有git仓库共用)
git config --global user.name "gitee用户名"
git config --global user.email "gitee绑定邮箱"
git push 语法
基础语法:
git push <远程主机名> <本地分支名>:<远程分支名>
如果本地分支名字 和 远程分支名字一样,冒号和后面的远程分支可以省略:
git push origin master
# 等价于
git push origin master:master
前面讲过的git push只有当前分支绑定了上游(跟踪关系) ,才能直接 git push
# 1. 新建并切换到本地dev分支
git checkout -b dev
# 2. 修改文件、add、commit
git add .
git commit -m "开发功能"
# 3. 第一次推这个分支,带上 -u 建立跟踪
git push -u origin dev:dev
# 之后再在dev分支提交,直接简写
git push
git pull 拉取远程代码
场景:别人 / 你自己在 Gitee 网页上直接改了文件,远程仓库版本跑在你本地前面了,本地代码落后,需要把远程最新代码抓下来合并到本地
git pull <远程主机名> <远程分支名>:<本地分支名>
底层本质: git pull = git fetch(下载远程更新记录) + git merge(自动合并到本地分支)
配置Git
忽略特殊文件
.gitignore :告诉 Git 哪些文件不要追踪、不要提交、不要上传到远程仓库。
怎么得到 .gitignore
两种方式:
- 新建仓库的时候(推荐) Gitee 创建仓库页面,勾选「添加 .gitignore」,选择对应语言模板(C/C++、Python、Java 等),平台自动帮你写好一大堆通用忽略规则。
- 仓库已经建好之后 自己在仓库根目录 手动新建名字为
.gitignore的文件(注意开头有个点,是隐藏文件),自己写规则。
必须放在仓库根目录才全局生效;放在子文件夹只对这个文件夹生效。
规则写法示例
# 井号 # 代表注释
*.ini # *是通配符:所有以 .ini 结尾的文件
*.so # 所有以 .so 结尾的文件(linux编译出来的动态库)
写完 .gitignore 之后,这个 .gitignore 本身也要提交到远程,让团队所有人共享这套忽略规则:
vim .gitignore # 编辑写入忽略规则
git add .
git commit -m "add .gitignore"
git push origin master
验证是否生效
touch a.so b.ini # 新建两个被规则匹配的文件
git status
输出:working tree clean
含义:Git 完全看不见 a.so、b.ini,不会提示这是新文件,忽略成功。
3 个重要配套命令
1. 强制添加被 ignore 屏蔽的文件:git add -f
正常情况下,写在 gitignore 里的文件 git add 会直接无视。 如果你特殊情况非要提交它 ,加 -f(force 强制):
git add -f a.so
不推荐经常用!一般是特殊需求才强制提交,违背 ignore 的初衷
2. 排查:看是哪一条规则把文件忽略了 git check-ignore -v
当你怀疑规则写错,想知道「为什么这个文件被忽略了」:
git check-ignore -v a.so
输出示例:
.gitignore:3:*.so a.so
解读:是 .gitignore 文件第 3 行的 *.so 这条规则,把 a.so 忽略了,方便你定位修改。
例外规则:! 取反
.* # 忽略所有以 . 开头的隐藏文件(.xxx文件)
!.gitignore # !代表【不要忽略这个文件】,例外放行
如果只写 .*,.gitignore 本身也会被忽略,就提交不上去; 加 !.gitignore 代表:虽然上面说了忽略所有点开头文件,但是 .gitignore 除外,要追踪它。
重点补充
注意:. .gitignore 只对 untracked(从未提交 / 已经从版本库移除)的文件生效;对 tracked(曾经 commit 过)的文件无效
git rm --cached 文件名
怎么用 git rm --cached和reset有什么不一样?
- 场景:文件从未 commit 过
- 不小心
git add了 → 用git reset HEAD 文件名撤回暂存- 此时文件回到 untracked,再写入
.gitignore可以忽略- 误add了但是只要没有commit,2条命令效果相同
- 场景:文件已经 commit 过(tracked),以后不想再跟踪
- 只做
git reset HEAD 文件+ 写进.gitignore不行!- reset 仅仅撤出暂存,文件仍然是 tracked,ignore 直接失效
- 正确做法:
git rm --cached 文件名→ 产生删除变更 → commit 提交这次变更- 提交后,文件变成 untracked,
.gitignore才会生效
git reset HEAD 文件:只操作暂存区,不改变 tracked 状态git rm --cached 文件:在暂存区生成 "删除文件" 变更,commit 后解除跟踪
再分清楚:
| 跟踪类型 | 作用对象 | 用什么命令 |
|---|---|---|
| 文件跟踪 | 单个文件 | git add |
| 分支上游跟踪 | 整个分支 | git push -u / git branch -u |
Git 别名 alias(命令简写)
作用:给很长、高频敲的 git 命令起短别名,少打字。
git config [--global] alias.别名名 原命令
eg:
# git ci 代替 git commit
git config --global alias.ci commit
# git br 代替 git branch
git config --global alias.br branch
# git co 代替 git checkout
git config --global alias.co checkout
查看已经配好的所有别名
git config --global --list
里面能看到你所有 alias.xxx
删除别名
git config --global --unset alias.st
Git 标签 tag
tag 本质:给某一条 commit 起一个好记的别名,一般用来标记版本里程碑,比如 v1.0、v2.1,代替长长的 commit-id。 用处:commit id 一串哈希很难记,tag 名字清晰;以后回退、查看某个正式版本直接用 tag,不用复制哈希。
创建轻量标签(默认,最简单)
① 给【最新提交(HEAD)】打标签
git tag v1.0
不加 commit id,默认打在当前最新这条 commit 上
② 给【历史某一条 commit】打标签
先查简短 commit id:
git log --pretty=oneline --abbrev-commit
拿到哈希(比如 c6ce3f0),再打 tag:
git tag v0.9 c6ce3f0
列出所有标签
git tag
标签是按字母排序,不是按创建时间排序! 比如 v0.9、v1.0,列表里 v0.9 会在上面。
查看这个标签对应的提交详情
git show v1.0
会展示对应的 commit 信息、作者、时间、文件改动 diff。
附注标签(带备注说明,推荐正式发布用)
git tag -a v1.1 -m "版本v1.1:完成基础功能" [commit-id]
-a:annotated,附注标签(独立对象,带说明、打标签人信息)-m "xxx":写标签备注- 末尾可选 commit-id,不写就是给最新 commit 打
对比:
- 轻量标签(不加 - a):仅仅是 commit 的一个别名,没有额外备注信息,适合临时标记
- 附注标签(-a):正式版本发布用,信息完整,推荐项目上线版本用
Git Tag 标签的推送与删除
删除【本地标签】
git tag -d v0.9
只删本地,远程不受影响;标签还没 push 到远程时,直接这条就够了
推送标签到远程
# 推送单个标签
git push origin v1.0
# 一次性推送所有本地标签
git push origin --tags
删除【已经推送到远程的标签】(两步!)
① 先删本地标签
git tag -d v1.0
② 再推送删除指令到远程
# 写法1:冒号语法,左边空代表删除
git push origin :refs/tags/v1.0
# 写法2:--delete,可读性更强,推荐你用这个
git push origin --delete v1.0
Git从本地到远程完整删除一个文件
git rm test.txt # 在 index(暂存区)写入【删除这条文件的改动】
git commit -m "删掉test.txt" # 把这个"删除改动打包进一个commit提交里"
git push # push 是推送 commit
Git删除分支完整指令
# 1. 先切到别的分支,不能在要删的分支里面
git checkout main
# 2. 安全删除本地分支
git branch -d test-branch
# 3. 删除远程Gitee上的分支
git push origin --delete test-branch
//或者
git push origin :分支名
删除远程分支、远程 tag 的远程命令格式是一模一样的:`git push origin --delete xxx`