git用法总结
本文最后更新于:2025年11月19日 下午
git使用
git 2.23之后,多了switch和restore命令,git –help已看不到checkout的踪影(还是支持)。因为checkout用法太多,语义的歧义太大了。
但是很多商业公司一直用着老旧的系统,老旧的软件,所以下面基本只会涉及checkout命令。
[toc]
配置
(1)初次配置用户名邮箱
1 | |
(2)解决git status中文文件名乱码
1 | |
(3)关闭git自动转换换行符
1 | |
(4)git status时忽略权限改变
1 | |
(5)配置默认编辑器
1 | |
(6)配置别名
1 | |
(7)配置提交注释模版
1 | |
(8)查看现有配置
1 | |
忽略文件
创建.gitignore文件即可,忽略遵从如下规则
#开头的行表示注释- 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中
- 匹配模式可以以(/)开头防止递归
- 匹配模式可以以(/)结尾指定目录
- 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反
1 | |
使用
git中的重要概念
工作区、暂存区、仓库
这是经常用到的概念,关系图如下:
sequenceDiagram
participant ws as 工作区
participant staged as 暂存区(staged)<br/>git里叫index
participant .git as .git目录(仓库)
participant remote as 远程仓库
ws ->> staged: git add
staged->>ws: git reset <file>
staged->>.git: git commit
.git->>ws: git checkout
.git->>remote: git push
remote->>.git: git fetch
remote->>ws: git pull
查看修改diff
查看当前工作区的修改(修改后还未暂存)
git diff查看暂存区中的修改(已暂存,下一次commit的修改)
git diff --staged查看某几个版本间修改文件列表
git diff --stat 38bb22e88660..HEAD -- . :^userspace/public/apps/lighttpd/web:^表示排除这个目录
远程仓库
1 | |
日志查看
-p 显示修改内容
-2 显示最近两次修改
git log -p -2
git log --stat 查看提交修改的文件统计
git log --since="2023-06-16 00:00:00" 查看从某天起迄今的日志。
查看某个函数的修改记录
1 | |
查看某行的修改记录
1 | |
双点和三点
分支多了,merge,cherry-pick混合使用,有时不清楚一个分支上究竟有哪些提交是独有的,可以通过如下命令来办。
双点
1 | |
三点
1 | |
可以通过下图看懂命令的不同

