如何在git rebase期间引用当前编辑的提交的原始文件?

Fab*_*ler -3 git git-rebase

我希望获得有关当前编辑的提交的原始信息,git rebase -i但HEAD引用了不同的提交哈希.我怎样才能引用原始提交?

例:

$ git rebase -i upstream
Run Code Online (Sandbox Code Playgroud)

(为提交选择"编辑")

[detached HEAD befa32f] Previous commit message
 1 file changed, 121 insertions(+), 1 deletion(-)
 rewrite README.md (100%)
Stopped at 9a1e25391e5a53965c80dc69e1285dba7c59f893... Current commit message
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue
Run Code Online (Sandbox Code Playgroud)

现在我想引用,9a1e25391e5a53965c80dc69e1285dba7c59f893但HEAD有不同的哈希和不同的属性,虽然它似乎是相同的提交:

$ cat .git/HEAD
1414539371fe6b122d5f326bc7b344eea761dc50
Run Code Online (Sandbox Code Playgroud)

这是从哪里来的,我如何引用原始提交?

tor*_*rek 5

对于它的价值,根据定义,HEAD始终是"当前提交" - 也许更准确地说"当前提交是HEAD它所说的".

在大多数"正常"时间,HEAD包含对分支名称的引用:cat .git/HEAD例如,如果您(或在文件查看器或编辑器中打开它),您将看到ref: refs/heads/master,或者ref: refs/heads/develop,取决于您所在的分支.在这种情况下,您在命名分支上,当前提交是该分支的提示.1

另一方面,如果您使用git checkout --detach或提供git checkout原始提交SHA-1,git会使您进入"分离的HEAD"模式.虽然这听起来像18世纪法国大革命的一个场景,但它只是HEAD指直接指原始SHA-1.在这种情况下,SHA-1是当前提交.

当你运行git rebase -i并让它停止提交时(通过设置处置edit),rebase HEAD将使你处于"分离的HEAD"模式,当前的commit-aka -being你现在可以编辑的提交.此时,您可以对树进行一些更改并执行git add以下操作:例如:您对树所做的更改,然后add现在位于暂存区域中.如果您接下来要做的是git commit --amend,git会创建一个新的提交,其父级与当前提交的父级相同:

       old   <-- HEAD before `git commit --amend`
      /
...--o
      \
       new   <-- HEAD after `git commit --amend`
Run Code Online (Sandbox Code Playgroud)

需要注意的是后git commit --amend,HEAD仍然是"当前的承诺"(顾名思义),它只是不再提交你要改变(old上图).

目前没有一种正确的方法来引用old名称的SHA-1 ,但是有几种方法可以找到它:git log --graph --decorate --oneline HEAD ORIG_HEAD例如,将显示两者的提交HEAD(你现在,提交时new)和ORIG_HEAD(它记录了您第一次启动rebase时的位置:这不一定是提交,old但它将old在其历史记录中提交).

例如,当rebase -i HEAD~2我在一个新的文件中添加了一个新文件并将其提交时git commit --amend,导致这样:

$ git log --graph --decorate --oneline HEAD ORIG_HEAD
* 9daa414 (HEAD) mod1, amended
| * bd49ea7 (master) mod2
| * f071da2 mod1
|/  
* 28c4ee8 initial
Run Code Online (Sandbox Code Playgroud)

或者你可以依赖于git内部(随着时间的推移而改变,所以不能保证这对你有用):

$ ls .git/rebase-merge
amend                   git-rebase-todo.backup  onto
author-script           head-name               orig-head
done                    interactive             patch
end                     message                 quiet
git-rebase-todo         msgnum                  stopped-sha
Run Code Online (Sandbox Code Playgroud)

这里,rebase-merge/stopped-sha在我停止编辑的时候,提交的SHA-1是当前的,所以:

$ git rev-parse rebase-merge/stopped-sha
f071da26a90f14945d89ccdeed3c278e9b499a2e
Run Code Online (Sandbox Code Playgroud)

正如Joseph K. Strauss在下面的评论中指出的那样,最简单的方法old就是使用git的reflogs.既然我们刚刚创建了commit new并且已经移动了HEAD,那么旧提交old的SHA-1就是简单的HEAD@{1}.当然,如果你做多次提交(例如,几个--amend在试着让它恰到好处),2 old可能下HEAD{2},HEAD@{3}或更高.

注意,此时,当我这样做时git rebase --continue,git所做的是将剩余的项目(rebase-merge/git-rebase-todo在上面的ls输出中)应用于当前HEAD.如果一切顺利,最后一件事rebase就是将当时的当前分支(在rebase-merge/head-name这种情况下包含refs/heads/master)重新指向它刚刚提交的最尖端提交,然后恢复间接引用状态HEAD,以便我'我现在在分支的新提示master:

$ git rebase --continue
Successfully rebased and updated refs/heads/master.
Run Code Online (Sandbox Code Playgroud)

1或者,作为特殊情况,如果HEAD包含对分支的引用但分支尚不存在,则说您处于"未出生的分支".在这种情况下,没有当前的提交,但是当你进行新的提交时,它将是新的,现在出生的分支的初始提交.通常人们只在以后在新存储库中创建第一个提交时才会看到这一点git init.但是,在git版本1.7.2及更高版本中,使用git checkout --orphan <branchname>创建一个新的未出现的分支,以便您可以将新历史记录与现有存储库中的现有历史记录无关.

2我不能代表别人,但我做这一切的时候.:-)