Git中的HEAD和ORIG_HEAD是什么?

294

这些符号指的是什么,它们代表着什么意义?(我在官方文档中找不到任何解释)


5
注意:HEAD现在(即将推出的git1.8.4)用'@'代替!请参见我下面编辑的答案 - VonC
注意:'@'(用于HEAD)仍在进行中,但不包括1.8.4 [答案已编辑和修正](https://dev59.com/h3NA5IYBdhLWcg3wbNQ4#964927)。 - VonC
2
注意:对于Git 1.8.5/1.9,HEAD的'@'已经回来了。答案再次编辑 - VonC
34
在Git中,HEADORIG_HEAD的作用类似于Bash中的$PWD$OLDPWD。 :) - musiphil
我发现在运行git checkout时,HEAD@不完全相同。此外,我还发现当运行git checkout时,HEADHEAD~0也不完全相同。实际上,@HEAD~0是相同的。以下是屏幕截图:@ vs HEADHEAD vs HEAD~0 - liuliang
4个回答

369

HEAD 是对当前提交的(直接或间接,即符号链接)引用。在工作目录中检查过的提交是您已经检查过的提交(除非您进行了一些更改或等效操作),而且它也是一个新提交的基础,“git commit”将创建一个新的提交。通常情况下,HEAD 是对某个命名分支的符号链接;这个分支是当前检出的分支或当前分支。HEAD 也可以直接指向一个提交,这种状态称为“分离 HEAD”,可以理解为处于未命名的匿名分支上。

自 Git 1.8.5 起,@ 单独使用时是对 HEAD 的快捷方式。

ORIG_HEADHEAD 的前一个状态,由具有可能存在危险行为的命令设置,以便轻松恢复它们。现在 Git 有 reflog,因此它不再那么有用:HEAD@{1} 大致相当于 ORIG_HEADHEAD@{1} 始终是 HEAD 的最后一个值,ORIG_HEAD 是危险操作前 HEAD 的最后一个值)。

更多信息请参见 git(1) 页的手册 / [gitrevisions(7) 页的手册][git-revisions]、Git 用户手册Git 社区手册Git 词汇表


2
嗨Jakub,感谢你的解释。你能详细说明HEAD@{1}中“大致相当”的部分吗?我在我的回答中提到了http://thread.gmane.org/gmane.comp.version-control.git/38379这个帖子(你在2007年2月份参与了其中),但我并没有完全理解你们讨论的@{...}语法。 - VonC
24
ORIG_HEAD 只会在执行“危险”的命令,即移动 HEAD 超过一个提交时设置(我认为)。因此,ORIG_HEAD 并不总是被设置,而 HEAD@{1} 则总是被设置。@{1} 是 $(git symbolic-ref HEAD)@{1},也就是使用当前分支的 reflog,而不是 HEAD 的 reflog。 - Jakub Narębski
2
“HEAD是一个提交,对其进行'git commit'操作将会新建一个提交。”——这点很值得铭记,谢谢!另外引用@VonC的话:“它是'git commit'操作基于其之上的提交,'git diff --cached'和'git status'则与其进行比较。” - Minqi Pan
2
git help revisions可以打开http://git-scm.com/docs/gitrevisions,该网站描述了引用提交的所有方式(包括“HEAD”和“ORIG_HEAD”)。 - dahlbyk
在使用某个版本的命令之前,git show ORIG_HEAD 是一个很好的检查方法。 - Brad Solomon
显示剩余4条评论

127

ORIG_HEAD

git reset

"pull" or "merge" always leaves the original tip of the current branch in ORIG_HEAD.

git reset --hard ORIG_HEAD

Resetting hard to it brings your index file and the working tree back to that state, and resets the tip of the branch to that commit.

git reset --merge ORIG_HEAD

After inspecting the result of the merge, you may find that the change in the other branch is unsatisfactory. Running "git reset --hard ORIG_HEAD" will let you go back to where you were, but it will discard your local changes, which you do not want. "git reset --merge" keeps your local changes.


在应用任何补丁之前,ORIG_HEAD 被设置为当前分支的最新提交。
如果您遇到多个提交的问题,例如在错误的分支上运行 'git am' 或提交中存在更容易通过更改邮箱来修复的错误(例如 "From:" 行中的 + 错误),则此功能非常有用。

此外,合并操作始终将 '.git/ORIG_HEAD' 设置为 HEAD 的原始状态,因此可以通过使用 'git reset ORIG_HEAD' 来删除有问题的合并。

Git 2.40 (2023年第一季度) 的文档更详细地介绍了 ORIG_HEAD

查看 提交 f1c9243, 提交 c6eec9c, 提交 0c514d5, 提交 d03c773, 提交 e29678b (2023年1月10日),由Philippe Blain (phil-blain)提交。
(由Junio C Hamano -- gitster --提交 9c2003a中合并,2023年1月21日)

git-rebase.txt: 添加有关 'ORIG_HEAD' 被覆盖的注释

报告者: Erik Cervin Edin
签署者: Philippe Blain
确认者: Phillip Wood

"ORIG_HEAD"在rebase开始时被写入,但不能保证在rebase结束时仍指向原始分支的末端。
实际上,在rebase期间使用其他写入"ORIG_HEAD"的命令,例如使用"git reset"(man) HEAD^"拆分提交,会导致"ORIG_HEAD"被覆盖。
对某些用户造成困惑
在“描述”部分添加关于此的注释,并提到更可靠的替代方法是使用分支的reflog。"

