一、父提交的表示方法
1.HEAD引用
在.git/HEAD目录下存在一个HEAD文件,其记录着当前工作区对应的SHA1。如果当前工作区从某个分支检出(checkout),那么这个HEAD文件中的引用最终执行分支对应的SHA1,如果处于分离头状态(不对应分支,从某个commit检查),那么这个HEAD文件中保存的就是检出的commit SHA1。
如果我们直接使用git checkout master分支,那么HEAD的值为ref: refs/heads/master。指向.git/refs/heads/master文件,其内容就是m6对应的SHA1。
如果我们使用git checkout ${m4.sha1} ,那么HEAD的值为 ${m4.sha1}
因此HEAD引用就是当前工作区对应的提交的SHA1
2.父提交的表示方法
可以使用~(波浪号)和^号表示父提交,但含义会略有不同。
</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的第二个父提交),因此如果存在数字表示父提交的父提交的父提交...(数字就是几层父提交)
因此当我们使用git log命令的时候,可以打印部分父提交。
git log --oneline HEAD~8..HEAD~5
3.git reflog
当我们对任何的分支修改(commit、pull、push)的时候,在.git/logs/refs目录都会记录变更情况,因此完全不用担心提交记录丢失的情况。.git/logs/refs/heads记录本地分支的变更记录,.git\logs\refs\remotes记录远程分支在本地的变更情况。
当我们使用git reflog命令的时候就会显示HEAD引用的变更情况。
同样可以通过git reflog master查看master分支的变更情况。
reflog表示法:[email protected]{1},表示HEAD引用之前的第一个变更。
git reset --hard [email protected]{1}。如果新拉取的代码有问题,但是拉取之前的代码不确定是否有问题,需要把代码回滚到拉取之前的代码,那么就可以执行这个命令
二、修改提交
本地提交代码的时候经常会出现需要更改提交、修改注释的情况,下面的几个命令可以实现修改提交。
1.git commit
git commit --amend可以方便的修改当前提及的注释。当执行这个命令的时候会弹出vim编辑器编辑注释信息(只修改提交注释信息)。
2.git reset
git reset命令可以把当前分支重置到某个提交。其选项有三个:
- --hard:把工作区、暂存区的内容也重置到该提交
- --mixed:默认选项,把暂存器的内容重置到该提交,但是保留当前工作区的内容
- --soft:工作区、暂存器保留原来的内容,分支的引用重置到某个提交
3.git revert
如果我们的提交已经push到远程仓库上,别人已经pull下来了,如果你想删除某次提交,reset就不能使用了,而是使用revert命令,revert即对某次提交产生一个反作用的提交。
git revert HEAD~3 -----创建一个提交,回滚最近的第四次提交
git revert master~5..master~2 ---回滚某个范围的提交
4.git rebase
git rebase可以对当前没有push的提交进行更改,设想一下一个功能你可以本地进行了多次提交,但是push的时候你想把这些提×××并成一个,就可以使用git rebase命令编辑提交。
假设我们需要对如下m9-m13的提交编辑。
场景一:把这些提交并成一个提交
使用squash命令和上一个提×××并,然后重新修改提交日志
场景二:删除某个提交
删除某个提交直接把该提交对应的行去除或者使用remove命令。如果存在合并冲突,然后解决冲突。
根据git命令行的提示,解决完冲突以后运行git add添加冲突的修改。
场景三:修改某个提交的日志:
使用edit命令或者reword命令修改,最好使用reword命令,这样rebase就可以之间弹出修改日志的vim编辑器,而不用git 弹出git commit --amend提示。
三、分支标签命令
1.git branch
使用branch命令可以管理分支。
$ git branch ------显示本地分支
$git branch -a -------显示本地和远程分支
$git branch xxxbranchName -------创建分支名xxxbranchName的分支,此时HEAD的引用仍然是指向原来的分支
$git branch -d xxxbranchName ---删除某一个分支,如果该分支的修改没有合并,那么删除失败
$git branch -D xxxbranchName -----强制删除分支
2.git tag
使用tag命令可以管理标签。标签和分支的区别是,标签是不可以修改的。如果要修改必须基于该标签拉出一个分支修改
$git tag -------------展示所有的tag
$git tag xxxtagName ---------------新建xxxtagName的标签
$git tag -d xxxtagName ---------删除xxxtagName的标签
3.git checkout
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等命令
四、合并命令
1.git merge
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完成。
2.git rebase
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文档)。慎用
3.merge和rebase的区别
1、merge命令会产生一个合并提交,而变基不会。变基命令的提交树会比较清晰,merge存在各种合并,看着比较混乱。
2、工作流不同,对于merge命令其合并是所有提交一次合并好,然后解决冲突,而变基命令只能一个提交一个提交的解决冲突。
merge:merge的时候把待合并的所有commit一次合并好,只显示一次冲突,解决完冲突以后运行一次git merge --continue就行。
rebase: 工作流程大概如下:
commit =nextNeedMergeCommit()
while(merge(commit)==confict)
{
resoveConfilec();
rebaseContinue();
commit =nextNeedMergeCommit()
}
4.Fast-forward快进式合并
在合并的时候经常会遇到快进式合并,那么什么是快进式合并么?
假设存在如下的场景:
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。
5.git cherry-pick
可以使用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命令继续
原文地址:http://blog.51cto.com/5162886/2087794