将git rebase -i HEAD~7命令应用于编辑器时,只显示“noop”。

14
我正在尝试将一个位于HEAD的提交压缩到几个之前的提交中。然而,当我运行“git rebase -i HEAD~7”时,在编辑器中只显示一个“noop”!我完全不明白这应该如何工作。
我正在一个分支(“cleanup”)中工作,我是在第一次“rebase”经历后意外删除了所有这些提交后创建的(使用“checkout -b cleanup ...”在“reflog”中找到的SHA1)。重点是,我不确定该分支的父级是什么(如果这很重要的话)。
我只是想做我已经多次阅读过的事情:我想稍微修改一些已提交的代码,但这不是最近的提交。无论这是否适用于“压缩”应用程序,或者仅在到达该点时进行修补,我都不知道。
在运行上述rebase命令后,当编辑器启动时,我还在STDOUT上看到了这个:
$ git rebase -i HEAD~7
usage: git rev-list [OPTION] <commit-id>... [ -- paths... ]
  limiting output:
    --max-count=<n>
    ...

除了使用HEAD〜7引用之外,我尝试过指定完整的SHA1和不同的refspecs到本地和远程分支。对于所有内容都得到相同的结果... 我错过了什么吗?感谢您的帮助!
$ git log --oneline HEAD~7..HEAD
d0fd20e temp Fix resume_cities table
ea2ffdf Fix db/seeds.rb to reflect recent database structure modifications
dbd2b8b Add several models/scaffolds that go along with the Geonames tables
9759091 Fix name of the ResumeSkill model file.
3fc3134 Added the SHA1 for the previous commit to the comments on the migration, to help link back to that.
bacbeb2 Consolidate database migrations! READ ME!
0c49a57 Moved back to gem versions of linkedin, omniauth, and twitter

我想修改的是提交记录 bacbeb2,使用 d0fd20e 进行修改。


根据 @MarkLongair 的建议,我在 /usr/lib/git-core/git-rebase--interactive 中添加了 set -x,并看到了以下奇怪的输出:

$ git rebase -i HEAD~7

[... output muted for brevity, see the full output, here: http://gist.github.com/1163118]
+ read -r shortsha1 rest
+ sed -n s/^>//p
+ git rev-list --no-merges --cherry-pick --pretty=oneline --abbrev-commit --abbrev=7 --reverse --left-right --topo-order 2c51946812a198ca908ebcad2308e4b8274624b3...d0e9ff6d9c1f8bc374856ca2a84ad52d6013b5bf
usage: git rev-list [OPTION] <commit-id>... [ -- paths... ]
  limiting output:
    --max-count=<n>
    --max-age=<epoch>
    --min-age=<epoch>
    --sparse
    --no-merges
    --remove-empty
    --all
    --branches
    --tags
    --remotes
    --stdin
    --quiet
  ordering output:
    --topo-order
    --date-order
    --reverse
  formatting output:
    --parents
    --children
    --objects | --objects-edge
    --unpacked
    --header | --pretty
    --abbrev=<n> | --no-abbrev
    --abbrev-commit
    --left-right
  special purpose:
    --bisect
    --bisect-vars
    --bisect-all
+ test t = 
+ test -s /home/ryan/Projects/social-jobs/.git/rebase-merge/git-rebase-todo
+ echo noop
[...]

我说“奇怪的输出”,因为如果我直接从命令行运行rev-list命令,它就会按预期工作。
$ git rev-list --no-merges --cherry-pick --pretty=oneline --abbrev-commit --abbrev=7 --reverse --left-right --topo-order 2c51946812a198ca908ebcad2308e4b8274624b3...d0e9ff6d9c1f8bc374856ca2a84ad52d6013b5bf
>0c49a57 Moved back to gem versions of linkedin, omniauth, and twitter
>bacbeb2 Consolidate database migrations! READ ME!
>3fc3134 Added the SHA1 for the previous commit to the comments on the migration, to help link back to that.
>9759091 Fix name of the ResumeSkill model file.
>dbd2b8b Add several models/scaffolds that go along with the Geonames tables
>ea2ffdf Fix db/seeds.rb to reflect recent database structure modifications
>d0e9ff6 !temp Fix resume_cities table !temp

4
你使用的是哪个版本的git? git log HEAD~7..HEAD 的输出是什么?(后一个命令用于生成要考虑进行变基的提交列表 - 你看到的行为可能是因为该列表由于某种原因为空 - 可能是一个错误或者关于你的代码库的某些非常奇怪的事情。) - Mark Longair
2
我在使用Git 1.7.4.1(来自Ubuntu仓库)时遇到了这种情况。 - Ryan Long
1
我不确定您是否看到了,@mark-longair,但我已编辑了问题,并附上了git log HEAD~7..HEAD的输出。Git似乎能够很好地组装那个列表。在这里,我完全被卡住了。要克隆我的存储库重新开始还是不需要这种类型的解决方案? - Ryan Long
我想这值得一试,但你指出的行为足够令人困惑,我很有兴趣弄清楚它的根本原因!我已经添加了一个答案,并提供了一些诊断问题的建议。 - Mark Longair
2个回答

12

更新: 在我的答案末尾有关于这种行为的解释,但是我已经留下了调试建议,以防对任何人有用。


我不确定我是否有一个真正的答案,但我会尽力说明正在发生什么。 当以git rebase -i HEAD~7调用时,如果.git/rebase-merge/git-rebase-todo文件为空或不存在,则Git应仅向该文件输出noop。 我们知道这不是权限问题,因为该文件(包含"noop"和注释行)已成功创建。从终端上看到git rev-list的错误也表明问题实际上是由于如何调用git rev-list导致的。 在git v1.7.4.1中,使用您引用的命令行应从以下位置找到要包含的提交列表:

git rev-list --no-merges --cherry-pick --pretty=oneline --abbrev-commit \
    --abbrev=7 --reverse --left-right --topo-order HEAD~7...HEAD

请注意,这与手册中建议的用法(git log <upstream>..HEAD)稍有不同,因为该范围使用 ... 而不是 ..

我猜测,由于你看到了来自 git rev-list 的错误,这可能是问题所在的命令。你可以尝试运行它并查看输出结果。如果似乎正常工作,则我怀疑存在一个早期错误导致此命令行出现格式错误。由于交互式变基是以 shell 脚本实现的,您可以通过在脚本开头添加 set -x 来轻松调查,类似于:

#!/bin/sh
set -x
#
# Copyright (c) 2006 Johannes E. Schindelin

# SHORT DESCRIPTION
[...]

如果你尝试运行 git rebase -i HEAD~7,你应该会看到脚本运行的每个命令,可能会看到 git rev-list 调用中的问题所在。

希望这能对你有所帮助。


更新:事实证明 这里的问题是提问者把 IFS 设置为只包括制表符和换行符,而不是默认的空格、制表符和换行符。

这导致了在 git-rebase--interactive 中一行的问题。

git rev-list $MERGES_OPTION --pretty=oneline [...]

由于MERGES_OPTION设置为--no-merges --cherry-pick,因为默认的IFS值(包括空格)在变量替换后将被分成两个参数。 但是,如果使用不包括空格的IFS,则--no-merges --cherry-pick将被解释为单个参数,这是未知的,导致git rev-list使用消息和空输出在脚本中传递。

一个很好的谜题 :)


