参考
概念
graph TB;
R(远程仓库<br>remote repository)
L(本地仓库<br>local repository)
S(暂存区<br>stage area)
W(工作区<br>work space)
W--add-->S
S--commit-->L
L--push-->R
R--pull-->W
R--clone/fetch-->L
L--checkout-->W
工作区
work space
(工作区)是本地文件系统中存储库目录, 可理解为在本地计算机上存放源代码目录
用户可在工作区进行代码编辑、添加、修改和删除等操作, 所有文件最新修改都体现在工作区中
状态
modified
(已修改)
表示文件已修改, 但还未提交到版本库中
staged
(已暂存)
表示文件已修改, 并且已添加到暂存区, 准备提交到版本库
committed
(已提交)
表示文件已提交到版本库
暂存区
stage area
(暂存区)是.git目录下名为index文件, 本质是数据库
暂存区作为缓冲地带, 分离工作区与版本库交互, 使工作区中更改先进入暂存区, 而不会立即进入版本库
本地仓库
本地仓库是在开发者自己电脑上git仓库, 包含项目全部提交历史, 用于存储本地工作区和暂存区变更(新增、修改、删除)文件
对工作区中文件修改, 并提交到暂存区和本地仓库后, 更改就永久保存在本地仓库历史记录中
远程仓库
远程仓库是在远程服务器git仓库, 用于存储备份、共享和协同工作代码
远程仓库允许团队成员将本地更改推送到远程仓库, 并从远程仓库拉取其他成员更改
操作
clone
(克隆)
将远程仓库复制到本地
push
(推送)
将本地仓库更改上传到远程仓库
pull
(拉取)
将远程仓库更改下载到本地仓库
版本管理
初始化
将当前目录初始化为本地仓库, 执行命令后自动创建.git
目录, 用于管理版本库
git init
初始化后当前目录及其子目录和文件都处于工作区
在工作区内创建或修改, git会将其视为未跟踪文件(untracked files), 添加到暂存区并提交到版本库后, 文件状态变为已跟踪文件(tracked files)
- 示例, 将git_test初始化为本地仓库
.git目录
.git目录是一个隐藏目录, 位于Git版本控制的仓库的根目录下, 包含了git仓库所有元数据和信息, 用于跟踪和管理版本控制
状态
查看文件状态
git status
未添加文件
- 示例, 未添加文件时状态
修改
- 示例, 新增文件, 状态为
untracked files
红色表示文件位于工作区并已修改, 还未添加到暂存区
撤销
撤销工作区内文件修改
将文件恢复到上一次提交状态
git restore 文件名
撤销工作区内所删除文件
从上一次提交中恢复被删除文件到工作区
git checkout -- 文件名
添加
将文件从工作区添加至暂存区, 指令中文件名为.
时表示全部文件
git add 文件名
- 示例, 将main.cpp添加到暂存区
绿色表示文件已添加暂存区
撤回
将已添加至暂存区文件撤回至工作区
git rm --cached 文件名
- 示例, 将暂存区文件main.txt撤回到工作区
提交
将暂存区文件提交至本地仓库
git commit (-m "commit信息")
- 示例, 提交main.cpp
(1) 若未设置邮箱用户名, 需先设置
(2) 设置完成后正常提交
查看记录
查看每次提交记录, 包含commit ID
、作者、提交时间信息
git log
- 示例, 查看git_test仓库提交记录
修改commit内容
假设需在commit后修改内容提交内容
修改最近一次commit
git commit --amend
回退
设原始test.txt
origin origin origin origin origin
设修改后test.txt
modify modify modify modify modify
未暂存回退
用于已修改未添加至暂存区(未执行git add
)回退, 指令中文件名为.
时表示全部文件
文件会恢复至修改前状态
git checkout -- 文件名
- 示例, 修改test.txt后, 在未添加到暂存区时回退
已暂存回退
用于已修改并添加到暂存区(已执行git add
)回退
注意!, git reset
只撤回添加操作, 不会撤回文件修改
# 回退指定文件
git reset HEAD 文件名
# 回退所有修改
git reset
- 示例, 将修改后test.txt添加到暂存区后回退
执行后文件被撤回到工作区, 但修改后内容不变
已commit退回
用于已修改并已commit回退, 分三种情况
git中HEAD
表示当前提交, 上版本表示为HEAD^
, 前100个版本表示为HEAD~100
设将修改后test.txt已提交到本地仓库
reset –hard
删除工作空间改动, 撤销git commit
, 撤销git add .
# 回退到上次commit
git reset --hard HEAD^
# 回退到任意版本
git reset --hard 某次commit_id
- 示例, 执行回退
回退后, 暂存区和工作区均会回到上次提交时状态, 所有自上次后修改全部被恢复
reset –soft
不删除工作空间改动, 撤销git commit
, 不撤销git add .
git reset --soft HEAD^
- 示例, 执行回退
回退后, 被修改文件会在暂存区, 且文件自上次修改后内容不会删除
reset –mixed
不删除工作空间改动, 撤销git commit
, 并撤销git add .
git reset --mixed HEAD^
- 示例, 执行回退
回退后, 修改后文件会在工作区, 且文件自上次修改后内容不会删除
分支
git分支允许在代码库中创建多个开发线
gitGraph
commit id: "main-1"
commit id: "main-2"
branch dev
checkout dev
commit id: "dev-1"
checkout main
branch fix
checkout fix
commit id: "fix-1"
每个分支本质上都是代码库一个快照, 可在不影响其他分支情况下独立进行开发和修改
graph LR;
P(特点)
P-->A(代码隔离)-->A1(分支之间代码独立, 可在不同分支上修改, 互不干扰)
P-->B(代码合并)-->B1(合并操作会将分支上所有更改应用到目标分支上)
P-->C(版本控制)-->C1(可创建多分支来跟踪不同版本或不同阶段开发)
查看
查看当前分支
初始化仓库时默认创建master(main)分支
git branch (-a, 表示所有分支)
- 示例, 查看git_test仓库所有分支
查看远程分支
git branch -r
创建
仅创建分支
git branch 分支名
创建分支并切换
git switch -c 分支名
- 示例, 创建dev分支并切换
gitGraph
commit id: "main 1"
commit id: "main 2"
branch dev
checkout dev
commit id: "dev 1"
修改
切换分支
git switch 分支名
- 示例, 切换回master分支
重命名
重命名当前分支
git branch -M 新分支名
删除
git branch -d 分支名
- 示例, 删除dev分支
合并
合并代码时分两种情况,
(1) 完全合并, 需要另一个分支所有变动, 使用 git merge
(2) 选择合并, 只需要部分变动(某几次提交), 使用 git cherry-pick
完全合并
git merge 待合并分支名
正常合并
git switch B分支
git merge A分支
- 示例, 将dev分支合并到master分支
(1) 设master分支上创建文件 test.txt, 提交
0 ---> origin
(2) 新建dev分支并切换, 对 test.txt进行两次修改, 并提交
第一次修改
0 ---> origin
+ 1 ---> modify first
第二次修改
0 ---> origin
1 ---> modify first
+ 2 ---> moidfy second
(3) 切换回master分支, 合并dev分支所有提交
gitGraph
commit id: "first commit"
branch dev
switch dev
commit id: "dev second commit"
commit id: "dev third commit"
switch main
merge dev id: "merge dev"
冲突情况
两个分支合并时可能会出现冲突错误
- 示例, 两分支修改同文件同位置, 导致合并冲突
(1) 设在master分支上创建 test.txt, 并提交
// test.txt
master master master master master
gitGraph
commit id: "master first commit"
(2) 创建dev分支切换, 修改 test.txt, 并提交
// test.txt
dev dev dev dev dev
gitGraph
commit id: "master first commit"
branch dev
switch dev
commit id: "dev first commit"
(3) 切回master分支, 再修改test.txt 提交
[master] upate upate upate upate upate
gitGraph
commit id: "master first commit"
branch dev
switch dev
commit id: "dev first commit"
switch main
commit id: "master second commit"
(4) 将dev分支合并到master分支
gitGraph
commit id: "master first commit"
branch dev
switch dev
commit id: "dev first commit"
switch main
commit id: "master second commit"
merge dev type: REVERSE
提示冲突, 因为两个分支修改同一文件, test.txt 内容如下
<<<<<<<
表示当前修改, >>>>>>>
表示传入修改
冲突是因两个分支都修改文件同一位置所导致
(5) 解决冲突
设保留双方更改, 修改后提交
gitGraph
commit id: "master first commit"
branch dev
switch dev
commit id: "dev first commit"
switch main
commit id: "master second commit"
merge dev id: "merge dev"
选择合并
git cherry-pick
可选择其他分支单次/多次提交, 并作为新提交引入到当前分支
git cherry-pick 某次commit_id
- 示例, 将dev分支上某次提交合并到main分支
(1) 设master分支上创建test.txt, 并提交
master master master master master
(2) 切换到pick分支, 对test.txt进行三次修改并提交
第一次修改
master master master master master
+ [pick] fix 1
第二次修改
master create origin
[pick] fix 1
+ [pick] fix 2
第三次修改
master create origin
[pick] fix 1
[pick] fix 2
+ [pick] fix 3
(3) 选择合并
将pick分支 commit “pick 2 commit”提交合并到master分支
gitGraph
commit id: "master 1 commit"
branch pick
switch pick
commit id: "pick 1 commit"
commit id: "pick 2 commit"
commit id: "pick 3 commit"
switch main
cherry-pick id: "pick 2 commit"
提示冲突, 查看test.txt
选择保留双方修改, 解决冲突后提交
后续可用git cherry-pick --continue
继续合并其他提交, 或用git cherry-pick --abort
放弃合并
应用多提交
按顺序逐一应用提交到当前分支上
git cherry-pick commit1 commit2...
应用范围提交
可指定提交范围应用
git cherry-pick 开始commit^结束commit
标签
tag
(标签)标记特定commit
, 用于记录项目开发过程中重要里程碑或发布版本
创建
指定commit
git tag 标签名 (某次commit_id, 为空表示最新commit)
- 示例, 使用最新commit作标签
git tag v1.0
gitGraph
commit id: "master 1 commit"
commit id: "cherry-pick pick 2 commit" tag: "v1.0"
- 示例, 使用commit 52e3a21e149837607fffe8126…作标签
gitGraph
commit id: "master 1 commit" tag: "v0.9"
commit id: "cherry-pick pick 2 commit" tag: "v1.0"
添加描述信息
git tag -a 标签名 -m 描述信息 某次commit_id
删除
删除本地tag
git tag -d 标签名
删除远程tag
git push origin :refs/tags/标签名
查看
git tag
远程仓库
远程仓库通常位于远程服务器, 如GitHub、GitLab、Bitbucket或Gitee等代码托管平台
克隆
通过克隆可将远程仓库内容复制到本地, 创建一个与之相同本地仓库
完全克隆
克隆远程仓库所有提交记录
git clone 仓库地址 (存放路径)
- 示例, 克隆github上仓库到本地
拉取最近记录
git clone --depth 提交次数 参数地址
查看
远程仓库地址
git remote -v
- 示例, 查看test_project项目
删除
按名称删除
git remote rm 远程主机名
- 示例, 删除远程仓库
按URL删除
git remote set-url --delete origin 远程仓库地址
添加
git remote add 远程主机名 远程仓库地址
- 示例, 添加远程仓库
拉取
从远程仓库获取更新, 使本地仓库保持同步
git pull 远程主机名 远程分支名:本地分支名
若远程分支是与当前分支合并, 可简写为git pull
- 示例, 从远程仓库master分支拉取更新到本地master分支
手动合并
git pull
过程可分解为,
(1) 通过git fetch
从远程主机将远程最新内容拉到本地, 用户可决定是否合并到本地分支中
git fetch 远程主机名 远程分支名
取回更新后, 会返回FETCH_HEAD
, 指某个分支在服务器上最新状态
通过git log -p FETCH_HEAD
查看更新文件名、作者和时间、代码, 可以通过这些信息来判断是否产生冲突
(2) 通过git merge
将拉取下来最新内容合并到当前所在分支中, 若提示冲突, 需手动解冲突后提交
git merge FETCH_HEAD
- 示例, 本地仓库通过手动合并远程仓库master分支更新
推送
git push
将本地分支更改上传到远程仓库
git push 远程主机名 本地分支名:远程分支名
设存在远程仓库http://192.168.1.128:3000/test_user/demo.git
推送已创建仓库
git remote add origin 仓库地址
git push origin 分支
- 示例, 本地建立demo项目
新建main.cpp提交, 将本地分支推送到远程仓库master分支
推送本地分支
git push 远程主机名 本地分支名:远程分支名
若本地分支与远程分支一致, 则可简写为git push
- 示例, 本地新建dev分支, 推送到远程仓库
设置跟踪关系(可选)
为在以后推送中不再每次指定远程分支名, 可使用-u(或–set-upstream)标志来设置跟踪关系
git push -u 远程仓库名 本地分支名
设置跟踪关系后, 后续只需调用git push
即可将更改推送到所关联远程分支
同时推送到多仓库
添加多个远程仓库地址, 就可同步push
到多个库
git remote set-url --add origin 远程仓库地址
推送本地标签
git push origin 分支名 --tags
- 示例, 本地master分支建立tag:v0.1并上传
子模块
git子模块(git submodules
)允许将一个git仓库作为另一个git仓库子目录
graph LR;
X(作用)
X-->A(依赖管理)-->A1(可将三方库作为子模块包含, 方便管理依赖关系)
X-->B(版本控制)-->B1(可单独跟踪和更新子模块版本)
X-->C(代码复用)-->C1(多个项目之间共享相同代码库, 而无需复制代码)
X-->D(隔离性)-->D1(可在不影响主项目情况下更新或修改子模块)
初始化
自动拉取
使用--recursive
在克隆项目同时拉取子模块
git clone --recursive 项目地址
- 示例, 克隆项目时拉取子模块
手动拉取
若克隆项目时未拉取子模块, 可在主项目根目录手动拉取
git submodule init
git submodule update --recursive
查看
git submodule
- 示例, 查看仓库内子模块
添加
git submodule add 子模块仓库地址 (子模块路径)
修改
更新
更新子模块以获取最新改动
git submodule update --remote
提交
子模块修改后, 与普通项目提交方式一致
删除
移除子模块
git submodule deinit -f 子模块本地路径
删除子模块目录
git rm 子模块本地路径
配置
下载
查看
系统配置
git config --system --list
用户配置
git config --global --list
修改
用户信息
配置用户名(必须)
git config --global user.name "用户名"
配置邮箱(必须)
git config --global user.email "邮箱"
设置
配置编辑器
git config --global core.editor "code -w"
防止中文乱码
git config --global core.quotepath false
启用文件大小写敏感
git config --global core.ignorecase false
设置代理
git config --global http.proxy 代理地址
取消代理
git config --global --unset http.proxy
使用
本地使用
- 示例, 本地新建项目git_demo
git init
新建hello.md文件
# Hello World
提交
git add .
git commmit -m "初次提交"
github使用
设置
注册github账号
配置公钥
github设置公钥后, 上传下载即可免输入密码
复制本地用户.ssh目录公钥id_rsa.pub值
上传
本地项目上传到github仓库上
graph LR;
S(开始)
S-->A[本地修改]-->B[本地commit]-->C{首次上传}
C--Y-->D[设置远程仓库地址]-->E
C--N-->E[git push]
E-->F(结束)
新建
- 示例, github上新建项目git_demo
首次上传
设是首次上传本地项目
# 修改分支名为min
git branch -M main
# 添加远程仓库
git remote add origin git@github.com:[替换实际仓库]/git_demo.git
# 首次上传
git push -u origin main
后续提交可直接使用git push
推送
下载
将github上项目下载(更新)到本地
graph LR;
S(开始)
S-->A{首次下载}
A--Y-->B[git clone]-->F
A--N-->C{直接合并}
C--Y-->C1(git pull)
C--N-->C2(git fetch and git merge)
C2-->F
C1-->F(结束)
克隆
首次将项目下载到本地
git clone 仓库地址
更新
假设仓库存在新修改, 同步到本地
git pull
PR
PR
(Pull Request)功能允许个人向其他项目贡献代码, 通常用于团队协作和开源项目贡献中
当开发者修改了他人代码后, 可以通过Pull Request将修改告知给代码原作者, 请求他合并这些修改
graph LR;
A[fork仓库]
B[创建分支]
C[修改推送]
D[创建RP]
A-->B-->C-->D
fork仓库
- 示例, fork仓库data-structure
修改推送
建立本地分支dmjcb_fix, 修改部分内容, 推送本地分支dmjcb_fix到远程分支
提交PR
搭建个人git
选择开源gogs
docker部署
docker run -itd --name=self_gogs -p 10022:22 -p 3000:3000 gogs/gogs
- 示例, 访问http://ip:3000地址, 出现安装界面
使用
建立用户
- 示例, 建立用户user1
建立仓库
- 示例, 建立仓库test_project
推送
- 示例, 本地修改推送
本地拉取test_project仓库
新建文件
// main.c
#include <stdio.h>
int main(void) {
printf("Hello World\n");
return 0;
}
提交
git工具
vscode
下载
修改
红色表示删除内容
绿色表示新增内容
添加暂存区
提交
推送
repo
安装
下载
mkdir -p ~/repo
cd ~/repo
git clone https://mirrors.tuna.tsinghua.edu.cn/git/git-repo
cd ~/repo/git-repo
sudo chmod +x ./repo
sudo cp ./repo /usr/bin/
设置环境变量
变量~/.bashrc
, 追加
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/'
source ~/.bashrc