← 返回博客

Git 常用操作

#git#devtools

git提交规范

# 模板
 
module.type(scope): subject
- #id1 xxxx
- #id2 xxxx
Related: #id
 
# eg
 
module.fix(#id): xxxxx
module.feat(#id): xxxxx
 
# 说明
 
type:
    feat: 新功能
    fix: 修复问题
    docs: 文档更新
    style: 代码格式(不影响代码运行的变动)
    refactor: 代码重构(既不是修复bug也不是添加新功能的代码更改)
    perf: 性能优化
    opt: 广义的优化,不局限于性能,表示对代码或实现的改进
    enhance: 用于表示改进现有功能的实现,但功能本质未发生变化。适用于用户体验优化、功能的轻微改进
    improve: 一般用于强调对代码或功能的改进,适用于广义的优化和提升
    refine: 用于小范围的优化和精细化调整,适合代码优化但不涉及结构性变化。
    test: 添加测试或更新测试
    build: 构建系统或外部依赖项的更改(如webpack,npm)
    ci: 持续集成相关的变动
    chore: 日常事务/维护, 适用于非功能性修改,例如日志打印、工具配置、脚本更新等。
    revert: 回滚某次提交

常用命令

# 删除本地分支
 
git branch -d master
 
# 删除远程分支
 
git push origin --delete master
 
# 移动目录
 
git mv
git mv plugins/uniplugin_wecall plugins/uni-ios-sdk/uniplugin_wecall

私人仓库认证

# 私人仓库总是提示输入密码, 保存用户, 以下命令开启后, 会将用户密码存储在: ~/.git-credentials中
 
git config --global credential.helper store
 
## 缓存 1 小时(3600 秒)
 
git config --global credential.helper 'cache --timeout=3600'
 
# 改用 SSH 免密(更安全), 添加SSH and GPG keys。然后把远程仓库地址改为ssh地址
 
# GCM(Git Credential Manager), 支持 GitHub、GitLab、Azure DevOps 等。
 
sudo apt install git-credential-manager
git-credential-manager configure

Gitea 合并选项一览

合并方式含义是否保留提交历史是否生成合并提交主干是否线性推荐场景
✅变基后创建合并提交先rebase再merge --no-ff✅ 是✅ 是❌ 否避免冲突、保留历史
✅创建合并提交普通merge,不 rebase✅ 是✅ 是❌ 否保留完整 PR 提交
✅变基后快进rebase再fast-forward✅ 是❌ 否✅ 是想要线性历史
✅创建压缩提交squash 所有 PR 提交成一个❌ 否❌ 否✅ 是主干清爽、PR小
✅仅快进merge --ff-only,不 rebase✅ 是(必须线性)❌ 否✅ 是用于自动更新分支
✅手动合并不自动合并,需自己操作⚠️ 取决于你⚠️ 取决于你⚠️ 取决于你高级场景、需要更多控制

git lfs安装

大文件支持

apt/deb repos: curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
 
yum/rpm repos: curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.rpm.sh | sudo bash
 
apt/deb: sudo apt-get install git-lfs
yum/rpm: sudo yum install git-lfs
 
# 验证安装
 
git lfs install

fork项目更新后, 原仓库也有更新, 冲突情况下合并

Fork 仓库后,自己的分支有提交,而原仓库(upstream)有更新,在 Gitea 网页上尝试合并时遇到了冲突。你需要 手动同步原仓库的最新代码到你的 Fork,并解决冲突。按照以下步骤操作:

步骤 1:添加原仓库(upstream)

如果你之前没有添加 upstream,需要先添加它:

git remote add upstream <原仓库的URL>

可以检查是否添加成功:

git remote -v

应该会看到 origin(你的 Fork)和 upstream(原仓库)。

步骤 2:获取原仓库的最新代码

git fetch upstream

然后切换到你的 main 分支(或者你 Fork 时的默认分支,如 master):

git checkout main

再合并 upstream 的最新代码:

git merge upstream/main

如果有冲突,Git 会提示哪些文件冲突。

步骤 3:解决冲突

打开有冲突的文件,手动修改代码,使其符合需求。通常冲突的代码长这样:

<<<<<<< HEAD
你的 Fork 仓库的代码
<mark>=</mark>==
原仓库(upstream)的最新代码
>>>>>>> upstream/main

你需要手动修改为正确的内容,并保存文件。

然后运行:

git add .
git commit -m "解决合并冲突"

步骤 4:推送到你的 Fork 仓库

git push origin main

这时你的 Fork 仓库已经同步了原仓库的最新代码,并且冲突已经解决。

步骤 5:在 Gitea 发起合并请求

现在可以回到 Gitea,在网页上尝试合并你的 Fork 到原仓库。如果没有新的冲突,应该可以顺利合并了。

如果你在分支上开发,而不是 main 直接改

如果你在 feature-branch 分支上开发,而 main 已经同步了 upstream/main,你还需要:

git checkout feature-branch
git merge main  # 把最新的 main 合并到你的分支
 
git push origin feature-branch

然后再在 Gitea 上合并。

这样,你的 Fork 就会和原仓库保持同步,同时保留你自己的修改!

如果还是有问题,可以发具体的错误信息,我帮你分析!😃

拆分大仓库

  • 在迁移时,git filter-repo 会保留子目录的历史记录,并删除其他目录的历史,这样在新仓库中只会保留你想要的子目录及其相关的提交历史。
  • 如果只需要迁移某些目录而不丢失其历史,确保在 filter-branch 或 filter-repo 过程中准确指定路径。
# 把几个目录拆分到新仓库
 
# 安装 git-filter-repo 工具
 
pip install git-filter-repo
 
# 克隆原仓库并进入
 
git clone --no-checkout <old-repository> temp-repo
cd temp-repo
 
# 过滤出多个子目录
 
git filter-repo --path <path-to-subdirectory1> --path <path-to-subdirectory2> --path <path-to-subdirectory3> --force
git filter-repo --path WeCall --path license/WeCall --force
 
# 添加远程仓库
 
git remote add origin <new-repository-url>
 
# 推送代码
 
git push -u origin master
 
cd ..
rm -rf temp-repo

git clone指定本地文件夹名

git clone xxx.git <dir_name>
git clone -b develop https://github.com/example/repo.git my_project
git clone -b self https://github.com/leiax00/NotionNext.git --config http.proxy=http://192.168.0.3:7890 notionNext

git丢弃本地修改, 同步服务器最新

# 丢弃所有本地更改
 
git reset --hard
 
# 获取远程最新代码
 
git fetch --all
 
# 强制同步到远程分支:
 
git reset --hard origin/分支名称

git分隔符设置

// 提交时转换为LF,拉取时转换为CRLF
git config --global core.autocrlf true
 
// 提交时转换为LF,拉取时不转换
git config --global core.autocrlf input
 
// 不转换
git config --global core.autocrlf false
 
# 建议设置成input; 或者所有都设置为false由开发者自行管理
 

git无法检测到文件变化

# 1. 删除.git/index
 
rm .git/index
 
# 2. 重置本地trace
 
git reset

关闭权限和所有者信息检查

git config --global core.fileMode true
git config --global core.ignoreStat false
 
# core.fileMode false 将会忽略文件的执行权限变更。
 
# core.ignoreStat true 将会忽略文件系统不支持的元数据信息(比如所有者信息)。
 
# 关闭后就无法显示文件变更了, 毫无意义
 

git创建远程仓库(服务端)

# 创建一个用户
 
adduser git
 
# 生成ssh证书
 
ssh-keygen
 
# 初始化git仓库, 根路径在: /repo_dev/git-server, 仓库以 .git后缀结尾
 
git init --bare test.git
 
# 设置仓库所属git
 
chown -R git:git test.git
 
# 添加要拉取该仓库客户端的公钥, 在客户端上执行
 
ssh-copy-id -i ~/.ssh/id_rsa.pub git@10.1.0.3
 
# 禁用git用户ssh登录(为了安全性, 也可不设置), 该步骤之后客户端公钥添加则需要手动添加到 /home/git/.ssh/authorized_keys 文件中, 一行一个
 
# git:x:1001:1001:,,,:/home/git:/bin/bash
 
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
 
# 客户端拉取仓库
 
git clone git@10.1.0.3:/repo_dev/git-server/test.git
 
# 权限管理: Gitolite: https://github.com/sitaramc/gitolite
 
# 公钥管理: Gitosis: https://github.com/res0nat0r/gitosis
 

git log中文乱码

git config --global i18n.commitencoding utf-8

git status中文文件名显示为转义字符

git status 查看时,中文路径显示为八进制转义(如 40-\345\267\245\344\275\234),原因是 Git 默认开启了路径转义(core.quotepath = true),会把非 ASCII 字符转义成八进制序列以避免乱码。

# 关闭路径转义,让中文文件名正常显示
git config --global core.quotepath false

修改分支名

git branch -m master main
git fetch origin
git branch -u origin/main main
git remote set-head origin -a

git修改远程地址

root@leiax-pi:/repo/dev/code/simple-zero/k8s# git remote set-url origin git@github.com:leiax00/simple-zero.git
 
root@leiax-pi:/repo/dev/code/simple-zero/k8s# git remote -v
 

git删除本地修改

git reset --hard origin/main
 
# git fetch --all
 

git忽略ssl

git config --global http.sslverify false
git config --global https.sslverify false

个人代码行数统计

git log --author=dingwei --since=2022-09-26 --until=2022-10-20 --format='%aN' | \\
sort -u | while read name; do echo -en "$name\\t"; git log --author="$name" --pretty=tformat: --numstat | \\
awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\\n", add, subs, loc }' -; \\
done
 
# leiax00 added lines: 36726, removed lines: 20575, total lines: 16151
 

git切换远程分支

git remote rm origin
git remote add origin git@github.com:leiax00/simple-zero.git
git push orrigin  /  git push --set-upstream origin main

git设置用户邮箱

git config --global user.name "leiax00"
git config --global user.email "leiax00@outlook.com"
 
# 仅当前库
 
git config user.name "lax-tx"
git config user.email "leiax00@outlook.com"
 
git config --global user.name "leiax00-robot"
git config --global user.email "leiax00@outlook.com"

git子模块操作

git submodule add <url> <path>   # 其中,url为子模块的路径,path为该子模块存储的目录路径。
 
# clonefu父项目后, 子项目更新方法
 
git submodule init
git submodule update
 
git submodule update --init --recursive
 
# 删除子模块较复杂,步骤如下:
 
rm -rf 子模块目录  # 删除子模块目录及源码
 
vi .gitmodules  # 删除项目目录下.gitmodules文件中子模块相关条目
 
vi .git/config  # 删除配置项中子模块相关条目
 
rm .git/module/*  # 删除模块下的子模块目录,每个子模块对应一个目录,注意只删除对应的子模块目录即可
 
# 执行完成后,再执行添加子模块命令即可,如果仍然报错,执行如下:
 
git rm --cached 子模块名称

git配置代理

git clone https://github.com/vuetifyjs/vuetify.git --config http.proxy=http://127.0.0.1:10809
 
git config --global http.proxy 'socks5://127.0.0.1:10808'
git config --global https.proxy 'socks5://127.0.0.1:10808'
 
git config --global http.proxy http://10.1.0.3:7890
git config --global https.proxy https://127.0.0.1:10809
 
git config --global --unset http.proxy
git config --global --unset https.proxy
 
# 不写 --global 或者设置为 --local 则只配置当前项目的代理
 
# 或者修改单个项目的 .git/config
 
[core]
	repositoryformatversion = 0
	filemode = false
	bare = false
	logallrefupdates = true
	symlinks = false
	ignorecase = true
[remote "origin"]
	url = https://github.com/leiax00/exploding-universe.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
	remote = origin
	merge = refs/heads/main
[submodule "universe-view"]
	url = https://github.com/leiax00/universe-view
	active = true
[http]
	proxy = http://127.0.0.1:10809

git多远程仓库提交

[core]
	repositoryformatversion = 0
	filemode = false
	bare = false
	logallrefupdates = true
	symlinks = false
	ignorecase = true
[remote "github"]
	url = https://github.com/leiax00/exploding-universe.git
	fetch = +refs/heads/*:refs/remotes/github/*
[remote "gitee"]
	url = https://gitee.com/jctecho/exploding-universe.git
	fetch = +refs/heads/*:refs/remotes/gitee/*
[remote "origin"]
	url = https://gitee.com/jctecho/exploding-universe.git
	fetch = +refs/heads/*:refs/remotes/origin/*
    url = https://github.com/leiax00/exploding-universe.git
[branch "master"]
	remote = origin
	merge = refs/heads/master

github配置ssh后无法正常拉取代码, 提示需要密码

# 配置了ssh, 但是在拉取代码时无法连接, 继续提示需要输入密码
 
# 通过 ssh -vT git@github.com 无法正常连接github
 
# 原因: 极大可能gihub的DNS被劫持了, 需要配置本地DNS接续
 
nano /etc/hosts
 
# <mark>=</mark><mark>=</mark><mark>=</mark><mark>=</mark>==
 
140.82.112.3 github.com
 
# <mark>=</mark><mark>=</mark><mark>=</mark><mark>=</mark>==
 
# github.com的真是IP可以通过网站获取: https://www.ipaddress.com/
 

What Is My IP Address? Free IP Lookup

将当前分支多个提交记录合并(已push)

  1. 创建一个临时分支保存当前内容:
git checkout -b temp-squash
  1. 回到你想保留一条提交的分支:
git checkout main  # 或你的目标分支
 
  1. 重置到上一个你想保留的基础提交(如果是全新仓库,可以用初始提交或者空提交):
git reset --soft <commit_hash>  # 或者 HEAD~N
 
  • --soft 保留修改在暂存区
  1. 创建一条新的提交:
git commit -m "保留最终修改的一条提交"
  1. 强制推送到远程(覆盖原来的历史):
git push -f origin main

⚠ 注意:强制推送会覆盖远程历史,其他克隆该仓库的人会受到影响。

git分支合并


方法1:保留完整提交记录

main 分支执行:

git checkout main
git merge --no-ff feature/b
  • 会生成一个 merge commit,保留 feature/b 分支的所有提交历史。
  • 如果有冲突,需要手动解决再提交。

方法2:压缩提交(squash 合并)

这里有两种情况:

2.1 直接 squash 合并

main 分支执行:

git checkout main
git merge --squash feature/b
git commit
  • 所有 feature/b 的改动会合成一个提交。
  • 不会生成 merge commit(看起来就像你在 main 上直接写了一个大提交)。

2.2 先在 feature 分支上 rebase 再合并

如果你希望 分支干净,但仍然要保留合并关系:

git checkout feature/b
git rebase -i main   # 压缩掉 feature/b 上的提交,整理为一个或少数几个提交
 
# 然后切回 main
 
git checkout main
git merge --no-ff feature/b
  • 这样最终 main 上会有一个 merge commit,但 feature/b 的历史是已经压缩过的。

📌 小结:

  • git merge --no-ff → 保留所有提交,生成 merge commit
  • git merge --squash → 压缩成一个提交,不会生成 merge commit
  • git rebase -i + git merge --no-ff → 先压缩分支历史,再带着 merge commit 合并