忽略cherry-pick,merge的提交
每次merge和cherry-pick都会产生新的提交,默认在使用双点,3点命令时,这些提交也会显示出来。但实际上并不希望看到这些。可通过如下参数控制。(实测双点没有效果,3点效果较好)git log foo...bar,只是打印二者所有的不同提交,看不出来谁是谁的,使用--left-right可以看出来哪边是哪边的
1 | |
--no-merges将不显示merge的提交--cherry-pick将会把cherry-pick的视为相同的提交--left-only --right-only将只显示一边的提交--cherry-mark将相同的提交用”=”号表示,不同的用”+”号标记
1 | |
cherry-pick大量代码
master分支上,哪些需要合并到ctc分支
1 | |
终端还是不方便,借助gitk来使用
1 | |
gitk界面搜索”通用”来过滤,右键cherry-pick
撤销
(1) 修改刚提交的日志信息
1 | |
(2) 提交时漏了文件
1 | |
(3) 撤销暂存区的文件(不会修改文件,只是取消文件暂存)
1 | |
(4) 撤销对文件的修改,会拷贝最新版本的文件覆盖当前文件
1 | |
(5) git commit之后撤销,只撤销commit,代码修改仍在
1 | |
--soft 不删除工作空间改动代码
--hard 删除工作空间改动
HEAD^ 上一个版本,也可以写成HEAD~1
(6) 撤销中间某次commit
1 | |
执行之后会自动提交。
status
(1)git status不显示Untracked的文件
1 | |
(2)取消某个文件的跟踪
如下命令会删除对这个文件的跟踪,即从版本库中删除,但本地还存在
1 | |
git忽略已经被提交的文件 - SegmentFault 思否
(3)对于已经跟踪的文件,使用.gitignore文件无效,可以使用
这个命令只对本地生效,只是设置了文件未修改的标记。
1 | |
显示哪些文件做了标记
1 | |
撤销对这些文件的忽略
1 | |
分支
1 | |
查看未合并的分支
1 | |
合并
合并单条提交
1 | |
变基rebase
变基:修改当前分支的基底。
如果可以直接快进合并,那么不需要变基。此时变基会提示:Current branch mesh_bug is up to date.
如果两边分支都有提交,那么可以变基,如下
1 | |
如果要线性修改提交记录,那么可以一直使用rebase,pull代码时也是用rebase: git pull -r
远程分支
1 | |
贮藏 stash
有时需要切换分支,但本地工作区已经很乱了,改了很多东西。想临时储存一下当前混乱的工作区。
1 | |
交互式暂存
有时我们修改了一个文件的两个地方,但是想分开提交,一次只提交文件中某几处差异。这时就可以使用交互式暂存。git add -i
1 | |
s查看状态,p就是我们需要的命令。p后,会让你选择要操作那个文件,选择文件后,什么也不输入回车,进入下一个选择页面,这个页面会一次次的出现差异,让你选择是否暂存,输入y或者n即可。
三棵树
HEAD: 上一次提交的快照,下一次提交的父节点,相当于该分支的最后一次提交。
Index:预期的下一次提交的快照,就是暂存区
work目录:就是自己的工作区。前两个都是抽象的.git目录下的一些东西。
每一次git操作,都会有一个快照产生,三棵树都指向各自的快照。
当work和index快照指向不同,那么git status就会显示“文件已修改,但未暂存”
当index和HEAD指向不同,那么git status就会显示“文件已暂存”
当三棵树的指向全部相同,那么git status就是干净的。
reset命令
对三棵树的操作根据选项不同,区别如下(默认是mixed选项)
1 | |
–soft
只是修改HEAD指向,相当于撤回了commit动作。所有修改的文件都是已暂存状态。
所以可以用–soft合并之前的多个提交(压缩提交,有时在一个bug分支上修改bug,修改完后又发现引入新问题,还要修改,提交了几次,最后验收通过,为了让分支上的日志就更容易看出来具体修改,而不是几次不完善的修改,可以压缩提交)。
–mixed
修改HEAD和index指向,相当于撤回了commit和add动作。所有撤回的修改都存在工作区中。
–hard
三棵树同时修改,相当于撤回了commit,add,和本地修改。(因为之前的已经提交了,还可以通过reflog救回来)
git reset [版本aa] 路径
git reset 跟路径的情况下,会把index更改为reset的版本状态,把work中的文件改为HEAD中的状态(即修改撤回到work了)。如果此时直接commit,那么commit后仓库中的文件跟版本aa是一样。
例子
1 | |
tag
查看tag
1 | |
添加tag
添加有注释的tag
1 | |
如果不使用-m参数,会打开编辑器,让你输入信息。查看tag的提交信息可以使用
1 | |
添加轻量级tag
1 | |
推送tag
tag默认不会推送到远程服务器。需要自己推送。
1 | |
如果要推送所有tag,可以使用如下命令,会推送所有本地的tag到远端服务器。
1 | |
gerrit推送tag也是上面这种命令,没有特殊的地方。
删除tag
1 | |
git-svn
使用git本地管理,修改推送到svn
注意:
git-svn并不能使用完整的git功能,为了避免遇到麻烦,保持线性提交,不能有merge产生的提交。把master分支外的修改全部变基到master分支。
(1)clone分支,-T表示trunk目录的名字,-b表示分支的名字,这样才会把分支这些一起clone下来
1 | |
svn上分支管理有可能比较乱,没有统一命名和目录管理,所以可以不用弄这些,直接clone一个分支
(2)日常修改,然后把修改推送到svn
1 | |
(3)如果本地在git分支上修改,需要先变基到跟踪的分支,再dcommit
1 | |
(4)拉取远程修改
1 | |
(5)其他svn操作
1 | |
(6)添加svn分支(针对不规则命名情况)
参考 git-svn:通过git来管理svn代码
通过如下命令来添加分支git config --add svn-remote.<远程分支名称>.url <svn地址,要包含具体分支路径>git config --add svn-remote.<远程分支名称>.fetch :refs/remotes/<远程分支名称>
实例如下:
1 | |
然后下载分支代码
1 | |
(7)如何同时在两个svn分支上开发
1 | |
注意:git br -vv并不能看到当前分支的跟踪分支是哪个svn分支,这和git远程分支不太一样。当git svn dcommit时,它会自动去找这个本地分支是从哪个svn分支来的,自动提交到对应的svn分支。
解决冲突
当dcommit有冲突时,需要git svn rebase拉取远程修改合入本地,解决冲突后再dcommit
1 | |
空目录问题
git不支持空目录权限管理,无法git add空目录,所以如果svn服务器上有空目录。使用会有一些注意点:
(1)git svn clone的最后一步,git会主动建立空目录,保持代码一致
(2)如果rm所有代码,然后git reset –hard,这时空目录会丢失。
(3)如果git stash -a暂存所有文件,空目录也会丢失。
(4)恢复办法为:git svn rebase,这时空目录会重新创建。
解决办法
(1)先通过svn下载代码,然后查找空文件夹 find -type d -empty
(2)在空文件夹下建一个.gitkeep(约定俗成),并提交这个空目录(视情况)
删除空目录问题
git 删除空目录传了之后,git svn dcommit并没有删除空目录。
工作流
2个固定分支
master主分支:不做任何修改,用于merge要提交的代码,从原厂仓库拉最新代码
工作空间分支:提交本地化的管理型代码(gitignore,.vscode,.gitkeep),同步最新的master分支
其他特性分支:从工作空间创建,修改bug,特性开发的分支。修改完后,将修改点rebase或者merge到master。从master提交代码,
(1)git svn clone代码
(2)创建工作空间分支,编译
(3)在工作空间分支创建特性分支
(4)将特性分支的修改merge到master
(5)在master上提交,拉取远程仓库代码
(6)把master分支合并到特性分支
修改url
(1) vi .git/config 修改url为新的url
(2) git svn fetch
(3) vi .git/config 修改url为老的url
(4) git svn rebase -l
(5) vi .git/config 修改url为新的url
(6) git svn rebase
清理
clean用于清理未暂存的文件,保持干净的工作区,可以代替make cleangit clean -xfd
1 | |
会删除空目录,记得git svn rebase
github
如何在github上下载某个项目的单独某个目录?
使用svn来下载,例如我想下载我的practice项目的hash_table目录
(1)在github上点开这个目录,浏览器地址栏可以得到这个地址
https://github.com/leon0625/practice/tree/master/hash_table
(2)将地址里的tree/master换成trunk
https://github.com/leon0625/practice/trunk/hash_table
(3)使用svn下载上面的地址
svn co https://github.com/leon0625/practice/trunk/hash_table
子模块
添加子模块
1 | |
添加之后,查看状态会出现一个.gitmodules文件和一个目录,这两个文件都要提交
克隆包含子模块的项目
直接clone之后,包含模块目录,但是不包含模块代码。有如下三种方式来clone完整代码
(1)分步执行
1 | |
(2)clone添加参数--recurse-submodules
1 | |
(3)update添加init,recursive参数
1 | |
更新子模块
当运行 git submodule update --remote 时,Git 默认会尝试更新 所有 子模块, 所以如果有很多子模块的话,你可以传递想要更新的子模块的名字。
更新之后,需要提交一下子模块目录,不然远程库上引用的子模块版本不会变
在子模块上提交
进入子模块目录,直接操作就好。推到远程库之后,记得在主仓库里面更新一下子模块。然后提交引用。
删除子模块
1 | |