git使用

 

参考

概念

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客户端官网下载

查看

系统配置

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