在.git/HEAD目录下存在一个HEAD文件,其记录着当前工做区对应的SHA1。若是当前工做区从某个分支检出(checkout),那么这个HEAD文件中的引用最终执行分支对应的SHA1,若是处于分离头状态(不对应分支,从某个commit检查),那么这个HEAD文件中保存的就是检出的commit SHA1。git
若是咱们直接使用git checkout master分支,那么HEAD的值为ref: refs/heads/master。指向.git/refs/heads/master文件,其内容就是m6对应的SHA1。
若是咱们使用git checkout ${m4.sha1} ,那么HEAD的值为 ${m4.sha1}
所以HEAD引用就是当前工做区对应的提交的SHA1vim
可使用~(波浪号)和^号表示父提交,但含义会略有不一样。
</br>
^表示父提交的第几个提交,后面若是跟数字就是表示第几个父提交。
例如上图中当前的工做区HEAD指向m10提交。那么HEAD^和HEAD^1相同都是指向m9。HEAD^^指向m8,而HEAD^2则是没有意义的,由于m10只有一个父提交就是m9。HEAD^^^指向是m7,HEAD^^^2指向d2(HEAD^^指向m8,后面的^2表示m8的第二个父提交)。分析^的时候若是^号后面没有数字则和^1等价,表示第一个父提交,若是存在数字就表示第几个父提交。
tips:若是^后面的形式如:^{commit},^{tree},^{blob},则表示当前对象的提交、树、blob对象。
</br>
~表示法:波浪号表示父提交的层次关系。那么HEAD~和HEAD~1相同都是指向m9。HEAD~ ~指向m8,而HEAD~2和HEAD~\~是彻底等价的。HEAD~\~\~指向是m7,HEAD~3和其等价。所以d2就能够表示为HEAD~2^2(HEAD~2指向m8,后面的^2表示m8的第二个父提交),所以若是存在数字表示父提交的父提交的父提交...(数字就是几层父提交)bash
所以当咱们使用git log命令的时候,能够打印部分父提交。
git log --oneline HEAD~8..HEAD~5编辑器
当咱们对任何的分支修改(commit、pull、push)的时候,在.git/logs/refs目录都会记录变动状况,所以彻底不用担忧提交记录丢失的状况。.git/logs/refs/heads记录本地分支的变动记录,.git\logs\refs\remotes记录远程分支在本地的变动状况。
当咱们使用git reflog命令的时候就会显示HEAD引用的变动状况。
一样能够经过git reflog master查看master分支的变动状况。
reflog表示法:HEAD@{1},表示HEAD引用以前的第一个变动。ide
git reset --hard HEAD@{1}。若是新拉取的代码有问题,可是拉取以前的代码不肯定是否有问题,须要把代码回滚到拉取以前的代码,那么就能够执行这个命令测试
本地提交代码的时候常常会出现须要更改提交、修改注释的状况,下面的几个命令能够实现修改提交。命令行
git commit --amend能够方便的修改当前说起的注释。当执行这个命令的时候会弹出vim编辑器编辑注释信息(只修改提交注释信息)。3d
git reset命令能够把当前分支重置到某个提交。其选项有三个:日志
若是咱们的提交已经push到远程仓库上,别人已经pull下来了,若是你想删除某次提交,reset就不能使用了,而是使用revert命令,revert即对某次提交产生一个副作用的提交。code
git revert HEAD~3 -----建立一个提交,回滚最近的第四次提交 git revert master~5..master~2 ---回滚某个范围的提交
git rebase能够对当前没有push的提交进行更改,设想一下一个功能你能够本地进行了屡次提交,可是push的时候你想把这些提×××并成一个,就可使用git rebase命令编辑提交。
假设咱们须要对以下m9-m13的提交编辑。
场景一:把这些提交并成一个提交
使用squash命令和上一个提×××并,而后从新修改提交日志
场景二:删除某个提交
删除某个提交直接把该提交对应的行去除或者使用remove命令。若是存在合并冲突,而后解决冲突。
根据git命令行的提示,解决完冲突之后运行git add添加冲突的修改。
场景三:修改某个提交的日志:
使用edit命令或者reword命令修改,最好使用reword命令,这样rebase就能够之间弹出修改日志的vim编辑器,而不用git 弹出git commit --amend提示。
使用branch命令能够管理分支。
$ git branch ------显示本地分支 $git branch -a -------显示本地和远程分支 $git branch xxxbranchName -------建立分支名xxxbranchName的分支,此时HEAD的引用仍然是指向原来的分支 $git branch -d xxxbranchName ---删除某一个分支,若是该分支的修改没有合并,那么删除失败 $git branch -D xxxbranchName -----强制删除分支
使用tag命令能够管理标签。标签和分支的区别是,标签是不能够修改的。若是要修改必须基于该标签拉出一个分支修改
$git tag -------------展现全部的tag $git tag xxxtagName ---------------新建xxxtagName的标签 $git tag -d xxxtagName ---------删除xxxtagName的标签
checkout命令能够检出某个提交或者分支。
$git checkout SHA-1 ----------检出某个SHA-1对应的提交 $git checkout xxxbranchName -------------咱们使用git branch xxxbranchName的时候只是新建了这个分支,须要执行该命令切换到该分支 $git checkout HEAD^ -----检出到HEAD的第一个父提交 $git checkout -b xxxbranchName -------------新建xxxbranchName并检出到该分支
当咱们checkout除分支外的其余SHA-1都会提示咱们处于detached HEAD状态,此时.git/HEAD文件里面的内容就是SHA-1
此时若是在分离头上作的修改和提交想合并到其余分支须要用到merge和rebase等命令
merge命令能够合并两个多个提交,并生成一个新的提交。当前分支始终是目标分支。
假设历史记录以下,且当前分支为master:
A---B---C topic / D---E---F---G master
而后运行 "git merge topic",将会产生一个新的提交H,其中H的父提交是C和G。
A---B---C topic / \ D---E---F---G---H master
$ git merge fixes enhancements 能够合并多个分支到当前分支 $git merge 8b9612d76178416c06da3b76cfab2945ddc98347 ----合并某个提交
合并中冲突的处理:
$ git merge feture1 Auto-merging gameoflife-deploy/pom.xml CONFLICT (content): Merge conflict in gameoflife-deploy/pom.xml Automatic merge failed; fix conflicts and then commit the result.
merge命令能够一次性把全部冲突的文件合并,而后提示用户合并冲突去解决。解决完冲突之后,须要运行git add命令把文件添加到暂存区。继续执行git merge --continue命令编辑新生成的提交的log信息。而后merge完成。
rebase命令除了能够更改提交之外,同时能够合并代码,不过和merge命令有些不一样。
假设历史记录以下,且当前分支为topic:
A---B---C topic / D---E---F---G master
那么运行git rebase master的时候,其提交以下:
A'--B'--C' topic / D---E---F---G master
其中A'、B'、C'和A、B、C已经不是同一个提交(其tree对象不是同一个,父提交也不是同一个),可是其修改的内容是相同的。
rebase命令合并的时候从两个分支(或者提交)公共的父提交开始变基。
整体变基命令用的很少,并且场景比较复杂(能够查看其help文档)。慎用
一、merge命令会产生一个合并提交,而变基不会。变基命令的提交树会比较清晰,merge存在各类合并,看着比较混乱。
二、工做流不一样,对于merge命令其合并是全部提交一次合并好,而后解决冲突,而变基命令只能一个提交一个提交的解决冲突。
merge:merge的时候把待合并的全部commit一次合并好,只显示一次冲突,解决完冲突之后运行一次git merge --continue就行。 rebase: 工做流程大概以下: commit =nextNeedMergeCommit() while(merge(commit)==confict) { resoveConfilec(); rebaseContinue(); commit =nextNeedMergeCommit() }
在合并的时候常常会遇到快进式合并,那么什么是快进式合并么?
假设存在以下的场景:
A---B---C topic / D---E master
那么咱们执行git merge topic命令的时候,其结果就是快进式合并以下:
D---E --- A---B---C master
而若是执行git merge topic --no-ff 非快进式提交,测试以下的结果以下:
A---B---C / \ D---E --------------M master
会多产生一个提交M,其父提交为E和C。
可使用cherry-pick摘取每一个提交的内容,并合并当前分支
假设历史记录以下,且当前分支为topic:
A---B---C topic / D---E---F---G master
假设咱们指向合并A、B到master分支,那么就可使用cherry-pick命令
$git cherry-pick topic~2 topic~1 A---B---C topic / D---E---F---G-----A'---B' master
若是出现合并冲突,一样须要处理冲突,而后使用git cherry-pick --continue命令继续
当出现冲突的时候:
可使用git ls-files -u命令查看冲突的文件。