git rebase现在在其手册页面中包含以下内容:

[注意]:
如果在rebase期间使用了写入该伪引用的其他命令(例如git reset),则不能保证ORIG_HEAD仍然指向先前的分支尖端。
然而,可以使用当前分支的reflog(即@{1})访问以前的分支顶部。

并且:

revisions.txt:明确说明写入“ORIG_HEAD”的命令

Signed-off-by: Philippe Blain
Acked-by: Phillip Wood

当提到 'ORIG_HEAD' 时,要明确哪个命令写了该伪引用,即 'git am'(man)、'git merge'(man)、'git rebase'(man) 和 'git reset'(man)

revisions现在在其手册页面中包含:

ORIG_HEAD是由移动您的HEAD的命令(如git amgit mergegit rebasegit reset)创建的,记录了它们操作之前HEAD的位置,以便您可以轻松地将分支的末端更改回运行它们之前的状态。


HEAD

注意:来自此处

HEAD是一个移动的指针。有时它表示当前分支,有时则不是。因此,在Git中,“HEAD”并非在所有情况下都是“当前分支”的同义词。在Git中,“HEAD”始终意味着“当前”,但这并不一定意味着“当前分支”(即分离的HEAD)。但它几乎总是指向“当前提交”。它是“git commit”所建立的提交,并且“git diff --cached”和“git status”与之进行比较。仅在非常有限的上下文中(即当我们想要在分支名称上操作时——通过提交/变基等重置和增长分支末端)才表示当前分支。Reflog是回到过去的工具,时间机器与“当前”概念有着有趣的交互作用。“HEAD@{5.minutes.ago}”可能意味着“解除引用HEAD symref以找出我们现在所在的分支,然后找出该分支顶部5分钟前的位置”。或者它可能意味着“我会在5分钟前引用为HEAD的提交是什么,例如如果我那时候做了“git show HEAD””。

Git 1.8.4 (2013年7月)引入了引入了一个新的符号!
(实际上,它将在1.8.5中使用,2013年第四季度:通过提交9ba89f4重新引入),由Felipe Contreras

现在你可以说"@"而不是输入四个大写字母"HEAD",例如"git log @"。

请参见提交cdfd948

输入:

输入 'HEAD' 很繁琐,我们可以使用 '@' 代替。

选择 '@' 的原因是它自然地遵循了 ref@op 语法(例如,HEAD@{u}),除了我们没有 ref 和操作,当我们没有这些时,假设 'HEAD' 是有意义的。

所以现在我们可以使用 'git show @~1',享受所有好处。

到目前为止,'@' 是一个有效的名称,但它与这个想法冲突,所以让我们使其无效。可能很少有人使用这个名称。

输出:

输入 'HEAD' 很繁琐,我们可以使用 '@' 代替。

选择 '@' 的原因是它自然地遵循了 ref@op 语法(例如,HEAD@{u}),除了我们没有 ref 和操作,当我们没有这些时,假设 'HEAD' 是有意义的。

所以现在我们可以使用 'git show @~1',享受所有好处。

到目前为止,'@' 是一个有效的名称,但它与这个想法冲突,所以让我们使其无效。可能很少有人使用这个名称。


运行 git reset ORIG_HEAD 和 commit 后,ORIG_HEAD 仍然在 HEAD 旁边的 References 下。为什么它没有从视图中移除? - powder366
@powder366 但是 git reset 会生成一个 ORIG_HEAD,所以你需要手动删除它。例如请参考 https://dev59.com/H2jWa4cB1Zd3GeqPqm8h#12418078。 - VonC
1
@VonC,@别名代表 HEAD 的功能在 Git 1.8.4版本中将被撤销(暂时?)!这是今天刚刚宣布的消息! - user456814
喜欢那个“提醒”的评论! - Robino
@snakecharmerb 是的,正如上面的答案所述,@ 单独使用是 HEAD 的快捷方式,这个功能从 Git 1.8.5 和 commit 9ba89f4 开始支持,时间是 2013 年第三季度。 - VonC
1
@snakecharmerb 好的,你说得对。我已经删除了还原部分,只保留了公告。 - VonC

5

来自man 7 gitrevisions:

HEAD指的是你工作区所基于的提交。FETCH_HEAD记录了你上一次git fetch命令从远程仓库中获取的分支名称。ORIG_HEAD由那些以激进方式移动你的HEAD位置的命令创建,用来记录操作前HEAD的位置,以便你可以轻松地将分支的最新位置改回运行这些命令之前的状态。MERGE_HEAD记录在运行git merge命令时要合并到你的分支中的提交。CHERRY_PICK_HEAD记录在运行git cherry-pick命令时要挑选的提交。


2

我的理解是HEAD指向当前分支,而ORIG_HEAD用于在进行“危险”操作之前存储先前的HEAD。

例如,git-rebase和git-am在应用任何更改之前记录分支的原始顶部。


4
HEAD 不总是指向当前分支(它可能会处于游离状态)。 - VonC
2
当HEAD处于“分离状态”时,“当前分支”是什么? - cjs
@CurtJ.Sampson 这是“无分支”。这就是为什么当您处于分离的 HEAD 时,您需要执行 git branch foo -b 以便为那些孤立的提交“创建”一个分支。 - Royi Namir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接