学习Git有一段时间了,一路上也一直在写有关于Git方面的文章,但总觉得不是我想要的,就是感觉有点肉肉的,不够直接,不够马上出效果,所以才有了这篇文章,当然这文章可能会不断更新和修正,希望读者可以作为一个工具文章使用,我也会努力将其优化的更加的符合工作场景
说明
1、在[...]中的内容,需要根据实际情况进行修改
[TOC]
说明
1、在[...]中的内容,需要根据实际情况进行修改
如何本地与远程建立信任联系?
要解决这个问题,需要使用SSH秘钥的方式,接下来我就讲一下怎么进行配置。
1.在本地生成私钥和公钥
git config --global user.name "username"//用户昵称
git config --global user.email "emailAddress"//github或者gitlib的邮箱地址
ssh-keygen -t rsa -C "emailAddress"//github或者gitlib邮箱账户地址
2.将电脑上的公钥与远程仓库进行绑定
本地会在上面的步骤中会生成一个id_rsa.pub(默认情况是这个名称),将该文件中的内容copy到远程仓库github或gitlib的settings的SSH配置选项中。
Tittle名称自由发挥
克隆工程
将远程的数据复制一份到本地
#【仓库copy地址】
git clone [[email protected]:zoeminghong/hello.git] [工程别名]
本地新建Git工程
现在打算将本地的工程,放到Git仓库进行托管了,并且远程Git仓库已经创建了该项目的工程
#本地初始化工程,会生成一个.git文件
git init
#将本地的工程与远程仓库中的项目进行关联(不用关心项目名不一致的问题)
#此时本地工程与远程仓库已经建立了联系
git remote add origin [[email protected]:zoeminghong/hello.git]
#将本地所有文件添加到Git中,进行监管
git add .
#将内容提交 【提交注释】
git commit -m "[...]"
#将本地的内容同步到远程仓库中
git push -u origin master
显示某一个特定的提交的日志
git show [十六进制码]
查看提交图
git log --graph --pretty=oneline --abbrev-commit
查看冲突未处理的文件列表
git ls-files -u
本地代码与远程代码冲突问题
本地代码未commit的前提下,解决与远程代码冲突问题
git pull #失败
#将当前修改进行暂存起来
git stash
#或
git stash save "[注释]"
#获取最新的远程仓库代码
git pull
#恢复暂存的内容
git stash pop
#stash其他操作
#恢复最近一次save的原工作区内容,,并删除stash记录
git stash pop
#恢复最近一次save的原工作区内容,但不删除stash记录
git stash apply [指定版本]
#删除stash记录
git stash drop
#获取暂存列表
git stash list
但,上面的也可能存在问题,由于本地存在未被追踪的文件,并且远程仓库pull的时候也存在同名的文件,就会存在pull失败,在这种情况下,在
git stash
后面追加--include-untracked
,会将远程的文件与本地的文件融合stash只会保存当前索引和工作目录的状态,其保存的是add和commit的中间状态,如果还没有被git追踪的文件,是不会被记录的
如果我对某文件进行了修改,但我不想要push到远程仓库,同时我又想获取最新的修改记录
git stash save
git pull --rebase
如果暂存内容现在不想在当前分支恢复了,而是想单独起一个分支
git stash branch [newBranchName]
想要查看当前工作区与暂存状态内容区别
git stash show -p stash{0}
本地代码已经commit后,解决与远程代码冲突问题
# 获取远端库最新信息 【分支名称】
git fetch origin [master]
# 做比较
git diff [本地分支名] origin/[远程分支名]
# 拉取最新代码,同时会让你merge冲突
git pull
方法2
# 获取最新代码到tmp分支上 [远程的分支:本地分支]
git fetch origin [master:tmp]
# 当前分支与tmp进行比较
git diff tmp
# 修改冲突部分,进行本地commit操作
git add .
git commit -m "[...]"
# 将tmp中内容合并到当前分支中
git merge tmp
# 删除分支
git branch -d tmp
删除文件
保留副本操作
git rm --cache [文件名]
直接文件删除
git rm [文件名]
后悔药
存在5个记录状态
未修改(
Origin
)已修改(
Modified
)已暂存(
Staged
)已提交(
Committed
)已推送(
Pushed
)
处于已修改,未暂存,还原到最近的版本,废弃本地做的修改(当前文件修改没有进行add操作的时候)
# 还原指定文件
git checkout -- [文件名]
# 还原所有
git checkout .
# 或
git reset --hard
取消已暂存未提交的文件(撤销先前"git add"的操作)
# 还原指定文件
git reset HEAD [文件名]
# 还原所有
git reset --hard
取消已提交未推送
#最近内容已经commit的情况下
git reset --hard origin/master
已推送
git reset --hard HEAD^
git push -f
回退到某个版本
# 获取所有的HEAD更改信息的sha1值
git reflog
git reset [SHA1]
回退到上一次提交的状态,按照某一次的commit完全反向的进行一次commit.(代码回滚到上个版本,并提交git)
git revert HEAD
使用reset是不会有日志记录的,revert则会要提交一个记录点
修改最新的提交信息(修改提交的注释信息)
git commit --amend
reset与revert的使用说明
reset一般用于本地还没有push到远端的时候,revert则用于想要远端也进行记录回退操作的时候,也就是说在push之后。
1、如果你已经push到远程仓库,reset删除指定commit以后,你git push可能导致一大堆冲突.但是revert 并不会
2、如果现有分支和历史分支需要合并的时候,reset 恢复部分的代码依然会出现在历史分支里.但是revert 方向提交的commit 并不会出现在历史分支里。
本地分支与远程分支相连
本地创建了一个分支,远程也有一个分支,进行两者关联
git checkout -b [本地分支名] origin/[远程分支名]
Tag使用
我们在开发的时候,可能存在线上发布了一个版本,需要给这个版本代码打上一个标签,到时候可以方便回退到这个版本
# 创建tag 【tag名】
git tag v1.0
(git tag -a [v1.4] -m ['my version 1.4'])
# 查看存在的tag
git tag
(git tag -l ['v1.4.2.*'])
# 将tag更新到远程,直接的push是不会将tag同步上去
git push origin --tags
接下来就讲解回退到具体的tag
# 保存当前编程环境
git stash
# 切换回某个tag(v1.0)
git show v1.0
#【sha1】
git reset --hard [2da7ef1]
# 创建分支来保存tag的数据,tag只是一个节点的标记,无法承载数据的修改记录,【分支名】
git checkout -b [branchName] [tagName]
# 接着你就可以在这里改啊改了
切换回主干或其他分支
# 切换分支
git checkout master
# 日志记录
git reflog
# 显示stash列表
git stash list
# 恢复之前的工作环境代码
git stash apply
# 删除stash
git stash drop
分支与主干合并
git add .
git commit -m "v1.1"
git checkout [bill]
# master分支最新的代码合并到bill分支上
git rebase [master]
git checkout master
# bill分支合并到当前分支【分支名】
git merge [bill]
关于代码的比较
# 显示暂存区和工作区的差异
git diff
git diff [filename]
# 显示暂存区和上一个commit的差异【文件名】
git diff --cached [hello.txt]
git diff --cached [HEAD或者SHA1] [filename]
# 已提交远程仓库的差异
git diff master origin/master
# 显示工作区与当前分支最新commit之间的差异
git diff HEAD
git diff [HEAD或分支名] [filename]
# 显示两次提交之间的差异【分支名】
git diff [first-branch]...[second-branch]
git diff [SHA1] [SHA1] [filename]
#分支之间的差异
#分支之间的差异
git diff [分支1] [分支2]
git diff [分支1]..[分支2]
#指定文件
git diff [分支1]:[file1] [分支2]:[file2]
#查看指定提交范围内的所有变更文件情况
git diff --stat master~[范围值] [分支名]
git diff --stat master~5 tmp
//还可以值查看具体某一个文件
git diff --stat master~5 tmp test.txt
定位哪个提交点导致文件出现问题
#先确定范围
git bisect start
git bisect bad #一般都是当前HEAD是坏提交【sha1】
git bisect good a794f9bd96f06b57b4c10433e4d6abb3f0855749
#上面的步骤就是确定范围的,接下来就是回答git的问题,他指定的提交点是好的还是坏的
git bisect good//如果是坏的,就bad,直到你找到哪个提交点导致出现问题
#查看维护日志
git bisect log
git branch
#完成操作后,要回切到工作分支上
git bisect reset
git branch
git reset --hard fb47ddb2db...
检查文件中每一行代码是谁提交的记录
git blame -L [起始行数],[文件名]
创建分支
#以当前节点作为分支的开始起点
git branch [分支名]
#以SHA1作为分支开始起点
git branch [分支名] [SHA1]
#创建并切换分支,sha1以哪个节点作为分支的起点
git checkout -b [分支名] [SHA1]
拉去远程仓库分支代码
git checkout 1.0
git pull
#或者
git checkout 1.0 origin/1.0
开发的过程中生成新分支
#因可能存在未被git监管和未提交的内容,需要将未提交的内容进行监管和暂存
git add .
git stash
#包含[SHA1]及之前的代码会被copy盗分支上
git branch [分支名] [SHA1]
重命名分支
在git中重命名远程分支,其实就是先删除远程分支,然后重命名本地分支,再重新提交一个远程分支。
//显示现在分支
git branch -av
//删除远程要删除的分支devel
git push --delete origin devel
//重命名本地分支devel为develop
git branch -m devel develop
//推送到远程
git push origin develop
这是由于在 github 中,devel 是项目的默认分支。要解决此问题,这样操作:
进入 github 中该项目的 Settings 页面;
设置 Default Branch 为其他的分支(例如 master);
重新执行删除远程分支命令。
查看远程仓库分支
git branch -a
获取远程仓库分支代码
git fetch origin [远程仓库分支名] [本地仓库分支名]
删除本地分支
git branch -d [分支名]
删除远程仓库分支
git remote remove [分支名]
查看分支
git show-branch
#或
git branch
分支前面都存在*或者!
*表示当前分支
在–之后的是记录分支的提交信息
像
*+ [tmp] 远程2
就表示该提交存在于两个分支中
显示某分支中某文件内容
git show [分支名]:[文件名]
显示某个节点某文件的内容
git show [SHA1] [文件名]
关于切换分支的逻辑
如果存在未被git追踪的文件,git是会将其忽略的
如果存在已追踪且被修改或删除,必须commit之后,才能切换
如果要不计后果的情况,强切,加
-f
将当前的分支修改的内容同步到其他的分支上
假如你希望变更作用于另一个分支上,但由于当前分支如果不提交,是无法切换到另一个分支上的
git checkout -m [另一个分支名]
将一个区间的提交,移植到另一个分支
#当前分支,得到dev分支中dev~2之前的所有提交内容
git cherry-pick dev~2
cherry-pick会生成一条新的提交记录
代码行数统计
统计某人的代码提交量,包括增加,删除:
git log --author="$(git config --get user.name)" --pretty=tformat: --numstat | gawk '{ add += $1 ; subs += $2 ; loc += $1 - $2 } END { printf "added lines: %s removed lines : %s total lines: %s\n",add,subs,loc }' -
统计某人一个月内的代码提交量,包括增加,删除:
git log --since=1.month.ago --author="$(git config --get user.name)" --pretty=tformat: --numstat | gawk '{ add += $1 ; subs += $2 ; loc += $1 - $2 } END { printf "added lines: %s removed lines : %s total lines: %s\n",add,subs,loc }' -
仓库提交者排名前 5(如果看全部,去掉 head 管道即可):
git log --pretty='%aN' | sort | uniq -c | sort -k1 -n -r | head -n 5
仓库提交者(邮箱)排名前 5:这个统计可能不会太准,因为很多人有不同的邮箱,但会使用相同的名字
git log --pretty=format:%ae | gawk -- '{ ++c[$0]; } END { for(cc in c) printf "%5d %s\n",c[cc],cc; }' | sort -u -n -r | head -n 5
贡献者统计:
git log --pretty='%aN' | sort -u | wc -l
提交数统计:
git log --oneline | wc -l
git log 参数说明:
--author 指定作者
--stat 显示每次更新的文件修改统计信息,会列出具体文件列表
--shortstat 统计每个commit 的文件修改行数,包括增加,删除,但不列出文件列表:
--numstat 统计每个commit 的文件修改行数,包括增加,删除,并列出文件列表:-p 选项展开显示每次提交的内容差异,用 -2 则仅显示最近的两次更新
例如:git log -p -2
--name-only 仅在提交信息后显示已修改的文件清单
--name-status 显示新增、修改、删除的文件清单
--abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符
--relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)
--graph 显示 ASCII 图形表示的分支合并历史
--pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)例如: git log --pretty=oneline ; git log --pretty=short ; git log --pretty=full ; git log --pretty=fuller
--pretty=tformat: 可以定制要显示的记录格式,这样的输出便于后期编程提取分析
例如:git log --pretty=format:""%h - %an, %ar : %s"" 下面列出了常用的格式占位符写法及其代表的意义。 选项 说明 %H 提交对象(commit)的完整哈希字串 %h 提交对象的简短哈希字串 %T 树对象(tree)的完整哈希字串 %t 树对象的简短哈希字串 %P 父对象(parent)的完整哈希字串 %p 父对象的简短哈希字串 %an 作者(author)的名字 %ae 作者的电子邮件地址 %ad 作者修订日期(可以用 -date= 选项定制格式) %ar 作者修订日期,按多久以前的方式显示 %cn 提交者(committer)的名字 %ce 提交者的电子邮件地址 %cd 提交日期 %cr 提交日期,按多久以前的方式显示 %s 提交说明
--since 限制显示输出的范围,
例如: git log --since=2.weeks 显示最近两周的提交 选项 说明 -(n) 仅显示最近的 n 条提交 --since, --after 仅显示指定时间之后的提交。 --until, --before 仅显示指定时间之前的提交。 --author 仅显示指定作者相关的提交。 --committer 仅显示指定提交者相关的提交。 一些例子: git log --until=1.minute.ago // 一分钟之前的所有 log git log --since=1.day.ago //一天之内的log git log --since=1.hour.ago //一个小时之内的 log git log --since=`.month.ago --until=2.weeks.ago //一个月之前到半个月之前的log git
log --since ==2013-08.01 --until=2013-09-07 //某个时间段的 log git blame
看看某一个文件的相关历史记录例如:git blame index.html --date short
子模块
保留子组件的现有目录结构的完整性,故而git创造了类似于maven中的module一样的功能,来实现子模块的管理
打个比方:现在我有一个父工程A,其工程路径下面有五个子工程BCDEF,按照往常是要git clone
6个工程才可以完全下载成功,而且工程与工程之间的路径关系也不知道。现在有了gitmodules就可以直接下载A工程就可以了,其他的5个子工程都会自动下载。
文件.gitmodules存放在父工程根目录下
[submodule "others/B"]
path = others/B
url = https://rep.XXX.com/crm/B.git
[submodule "sources/C"]
path = sources/C
url = https://rep.XXX.com/crm/C.git
[submodule "sources/D"]
path = sources/D
url = https://rep.XXX.com/crm/D.git
.....
添加子模块
git submodules add [远程仓库地址] [相对于父模块的相对路径]
注:
直接手动更改gitmodule文件是没有用的哦
远程仓库地址要先于子模块之前准备好
子模块的名称是可以与[相对于父模块的相对路径]不一致的
创建完成以后会生成.gitmodules
与.gitattributes
这两个文件
.gitmodules
和.git/config
保存着子模块的信息
从远程仓库获取所有模块数据
#方式一
git clone --recursive [远程仓库地址]
#方式二
git clone [远程父仓库地址]
cd [父模块路径]
git submodule init
git submodule update
或者
git checkout [branchname]
git submodule update --init --recursive
删除子模块功能
先清空.gitmodules
中的内容
再执行文件的删除
————
其他命令
# .gitmodules中子模块的内容更新到.git/config中
git submodule init
gitmodules参考
关闭issue
格式Fixes #45
,45是issue的ID,在相应的issue的链接地址就有。
可以关闭issue的关键字:
close
closes
closed
fix
fixes
fixed
resolve
resolves
resolved
不同的仓库中关闭issue
格式close username/repository#issue_number
关闭多个issues
格式closes #34, closes #23, and closes example_user/example_repo#42
更多内容可以关注微信公众号,或者访问AppZone网站