title: GitBase
date: 2024-01-04 10:45:28
tags:
categories:
💠
💠 2024-05-30 19:34:10
Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency. -- git-scm.com
Official Doc: git | Github:git | Arch Wiki: Git | Gitee: about git | git-for-windows 安装包镜像源
防止Git仓库存储爆炸
git-tips
学习Git的仓库
git权威指南的组织完整书籍,以及相关测试题
使用
git help 子命令
, 就能看到子命令对应的文档
--system
作用所有用户, 对应文件 /etc/gitconfig
--global
作用当前用户, 对应文件 ~/.gitconfig
--local
作用当前项目, 对应文件 ./.git/gitconfig
git config user.email ***
和 git config user.name ***
这两个是必须的,git config http.postBuffer 524288000
设置缓存区大小为 500mgit config core.fileMode false
忽略文件的mode变化,一般发生在文件放在挂载盘的时(默认755)git config branch.master.description
查看master分支描述信息,命令后附带信息则是设置
打开 ~/.gitconfig
文件能够发现这是 ini 格式的配置文件
[user]
email = kuangcp@aliyun.com
name = kuangcp
[core]
quotepath = false # 配置路径显示为中文
autocrlf = false
safecrlf = false
[credential]
helper = store
可用: opendiff kdiff3 tkdiff xxdiff meld kompare gvimdiff diffuse diffmerge ecmerge p4merge araxis bc codecompare smerge vimdiff emerge 工具 详细
git clone URL 目录
克隆下来后更名为指定目录-b branch
克隆远程仓库的指定分支 从Git 1.7.10开始支持
--single-branch
只克隆当前分支git clone --depth n URL
只克隆最近n次提交的历史, 能大大减小拉取的大小只克隆 指定标签或分支 且不包含内容 git clone -b <tag_name> --single-branch --depth 1 <repo_url>
大大缩减需下载的仓库大小
Shallow Clone: git clone --depth n URL
克隆的本地仓库
限制:
shallow update not allowed
git checkout -b branch origin/branch
的方式,
git fetch origin branch:branch
git push -u origin branch
git remote set-branches origin branch
再 git fetch
转为完整库的方案:
git fetch --unshallow
转换为完整仓库git remote set-branches origin '*'
然后 git pull
就会拉取最新所有分支成为可正常checkout的仓库,但仍旧残缺graft
的标记此时,只会从remote端pull下来符合 sparse-checkout 文件内规则(与 .gitignore 写法一致)的目录或文件,适合拉取大仓库中的局部目录和文件
git add file dir ...
git add .
git add -p
git rm file1 file2 ...
git rm --cached 文件
.gitignore
文件中注明, 不然又add回去了git status --help 查看详细介绍
-s --short
简化输出
git commit -am "init"
: a git库已有文件的修改进行添加, m 注释
git add *
如果有新建立文件就要add 再之后commit就不要a参数了 git commit -m ""
git commit -am ""
git commit
会自动进入VI编辑器
--amend
追加文件到上次commit
--no-edit
沿用上次 commit msg--allow-empty
提交空提交git restore -s master~2 Readme.md
git restore -s commitid filepath
git restore '*.java'
注意支持 regexgit restore :/
git revert .
git revert HEAD
git revert commitId
注意该操作可嵌套 即 撤销撤销某次提交git revert --no-commit 032ac94ad...HEAD
git commit -m "rolled back"
场景: 一个特性分支不该合并到主开发分支, 但是已经合并了, 并且合并后又做了很多其他修改, 这时候怎么影响最小地撤销这次错误的合并?
git revert commitId -m 1
展示提交的详细信息 注意show和 diff 的输出仅仅相似 不可用于 patch
git show HEAD
^
语法 HEAD^ 就是HEAD的前一次,两个就是前两次,commit id 同理~
语法 例如 ~2 ~3 就等价于 ^^ ^^^
git show HEAD~2^2
表示取第前两次提交的第二个父提交, 如果这是一个merge节点的话,否则会报错第一父提交
是合并时所在分支,第二父提交
是所合并的分支HEAD{10}
git show :/query
更多说明 查看
git help log
| Official Doc
-g
包含 reflog 信息
-p
显示所有提交的修改内容 git log -p -2
则仅显示最近两次提交的差异
--stat
查看每一次提交的修改文件修改概述 (pull时看到的那些++--的内容)
---pretty=[online/short/full/fuller/format]
使用预定义格式显示
图形的样子显示分支图 --graph
显示每个分支最近的提交 --simplify-by-decoration
输出简短且唯一的 SHA-1 值 --abbrev-commit
git log --author='A'
输出所有A开头的作者日志
git log 文件名 文件名
输出更改指定文件的所有commit 要文件在当前路径才可
git log --after='2016-03-23 9:20' --before='2017-05-10 12:00'
输出指定日期的日志
git shortlog
按字母顺序输出每个人的日志
--numbered
按提交数排序-s
只显示每个提交者以及提交数量
彩色输出Log
alias glogc="git log --graph --pretty=format:'%Cred%h%Creset %Cgreen%ad%Creset | %C(bold cyan)<%an>%Creset %C(yellow)%d%Creset %s ' --abbrev-commit --date=short" # 彩色输出
alias gloga='git log --oneline --decorate --graph --all' # 简短彩色输出
alias glo='git log --oneline --decorate' # 最简单
alias glol='git log --graph --pretty='\''%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'\'
alias glola='git log --graph --pretty='\''%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'\'' --all'
commit差异
查看dev有,master没有的那些提交
git log master..dev
或 git log dev ^master
(^表示非,等价于 --not)git log dev ^master ^fea/feature1
表示:在dev有后两个分支没有的commitgit log origin/master..master
对比分支的差别 git log dev...master
也就是那些非两个分支共有的commit
git log --left-right dev...master
内容差异
git diff dev master
可以理解为 从 dev 分支切换到 master 分支将发生的修改git log fileName
或者 git log --pretty=oneline fileName
更容易看到 sha-1 值git log --oneline -S "search keyword" --source --all
查看所有提交修改的模块分布
git --no-pager log --format=format:'%h' --no-merges | awk '{system(" git --no-pager diff --stat-name-width=300 --name-only "$1" "$1"~") }' | sed 's/\/.*//g' | sort | uniq -c | sort -hr
--stat-name-width=300
规避路径过长被折叠成...sed 's/\/.*//g'
只保留第一级目录--after='2022-01-01 0:00' --before='2023-01-01 0:00'
追加时间过滤查看文件提交记录
git blame file
--cached
stage 区 和 index 区 进行比较, 等同于 --staged
git diff [options] [<commit>] [--] [<path>...]
git diff [options] --cached [<commit>] [--] [<path>...]
git diff [options] <commit> <commit> [--] [<path>...]
git diff [options] <blob> <blob>
git diff [options] [--no-index] [--] <path> <path>
Github:diff-so-fancy
一个更方便查看diff的工具
安装:npm install -g diff-so-fancy
查看当前分支和master的文件差异列表
git diff master --stat=200 --compact-summary
, 在一个时间周期长,改动范围大的功能分支上可以在上线前快速确认下有没有漏SQL执行,漏配置项
git diff branch1 branch2 > first.patch
git diff branch1 branch2 path/file1 path/file2 > first.patch
git diff filePath > first.patch
路径为Git项目根路径的相对路径将patch文件应用到 index区。 Apply a patch to files and/or to the index
git apply --ignore-space-change --ignore-whitespace first.patch
patch -p1 < first.patch
git apply失败可以尝试这个方式将patch文件应用为commit。 Prepare patches for e-mail submission 参考: How To Create and Apply Git Patch Files
创建 patch
git format-patch -1 commit-sha
指定commit 创建 patch
-2
-3
... 数字表示 commit id 之前的 几个 commit 也创建 patchgit format-patch master -o patches
对那些 master分支 中有而当前分支没有的 commit 创建 patch 到 patches 目录git format-patch master --stdout > total.patch
将所有patch文件合并为一个使用 patch
Apply a series of patches from a mailbox
git tag
-l 'v1.0.*'
列出v1.0.*git show tagname
展示标签注释信息git tag -a v1.0.0 -m "初始版本"
git tag -a v1.2.4 commit-id
git checkout tagname
和切换分支一样的,但是标签只是一个镜像,不能做提交git checkout -b branchname tagname
git tag -d tagname
git push origin -d tag <tagname>
git push origin :refs/tags/<tagname>
git reset -h
用法:git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<提交>]
或:git reset [-q] [<树或提交>] [--] <路径>...
或:git reset --patch [<树或提交>] [--] [<路径>...]
-q, --quiet 安静模式,只报告错误
--mixed 重置 HEAD 和索引
--soft 只重置 HEAD
--hard 重置 HEAD、索引和工作区
--merge 重置 HEAD、索引和工作区
--keep 重置 HEAD 但保存本地变更
--recurse-submodules[=<reset>] control recursive updating of submodules
-p, --patch 交互式挑选数据块
-N, --intent-to-add 将删除的路径标记为稍后添加
git reset 文件
将指定文件 或者 git reset .
当前目录(递归) 都取消暂存git reset --soft HEAD^
撤销最近那次 commit 行为git commit -c ORIG_HEAD
使用撤销的那次 commit 的注释进行提交注意 reset 操作会将老的HEAD会备份到文件 .git/ORIG_HEAD 中,命令中就是引用了这个老的相关信息 -c 参数是复用指定节点的提交信息
git branch feature/new
git reset --hard HEAD^3
git checkout feature/new
相当于是将master上这三次的修改都转移到了这个分支上, master 从来没有过这三次提交一样 如果没有在 执行 reset --hard 之前新建分支的话, 这三次提交就永远删除了
注意: 这个操作在多人的协作中, reset --hard 比较危险, 可能引起别人分支的混乱
git reset --hard ORIG_HEAD
注意: 该命令会将 index 和 stage 的修改清空git pull
reset --merge ORIG_HEAD
使用 --hard 会直接回滚,直接丢失当前未提交的所有更改
在开发一个功能的时候, 突然有别的需求插进来了, 就可以通过 commit 一次, 然后回滚该次 commit 的方式 将工作状态暂存, 且不会产生垃圾提交
git gc -h
:
--aggressive
默认使用较快速的方式检查文档库,并完成清理,当需要比较久的时间,偶尔使用即可--prune[=<日期>]
清除未引用的对--auto
启用自动垃圾回收模式--force
强制执行 gc 即使另外一个 gc 正在执行Remove untracked files from the working tree
git clean --help
-n
参数预览删除文件列表
Git 的分支是轻量型的, 能够快速创建和销毁
获取当前分支名 git symbolic-ref --short -q HEAD
拉取远程分支到本地并建立同名分支
git fetch --all
git pull <远程主机名> <远程分支名>:<本地分支名>
按颜色列出分支上的提交和图示
可以查看到每次提交所属的分支
将当前修改缓存起来, 避免不必要的残缺提交 stash命令的缓存都是基于某个提交上的修改, 是一个栈的用法
参考: Git Stash的用法
底下的评论也很有价值, 值得思考
参考: git-stash用法小结
git stash --help 查看完整的使用说明
基本动作
stash@{num}: On branchName : comment
push动作 实用参数
--keep-index
-k
stash 将不缓存 已经被add进index区的内容
--include-untracked
或 -u
stash 将缓存未被track的文件
--patch
交互式选择哪些内容需stash缓存哪些进入index区
如果需要恢复 stash@{0}: On feature-test: test
注意 stash 是一个项目范围内的栈结构, 所以如果多个分支执行了stash, 那缓存都是共用的 要先确定好当前分支 stash 的 id (通过记录comment的方式会更好) 再 pop 或者 apply (不能无脑pop 血泪教训)
alias wip='git stash list | grep $(git branch --show-current)'
git stash show -p stash@{0}
alias gsh.st='__gshst(){ index=$1; if test -z $index; then index=0; fi; git stash show -p stash@{$index} }; __gshst'
gsh.st > dev.patch
可以恢复 stash drop 或者 clean 的内容。stash drop后会输出 Dropped refs/stash@{0} (......)
, 括号内就是该次stash对应的commitId
git fsck --no-reflog | awk '/dangling commit/ {print $3}'
gitk --all $(git fsck --no-reflog | awk '/dangling commit/ {print $3}')
| xargs git show
, 查找代码内容查看所有参数
git branch --help
-a --all
--list 'feature*'
-r --remote
-vv
本地分支和远程分支的关联状态--contains [<commit>]
--no-contains [<commit>]
commit 缺省为 HEAD(也就是最近的一次提交)git branch name
并设置当前分支的对应远程分支 -t <remote>/<branch>
-m old new
对于远程来说就是先要删除再新建分支-d 分支
-D
强制删除. 等价于 --delete --force
--set-upstream-to=<remote>/<branch> <branch>
--merged
--no-merged
gh feature/a
gh feature/a origin/feature/a
撤销文件修改
gh .
取出最近的一次提交, 覆盖掉 work 区下当前目录(递归)下所有已更改(包括删除操作), 且未进入 stage 的内容, 已经进入 stage 区的文件内容则不受影响
gh 文件1 文件2...
同上, 但是只操作指定的文件gh [commit-hash] 文件1 文件2...
根据指定的 commit 对应hash值, 作如上操作, 但是区别在于 从 index 直接覆盖掉 stage 区, 并丢弃 work 区
gh [commit-hash] .
如在项目根目录执行该命令, 会将当前项目的所有未提交修改全部丢失, 不可恢复!!!!
git checkout [commit-hash] 节点标识符或者标签 文件名 文件名 ...
git reset HEAD
来清除这种状态实验性命令: git switch branch
merge rebase squash 三种合并策略
Git 在合并分支的时候使用的是 三向合并策略,即当前分支和目标分支的共同祖先commit节点, 和两个分支的当前commmit节点进行比较确定哪一方发生修改需要纳入,如果两方都修改就要提示冲突
根据 Git 的合并策略,在合并两个有分叉的分支(上图中的 D、E‘)时,Git 默认会选择 Recursive 策略。找到 D 和 E’的最短路径共同祖先节点 B,以 B 为 base,对 D,E‘做三向合并。
B 中有 http.js,D 中有 http.js 和 main.js,E’中什么都没有。根据三向合并,B、D 中都有 http.js 且没有变更,E‘删除了 http.js,所以合并结果就是没有 http.js,没有冲突,所以 http.js 最终会被删除。
git merge-base 分支1 分支2
查看两个分支共同祖先(前提:两个分支通过merge命令发生的合并,如果是rebase则找不到真正的祖先节点)git show-branch 分支1 分支2 分支3
查看若干分支差异提交情况git merge develop
默认 是 ff(fast forward) 不生成新节点,直接将当前分支指向Develop分支。(一条拐弯的分支线)
git merge --no-ff develop
在当前分支 主动合并
分支Develop,生成一个新节点,分支图的合并路径清晰--squash
和 --no-squash
该参数和 --no-ff
冲突
--squash
时,当一个合并发生时,从当前分支和对方分支的共同祖先节点,一直到对方分支的顶部节点内的所有提交内容将修改当前工作区,使用者可以经过审视后进行提交,产生一个新的节点。git mergetool
使用工具进行分析冲突文件方便修改配置mergetool工具kdiff3, 同类的还有meld:
git config --global merge.tool kdiff3
git config --global mergetool.kdiff3.cmd "'D:/kdiff3.exe' \"\$BASE\" \"\$LOCAL\" \"\$REMOTE\" -o \"\$MERGED\""
git config --global mergetool.prompt false
git config --global mergetool.kdiff3.trustExitCode true
git config --global mergetool.keepBackup false
衍和操作 参考博客 | Git rebase -i 交互变基 | git rebase的原理之多人合作分支管理 这种合并方式,不会像merge方式那样在分支图上出现多个圈,而是线性演进, 但是遇到冲突后会改动历史提交,导致提交不是按时间演进,不利于分布式协作
git merge master
换成 git rebase master
git rebase --abort
放弃rebasegit rebase --continue
修改好冲突后继续master 提交了 b,c dev 提交了 d,e
merge master:
master: a - b - c
\ \
dev: d - e
rebase master:
master: a - b - c - d' - e'
merge 会保留分支图, rebase 会保持提交记录为单分支
git cherry-pick <commit-id>
简单来讲, 就是将指定的某个提交(任意分支上的)上的修改, 重放到当前分支上 和 stash pop 命令相比, 在重放上是一致的, 使修改内容生效,commitId会变化
用途
fea/something
上的四个提交其实可以合并, 使得提交信息更清晰, 不冗余, 就可以从 fea/something
通过分析提交历史查到哪次提交引起的Bug然后检出,修复
Manage multiple working trees doc
Git大部分命令都是本地的, 所以执行效率很高, 但是协同开发必须有同步的操作
其实单独的两个主机也能完成同步, 两个主机之间 使用同一个仓库进行开发 两个人互为对方的远程库(使用 git daemon 即可搭建简易服务端), 添加为 remote 即可操作
指定本地开发分支和远程的绑定关系 git branch --set-upstream dev origin/dev
而且 一个本地库是能够绑定多个远程的
Github上fork的项目
合并对方最新代码
git add remote A A_URL
git fetch A
git merge --no-ff A/master
Github上PR
Using git to prepare your PR to have a clean history
add name URL地址
添加远程关联仓库 不唯一,可以关联多个, 一般默认是originset-url name URL地址
修改关联仓库的URLrm URL
删除和远程文档库的关系rename origin myth
更改远程文档库的名称show origin
查看远程分支的状态和信息git ls-remote
git remote -v
常用参数
-q
控制台不输出任何信息-f
强制推送提交 使用这个参数时要再三考虑清楚
--all
推送所有分支-u
upstream 设置 git pull/status 的上游
git push origin master
和 git push -u origin master
区别在于 前者是使用该远程和分支进行推送-d --delete
删除引用(分支或标签)删除远程分支
git push origin -d 分支名称
git push origin :分支名称
第一次将本地分支与远程建立关系
git push -u origin master
| git push --set-uptream master
| git push -all
(会将所有分支一起push)提交指定tag git push origin tagname
git push --tags
出现 RPC failed; result=22, HTTP code = 411
的错误
git config http.postBuffer 524288000
访问远程仓库, 拉取本地没有的远程数据
git init
然后 git fetch URL
git checkout -b master FETCH_HEAD
git fetch --all
git fetch --all
由远程分支创建新分支并设定跟踪 git checkout -b dev origin/dev
git fetch origin dev:dev
git push -u origin dev
进行设置git fetch -p
git fetch origin dev-test
下拉指定远程的指定分支 至 origin/dev-test 但不会创建本地分支fetch 不到所有远程分支的原因和解决方案
git config --get remote.origin.fetch
git config --add remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
不仅仅是 fetch 代码, 还会进行 merge 操作, 所以安全起见, 是先 fetch 然后再手动 merge
git pull origin dev
下拉指定远程的指定分支git pull --all
下拉默认远程的所有分支代码并自动合并 git branch -r | grep -v '\->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
git fetch --all
git pull --all
git pull 默认策略配置
error: cannot lock ref 'refs/remotes/origin/test/v1.0.0' : 'refs/remotes/origin/test' exists;
原因: 由于git的分支都是以目录和文件形式存储,分支名包含 / 时会创建对应的目录, 因此无法同时创建 test 分支和 test/v1.0.0 分支,目录test和文件test冲突了
需要手动删除test分支,或者重命名test/v1.0.0 为 test_v1.0.0 .
上诉错误容易出现在Clone多份仓库时,某份仓库删了test分支并push, 但是这份仓库的 remote 引用管理未清理
清理远程引用: git update-ref -d refs/remotes/origin/test
git submodule add url dir
目录为可选项当主仓库 clone 时 只会将子模块作为空目录克隆下来
git submodule init
git submodule update
以上两条命令等价于 git submodule update --init --recursive
删除子模块
图形化展示分支 需要依赖 tcl tk
git grep docker
-n
搜索并显示行号--name-only
只显示文件名,不显示内容-c
查看每个文件里有多少行匹配内容(line matches):git grep xmmap v1.5.0
git grep --all-match -e '#define' -e SORT_DIRENT
匹配两个字符串git archive -v --format=zip v0.1 > v0.1.zip
git reflog
显示commit操作详情,仅本地保存该工具是Git内部命令 往往被其他子命令使用
git rev-parse fea/new
Git scalar 自2.42.1起支持,原理为先稀疏检出,然后定时任务拉取变更
Github: gitignore | 一行则是一个配置,且可以仓库和目录存在不同的配置,git会按就近原则匹配
#
注释一行test.txt
忽略该文件*.html
忽略所有HTML后缀文件*[o/a]
忽略所有o和a后缀的文件!foo.html
不忽略该文件 */ #忽略所有文件
build/ #所有build目录
/build #只忽略当前目录的build, 子目录的不忽略
*.iml #所有iml文件
?.log #忽略所有 后缀为log, 文件名字只有一个字母
!*.java #不忽略所有java文件
a.[abc] #忽略 后缀为 a或者b或者c 的文件
doc/*.txt #忽略 doc一级子目录的txt文件, 不忽略多级子目录中txt
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。