Git笔记
目录
一、git概述
- Git 是一个开源的分布式版本控制系统,是 Linus Torvalds为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
- git基本概念
- 工作区 任何当前所做的临时改动都在工作区
- 暂存区 add之后到暂存区
- 本地仓库 commit之后到本地仓库
- 远程仓库 push之后到远程仓库
- 强烈建议所有的git仓库都有README, LICENSE, .gitignore三个文件
二、git核心命令
(一) Git 全局设置:
git config --global pull.rebase true #配置库默认使用 pull --rebase
git config --global user.name "nickname" #配置提交用户名
git config --global user.email "XXX@mail.com" #配置邮箱
git config --global core.excludesFile C:\Users\root\.gitignore #配置全局忽略文件夹
git config --global gui.encoding utf-8 #设置图形化界面编码为utf-8
git config --global http.proxy http://127.0.0.1:7890 #设置当前代理
git config --global https.proxy http://127.0.0.1:7890 #设置当前代理
git config --global --unset http.proxy #取消全局代理
git config --unset http.proxy #取消当前代理
git config http.proxy socks5://127.0.0.1:7890 #设置socks5代理
git config --global branch.autosetuprebase always #设置默认以rebase方式pull
git config core.longpaths true #启用长路径(clone时文件长路径,报fatal: cannot create directory:xx: Filename too long)
git config --get core.longpaths #获取配置信息(--get可省略)
(二) 常规操作
- 初始化仓库
git init
- 添加文件到Git仓库
git add <file> #提交到暂存区
git add . #添加所有文件到暂存区,但不包括被删除文件
git add -u #提交已被跟踪的所有文件到暂存区,但不包括新建的文件
git add -A #添加所有文件改动到暂存区,包括删除的和新建的
git commit -m <message> #提交到本地仓库
git commit --amend [--no-edit] #修正上回提交,可修改提交信息(已推送到远程则不要用这个命令,避免不必要的麻烦)
git commit --allow-empty-message #提交到本地仓库但不带描述信息
- 分支操作
git branch -a #查看所有分支,包括远程分支
git branch <name> #创建分支
git branch -d <branch-name> #删除分支
git branch -D <branch-name> #强制删除
git checkout <name> 或 git switch <name> #切换分支
git checkout -b <name> 或 git switch -c <name> #创建并切换到新分支
git checkout -b feat1 remotes/origin/feat1 #创建远程分支的本地分支
git merge --no-ff -m "merge with no-ff" <name> # 推荐方式(合并后可看到被合并的分支)
git merge <name> # 默认方式(合并看不到分支,看不出曾做过合并。即--ff, 快进(fast-forward)方式)
- 查看提交信息
git status #查看git工作区的状态
git show <commit-id> #查看某个提交的详细信息
git log #显示所有提交过的版本信息
git log <filePath> #显示指定文件的提交历史
git log --graph #同上,多了分支合并图
git log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)' --all
git log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(auto)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
git log --pretty='format:%C(auto)%h %as (%s, %ad %cn[%ce])' # xxx 2025-04-21 (修改:xxx问题, Mon Apr 21 19:11:10 2025 +0800 提交人[xxx@xxx.com])
git log --pretty=oneline #同上,但只会显示版本号和提交时的备注信息
git log --pretty=oneline path/filename
git log -p -L 8,27:data/tools.toml # 查看10~20行全部历史变更,附带diff
git log --reverse -p -L 8,27:data/tools.toml # 代码历史变更,正序:从最早到最新,看代码一步步演化(适合溯源)
git log --reverse --author="root" -p -L 8,27:data/tools.toml #指定作者
--since="2026-09-30" --until="2026-10-02" # 指定时间
git blame -L 8,27 data/tools.toml # 如果只想看当前行最后的提交信息
git reflog #显示所有分支的所有操作命令记录
- 从版本中删除文件
git rm <file> #从工作区和暂存区中删除文件
git rm --cached <file> #从暂存区中删除文件,工作区文件还在
git rm --cached -r <Directory> #从暂存区中删除文件夹,工作区文件还在
- 查看修改
git diff <file> #查看当前没有add 的内容修改
git diff --cached #查看已经add 没有commit 的改动 使用
git diff origin/分支名 HEAD #查看未推送的详细改动(查看已commit和远程分支的区别)
git diff HEAD -- readme.txt #可以查看工作区和commit版本库里面最新版本的区别
git diff --name-only 562d562ef7ab57bf7c1fe3d3a05abb4cff018d84 HEAD | xargs tar -zcvf diff.tar.gz # 将差异文件打包
git diff fee9f9cf4b cdd577e352 app/build.gradle #比较两次commit的指定文件差异,不指定文件则比较所有差异
git diff > xxx.patch #将当前工作区修改的内容保存到patch文件中
git apply --stat xxx.patch #查看patch文件内容
git apply --check xxx.patch #检查patch文件是否正确
git apply xxx.patch #应用patch文件
- 撤销修改
git checkout -- file
#撤销工作区所有修改,若有修改添加到暂存区,则恢复暂存区修改版本到工作区
#若暂存区无记录则恢复工作区和本地版本库一致
git reset HEAD <file>
#恢复最近一次提交的本地版本库的文件到暂存区,即把暂存区的修改撤销掉
#该操作不影响工作区,撤销git add
git commit --amend
#相当于上次提交错误的信息被覆盖。修改上一次提交(commit),将两次提交合并为一次提交。
#修改错误之后,执行该commit,可覆盖上次提交的注释及文件记录
#不要试图去修改已push到线上的记录
- 回退到上一个版本/指定版本
- 在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,可写成HEAD~100。
git reset --hard HEAD^
git reset --hard <commit_hash>
(三) 远程仓库操作
- 从远程库克隆
git clone git@host:path/repo-name.git
git clone -b branch1 git@host:path/repo-name.git # 克隆远程指定分支
git clone --depth 1 git@host:path/repo-name.git # 浅克隆(仅克隆部分的存储库历史记录)
- 本地仓库关联远程仓库
git remote add origin git@host:path/repo-name.git
git remote set-url origin git@host:path/repo-name.git #修改origin远程地址
- 推送本地dev分支到远程origin仓库
git push origin dev
- 删除远程dev分支
git push origin --delete dev
- 从远程库获取更新信息
git remote -v #查看远程库的信息
git fetch #获取远程更新,但不合并分支
git pull #获取远程更新并合并分支,同“git fetch & git merge”
git pull --rebase #获取远程更新并将本地提交放到远程代码最后
git checkout -t origin/remoteBranchName #在本地建立一个和远程分支名字一样的分支
git checkout -b localBranchName origin/remoteBranchName #在本地建立远程分支内容的分支名为localBranchName的分支
(四) 标签操作
- 列出标签
git tag
git tag -l "通配符字符串"
- 创建标签
git tag v1.0.1 #给最新的提交打标签
git tag -a v1.4 -m "my version 1.4" #带附注的标签
git tag -a v1.2 <commit_hash> #给指定版本的提交打标签
- 提交标签到远程仓库
git push origin <tagname>
- 删除标签
git tag -d <tagname> #删除本地标签
git push origin --delete <tagname> #删除远程仓库标签(1)
git push origin :refs/tags/<tagname> #删除远程仓库标签(2)
(五)进阶操作-待完善
- git stash
- git stash list
- git stash pop 0
- git stash drop 0
- git stash -m “feat:xxx”
- git rebase
- git cherry-pick <commit_hash>
三、实践
- 合并分支
# 合并到master
git checkout dev
git pull
git checkout master
git merge dev
git push -u origin master
# 合并master更新到dev
git checkout master
git pull
git checkout dev
git merge master
git push -u origin dev
- 回退到指定版本
git reset --hard <commit_hash> #回退到指定版本
git push -f #强制提交
- 强制提交dev后,和test分支不一致,分支污染–>分支回归一致
# 情况复现步骤:
#1. 用在dev提交feat1,且构建到test了
#2. 用户将DEV分支git reset --hard HEAD^回退后,开发了feat2后强制提交(git push -f)
#3. 此时dev和test处于不同的提交路径上,jenkins拒绝构建合并
[test] git revert <feat1_commit_hash> # 如果需要在qa上修改,最后需要合并回dev才能正常提交jenkins构建(git merge --no-ff test)
[test] git merge --no-ff dev # 把dev提交合并过来,两个分支就处于同一路径上了
[test] git push origin qa
- 回退新功能提交,保留fix提交
git log #查看之前新功能版本的<commit_hash>信息
git revert <commit_hash> #反做新功能版本,并生成新提交
git rebase -i HEAD~3 #合并revert3个版本的提交
#修改两个pick为squash (pick表示保留提交、squash指将这个提交合入其他提交)
#如果有冲突,需要解决冲突 然后执行
git add .
git rebase --continue
#如果要放弃rebase,执行
git rebase --abort
#没有冲突的话,会出现commit message界面,wq保存后即可
- 创建SSH Key
- 执行以下命令,然后一路回车,使用默认值即可
- 登陆GitHub,打开 “Account settings” =》 “SSH Keys” 页面
- 点击 “Add SSH Key”,在Key文本框里粘贴此步生成的 id_rsa.pub 文件的内容
- 之后采用git协议访问仓库,可不需要输入密码
ssh-keygen -t rsa -b 4096 -C "youremail@example.com"
- 打开原Windows下硬盘中工程,Git中所有文件均提示CRLF换行符变更解决方案
git config --global core.autocrlf input #true:提交时转换为LF,检出时转换为CRLF,input:提交时转换为LF,检出时不转换, false:提交检出均不转换
git config --global core.safecrlf true #true拒绝提交包含混合换行符的文件,false允许提交包含混合换行符的文件,warn提交包含混合换行符的文件时给出警告
- 合并三个提交为一个提交
git rebase -i HEAD~3
修改需要合并的commit的行,将commit前的pick改为squash或者缩写s即可
保存,修改提交信息
- 修改远程倒数第三个提交中的某个文件,删除敏感信息
#确保所有改动都提交后
git rebase -i HEAD~5 # 启动交互式变基,停在指定提交,弹出编辑器把要改的那一行的 pick 改成 edit
git add filename # 修改
git commit --amend --no-edit # 覆盖提交 --no-edit:保持原来的提交信息不变,只改文件内容。
git rebase --continue # 把后面的提交 “接回来”
三、其他
Git数据存储的原理浅析 - 个人文章 - SegmentFault 思否 https://segmentfault.com/a/1190000016320008?utm_source=tag-newest
Linux源码克隆错误:Clone succeeded, but checkout failed. drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
git config core.protectNTFS false
git reset --hard HEAD
gitmoji表情使用规范:https://gitmoji.dev/
新建的远程仓库操作命令行指令:Command line instructions
- Git global setup
git config --global user.name "root"
git config --global user.email "root@mail.com"
- Create a new repository
git clone git@github.com:username/repository.git
cd dify
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
- Existing folder
cd existing_folder
git init
git remote add origin git@github.com:username/repository.git
git add .
git commit -m "Initial commit"
git push -u origin master
- Existing Git repository
cd existing_repo
git remote rename origin old-origin
git remote add origin git@github.com:username/repository.git
git push -u origin --all
git push -u origin --tags
- svn操作
git svn clone https://svn.example.com/svn/repo --username test
git svn clone -T trunk -b branches -t tags https://svn.example.com/svn/repo
git svn log # 查看 SVN 日志
git checkout -b hotfix remotes/branches/hotfix # 处理分支
git add -A .
git commit -m "概要设计书"
git svn fetch # 获取远程分支更新
git svn rebase # 更新
git svn dcommit # 推送
- 批量修改提交用户及邮箱
git filter-branch --env-filter '
NEW_NAME="username"
NEW_EMAIL="username@mail.com"
# ========== 在这里维护所有旧邮箱列表 ==========
OLD_EMAILS=(
"root@mail.com"
)
# ========== 在这里维护所有旧用户名列表 ==========
OLD_NAMES=(
"root"
)
# 判断函数:检查入参是否在数组内
in_array() {
local val="$1"
shift
for item in "$@"; do
if [ "$val" = "$item" ]; then
return 0
fi
done
return 1
}
# 处理 committer
if in_array "$GIT_COMMITTER_EMAIL" "${OLD_EMAILS[@]}" || in_array "$GIT_COMMITTER_NAME" "${OLD_NAMES[@]}"
then
export GIT_COMMITTER_NAME="$NEW_NAME"
export GIT_COMMITTER_EMAIL="$NEW_EMAIL"
fi
# 处理 author
if in_array "$GIT_AUTHOR_EMAIL" "${OLD_EMAILS[@]}" || in_array "$GIT_AUTHOR_NAME" "${OLD_NAMES[@]}"
then
export GIT_AUTHOR_NAME="$NEW_NAME"
export GIT_AUTHOR_EMAIL="$NEW_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
- 将主仓库根目录下 static 目录剥离历史,转为独立Git子模块,并保留完整提交历史 。
注意:这套脚本适用前提:
static在仓库根目录- static目录的文件已经提交进主仓库git历史(不是仅暂存未commit)
- 目标远程仓库
hugo-static是空仓库(无README、无初始commit)
# 进入主仓库根目录
# 1. 从主仓库历史剥离 static 目录,新建临时分支 static,保留全部历史提交
git subtree split --prefix=static -b static
# 2. 主仓库:解除 static 的索引跟踪,本地磁盘文件保留不动
git rm -r --cached static
# 3. 进入 static 目录,初始化为新Git仓库(main分支)
cd static
git init -b main
# 4. 临时添加上层主仓库作为remote,用来拉取刚才split出来的历史
git remote add split ..
# 5. 拉取主仓库中临时分支 static(split剥离出来的历史)
git fetch split static
# 6. 将当前static仓库main分支强制重置到split出来的提交,一次性载入历史+文件
git reset --hard FETCH_HEAD # !会覆盖:替换为split导出的版本会覆盖static目录工作区文件
# 7. 删除临时remote,不再依赖主仓库对象库
git remote remove split
# 8. 绑定static独立远程仓库,推送到远端
git remote add origin git@github.com:username/hugo-static.git
git push -u origin main
# 9. 返回主仓库根目录
cd ..
# 10. 在主仓库挂载static为git子模块(使用远程仓库地址)
git submodule add git@github.com:username/hugo-static.git static
# 11. 吸收内嵌的.git目录,修复子模块目录嵌套git问题(submodule add不会自动做)
git submodule absorbgitdirs
# 12. 提交主仓库变更:.gitmodules配置 + static子模块commit指针
git add .gitmodules static
git commit -m "refactor: convert static folder to submodule, retain full history"
# 13. 删除主仓库内split产生的临时载体分支,清理垃圾
git branch -D static
# 📌 后续日常维护命令(配套保存,写完上面脚本顺带存这个)
# ========== 日常更新静态资源流程 ==========
# 1. 进入子模块目录修改文件
cd static
# 2. 在子模块内提交改动
git add .
git commit -m "feat: add new demo image"
# 3. 推送到static独立远程仓库【必须push,否则别人拉主仓库会找不到commit】
git push origin main
# 4. 返回主仓库,更新主仓库记录的子模块commit指针
cd ..
git add static
git commit -m "update static submodule reference"
git push origin main
# 新机器克隆整套项目完整命令:
git clone 你的博客主仓库地址 blog
cd blog
git submodule update --init --recursive