如何在git中的提交之间前进和后退?


105

我正在做一个,git bisect并且在到达有问题的提交之后,我现在正在尝试向前/向后前进一步,以确保我处于正确的位置。

我知道HEAD^历史会倒退,但是还有另一个捷径可以使我前进(将来走向特定的提交),例如:

A - B - C(HEAD) - D - E - F

我知道,我的目标是˚F,我想摆脱Çd


注意:这不是Git的副本:如何在各次提交之间来回移动,我的问题略有不同,此处未回答



git checkout -b new_branch HEAD~4返回HEAD的4次提交,如stackoverflow.com/a/4940090/911945
Anton Tarasenko '17

Answers:


57

我做了一些实验,这似乎可以实现向前导航的技巧(编辑:仅当您具有没有合并提交的线性历史记录时,它才能很好地工作):

git checkout $(git rev-list --topo-order HEAD..towards | tail -1)

towards提交或标记的SHA1 在哪里。

说明:

  • 内部命令的$()含义是:获取当前HEADtowards提交之间的所有提交(不包括HEAD),并按优先顺序对它们进行排序(如git log默认设置-而不是按时间顺序排列,这是奇怪的默认设置rev-list),然后取最后一个(tail),即我们要转到的那个。
  • 它将在子shell中进行评估,并传递git checkout给执行结帐。

您可以在.profile文件中定义一个可作为参数期望别名的函数,以向前导航至特定提交:

# Go forward in Git commit hierarchy, towards particular commit 
# Usage:
#  gofwd v1.2.7
# Does nothing when the parameter is not specified.
gofwd() {
  git checkout $(git rev-list --topo-order HEAD.."$*" | tail -1)
}

# Go back in Git commit hierarchy
# Usage: 
#  goback
alias goback='git checkout HEAD~'

2
前进在历史的各个部分都可以正常工作,但是在遇到合并时会陷入循环。
Kostas 2013年

是的,实际上我还没有在合并中对其进行测试。我会尽量利用业余时间,但是暂时没有什么动力,因为我们已经同意在项目中拥有严格的线性历史;)
jakub.g 2013年

2
好答案!修改为自动指定当前分支:stackoverflow.com/a/23172256/480608
Raine Revere 2014年

这是不正确的。git log默认情况下,按时间顺序显示提交,与相同rev-list,但使用--graph标志时除外。
papiro

令人信服的证据表明git太复杂了。对于通常像“撤消”或“重做”之类的简单操作,这里我们列出了一系列相互矛盾的答案。而且,我什至没有研究任何链接的答案。FWIW,我尝试了一个简单的线性提交集,并最终放弃了。
Snowcrash

49

您需要清除的所有信息(而不是分离的磁头状态)是重置而不是检出。

git reset HEAD@{1}

5
git reset "HEAD@{1}"在某些外壳中,例如fish和powershell .. git reflog也可能有助于找到正确的提交。
史蒂夫·库克

1
除非您明确希望外壳程序尝试解释/扩展内容,否则请在外壳程序命令中始终使用单引号。在这样的情况下,这尤其重要,在这种情况下,目标是防止shell解释特殊字符。这样,您无需知道字符串是否包含任何有问题的内容。
克里斯·佩奇

我这样做是为了时光倒流,然后我又git reset HEAD回到了原来的位置。。。现在我不知道我的存储库处于什么状态,而且一切都很恐怖。我现在应该怎么办?
theonlygusti

47

我相信你可以做到:

git reset HEAD@{1}

要及时作出承诺。要进行多次提交,请使用HEAD @ {2},HEAD @ {3}等。


20

这就是我用来来回导航的内容。

移至下一个提交

function n() {
    git log --reverse --pretty=%H master | grep -A 1 $(git rev-parse HEAD) | tail -n1 | xargs git checkout
}

移至上一个提交

function p() {
    git checkout HEAD^1
}

谢谢!我现在正在用这个!其他像我这样的初学者的注意事项:重新附加HEAD,git checkout <current branch>附加到最新提交。git checkout -b <new-branch-name>从当前提交允许更改新分支。git rebase -i也可以。另外,我将n()函数命名为nx()避免与节点版本管理器“ n”冲突。确保检查别名!
史蒂文·崔

function(){...}用于编写Unix / Linux bash脚本文件,我来自Windows,首先让我很难理解
IcyBrk

9

说F是最新的提交trunk(在此处插入您自己的分支名称)...您可以将其称为trunk~0(或只是trunk),将E称为trunk~1,将D称为trunk~2等。

在您的reflog中查看更多命名提交的方法。


1
〜往回走,不要向前走,树干〜2是A
EmmanuelMess

是。该答案假定您有一个称为trunk的分支,指向F,并且您知道该分支在历史中要移至的位置。它不是在尝试相对于HEAD前进,而是相对于躯干较远的后退。
没用的

@EmmanuelMess trunk~2A 怎么样?
theonlygusti

@theonlygusti您从HEAD移了两次。
EmmanuelMess

您仍然假设分支trunk和您的当前HEAD相同,但问题并未显示,我说的不是我所假设的,而且不太可能是中途bisect
无用的

3

向后移动是微不足道的,因为您正在向下移动树,而且总是有一种方法

  function git_down
        git checkout HEAD^
  end

向前遍历时,您将向上移动树,因此需要明确要针对的分支:

  function git_up 
        git log --reverse --pretty=%H $argv | grep -A 1 (git rev-parse HEAD) | tail -n1 | xargs git checkout
  end

用途:git downgit up <branch-name>


当涉及合并时,后退也不是完全唯一的。虽然HEAD^通常是一个合理的默认值。
kdb

2

如果您想向前看,可以执行此技巧,因为Git对此没有严格的命令。

git log --reverse COMMIT_HASH..

日志历史记录哈希列表:

A
B
C -> put this
D

使用命令git log --reverse C..,在输出你会看到一个


1

可能不是最好的方法,但是您可以使用它git log来查看提交列表,然后使用git checkout [sha1 of D]来移动到D。


6
我不明白,如果他在C,然后git的日志将只显示他的C,B和A
Bilthon

好的,知道了,但是您必须像VonC
Bilthon 2012年

1

我只是对此进行了测试。例如说您在master分支中,然后执行以下操作:

git checkout HEAD@{3}

这样head就会分离,然后您可以再次尝试进行其他提交:

git checkout HEAD@{4}

环顾四周后,只需签出该分支即可回到原始状态。在我的示例中:master分支

git checkout master

如果您不想进入原始状态,并希望保留其中一个提交作为头并从那里继续,那么您需要从那里分支出去。例如,在“ git checkout HEAD @ {4}”之后,您可以发出

git checkout -b MyNewBranch



0
branchName=master; commitInOrder=1; git checkout $(git log --pretty=%H "${branchName}" | tac | head -n "${commitInOrder}" | tail -n 1)

哪里:

branchName 等于分支名称

commitInOrder 等于从选定分支中的第一个提交开始按顺序进行的提交(因此1是分支中的第一个提交,2是分支中的第二个提交,依此类推)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.