1
好的提示。我尝试了一下...现在还是很困惑。rev-list命令在直接调用时可以正常工作(请参见上文),但在从rebase调用时打印其用法,这肯定与某个环境变量有关(我的意思是,可能会因为不同的环境而改变,而不是env),而我并不知道这个变量是什么。 - Ryan Long
你能否在问题中添加一下修改后脚本在终端上的输出结果? - Mark Longair
我在另一台机器上尝试了一下,使用的是与我遇到问题的仓库克隆版本相同的git版本。完美地工作了。与我的开发环境相比,这台其他机器有很多不同之处,所以很难说,但它没有安装RVM...我想我会在那里安装它,看看是否会再次破坏git... - Ryan Long
这里似乎不是RVM的问题。我在另一台机器上安装了它,rebase仍然很好用。我甚至尝试将repo目录通过rsync -ra同步到那台机器上(我想也许是git在clone期间修复了问题)...没有任何问题。根据我的推理,我拥有的本地repo完全没问题。我正在重新安装git和我能够暂时移除的所有依赖项。我认为这一定与git安装有关... - Ryan Long
1
越来越好奇了。你不认为在有问题的机器上设置了GIT_环境变量之一吗? - Mark Longair
显示剩余2条评论

7

这个问题是由于我在 .bashrc 中设置的 IFS 导致的:

# remove the space character from IFS
# (http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html#IFS)
IFS="`printf '\n\t'`"

我完全不记得为什么要在那里放这个。我确定它与“修复UNIX/Linux文件名”有关,因为我包含了那个URL。无所谓。

不过,我删除了那个声明并且:突然间问题就解决了!

特别感谢@MarkLongair的帮助!


1
这是否让任何人感觉到存在错误?我的理解是,一般来说,一个 shell 脚本不应该依赖于那种类型的环境变量,除非它已经显式地设置了该变量。 - Ryan Long
2
也许你应该在git邮件列表上询问:git@vger.kernel.org - svick
啊,这就解释了一切 :) 很高兴听到你已经解决了这个问题 - 我已经更新了我的答案,并解释了为什么这个 IFS 设置会破坏脚本。 - Mark Longair

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