版本管理
Git
私有服务搭建:Gitea
仓库信息读取
1. commit统计
# 读取仓库贡献者和对应的commit数
# -s (--summary):只显示提交总数,不列出具体的 commit 信息。
# -n (--numbered):按照提交数量从多到少排序。
git shortlog -snCommit规范
Commit 信息的基本结构
一个规范的 Commit 信息通常包括以下部分:
- 类型(Type):说明 Commit 的类型,例如
feat、fix、docs等。 - 范围(Scope):可选,说明 Commit 影响的范围,例如模块、组件或文件。
- 主题(Subject):简洁地描述 Commit 的目的,不超过 50 个字符。
- 正文(Body):可选,详细描述 Commit 的内容和动机。
- 脚注(Footer):可选,用于关联 Issue 或 Breaking Changes。
<类型>(<范围>): <主题>
<正文>
<脚注>以下是常见的 Commit 类型:
| 类型 | 描述 |
|---|---|
feat | 新增功能(Feature)。 |
fix | 修复 Bug。 |
docs | 文档更新(Documentation)。 |
style | 代码格式调整(不影响代码逻辑,如空格、缩进等)。 |
refactor | 代码重构(既不修复 Bug 也不新增功能)。 |
perf | 性能优化(Performance)。 |
test | 测试代码(新增或修改测试用例)。 |
chore | 构建过程或辅助工具的变动(如依赖更新、配置文件修改等)。 |
ci | 持续集成(Continuous Integration)相关的修改。 |
revert | 回滚之前的 Commit。 |
build | 构建系统或外部依赖的修改(如 Webpack、Gulp 等)。 |
merge | 合并分支。 |
Commit 信息的基本结构
feat: 新增用户登录功能fix(用户模块): 修复登录时密码验证失败的问题
在用户登录时,密码验证逻辑存在错误,导致部分用户无法登录。此 Commit 修复了该问题。eat(订单模块): 新增订单取消功能
BREAKING CHANGE: 订单取消接口的返回值结构发生变化,请前端同事注意更新。配置用户和Email
配置文件通常位于~/.gitconfig中。
# 配置
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
# 获取
git config --global --get user.email常规操作
删除远程分支
git push origin --delete feature-branch仅更新远程信息
# 这个命令不会将远程分支拉下来,只会更新remote信息。
git fetch --all/[remote name]
# 来更新远程引用并删除已删除的远程分支的引用
git fetch --prune
# 只拉取一层
git fetch --depth=1 origin <branch>停止跟踪文件
如果你想停止跟踪文件example.txt,可以运行,这样会停止跟踪这个文件并且不会删除这个文件。
git rm --cached example.txt获取信息
# 获取简短的版本号
git rev-parse --short HEAD
# 获取一行详细信息
git log --pretty='format:[%ci][%h] %s' -1
# 在未同步submodule的情况下获取commit id
git ls-files --stage data | awk '{print $2}'tag
# 查看所有标签
git tag
# 查看标签详情
git tag v1.0.0
# 创建附注标签
git tag -a <tag_name> -m "message"
# 推送tags
git push origin --tags
# 推送特定tag:eg v1.0.0
git push origin v1.0.0
# 同步远端tags
git fetch --tags
# 同步且删除本地 远端没有的tag
git fetch --prune origin "+refs/tags/*:refs/tags/*"
# 删除远端tag
git push origin --delete <tag-name>记住密码
使用cache
# linux下配置上超时记录密码,可以避免多次输入密码
git config --global credential.helper 'cache --timeout=3600'使用GCM(git credential manager)
配置文档见: https://github.com/git-ecosystem/git-credential-manager/blob/main/docs/credstores.md
# 从https://github.com/git-ecosystem/git-credential-manager/releases 下载对应的包
# 通常使用deb进行安装
sudo dpkg -i name.deb
git-credential-manager configure
# 安装pass
sudo apt install pass
# 生成gpg pair
gpg --gen-key
# 查看gpg-id
gpg -k
# init passl
pass init <gpg-id>
# 更新git credential 使用gpg
git config --global credential.credentialStore gpg
# 配置信息都可以在~/.gitconfig中看到
# gpg的相关配置
# 重启gpg,重新认证
gpgconf --kill gpg-agent
gpgconf --launch gpg-agent
# 尝试解码
gpg --decrypt /home/faceunity/.password-store/git/https/yourhost.com/kaihang.gpg
# 如果遇到ssh -Y 情况下 git pull调用gpg出错,错误如下,这时候是gpg没有正确找到tty,需要配置export GPG_TTY=$(tty)
> git pull
fatal: Failed to decrypt file '/home/faceunity/.password-store/git/https/yourhost.com/kaihang.gpg' with gpg. exit=2, out=, err=gpg: encrypted with 3072-bit RSA key, ID 857FF0A72B89406E, created 2025-01-16
"kaihang <kaihangy@outlook.com>"
gpg: public key decryption failed: Inappropriate ioctl for device
gpg: decryption failed: No secret key
Username for 'https://yourhost.com':
# 修改密码之后使用libsecret
# linux
# Install dependencies
sudo apt install make gcc git libsecret-1-0 libsecret-1-dev libglib2.0-dev
# Compile binary
sudo make --directory=/usr/share/doc/git/contrib/credential/libsecret
# Configure git to use binary as credential storage
git config --global credential.helper /usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret
# 查看
cat ~/.gitconfig打包commit
方法:
git format-patch和git am(保留提交历史) 适用场景: 你希望在目标工程中保留完整的 Git 提交记录(Commit Log、作者、时间)。这是 Git 标准的协作方式。
打包(导出 Patch)
在源仓库中,使用 format-patch。它会为每一个 commit 生成一个单独的 .patch 文件。
打包两个 Commit 之间的所有变更(区间):
# 语法:git format-patch <起始Commit>..<结束Commit> # 注意:生成的 patch 不包含起始Commit本身,包含结束Commit git format-patch 8a1b2c..9x8y7z这会在当前目录下生成类似于 0001-xxx.patch, 0002-xxx.patch 的文件。
打包单个 Commit:
git format-patch -1 <CommitHash>技巧:把所有 patch 打包到一个指定文件夹:
git format-patch 8a1b2c..9x8y7z -o ./my_patches
应用(导入 Patch)
将生成的 patch 文件(或文件夹)复制到目标工程,然后使用 git am (apply mailbox) 命令。
应用单个文件:
git am 0001-fix-login-bug.patch应用文件夹下的所有补丁(按顺序):
# 其中-3 表示使用 3-way Merge(智能合并)。 # 默认的 git am 是“傻瓜式”覆盖,而加上 -3 参数后, # Git 会尝试寻找两个仓库共同的祖先,像合并分支一样进行智能合并, # 能自动解决大部分行号偏差或轻微的上下文不一致问题。 git am -3 my_patches/*.patch
submodule
增加新的submodule
git submodule add repoid your_directory修改submodule的remote
# 先修改.gitmodules中需要修改的模块的url
# 更新子模块配置
git submodule sync
# 更新子模块的remote url
git submodule update --init --recursive删除submodule
- 步骤 1: 删除 submodule 的引用
git submodule deinit -f path/to/submodule这个命令会从 .git/config 文件中删除 submodule 的引用。你也可以手动编辑 .git/config 文件删除相应的 submodule 配置。
- 步骤 2: 删除 submodule 文件
git rm -f path/to/submodule
# 该命令,git version 2.25.1 会同步删除.gitmodules的对应条目这个命令会从 Git 仓库中删除 submodule 所在的目录
- 步骤 3: 更新
.gitmodules文件
vim .gitmodules或者使用你喜欢的编辑器打开 .gitmodules 文件,然后删除与 submodule 相关的条目。
多重remote下url的管理
# 假如当前仓库和submodule都有两个remote:origin、self
# 如何优雅的分别往两个仓库推,并且不冲突呢,问题主要在.gitmodules这个文件
# 这里假定以origin为主,首次的情况下
# submodule每个remote分别推送
git push origin master # 往origin推
git push self master # 往self推
# 当前仓库下
# 首先修改origin下的东西,并且推送
git push origin master
# 随后切换到remote self的master
# 注意这里是临时分支,修改完之后通过HEAD:remote_branch进行推送
git checkout self/master
# 合并remote origin的修改
git merge origin/master
# 修改.gitmodules文件中submodule的url到remote self
...
# 随后执行以下指令更新submodule的链接
git submodule sync
git submodule update
# 随后commit,并且推送
...
git push self HEAD:master
# 同步self/master代码,注意不要pull
git fetch self未同步情况下操作
# 在未同步submodule的情况下获取commit id
git ls-files --stage data | awk '{print $2}'
# 未同步的情况下更新submodule的commit id
git update-index --add --cacheinfo mode,sha1,submodule_path
# he `mode` value can get from `git ls-files --stage submodule_path | awk '{print $1}'`remote操作
# 查看remote地址
git remote get-url origin
# 修改remote地址
git remote set-url origin your_repo_address
# 删除remote
git remote remove origingit lfs
# 初始化
git lfs install
# 跟踪文件
git lfs track path_to_your_file
# 跟踪文件夹和其子文件夹
git lfs track your_dir/**
# 卸载git lfs
git lfs untrack your_dir/**
# 查看所有跟踪信息
git lfs track
# 查看跟踪的文件
git lfs ls-files
# 将lfs指针转换为普通文件
git lfs migrate export --include="your_dir/**"
# 删除本地git lfs数据
rm -rf .git/lfs
# 迁移仓库
# 首先在本地拉取所有的lfs数据
git lfs fetch --all
# 随后先推送lfs数据
git lfs push --all origin网络相关
http代理
# 设置代理
git config --global http.proxy http://ip:port
git config --global https.proxy http://ip:port
# 获取代理
git config --global --get http.proxy
git config --global --get https.proxy
# 清空代理配置
git config --global --unset http.proxy
git config --global --unset https.proxyssh代理
# ~/.ssh/config
Host github.com
HostName github.com
User git
# 走 HTTP 代理
ProxyCommand socat - PROXY:192.168.0.52:%h:%p,proxyport=7890查看当前ssh使用的key
ssh -T git@<your_git>gitlab-runner
example
variables:
GIT_CLEAN_FLAGS: -ffdx -e release-repo/
stages:
- build
- release
- deploy
# build_linux
build_linux:
stage: build # 任务阶段
script:
- ./scripts/ci/build/build_linux.sh -r # Default build release lib
tags:
- cuda
- linux
- fugan
# build_windows
build_win64:
stage: build # 任务阶段
script:
- .\scripts\ci\build\build_win64.bat -r # Default build release lib
tags:
- cuda
- windows
- fugan
# Only build debug library
build_linux_debug_libs:
stage: build
script:
- ./scripts/ci/build/build_linux.sh -d -i # build and archive debug libs.
artifacts:
paths:
- ./release/**
expire_in: 1 days
when:
manual
tags:
- cuda
- linux
- fugan
build_linux_tools:
stage: build
script:
- ./scripts/ci/build/build_linux.sh -r -i -t # build and archieve tools with libs
artifacts:
paths:
- ./release/**
expire_in: 1 days
when:
manual
tags:
- cuda
- linux
- fugan
# Release scripts
release_linux:
stage: release
needs: [build_linux]
script:
- ./scripts/ci/release/release_linux.sh # release win64
artifacts:
paths:
- ./release/**
expire_in: 1 days
tags:
- cuda
- linux
- fugan
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+(-[a-zA-Z]+[0-9]*)?(\+.*)?$/'
when: on_success
- when: never
release_win64:
stage: release
needs: [build_win64]
script:
- .\scripts\ci\release\release_win64.bat # release win64
artifacts:
paths:
- .\release\**
expire_in: 1 days
tags:
- cuda
- windows
- fugan
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+(-[a-zA-Z]+[0-9]*)?(\+.*)?$/'
when: on_success
- when: never
deploy:
stage: deploy
needs: [release_linux, release_win64] # will download artifacts
script:
- ./scripts/ci/deploy/deploy.sh $CI_COMMIT_TAG
tags:
- deploy
- linux
- fugan
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+(-[a-zA-Z]+[0-9]*)?(\+.*)?$/'
when: on_success
- when: neverartifacts
artifacts是可以跨阶段和跨机器的,需要定义needs,之后这个需要的阶段会自动下载artifacts。
保持文件不删除
variables:
GIT_CLEAN_FLAGS: -ffdx -e release-repo/案例
优化中文不正常显示
# 如果git status中文显式数字的话,执行以下代码。
git config --global core.quotepath false将 Commit 从 A 处迁移到 B 处
1. 导出变更(在源仓库)
A. 保留提交历史(推荐)
生成包含作者、时间、Commit 信息的文件,适合标准迁移。
# 打包最近的一次 commit
git format-patch -1 HEAD
# 打包指定区间 (不含 start, 含 end)
git format-patch <StartCommitHash>..<EndCommitHash>
# 打包到指定目录
git format-patch <Start>..<End> -o ./patchesB. 仅导出代码内容(无 Commit 记录)
git diff <Start> <End> > changes.patch2. 应用变更(在目标仓库)
A. 标准应用(对应 format-patch)
# 应用单个或多个
git am *.patchB. 仅应用代码(对应 diff)
git apply changes.patch3. 遇到冲突时的解决方案(按严重程度排序)
当 git am 报错(如 patch failed)且流程暂停时,请按以下步骤处理:
方案一:开启 3-way Merge(最常用,推荐首选)
git am 默认很严格,开启 -3 可以让 Git 尝试智能合并(类似 git merge)。
# 1. 放弃当前失败状态
git am --abort
# 2. 重新应用,带上 -3 参数
git am -3 *.patch- 结果:如果成功则自动通过;如果有冲突,会产生
<<<< >>>>标记,手动修完后git add .然后git am --continue。
方案二:忽略空白字符(针对缩进问题)
如果报错提示 whitespace 相关,或仅仅因为 Tab/Space 不一致:
git am --ignore-whitespace *.patch方案三:强制手动修补(终极方案)
当方案一报错:It does not apply to blobs recorded in its index,说明两个仓库差异太大,Git 找不到合并基准。此时不要 abort,直接原地手动修。
- 强制打入补丁(Git 会把当前卡住的 patch 强行应用,无法应用的生成 .rej 文件):
# .git/rebase-apply/patch 是 git am 正在处理的那个补丁文件 git apply --reject .git/rebase-apply/patch - 查看状态:
git status # 关注生成的 *.rej 文件 - 手动修复:
- 打开 .rej 文件查看丢失的代码片段。
- 打开对应的源码文件,手动将代码粘贴进去。
- 修复完成后,删除 .rej 文件。
- 提交修复并继续:
# 将修改好的文件放入暂存区 git add . # 告诉 git am 继续处理下一个 patch (不需要 git commit) git am --continue
4. 常用控制命令
- 放弃本次所有操作,回到原点:
git am --abort - 跳过当前这个报错的 Commit:
git am --skip - 解决完冲突后继续:
git am --continue
SVN
私有SVN搭建:SVN服务
命令
add
# 添加文件
svn add <filename:1> [<filename:2> ...]
# 添加文件夹和文件夹中的所有内容
svn add <dirname:1> --force
# 添加所有未版本控制的文件
svn add . --forcestatus
# ?: 表示文件、文件夹不在SVN版本控制中
# A: 表示文件、文件夹已被添加到版本控制
# M: 表示文件已修改
# !: 表示找不到文件夹,通常是文件系统删除掉了,但是没有通知svn,这种无法commit
# D: 表示使用svn remove删除了,可以commit了checkout
# checkout repo 到某个local文件夹
svn checkout <repository_url> [local_directory]update
# 将本地工作副本更新为SVN仓库中最新的版本
svn update [path] [-r revision]revert
# 恢复文件
svn revert <path_to_your_file>
# 递归恢复文件夹
svn revert -R <path_to_your_dir>commit
# 推送修改
svn commit -m [--message]