git笔记
[TOC]
- 不要对git抱有信仰
- git要适配工作流,如果不能提高流程的效率,不要试图推行git
本文不是一个教程文章,如果不熟悉这张图,那么你可能并未用过git,下方有些内容对你来说可能难以阅读
官方文档
https://git-scm.com/book/en/v2
设置 SSH Proxy
确保已安装netcat(linux),或connect.exe(window),打开或创建~/.ssh/config
文件,ProxyCommand填写netcat或connect.exe的安装路径
Host github.com
Hostname ssh.github.com
IdentityFile YOUR_SSH_PRIVATE_KEY
User git
Port 443
ProxyCommand /usr/bin/nc -v -x 127.0.0.1:YOUR_PROXY_PORT %h %p
如果是window则将ProxyCommand填写为
ProxyCommand "C:\Program Files\Git\mingw64\bin\connect.exe" -S 127.0.0.1:7890 %h %p
设置http&https Proxy
git config --global http.proxy socks5h://127.0.0.1:7890
换行符设置
window以CRLF换行,linux/macos以LF换行
- 期望在window编码,并且能兼顾在window/linux/macos中运行。设置为
git config --global core.autocrlf true
,检出代码时自动转为CRLF,提交到自动转为LF - 不要求开发环境,但运行环境在linux/macos中,
git config --global core.autocrlf input
,检出代码时不自动转换,提交时自动转为LF - 无任何编码和运行环境要求。
git config --global core.autocrlf false
,检出和提交时都不自动转换 另外方案,配置.gitattributes的eol选项
忽略文件权限变化检查
仓库文件中包含可执行文件,但本地文件权限的原因导致你下载到本地后不可执行。而你又不想对该文件的权限变动,上传到远端。可通过以下指令忽略权限修改
git config --global core.filemode false
status和log命令显示中文字符
git config --global core.quotepath false
git fetch时报错would clobber existing tag
本地的tags信息与远端的不一致时会产生该报错
- 如果报错涉及的tag是你负责的,要看一下
git log
,是否其他人也在创建同名的tag,还是对方用相同的名名称重打了新tag,与对方沟通并处理好相关冲突 - 如果tag不是你负责的,而作者重打了tag。操作
git fetch --tags -f
强制刷新到最新tag信息
仓库管理
fetch
、pull
和push
的命令参数中,都涉及到两个参数[<repository> [<refspec>…],
repository 表示本地仓库名称
refspec 表示引用对象,包括分支名称,标签名称等
我从svn转过来用git时,不理解为什么会有这些参数。这源于git支持本地同时多仓库管理,比如我们期望pull
追踪某些仓库的修改内容
必须指定操作的目标仓库名称repository和该仓库的引用对象refspec,clone
时默认将repository设置为origin refspec设置为clone时指定的–branch参数
- 新增仓库
git remote add [自定义仓库名称] [仓库地址]
- 删除仓库
git remote remove [自定义仓库名称]
rebase
网上好多文章作了介绍rebase的用处,此处不例举,简单记录下rebase的两个高频功能:
- [共享分支]合并到[功能分支]
- 将【功能分支】的所有
fast-forward
提交合并为1次
[功能分支]merge到[共享分支]前的工作流程:
git fetch --all
拉取远端最新内容git checkout [功能分支名称]
切换到功能分支git rebase [共享分支名称]
解决冲突后,继续执行中断的变基git rebase –continue- 1git rebase -i HEAD~N`,合并最近N次,视本地的提交情况设置N的值,如HEAD~2期望合并最近2次提交
- 弹出的编辑窗口,除了首行是pick,其它均修改为squash, 退出编辑窗口
git checkout [共享分支名称]
git merge [功能分支名称]
网上有不少有关rebase/merge的论战,双方集中在日志追踪的问题上。
merge --no-ff
的好处是突出合并线,追踪修改时更容易查阅- rebase会将分支的修改排在主干的前,突出最新修改,减少分支线图清晰易读。
我的个人观点是:
- 如果branch是多人共享的,千千千万万万!!!!!别使用rebase,因为rebase后commitId会重新生成,对于缺乏git使用经验的人员来说, 他们本地commitId与线上的不致,会导致他们下一次pull失败。
- 如果分支是自己用的,不用操心问题1,随便
rebase
各种操作,包括上面提交到拉取共享分支和合并N次提交。因为其他人在你将内容合并到主干前,并不关心你改了什么内容,此种情况如果用merge
将生的合并线反而令git log
上的分支线更加混乱 总结:多人共享的分支只用merge,否则看个人偏好merge和rebase都可以用,建议用rebase能使分支线图更清晰
子模块的在父工程引用的问题
经常出现问题是,子模块有新的提交,但父工程忘记同时要对子模块提交一次新的版本号。其他人在拉取父工程,得不到子模块的最新更新(游离状态),此时如果操作不当,子模块未提交的内容有掉失的可能。
但不是说就能使用了,如果对方的工作内容,只是拉取最新的线上内容,那么可以通过提供脚本git fetch --all & git reset--hard origin/YOUR_BRANCH
辅助他们拉取
github flow
- 在github网站将[目标仓库]fork到个人账号下[个人仓库]
- clone[个人仓库]到本地
- 在本地[个人仓库]添加追踪[目标仓库]
git remote add [目标仓库-别名] [目标仓库地址]
- 拉取[目标仓库]信息
git fetch [目标仓库-别名]
- 创建一个本地功能分支
git checkout -b [功能分支] [目标仓库-别名]/[目标分支]
git checkout [功能分支]
- 开发新内容
- ….
- 开发完成后,将[功能分支]合并main分支,
git checkout main & git merge [功能分支]
- 拉取[目标仓库]最新代码
git pull [目标仓库-别名]
并解决冲突 - github上提交pull request
cherry-pick
- 先用git log查看,要cherry-pick的commitId,复制下来
git checkout [目标分支]
- 依次
git cherry-pick [commitId]
- …
- 如果出现冲突,解决完成用git add将解决了冲突的文件添加到暂存区
- 标识完成冲突
git cherry-pick --continue
工作目录与裸仓库
工作目录(worktree)是指`git clone YOUR_WORKSPACE_DIR`的下载目录
仓库信息目录(gitdir)是指,git clone时没特别指名,默认存放在YOUR_WORKSPACE_DIR下的.git目录
实际上,这两个目录无需存在父子目录关系。git clone
时指定--bare
选项,可以只下载.git裸仓库内容
git clone --bare --branch YOU_BRANCH YOUR_REPO`
如果想将.git放在其它路径,可以使用选项–separate-git-dir
git clone --separate-git-dir=/path/to/gitdir <repository_url> /path/to/workingdir
网上大多数文章介绍用--bare
去搭建git远端仓库。其中一个使用场景是,如果当前不方便切换工作目录,git提供全局选项--git-dir
和--work-tree
指工程位置
git --git-dir=YOUR_WORKSPACE/.git --work-tree=./YOUR_WORKSPACE pull
HEAD
HEAD指向本地仓库的当前分支最新提交id,orign/HEAD指向远端仓库的当前分支最新提交id HEAD可以用到任何git命令中需要commitId参数的地方,有关其它变量见https://git-scm.com/docs/git-rev-parse#_specifying_revisions 以下输出HEAD的值
git rev-parse --short HEAD
fde831d
以下示例,commit但未push提交日志的前后对比
- commit前,两者的值相同
git log -5 --oneline fde831d (HEAD -> master, origin/master, origin/HEAD) Update 2023-09-30-docker笔记.md b19cb24 Update 2022-06-26-整理常用linux命令.md afb9ed0 wsl2搭建centos、docker mongo 33c8d2b Update 2023-09-30-docker笔记.md d78c147 Update 2023-09-30-docker笔记.md git rev-parse --short HEAD fde831d git rev-parse --short origin/HEAD fde831d
- commit前,两者的值不相同
git add xxxxx.jpg git commit -m "add git笔记 jpg" git log -5 --oneline 148dc7c (HEAD -> master) add gi_repo.jpg fde831d (origin/master, origin/HEAD) Update 2023-09-30-docker笔记.md b19cb24 Update 2022-06-26-整理常用linux命令.md afb9ed0 wsl2搭建centos、docker mongo 33c8d2b Update 2023-09-30-docker笔记.md git rev-parse --short HEAD 148dc7c git rev-parse --short origin/HEAD fde831d
特殊的符号
具体参见:https://git-scm.com/docs/git-rev-parse#_specifying_revisions
~
使用形式commitId~{n}
,相对于commitId回溯n次提交
- HEAD = HEAD~0
- HEAD~ = HEAD~1
- HEAD~~ = HEAD~2
- HEAD{n个~} = HEAD~n
^
使用形式commitId^{n}
,相对于commitId上n次父提交
* HEAD^:当前分支的上一个提交。
* HEAD^^ 或 HEAD^2:当前分支的上两个提交。
@
@ 是 HEAD 的简写
.. (Double Dot)
用于指定两个提交之间的范围(不包括第一个提交)。
A..B:表示从提交 A 的下一个提交到提交 B 的所有提交(不包括 A,包括 B)。
master..feature:表示 master 分支不包含而 feature 分支包含的所有提交。
打包
如果打包的目的只是单纯地备份(归档),那么用git archive
配合gitattributes的eol选项就足够了。但如果有定制的打包流程,比如 1. 打包时设置发布参数 2.打包需要记录版本日志
3.原始工程包的代码很,打包时要排除非发布内容 4. 对包加密等。
总的来说,你大概率仍然需要一个原始工程,执行一些打包脚本。
打包场景的特性:
- 整包,只针对某个分支的最新提交
- 差异包(热更包),某段范围的提交
默认情况下.git裸仓库内容,会全部下载到本地,实际在打包场景并不必要,所以可以配合以下指令加快下载速度
- –single-branch 只下载单个分支的代码内容,配合—branch使用
- –depth=1 只下载最后一次提交日志
- –shallow-submodules 同–single-branch,表示子模块也只下载单个分支代码内容
假定以tag为打包目标
当打整包时,可以同时使用以上3个选项,如下表示从远端YOUR_GIT_ADDRESS,只下载下载YOUR_BRANCH分支,分支与子模块的裸数据只包含最后一次提交日志
git clone -b YOUR_TARGET --single-branch --depth=1 --shallow-submodules YOUR_GIT_ADDRESS
当打差异包时(以tag为文件为最小差异单位),需要至少2个以上的提交日志才能做差异内容,所以不能用–depth选项,另外利用xargs和cp命令将差异提出出来
git clone -b YOUR_BRANCH --single-branch --shallow-submodules YOUR_GIT_ADDRESS
git diff --ignore-submodules --name-only --diff-filter=AUMR $YOUR_SRC_TAG $YOUR_DST_TAG | xargs -I {} cp --parents "{}" $YOUR_OUTPUT_DIR
vimdiff&vimmerge常用命令
引用文章: https://gist.github.com/karenyyng/f19ff75c60f18b4b8149#resolving-conflict-from-a-git-pull
- 设置vimdiff作为diff和merge工具
git config --global core.editor vim git config --global diff.tool vimdiff git config --global merge.tool vimdiff git config --global --add difftool.prompt false
- 设置vim在diff文件时的颜色码,加打或创建~/.vimrc文件,追加以下内容
" 显示空白字符 set list " vimdiff 高亮关闭 if &diff colorscheme evening endif
- vimdiff快捷键
快捷键 | 说明 |
---|---|
]+c | 跳转到下一个不同处 |
[+c | 跳转到上一个不同处 |
2]c | 跳转到下两个不同处 |
do dp | do:在当前光标位置,用另一个窗口的不同处替换当前位置的内容;dp反之 |
:1,100 diffg 或 :1,100 diffget | 等同于do,只是指定了范围1-100行 |
:1,100 diffp 或 :1,100 diffput | 等同于dp,只是指定了范围1-100行 |
Ctrl-w w | 跳到下一个窗口 |
ctrl-w h | 跳到左侧窗口 |
ctrl-w l | 跳到右侧窗口 |
ctrl-w j | 跳到下方的窗口 |
ctrl-w k | 跳到上方的窗口 |
:diffupdate | 手动刷新文件的比较结果 |
撤销修改 | u |
以密钥访问git
生成密钥ssh-keygen -t ed25519 -C "YOUR_MAIL_ADDRESS"
将git客户端 ssh public key添加到git server
这一步允许客户端设备账号能访问稍后创建的git仓库。需要将git客户端.ssh/id_rsa.pub文件内容,追加到git服务器.ssh/authorized_keys。以下提供一个操作方法,使用scp传输到远程服务器(需要支持ssh远程访问),然后追加到authorized_keys
// 客户端
~/.ssh/scp id_rsa.pub root@192.168.0.206/home/git
// 服务端
cat id_rsa.pub >>.ssh/authorized_keys
git常用大杂烩
注意,某些命令&选项到某个git版本才有
子模块
- 添加子模块
git submodule add [子模块仓库地址] [子模块存放路径] git push
- clone工程时,同时下载子工程
git clone --recursive [父工程仓库地址]]
- 已clone主工程,但未下载子模块,需要手动初始子模块
git submodule update --init --recursive
- 更新子模块
git submodule update
分支管理
- 创建分支
git branch NAME
删除分支
git branch -D NAME git push origin :NAME
提交类
- 以交互的方式添加文件到暂存区
git add -i
日志类
- 差异查看最近的2条日志
git log -p -2
- 显示短commit-id
git log -p -10 --abbrev-commit
- 以所有分支图谱视图,显示最近2条日志,
git log -10 --all --graph
提交类
- 修改最后一次提交的注释
git commit --amend -m "对提交进行说明"
- .gitignore文件常用过滤规则
*.vscode *.so *.code-workspace
修改&还原类
- 取消本地文件修改
git restore [要对比的文件路径]
- 取消暂存区文件修改
git restore --staged [要对比的文件路径]
- 删除暂存区文件
git rm -r --cache [要对比的文件路径]
- 取消本地和暂存区的修改,并还原到本地HEAD指向的版本
git reset --hard HEAD
- 取消本地和暂存区的修改,还原到远端的最新版本
git reset --hard origin/<BRANCH_NAME>
- 回退远程到某次版本
git reset --hard <COMMITID>
- 清理未跟踪的目录和文件
git clean -f -d
- 交互模式清理未跟踪的文件
git clean -i
- 暂存当前修改,TODO: –keep-index和–index的区别
git stash
- 查看暂存列表
git stash list
- 恢复暂存的修改
git stash apply (恢复后不删除暂存) git stash pop (恢复后删除暂存)
- 删除暂存
git stash drop
标签类
- 标签排序
git tag -l --sort=v:refname "cn*"
- 反向排序
git tag -l --sort=-v:refname "cn*"
- 强制刷新本地tags信息
git fetch --tags -f
账号管理
- 设置账号有效时间X秒
git config --global credential.helper 'cache --timeout=秒数'
比较差异
- 工作区与本地仓库区的差异
git diff HEAD
- 查看包含本地子模块的差异
git diff --submodule
- 暂存区与本地仓库区的差异
git diff --cached HEAD
- 指定文件在暂存区与本地仓库区的差异
git diff --cached HEAD FILE_NAME
git lfs
- 对使用lfs的工程安装lfs,lfs不是git内置工具,需要额外安装https://git-lfs.com/
否则下面指令会报错
git lfs install
- 设置checkout,clone,pull等自动下载lfs文件
git config --global lfs.auto-fetch true
- 添加大文件筛选规则,如下将
.psd
文件以大文件看待git lfs track "*.psd"
原文:
https://lizijie.github.io/2024/08/11/git%E7%AC%94%E8%AE%B0.html
作者github:
https://github.com/lizijie