【问题标题】:How do I run git rebase --interactive in non-interactive manner?如何以非交互方式运行 git rebase --interactive?
【发布时间】:2012-09-05 19:50:54
【问题描述】:

是否可以进行以下操作?

  1. 使git rebase --interactive 仅将标准样板输出到文件,而不是输出到文件并在编辑器中打开它。
  2. 让用户编辑文件。
  3. 让用户以编辑后的文件名重新运行git rebase
  4. 继续通常的变基过程。

用例:当然是脚本化变基。例如,请参阅how to re-order commits in Git non-interactively

【问题讨论】:

标签: git scripting git-rebase non-interactive


【解决方案1】:

经过一些思考和研究,答案被证明是微不足道的:git rebase -i 从著名的 EDITOR/VISUAL 环境变量中获取编辑器名称,因此覆盖它以指向非交互式脚本就可以了。

但是,EDITOR/VISUAL 对提交列表、改写时的提交消息和其他任何内容都无动于衷。所以,从 http://git.kernel.org/?p=git/git.git;a=commit;h=821881d88d3012a64a52ece9a8c2571ca00c35cd 开始,有一个特殊的环境变量 GIT_SEQUENCE_EDITOR 只适用于提交列表。

因此,重新排序或展平提交的方法是:

运行:GIT_SEQUENCE_EDITOR=<script> git rebase -i <params>。 您的 <script> 应该接受一个参数:包含标准变基提交列表的文件的路径。它应该就地重写它并退出。之后发生通常的变基处理。

【讨论】:

  • 或者,不要为此目的创建脚本,而只需使用现有的命令true,它会忽略任何参数并具有固定的返回码0
  • 这是另一个修复最后五个提交消息中的错字的示例:EDITOR="sed -i -e 's/borken/broken/g'" GIT_SEQUENCE_EDITOR="sed -i -e 's/pick/reword/g'" git rebase -i HEAD~5
  • 由于某些未知原因,EDITOR 现在被 git --version 2.5.5 忽略。另一方面,VISUAL 仍然有效。所以这是另一个重新生成最后 5 个 Change-Id 的示例。这假设安装了 Gerrit 提交挂钩。 VISUAL="sed -i -e '/^[[:blank:]]*Change-Id/ d'" GIT_SEQUENCE_EDITOR="sed -i -e 's/pick/reword/g'" git rebase -i HEAD~5 。使用 git 版本 2.5.5 测试成功
  • 我发现VISUALautomated git rebase 的尝试中也没有工作,但GIT_EDITOR 工作。
【解决方案2】:

添加到@pfalcon 的答案,您可以使用 sed 作为您的 GIT_SEQUENCE_EDITOR。例如,我想编辑每个提交,所以我这样做了:

GIT_SEQUENCE_EDITOR="sed -i -re 's/^pick /e /'" git rebase -i

