前要
以下包含一些平时经常会用到但容易忘记的操作,或一些有记录价值的操作,但不包含那些更基本的命令或操作,一些较新版本的命令也不记录。部分存在比较官方的文档进行讲解的操作或命令,为了保持文章简短,会给出文档的链接,这里不会再展开。
正式文档
配置全局用户名和邮箱
git的当前用户的主配置文件在(在用户目录的.gitconfig文件)
1 2
| git config --global user.name "username" git config --global user.email "[email protected]"
|
配置默认编辑器
1
| git config --global core.editor vim
|
提交时自动把所有换行符转换为LF()
1
| git config --global core.autocrlf input
|
配置crlf检查处理
core.safecrlf结合core.autocrlf配置使用,配置为warn出现告警但是仍然允许提交(默认配置),配置为true(直接Fatal拒绝提交),false(不做任何提示,但是仍然会做转换)。
1
| git config --global core.safecrlf warn
|
冗余空白检查
在本地使用git diff等命令的时候将无意义的空白加亮,但是不会做自动修复
1
| git config --global core.whitespace "trailing-space,space-before-tab,tab-in-indent,tabwidth=4
|
生成本机的ssh密钥
生成的密钥在用户目录的.ssh文件夹(包括公钥和私钥),需要在远程git仓库托管服务的配置中添加生成的公钥。
将密码保存到~/.git-credentials
解决bash终端中git中文显示乱码的问题
对于windows使用mingw终端可以直接修改终端窗口的配置
1 2 3
| Options->Text Locale修改为zh_CN Character set修改为UTF-8
|
直接修改配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
[gui] encoding = utf-8 [i18n] commitencoding = utf-8 [svn] pathnameencoding = utf-8 [core] quotepath = false
|
windows下的图形化git管理工具
windows下推荐使用TortoiseGit
1
| https://tortoisegit.org/
|
建立一个基于CGI脚本生成网页的简易项目查看器
gitweb依赖一个web服务器,这里使用的是lighttpd。在linux环境下会比较方便,但是需要注意一些权限分配的问题。而在windows下需要修改一些仓库下的配置。 ### 几个基本的命令 #### 初始化并启动gitweb
#### 启动gitweb
#### 停止gitweb
### gitweb搭建与配置 #### 1.安装lighttpd
1 2
| # 下载与系统对应版本lighttpd,解压到系统上并把lighttpd所在的路径添加到PATH环境变量上 http://lighttpd.dtech.hu/
|
#### 2.初始化并启动本地仓库的gitweb
如果在windows上,这时候去访问gitweb的页面是不正常的,需要修改
/.git/gitweb内的配置。3.修改本地仓库gitweb的配置
所有配置的修改都要在调用完git instaweb之后进行,并且之后要用git instaweb start来启动gitweb,而不能是git instaweb,不然会把修改过的配置重新替换掉。修改前先把lighttpd停止掉,如果git instaweb stop无法停止,直接在任务管理器上结束掉lighttpd。 -/.git/lighttpd.conf -/.git/gitweb_config.perl
4. 修改lighttpd.conf
- server.document-root
1 2
| server.document-root = "E:/Git/mingw64/share/gitweb"
|
- cgi.assign
1 2
| cgi.assign = ( ".cgi" => "E:/Git/usr/bin/perl.exe" )
|
5. 修改gitweb_config.perl
- \(projectroot和\)git_temp
1 2 3 4
|
our $projectroot = "/E/Project/excelfilter"; our $git_temp = "/E/Project/excelfilter/.git/gitweb/tmp";
|
6. 安装CGI.pm模块
这个是perl的CGI支持模块(点击下载),解压到/usr/lib/perl5/vendor_perl下。
7. 启动并访问gitweb
1 2 3 4
| git instaweb start
git web--browse http://127.0.0.1:1234
|
8.效果预览
and与unadd操作
add
1 2 3 4 5 6 7 8 9 10 11 12
| git add -u
git add .
git add -A git add --all
git add -p
|
补充遗漏的文件
如果已经commit了,但是还存在遗漏的文件没有add,可以用下面两种方法补充进去(推荐第一种做法)。
commit --amend
1 2 3 4 5
| git add filename
git commit --amend
|
reset --soft
1 2 3 4
| git reset --soft head^
|
去掉上次提交不应该加进来的文件
1 2 3 4 5 6 7 8 9
|
git reset --soft head^
git reset filename
|
unadd
清空暂存区并保留工作区
1 2 3
| git reset head git reset --mixed head
|
撤销特定文件的add操作,把它移出暂存区
1 2
| git reset head filename git reset --mixed head filename
|
rm操作
把文件从仓库中移除并保留本地文件
1 2 3 4 5
| git rm --cached filename
git rm --cached -r folder
|
把文件从仓库和本地都删除
1 2 3 4 5
| git rm filename
git rm -r folder
|
把文件从所有提交中删除
1 2
| git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
|
忽略文件
.gitignore文件
把需要忽略掉的文件的路径/文件名加入.gitignore中(支持正则表达式),关于格式可以参考git Documentation。
忽略仓库中特定文件类型的所有文件
忽略已添加入仓库的文件的修改
1 2 3 4 5
| git update-index --assume-unchanged filename
git update-index --no-assume-unchanged filename
|
commit
自动把原本已加入仓库的文件放到暂存区(add操作)后提交
1
| git commit -am "message"
|
文件修改撤销
==注意:checkout相比reset更加不可逆一些,checkout操作需要慎重,不然原本的修改可能很难找得回来,但是reset会保留或者可以恢复。==
撤销未进入过暂存区的修改,恢复至版本库
状态预览1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| git checkout filename git checkout -- filename
git checkout folder git checkout -- folder
git checkout . git checkout ./
git checkout <commit sha1 id> filename git checkout <commit sha1 id> -- filename
|
撤销已进入暂存区的修改,恢复至版本库
状态预览1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| git checkout head filename git checkout head -- filename
git checkout head folder git checkout head -- folder
git checkout head . git checkout head ./
git checkout <commit sha1 id> filename git checkout <commit sha1 id> -- filename
|
当修改已进入暂存区,工作区再次发生修改,恢复到暂存区
状态预览1 2 3 4 5 6 7 8 9 10 11
| git checkout filename git checkout -- filename
git checkout folder git checkout -- folder
git checkout . git checkout ./
|
当修改已进入暂存区,工作区再次发生修改,恢复到版本区
状态预览1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| git checkout head filename git checkout head -- filename
git checkout head folder git checkout head -- folder
git checkout head . git checkout head ./
git checkout <commit sha1 id> filename git checkout <commit sha1 id> -- filename
|
强制撤销工作区和暂存区的所有修改
恢复误删除,原本已加入版本库的文件
1 2
| git checkout <commit sha1 id> -- filename
|
关于git checkout误操作的恢复
暂时没有很好的方法,可通过git fsck、git reflog等检查一致性、日志或其他第三方工具的方法来尝试恢复。
版本回退
关于reset的三种模式
保留工作区,并把暂存区(stage)和重置HEAD带来的差异也都放到工作区上,这是reset的默认模式
回退到特定版本,只回退commit信息,保留工作目录,并把重置 HEAD 所带来的新的差异放进暂存区(stage)
重置暂存区(stage)和工作区
回到文件的特定版本,把当前所有暂时修改都放到工作区,并把两个版本的差异放到暂存区上
1
| git reset --soft <commit sha1 id>
|
回到文件的特定版本,把当前所有暂时修改都放到工作区,也把两个版本的差异放到工作区上
1 2
| git reste <commit sha1 id> git reset --mixed <commit sha1 id>
|
强制把工作区和暂存区都回退到特定版本
1
| git reset --hard <commit sha1 id>
|
本地状态回退到与远程分支一致
1
| git reset --hard origin/master
|
撤销reset --hard
1 2 3 4 5
| git reflog
git reset --hard <commit sha1 id>
|
revert
撤销(反做)某个提交
将某个提交进行反向操作然后产生一个revert commit message。
1
| git revert <commit sha1 id>
|
提取文件特定版本的内容(即使文件已经删除)
1 2
| git show <commit sha1 id>:<filename> git show <commit sha1 id>:<filename> > <new-filename>
|
clone某些仓库时,切换里面的不同版本
变基(rebase)
整合来自不同分支的修改有两种方法:merge
以及rebase
。rebase
即变基,可以理解为修改了分支原本的基底
,它会修改新提交的Commit Hash ID,rebase
相对使用merge
的好处是可以使提交记录更加简洁。
当执行rebase操作时,git会从两个分支的共同祖先开始提取待变基分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改应用到基分支的最新提交的后面。
延伸阅读:Git分支 - 变基。
基本命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| git rebase -i <commit sha1 id>
git rebase --abort
git rebase --continue
pick: 无修改 reword: 修改commit message edit: 会停下来执行amending
squash: 合并后面的提交(注意位置),并合并日志 fixup: 合并后面的提交(注意位置),但是不合并日志
drop: 丢弃提交的内容
exec: 放在最后一行,执行shell命令
|
merge与rebase的对比
这里直接以例子来看它们之间的区别:
有两个人在协作开发,都是基于dev
分支,从其拉出了feature/hzq
和feature/zhonghang
分支,它们的基底都是dev
分支上的cbbceac
这条提交。
现在上图的状况是这样的,feature/hzq
和feature/zhonghang
分支都各自有两个新的提交,但是feature/hzq
已经先feature/zhonghang
分支合并到了dev
分支上。
而今天刚进入工作,feature/zhonghang
分支需要合并dev
上的最新改动,然后继续工作,选择有两个,即merge
或rebase
。
使用merge
对于以上两张图,第一张是在feature/zhonghang
,执行git merge dev
后的结构,第二张是切到dev
分支合并feature/zhonghang
后的结构,即执行git merge feature/zhonghang
。可以得到以下结论:
merge
之后基底
不变feature/zhonghang
分支的两个新提交记录的Commit Hash ID
不变,与merge
前一样- 会多出一条新的提交
Merge branch 'dev' into feature/zhonghang
使用rebase
以上两张图,第一张是在feature/zhonghang
,执行git rebase dev
后的结构,第二张是切到dev
分支合并feature/zhonghang
后的结构,即执行git merge feature/zhonghang
。可以的到以下结论:
rebase
之后feature/zhonghang
的基底变了feature/zhonghang
分支的两个新提交记录的Commit Hash ID
变了- 提交记录相比
merge
更加清爽简洁
变基的风险
rebase
会改变原提交的Commit Hash ID
,如果执行变基的分支,在此之前后其它副本分支,那么带来的影响将会不可控- 执行
rebase
之后,分支原有的结构细节可能会丢失
执行变基基本原则
- 如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基
- 多人协作时,拉取一个被变基然后强制推送的分支,要通知每个人执行再次变基(
git pull --rebase
) - 不要对存在副本分支的分支执行rebase,否则在之后合并时会产生不可控的冲突
- 不要对已经合并到其它分支的本地修改进行变基
- 不要在预发布分支或正式分支上执行
rebase
- 只允许对未推送与不存在副本分支的分支执行
rebase
修改某些提交的commit message
1 2
| git rebase -i <target sha1>
|
对某些提交执行amend操作
1 2
| git rebase -i <target sha1>
|
合并多个提交
1 2
| git rebase -i <target sha1>
|
丢弃某些提交的修改
1 2
| git rebase -i <target sha1>
|
pull时执行变基
diff & patch
diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
git diff git diff --
git diff --staged git diff --cached
git diff head git diff head^^ git diff head~2
git diff head --staged git diff head^^ --cached git diff head~2 --cached
git diff <commit sha1 id> <commit sha1 id>
git diff <branch name one> <branch name two> git diff <branch name one>..<branch name two>
git diff master...sub-branch git diff sub-branch...master
git diff --stat
git diff --name-status
git diff -R
|
生成patch
1 2 3 4 5
| git diff > <branch name>-<short commit id>-<desc>.patch
git diff > `git name-rev --name-only head`-`git rev-parse --short head`-<desc>.patch
|
应用patch
1 2
| git apply <branch name>-<short commit id>-<desc>.patch patch < <branch name>-<short commit id>-<desc>.patch
|
使用二分法(bisect)定位引入的bug
情景模拟准备
仓库中有一个record.txt文本文件,如果有一行的文本为“有bug”表示存在bug。已知其中一个正常提交的commit id是902c829f42b14d547330519993674e7f909a73a4,引入bug提交的commit id是98068739138d5785f2186d37efdfadfe9b5ebf1d。
名词定义
bad:存在bug的提交
good:无bug的提交
做法1
- 开始进入二分法定位bug时需要指定一个已知存在bug(bad)与无bug(good)的提交
- 初始化并进入二分操作
- 标记一个good的提交
1
| git bisect good 902c829f42b14d547330519993674e7f909a73a4
|
- 标记当前commit存在bug,这时会采用二分法跳到good与bad中间的commit
- 经过上面标记完成后,二分法定位bug正式开始。到了下一个commit,需要检查该提交是否存在bug,然后完成标记或者跳过该提交
1 2 3 4 5 6 7 8
| git bisect bad
git bisect good
git bisect skip
|
- 执行上面操作之后都会定位到下一个commit,重复操作直到定位到bug,git会给出首次引入bug的commit的提示的
- bug定位完成后退出二分查找### 做法2
- 在初始化时标记一个bad提交和一个good提交
1 2
| git bisect start head 902c829f42b14d547330519993674e7f909a73a4
|
- 剩下的做法与做法1相同
做法3(使用图形化)
- 初始化
1
| git bisect start head 902c829f42b14d547330519993674e7f909a73a4
|
- 进入图形化操作
做法4(使用脚本让git自动完成定位)
- 编写一个可以检查bug的脚本,脚本返回0表示无bug,返回其它任意值表示存在bug,例如:
1 2 3
|
! grep -q "有bug" record.txt
|
- 开始执行二分法定位bug
1 2
| git bisect start head 902c829f42b14d547330519993674e7f909a73a4 git bisect run ./check
|
查看日志
暂储(stash)
stash在把当前的修改打包存储起来,然后执行其它操作时会很有用。 ### 基本命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| git stash list
git stash show
git stash pop git stash pop stash@{0}
git stash apply stash@{index}
git stash drop stash@{index}
git stash clear
|
从stash中创建出新分支
1 2 3 4 5 6 7 8 9 10 11 12
| git stash git stash branch <new branch name> <stash id>
git stash git stash branch feature-modify stash@{0}
git stash git checkout -b <new branch name> git stash pop
|
grep
1 2 3 4 5 6 7 8
| git grep "text"
git grep -n "text"
git grep -c "text"
|
获取版本库的某些信息
获取最新提交的commit id
1 2 3 4 5
| git rev-parse head
git rev-parse --short head
|
获取当前分支名字
1 2 3 4 5 6 7 8 9 10 11 12
| git branch | awk '$1 == "*"{print $2}'
git name-rev --name-only head
git symbolic-ref --short HEAD
git rev-parse --abbrev-ref HEAD
git symbolic-ref HEAD | sed -e "s/^refs\/heads\///"
|
生成版本号
branch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| git fetch --all
git branch -a
git branch -r
git push origin --delete <branch name>
git fetch origin <branch name> git fetch origin <branch name>:<local branch name>
git branch --set-upstream-to <local branch name> origin/<remote branch name>
|
worktree
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| git worktree list
git worktree add <new path> -b <new branch> <base branch>
git worktree lock <path>
git worktree unlock <path>
git worktree remove <path>
|
tag部分操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
git tag -a vX.X.X
git tag -a vX.X.X -m "message"
git tag -a vX.X.X <commit sha1 id> -m "message"
git show vX.X.X
git tag -d vX.X.X
git push origin master --tags git push --tags
git fetch --tags
git push origin master :refs/tags/vX.X.X
|
remote
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| git remote -v
git remote add <new name> <url> git remote add --mirror=push <new name> <url> git remote add --mirror=fetch <new name> <url>
git remote remove <name>
git remote rename <old name> <new name>
git remote get-url <name> git remote get-url --push <name> git remote get-url --all <name
git remote set-url --add <name> <new url> git remote set-url --delete <name> <url>
git ls-remote
|
log
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| git log master develop
git log develop ^master
git log master...develop
git log 起始..结束 git log --pretty=oneline 75ec652..head
git log --pretty=oneline
git log --follow -p filename
|
reflog
reflog == ref log,查看更多的log,reflog是属于本地的,可设定过期时间
1 2 3 4
| git reflog
git log -g git log --walk-reflogs
|
whatchanged
1 2 3 4 5
| git whatchanged filename
git whatchanged
|
blame
检查某些修改造成的后果应该由谁负责。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| git blame filename
git blame 3,4 filename git blame 3,3 filename git blame 3,+4 filename
git blame -n filename
git blame head^ filename
git blame head^^^.. filename
git blame --since=1.weeks -- filename
git blame --since=1.days -- filename
|
notes
1 2 3 4 5 6 7
| git notes edit head git notes edit c6127b38c1aa25968a88db3940604d41529e4cf5
git notes show head git notes show c6127b38c1aa25968a88db3940604d41529e4cf5
|
objects
查看所有对象
1
| find .git/objects -type f
|
ls-files
查看对象的内容
1 2 3 4 5
| git show <object>
git cat-file -p <object>
|
查看树对象
1 2
| git show <commit sha1 id>^{tree} git cat-file -p <commit sha1 id>^{tree}
|
查看对象的类型
1
| git cat-file -t <object>
|
查看对象的大小
1
| git cat-file -s <object>
|
archive
为仓库创建归档文件,如:.zip、tar.gz等文件。
1 2 3 4 5 6 7 8 9 10 11
| git archive -l
-0 ~ -9,指定-0时不进行压缩
--prefix=<prefix>
-o <path>
|
例子
1 2
| git archive --format=tar.gz -o example.tar.gz -0 head
|
从远端拉取tag然后建立归档
1
| git archive --remote=origin --format=tar.gz -o v1.0.tar.gz v1.0
|
维护相关
var
clean
bundle
&esmp;把一些操作打包导出,在其他地方导入,详细参考文档。
1 2 3 4 5
| git bundle create <bundle file name> <branch name>
git fetch <bundle file name> <bundle branch name>:<local branch name>
|
pack
Git 最初向磁盘中存储对象时所使用的格式被称为“松散(loose)”对象格式。 但是,Git 会时不时地将多个这些对象打包成一个称为“包文件(packfile)”的二进制文件,以节省空间和提高效率。 当版本库中有太多的松散对象,或者你手动执行 git gc 命令,或者你向远程服务器执行推送时,Git 都会这样做。
当文件是悬空(dangling)的时,不会将它们打包进新生成的包文件中。
∗.pack是包文件,∗.idx是索引文件。
详细的说明看文档。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| find .git/objects -type f
git verify-pack -v .git/objects/pack/pack-<sha1 id>.idx
git gc
git repack
git pack-refs --all
git pack-redundant --all
git count-objects -v
|
hooks
<repso path>/.git/hooks下面有各种钩子的example,修改脚本内容并把.sample后缀去掉就可以启用钩子了。具体钩子的用处和含义看文档。