What's the difference between HEAD^ and HEAD~ in Git?
https://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git
Rules of thumb
- Use
~
most of the time — to go back a number of generations, usually what you want - Use
^
on merge commits — because they have two or more (immediate) parents
Mnemonics:
- Tilde
~
is almost linear in appearance and wants to go backward in a straight line - Caret
^
suggests an interesting segment of a tree or a fork in the road
Tilde
The “Specifying Revisions” section of the git rev-parse
documentation defines ~
as
<rev>~<n>
, e.g.master~3
A suffix~<n>
to a revision parameter means the commit object that is the nth generation ancestor of the named commit object, following only the first parents. [For example,]<rev>~3
is equivalent to<rev>^^^
which is equivalent to<rev>^1^1^1
…
You can get to parents of any commit, not just HEAD
. You can also move back through generations: for example, master~2
means the grandparent of the tip of the master branch, favoring the first parent on merge commits.
Caret
Git history is nonlinear: a directed acyclic graph (DAG) or tree. For a commit with only one parent, rev~
and rev^
mean the same thing. The caret selector becomes useful with merge
commits because each one is the child of two or more parents — and
strains language borrowed from biology.
HEAD^
means the first immediate parent of the tip of the current branch. HEAD^
is short for HEAD^1
, and you can also address HEAD^2
and so on as appropriate. The same section of the git rev-parse
documentation defines it as
<rev>^
, e.g.HEAD^
,v1.5.1^0
A suffix^
to a revision parameter means the first parent of that commit object.^<n>
means the nth parent ([e.g.]<rev>^
is equivalent to<rev>^1
). As a special rule,<rev>^0
means the commit itself and is used when<rev>
is the object name of a tag object that refers to a commit object.
http://www.paulboxley.com/blog/2011/06/git-caret-and-tilde
I spent a little bit of time playing with Git today, specifically the way that the ^ (caret) and ~ (tilde) work and thought I'd document it here in case I forget.
The short version
If you want a deeper explanation skip down to "The long version".
ref~
is shorthand for ref~1
and means the commit's first parent. ref~2
means the commit's first parent's first parent. ref~3
means the commit's first parent's first parent's first parent. And so on.
ref^
is shorthand for ref^1
and means the commit's first parent. But where the two differ is that ref^2
means the commit's second parent (remember, commits can have two parents when they are a merge).
The ^ and ~ operators can be combined.
Here's a diagram showing how to reference various commits using HEAD as the starting point.
HEAD~1^2 commit的 first parent的second parent
The long version
I've created a dummy repository with several commits in it.
$ git log --graph --oneline
* 8329384 Seventh commit
* f5717b0 Merge branch 'my_branch'
|\
| * 956c87d Fourth commit on a branch
* | a8fe411 Sixth commit
|/
* c7c2590 Third commit on a branch
* 86362ff Second commit on a branch
* 748855b First commit on a branch
* 1855b25 Fifth commit
* 67cf3a7 Fourth commit
* ea29778 Third commit
* 28c25b1 Second commit
* cd00b76 First commit
Starting at the bottom, the early commits were made straight onto master.
The commits starting at 748855b
and moving up to c7c2590
were made on a branch and merged into master, but no changes had been made on master in the mean time.
The commits a8fe411
and 956c87d
were made on separate branches at the same time. They were merged together in commit f5717b0
.
Finally, 8329384
was committed straight onto master.
We can use git show
to look at individual commits.
You'll already know that HEAD
points to the tip of the current branch:
$ git show --oneline HEAD
8329384 Seventh commit
Putting the caret symbol (^) next to a commit means the parent of that commit. So the following will show the parent of HEAD
:
$ git show --oneline HEAD^
f5717b0 Merge branch 'my_branch'
...
HEAD^
is shorthand for saying HEAD^1
, which literally means show me parent 1 of that commit. You can also say HEAD^2
but in this instance it won't make any sense:
$ git show --oneline HEAD^2
fatal: ambiguous argument 'HEAD^2': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions
Because HEAD
only has 1 parent.
But f5717b0
, the point where the two branches were merged, has two parents, one on master and one on the branch:
$ git show --oneline f5717b0^1
a8fe411 Sixth commit
...
$ git show --oneline f5717b0^2
956c87d Fourth commit on a branch
...
The tilde symbol (~) works in a similar way. In fact HEAD~
will reference the same commit as HEAD^
:
Again, HEAD~
is shorthand for HEAD~1
, but here this means the first ancestor of HEAD
– HEAD~2
is not the second parent of HEAD
but the grandparent of HEAD
:
$ git show --oneline HEAD~1
f5717b0 Merge branch 'my_branch'
...
$ git show --oneline HEAD~2
a8fe411 Sixth commit
...
$ git show --oneline HEAD~3
c7c2590 Third commit on a branch
As you can see, 956c87d Fourth commit on a branch
is not visible when using the tilde operator. This is because the tilde operator always presumes you want to view the first parent's parent.
To access the second parent's parent the tilde and caret symbols can be combined:
$ git show --oneline HEAD~1^1
a8fe411 Sixth commit
...
$ git show --oneline HEAD~1^2
956c87d Fourth commit on a branch
...
In this way you should be able to reference any commit in your repository's history.
作者:Chuck Lu GitHub |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2017-07-02 Create the Project
2015-07-02 C#中的AssemblyInfo 程序集信息
2015-07-02 Application.CommonAppDataPath的路径
2015-07-02 Factorial