【讨论】:

    【解决方案3】:

    变量GIT_SEQUENCE_EDITOR 最初用于更改编辑器。可以将脚本传递给该变量以以非交互方式使用git rebase -i。所以可以使用:

    GIT_SEQUENCE_EDITOR="sed -i -re 's/^pick 134567/e 1234567/'" git rebase -i 1234567^
    

    此命令将在git rebase -i 提供的文件上运行sed。它会将pick 134567 行更改为e 1234567(因此,编辑提交1234567)。您可以将e 更改为r(返工)、f(修复)、s(壁球)或d(删除)(旧版本的git 不支持后者)。

    在此基础上,我写了一个脚本来自动化这个任务:

    #!/bin/bash
    
    ACTION=$1
    COMMIT=$(git rev-parse --short $2)
    [[ "$COMMIT" ]] || exit 1
    CORRECT=
    for A in p pick r reword e edit s squash f fixup d drop t split; do
         [[ $ACTION == $A ]] && CORRECT=1
    done 
    [[ "$CORRECT" ]] || exit 1
    git merge-base --is-ancestor $COMMIT HEAD || exit 1
    if [[ $ACTION == "drop" || $ACTION == "d" ]]; then
        GIT_SEQUENCE_EDITOR="sed -i -e '/^pick $COMMIT/d'" git rebase -i $COMMIT^^
    elif [[ $ACTION == "split" || $ACTION == "t" ]]; then
        GIT_SEQUENCE_EDITOR="sed -i -e 's/^pick $COMMIT/edit $COMMIT/'" git rebase -i $COMMIT^^ || exit 1
        git reset --soft HEAD^
        echo "Hints:"
        echo "  Select files to be commited using 'git reset', 'git add' or 'git add -p'"
        echo "  Commit using 'git commit -c $COMMIT'"
        echo "  Finish with 'git rebase --continue'"
    else
        GIT_SEQUENCE_EDITOR="sed -i -e 's/^pick $COMMIT/$1 $COMMIT/'" git rebase -i $COMMIT^^
    fi
    

    第一个参数应该是一个动作。该脚本使用与 git-rebase 相同的操作名称。它还添加了“拆分”操作(并允许在旧版本的 git 中使用 drop)。

    它还会检查您请求的提交是否是 HEAD 的祖先。这是rebase -i 的常见错误(而且非常烦人)。

    第二个参数是要编辑/删除/拆分/改写的提交。

    然后你为你的 .gitconfig 添加一个别名:

    [alias]
      autorebase = ! path_to_your_script
    

    【讨论】:

    • 很好的答案,谢谢!您能否添加 cmets 来解释一下每个步骤的作用?
    【解决方案4】:

    扩展 pfalcon 的答案:

    运行GIT_SEQUENCE_EDITOR=<script> git rebase -i <params><script> 应该接受单个参数 - 包含标准变基提交列表的文件路径。脚本应该就地重写它并退出。之后发生通常的变基处理。

    如果你有一个包含你想要的内容的环境变量:

    GIT_SEQUENCE_EDITOR='echo "$REBASE_DATA" >' git rebase -i [<additional params>]
    

    分类文件也可以:

    GIT_SEQUENCE_EDITOR='cat rebase_data_file >' git rebase -i [<additional params>]
    

    【讨论】:

      【解决方案5】:

      您可以使用touch 作为编辑器,该编辑器将触摸文件,使其显示为已修改。例如

      GIT_SEQUENCE_EDITOR=touch git rebase -i [commit]
      

      给它取别名,给定 baseline 作为我想要重新定位的标签

      git config alias.baseline '!GIT_SEQUENCE_EDITOR=touch git rebase -i baseline'
      

      别名在 Windows 下工作,因为它正在执行的 shell 是 bash 而不是 cmd

      【讨论】:

      • 这适用于git --interactive --exec &lt;cmd&gt; &lt;branch&gt;。我将&lt;cmd&gt; 设置为运行由我的分支引入或修改的测试的命令,并将&lt;branch&gt; 设置为master。这会导致 git 针对分支中的每个提交运行我的测试。
      • 你可以通过使用-c sequence.editor=touch而不是GIT_SEQUENCE_EDITOR来使用git的原生aliases。例如,在您的 .gitconfig [alias] 部分中:rs = -c sequence.editor=touch rebase --interactive --autosquash --autostash
      【解决方案6】:

      交互模式会调出可使用的集合编辑器。
      可以通过以下方式检索正在使用的编辑器:

      git config --get core.editor
      

      因此,如果您设置 非交互式 编辑器 - 即接受标准输入命令的编辑器,您可以在 非交互式 中使用 --interactive方式:)
      我确定vim 接受命令,标准编辑器 ed 当然也接受命令。

      所以,拿着交互式编辑器(如果需要)

      $ ied="$(git config --get core.editor)"
      

      设置非交互式编辑器

      $ git config --unset-all core.editor
      $ git config --add core.editor ed
      

      并使用它..

      $ printf '%s\n' "some-ed-cmd" "another-ed-cmd" "wq" | git rebase -i HEAD~5
      

      并恢复编辑器(如果需要)

      $ git config --unset-all core.editor
      $ git config --add core.editor "$ied"
      

      【讨论】:

      • 谢谢,我们可能是在同一时间开始写答案的,在发布我的答案之前我没有看到你的答案;-)
      • 我认为在每个会话或每个命令的基础上重新定义 EDITOR 会更简单。
      • 我强烈建议不要做git config --unset-all 或任何可以在脚本中修改用户配置文件的事情。要为一个命令设置一个 git config 变量,请使用git -c var=val,在这种情况下设置EDITOR 要简单得多。它是一个环境变量,所以只适用于当前进程,它不会干扰其他进程或向磁盘写入任何内容。
      • 我发现设置EDITOR 不再起作用,我需要改用GIT_EDITOR
      【解决方案7】:

      我找到了解决方案。您可以使用:

      $ GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash $COMMIT_HASH~1
      

      【讨论】:

        【解决方案8】:

        正如其他人所提到的,您需要提供一个自定义 GIT_SEQUENCE_EDITOR 值,该值将修改交互式 rebase 文件。如果你只想对单个提交执行一个操作,你可以这样做:

        # Runs "edit" on HEAD~3
        GIT_SEQUENCE_EDITOR="sed -i -ze 's/^pick/edit/'" git rebase -i HEAD~3
        

        或者,这里有一个概括这一点的函数:

        # Usage: git-rebase-custom edit HEAD~3
        git-rebase-custom() {
            local action=$1
            shift
        
            GIT_SEQUENCE_EDITOR="sed -i -ze 's/^pick/$action/'" git rebase -i "$@"
        }
        

        【讨论】:

        • 应该引用 $1 和 $@
        • 在变量赋值中引用无关紧要,但我确实删除了对variables 的赋值,因为除非使用数组赋值,否则它只会获取第一个额外参数。
        【解决方案9】:

        要完全按照原始问题的要求进行操作,请使用 sed -i '1s/^/b\n/' 作为您的编辑器

        git -c sequence.editor="sed -i '1s/^/b\n/'" rebase --interactive
        

        说明

        • git -c 指定使用指定设置运行以下 git 命令
        • sequence.editor 确定将编辑 redbase-todo 文件的“编辑器”的设置
        • sed -i 就地运行 sed 命令
          • 第一行1s
          • ^匹配开头
          • b\n 插入 b 和换行符 \n 字符。 bbreak 是用于停止交互式变基的变基命令。
        • rebase --interactive运行变基命令

        这会立即停止交互式变基。 现在您可以编辑.git/rebase-merge/git-rebase-todo 并运行git rebase --continue

        【讨论】:

          【解决方案10】:

          基于Jezz's answer, 我制作了一个与 shell 无关的脚本 (GitReb) 它适用于多参数修订, :/&lt;text&gt; 语法、root 提交以及一些完整性检查。

          我还简化了它并删除了t/split 操作 和delete->drop 转换 哪些 IMO 不在此脚本的范围内。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-06-25
            • 1970-01-01
            • 2019-11-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-01-08
            • 1970-01-01
            相关资源
            最近更新 更多