记录平时对git的使用方法和技巧
创建本地git库 进入test.git
1 git init --bare --shared
Window下进行跨平台的clone操作,下载链接前需要添加ssh
1 git remote add origin ssh://hostname@192.168.1.1:/test.git
Linux:
1 git remote add origin hostname@192.168.1.1:/test.git
新建单独用户下载:
1 2 3 4 5 6 7 8 9 10 # 为了禁止登录将shell,修改为git-shell或者/bin/false将禁止登录 sudo useradd -c 'git version control' -s /usr/bin/git-shell -M git -d /git # 设置密码 sudo passwd git # 创建home目录 sudo mkdir /git # 修改所属权限 sudo chown -R git:git /git/ # 测试仓库 sudo git init --bare --shared /git/123.git
1 2 sudo adduser git sudo usermod -G sudo -a git
创建分支 删除本地分支:
1 git branch -d branch_name
切换分支 1 git checkout branch_name
下载 下载较大工程:
depth用于指定克隆深度,为1即表示只克隆最近一次commit.
创建本地镜像仓库 1 git clone --mirror <URL>
日志 日志规范 1 2 3 4 5 <type>(<scope>): <subject> // 空一行 <body> // 空一行 <footer>
type feat
:新功能(feature)fix
:修补bugdocs
:文档(documentation)style
: 格式(不影响代码运行的变动)refactor
:重构(即不是新增功能,也不是修改bug的代码变动)test
:增加测试chore
:构建过程或辅助工具的变动scope scope
用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。
subject subject是 commit 目的的简短描述,不超过50个字符。填写要求:以动词开头
提交 更新 添加代码 1 2 git add <filename> git add -A #添加所有修改
查看日志 1 2 3 4 5 6 git log git log -n #查看前n条日志 git log --stat #查看日志的修改情况 git log -p #查看日志的具体修改 git log <filename/dirname> #查看该文件或目录的修改日志 git log -S [keyword] #在提交log中搜索关键词
tig 命令行下查看git历史提交记录的工具
回退 1 git reset HEAD <filename> #将该文件从缓冲区撤回
查看远程库 添加远程库:
1 git remote add <name> <url>
获取远程库中的最新版本,但与git pull 不同它不会merge 作用:可以对比远程库与当前本地的差异。
查看标签 作用:一个稳定的版本或者完成一个功能,为了发布或者保存而打的标签,主要是发布
切换标签 暂存当前改动 保存当前工作进度,会把暂存区和工作区的改动保存起来。执行完这个命令后,在运行git status命令,就会发现当前是一个干净的工作区,没有任何改动。使用git stash save ‘message…’可以添加一些注释
显示保存进度的列表。也就意味着,git stash命令可以多次执行。
1 git stash pop [–index] [stash_id]
git stash pop 恢复最新的进度到工作区。git默认会把工作区和暂存区的改动都恢复到工作区。
1 git stash apply [–index] [stash_id]
除了不删除恢复的进度之外,其余和git stash pop 命令一样。
1 git stash drop [stash_id]
删除一个存储的进度。如果不指定stash_id,则默认删除最新的存储进度。
删除所有存储的进度。
恢复本地错误操作 查看所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作)
1 2 $git reflog -h usage: git reflog [ show | expire | delete ]
show
: 显示所有条目,缺省值expire
: 删除掉更老的reflog条目delete
: 从reflog中删除一个条目模块管理 添加模块
1 git submodule add projectB.git projectB
使用子模块
1 2 git submodule init git submodule update
克隆项目后,默认子模块目录下无任何内容。需要在项目根目录执行此命令完成子模块的下载
在clone整个项目时添加递归参数:--recurse-submodules
删除子模块
rm -rf 子模块目录
删除子模块目录及源码vi .gitmodules
删除项目目录下.gitmodules文件中子模块相关条目vi .git/config
删除配置项中子模块相关条目rm .git/module/*
删除模块下的子模块目录,每个子模块对应一个目录,注意只删除对应的子模块目录即可执行完成后,再执行添加子模块命令即可,如果仍然报错,执行如下:
commit统计 可以大致了解一下每个人对这个项目提交的commit数量和大致的贡献度
git获取最近一次提交的commit-id 获取完整commit id
获取short commit id
1 git rev-parse --short HEAD
.git无法忽略target,或者不生效的情况 .gitignore
未生效,原因是.gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。那么解决方法就是先把本地缓存删除(改变成未track状态),然后再提交
1 2 3 git rm -r --cached . git add . git commit -m 'update .gitignore'
强制更新代码 1 git push origin master --force
错误:1 remote: error: denying non-fast-forward refs/heads/master (you should pull first)
该消息表示您不允许进行非快进推送, 远程存储库很可能在其配置中denyNonFastforwards = true
, 要更改设置,请执行git config receive.denynonfastforwards false
从git中打包代码 打包某一个分支1 git archive --format=tar.gz --output "output.tar.gz" master
打包某一个commit1 git archive --format=tar.gz --output "output.tar.gz" ac1c53d
打包某些目录1 git archive --format=tar.gz --output "output.tar.gz" master dir1 dir2
合并代码 合并指定分支到当前分支
选择一个commit,合并到当前分支
1 git cherry-pick [branch_name]
查看信息 git服务器 1 git daemon --export-all --verbose --base-path=.
--export-all
: “–base-path”下所有的repo仓库--base-path=.
: 定义为当前目录--verbose
: 任何操作都会给当前repo通知svn仓库迁移至git svn的日志提交者与git相关用户进行绑定1 svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > users.txt
users.txt
的意义仅在于,将svn里面的提交者日志,注意是提交者,不是svn里面所有的用户信息都得关联
1 2 aaa = git-aaa <aaa@xx.com> #用户名 邮件地址 bbb = git-bbb <bbb@xx.com>
1 sudo apt install git-svn
1 git svn clone <SVN_URL> --no-metadata --trunk="svnproject" --tags="tags" --branches="svnbranches" --authors-file=users.txt --preserve-empty-dirs project-dir
--no-metadata
: 阻止git导出SVN包含的一些无用信息--trunk="svnproject"
: 指定导出仓库的主干项目路径,默认trunk--tags="tags"
: 日志标记--branches="svnbranches"
: 指定svn的分支项目路径--authors-file=users.txt
: 指定svn帐号在git中的映射--preserve-empty-dirs
: 保留原SVN项目中的空目录1 git remote add origin <GIT-URL>
1 git push origin master #--all
修改已提交的用户名和邮箱 1 2 3 4 5 6 7 8 9 git filter-branch --commit-filter ' if [ "$GIT_AUTHOR_EMAIL" = "old_email@email.com" ]; then GIT_AUTHOR_NAME="new_name"; GIT_AUTHOR_EMAIL="new_email@email.com"; git commit-tree "$@"; else git commit-tree "$@"; fi' HEAD
注 :可以修改但是在github中还是可以看到之前的用户名,效果不太好
命令行工具——tig commit操作: 上/下键
可以选择log中的commit 查看修改信息: j/k
展示commit-id: shift+x
删除已删除文件或目录的所以历史记录 查找大文件
1 2 3 4 5 # 列出前5个大文件 git verify-pack -v .git/objects/pack/pack-*.idx | sort -k 3 -g | tail -5 # 查看大文件路径 git rev-list --objects --all | grep 8f10eff91bb6aa2de1f5d096ee2e1687b0eab007
删除文件
1 git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch pom.xml' --prune-empty --tag-name-filter cat -- --all
删除目录
1 git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch qemu/qemu-4.2.0/' --prune-empty --tag-name-filter cat -- --all
删除回收
1 2 3 4 rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --prune=now git gc --aggressive --prune=now
rebase方式合并分支,分支在一条线 checkout到需要合并的分支feature 在feature分支上合并master分支的修改,生成一个新的分支版本 如果存在冲突解决冲突1 2 git mergetool git rebase —continue
checkout到master分支 合并新的feature分支到master分支 合并完毕,可以删除feature分支1 git branch --delete feature
提交更新1 git push origin master --force
删除已提交的commit 1 git rebase -i [commit-id]
commit-id: 为要删除的commit的下一个commit号
示例:
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 pick 1821834 add gnuplot test pick 5522ce1 add gnuplot test shell # Rebase e6fcac3..5522ce1 onto e6fcac3 (2 commands) # # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash" , but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with ' git rebase --continue ') # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # . create a merge commit using the original merge commit' s# . message (or the oneline, if no original merge commit was # . specified). Use -c <commit> to reword the commit message. # # # #
将需要删除的commit前面的pick
改写为drop
后,保存退出
退出后,可能存在冲突通过git mergetool
解决掉冲突后,使用git rebase —continue
继续直到解决完所有冲突提示rebase成功,删除完成。 如果中途不想删除后,可以通过git rebase --abort
终止删除动作 仓库地址为http时,用户名密码保存 1 git config --global credential.helper cache
1 git config --global credential.helper store
需要在第一次使用该仓库时,输入用户名密码后,会以配置文件(.git-credentials)保存到本地,后期使用不再需要输入用户名密码
删除保存的用户名密码配置文件:rm ~/.git-credentials
当前仓库信息 1 2 3 4 5 6 7 remote=$(git remote -v | grep fetch | awk '{print $2}') branch=$(git symbolic-ref --short -q HEAD) tag=$(git log -1 --decorate=short --oneline|grep -Eo 'tag: (.*)[,)]+'|awk '{print $2}'|sed 's/)//g'|sed 's/,//g') commit=$(git rev-parse --short HEAD) mesg=$(git log -1 --pretty=format:%B) echo "$lib info: branch=$branch, tag=$tag, commit=$commit, mesg=$mesg"
git show/diff tab显示宽度 设置Tab显示为4个字符的宽度
1 git config --global core.pager 'less -x1,5'
设置Tab显示为8个字符的宽度(默认)
1 git config --global core.pager 'less'
.gitattributes 当执行 git 动作时,.gitattributes 文件允许你指定由 git 使用的文件和路径的属性
1 2 3 4 5 # Declare files that always have LF line endings on checkout * text eol=lf # Denote all files that are truly binary and should not be modified *.bmp binary *.ttf binar
* text eol=lf
:所有文件上传仓库时将windows下的eol
转换为linux下的lf
开发者使用不同的操作系统,默认的文件结尾行就会不同。在 Windows 上默认的是回车换行(Carriage Return Line Feed, CRLF),然而,在 Linux/MacOS 上则是换行(Line Feed, LF)。
错误处理 git clone 1 2 3 fatal: The remote end hung up unexpectedly fatal: early EOF fatal: index-pack failed
1 git config --add core.compression -1
compression 是压缩的意思,从clone的终端输出就知道,服务器会压缩目标文件,然后传输到客户端,客户端再解压。取值为 [-1, 9],-1 以 zlib 为默认压缩库,0 表示不进行压缩,1..9 是压缩速度与最终获得文件大小的不同程度的权衡,数字越大,压缩越慢,当然得到的文件会越小。
DoTo Git 最佳实践:分支管理 git-config(1) Manual Page