如何知道是否正在进行git rebase操作?

81

当我执行git rebase -i命令后,我可以通过git rebase --continue或者git rebase --abort来执行相应的操作,但是这些命令只有在rebase正在进行时才有效。

如何判断是否有一个rebase正在进行?

(我非常希望能够了解rebase内部工作的详细信息;git对存储库做了什么以使其具有“正在进行rebase”的状态?)

8个回答

52

2021年更新:

如我在“git stash is slow on windows”中提到的,从Git for Windows 2.19(2018年9月)开始,git stash(和git rebase)不再是脚本,而是使用git.exe编译的二进制文件。

Timanswer说明了如何确定重定基正在进行仍然很困难。

这在邮件列表中得到了讨论,并导致像“status: rebase and merge can be in progress at the same time”这样的补丁:

自从引入git rebase -r以来,这是可能的。
但我们的机器无法考虑到这一点,并在合并过程中未能说明正在进行的重定基。

早在2016年,就有一个关于“正在进行rebase”的检测案例,使用了 "worktree.c: check whether branch is rebased in another worktree"。

find_shared_symref() 函数在以下几个地方被使用:

  1. builtin/branch.c 中:用于检测分支是否在其他地方被检出,并拒绝删除该分支。
  2. builtin/notes.c 中:用于检测笔记是否正在另一个工作树中合并。
  3. branch.c 中,函数 die_if_checked_out() 实际上被 "git checkout" 和 "git worktree add" 使用,以查看分支是否已经在其他地方被检出,并拒绝操作。

在情况1和3中,如果正在进行rebase,则"HEAD"将处于分离模式
find_shared_symref() 无法检测到它并声明 "no branch is checked out here",这不是我们想要的结果。


原始答案:2010

首先,在重新设置基础时会有一个ORIG_HEAD(但不仅限于重新设置基础命令)

但你也可以查看2010年Git 1.7.0的git-rebase.sh脚本本身(这是尽可能“内部”的方式;)。
像这样的行可以给你另一个线索:

dotest="$GIT_DIR"/rebase-merge
test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || die "No rebase in progress?"

sabgenton comments

  • 文件夹rebase-apply似乎只在使用rebase时出现,
  • 但是文件夹rebase-merge仅在使用rebase -i时出现。

hippy也在2017年comments

The coding guidelines discourage the usage of -o (see Documentation/CodingGuidelines), so the correct way now (2017, but also since 2011, Git 1.7.6) is:

(test -d ".git/rebase-merge" || test -d ".git/rebase-apply") || die "No rebase in progress?"

Jelaby建议在评论中

(test -d "$(git rev-parse --git-path rebase-merge)" || \
 test -d "$(git rev-parse --git-path rebase-apply)" )

This correctly handles worktrees and unusual or non-standard layouts that don't have a .git directory, and also allows you to run this test from a subdir of the working directory.

这是因为 git rev-parse --git-path <path> 命令会解析 "$GIT_DIR/<path>"。

Elizandro - SparcBR 在评论中补充道:在注释中

Could also redirect the error to null:

(test -d "$(git rev-parse --git-path rebase-merge)" || test -d "$(git rev-parse --git-path rebase-apply) 2>/dev/null"

Git 2.6+(2015年第三季度)将在rebase期间输出更多信息:

查看commit 592e412commit 84e6fb9(2015年7月6日),commit 84e6fb9(2015年7月6日)和commit df25e94commit 05eb563(2015年6月30日),由Guillaume Pagès(gitster
(由Junio C Hamano -- gitster --合并于commit 178d2c7,2015年8月3日)

状态:在rebase -i期间提供更多信息

git statusrebase -i期间提供更多信息,有关正在进行的rebase期间执行的命令列表。

它显示:
  • 已执行的最后两个命令和
  • 即将执行的下两行。

它还提示如何在.git目录中找到整个文件。


尝试检测提示符无法在Git 2.26+中使用,如提交6d04ce7所示。

"git rebase"已经默认学会使用合并后端(即驱动"rebase -i"的机制),同时允许"--apply"选项使用应用后端(例如道德等价于"format-patch piped to am")。 (可以设置rebase.backend配置变量进行自定义。)

查看commit 10cdb9f, commit 2ac0d62, commit 8295ed6, commit 76340c8, commit 980b482, commit c2417d3, commit 6d04ce7, commit 52eb738, commit 8af14f0, commit be50c93, commit befb89c, commit 9a70f3d, commit 93122c9, commit 55d2b6d, commit 8a997ed, commit 7db00f0, commit e98c426, commit d48e5e2 (15 Feb 2020),以及commit a9ae8fd, commit 22a69fd (16 Jan 2020)由Elijah Newren (newren)提交。
(由Junio C Hamano -- gitster --合并于commit 8c22bd9, 02 Mar 2020)

git-prompt: 更改交互式rebase的提示符

In the past, we had different prompts for different types of rebases:

REBASE: for am-based rebases
REBASE-m: for merge-based rebases
REBASE-i: for interactive-based rebases

It's not clear why this distinction was necessary or helpful; when the prompt was added in commit e752019 ("Improve bash prompt to detect various states like an unfinished merge", 2007-09-30, Git v1.5.5-rc0), it simply added these three different types.
Perhaps there was a useful purpose back then, but there have been some changes:

  • The merge backend was deleted after being implemented on top of the interactive backend, causing the prompt for merge-based rebases to change from REBASE-m to REBASE-i.
  • The interactive backend is used for multiple different types of non-interactive rebases, so the "-i" part of the prompt doesn't really mean what it used to.
  • Rebase backends have gained more abilities and have a great deal of overlap, sometimes making it hard to distinguish them.
  • Behavioral differences between the backends have also been ironed out.
  • We want to change the default backend from am to interactive, which means people would get "REBASE-i" by default if we didn't change the prompt, and only if they specified --am or --whitespace or -C would they get the "REBASE" prompt.
  • In the future, we plan to have "--whitespace", "-C", and even "--am" run the interactive backend once it can handle everything the am-backend can.

For all these reasons, make the prompt for any type of rebase just be "REBASE".


自 Git 2.17(2018年3月)起,您还可以:

git rebase --show-current-patch

在交互式变基期间,它显示.git/REBASE_HEAD的内容,可以在冲突期间暂停。


6
Git 状态命令难道不能告诉你这个吗? - cmcginty
5
从git版本1.7.3.1开始,git状态不会显示有关变基状态的任何信息。 - Olivier Verdier
4
然而,EasyGiteg status 命令确实会告诉你其状态信息(详情参见:https://dev59.com/iW865IYBdhLWcg3wOb9h#12098177)。 - Rory O'Kane
2
通过解释此答案中的 git-rebase.sh 代码,Git 可以知道是否存在正在进行的 rebase,如果在存储库根目录下的 .git 文件夹内,存在 rebase-mergerebase-apply 目录,则表示存在 rebase。 - Rory O'Kane
3
在Git 2.7及更早版本中,您可以使用类似于(test -d "$(git rev-parse --git-path rebase-merge)" || test -d "$(git rev-parse --git-path rebase-apply)"的东西。这样可以正确处理工作树和不具有.git目录的非常规或非标准布局,并且还允许您从工作目录的子目录运行此测试。 - Jelaby
显示剩余13条评论

24

你还可以查看contrib/completion/git-prompt.sh中的__git_ps1函数来了解如何进行这样的检测,该函数可用于支持Git的bash提示符:

                if [ -f "$g/rebase-merge/interactive" ]; then
                        r="|REBASE-i"
                        b="$(cat "$g/rebase-merge/head-name")"
                elif [ -d "$g/rebase-merge" ]; then
                        r="|REBASE-m"
                        b="$(cat "$g/rebase-merge/head-name")"
                else
                        if [ -d "$g/rebase-apply" ]; then
                                if [ -f "$g/rebase-apply/rebasing" ]; then
                                        r="|REBASE"
                                elif [ -f "$g/rebase-apply/applying" ]; then
                                        r="|AM"
                                else
                                        r="|AM/REBASE"
                                fi
                        fi
                fi

9
这里有一些错误的回答。git 实际上没有说明它应该如何工作,所以唯一的答案是“git 如何实现它?”。相应的代码在这里
int wt_status_check_rebase(const struct worktree *wt,
               struct wt_status_state *state)
{
    struct stat st;

    if (!stat(worktree_git_path(wt, "rebase-apply"), &st)) {
        if (!stat(worktree_git_path(wt, "rebase-apply/applying"), &st)) {
            state->am_in_progress = 1;
            if (!stat(worktree_git_path(wt, "rebase-apply/patch"), &st) && !st.st_size)
                state->am_empty_patch = 1;
        } else {
            state->rebase_in_progress = 1;
            state->branch = get_branch(wt, "rebase-apply/head-name");
            state->onto = get_branch(wt, "rebase-apply/onto");
        }
    } else if (!stat(worktree_git_path(wt, "rebase-merge"), &st)) {
        if (!stat(worktree_git_path(wt, "rebase-merge/interactive"), &st))
            state->rebase_interactive_in_progress = 1;
        else
            state->rebase_in_progress = 1;
        state->branch = get_branch(wt, "rebase-merge/head-name");
        state->onto = get_branch(wt, "rebase-merge/onto");
    } else
        return 0;
    return 1;
}

这基本上是检查这些几个文件/目录是否存在(请注意,!stat()意味着“文件是否存在”)。amgit am,适用于从邮箱中应用补丁,我怀疑除了Linux开发人员以外,没有其他人会使用它。

  • rebase_in_progress.git/rebase-apply && !.git/rebase-apply/applying || .git/rebase-merge && !.git/rebase-merge/interactive
  • interactive_rebase_in_progress.git/rebase-merge && .git/rebase-merge/interactive
  • am_in_progress.git/rebase-apply && .git/rebase-apply/applying

我想如果你想知道任何类型的rebase/am是否正在进行中,只需检查.git/rebase-apply.git/rebase-merge是否存在即可。


如果.git是一个包含实际git文件夹路径的文件,应该如何修改? - Moberg
1
如果您在工作树中,而.git是一个文件,则需要解析该文件(例如,它可能包含gitdir:/path/to/repo/.git/worktrees/worktreename),然后检查/path/to/repo/.git/worktrees/worktreename/rebase-apply等。 - Timmmm

4
如果正在进行交互式变基,这将告诉您进程的位置:
$ cat .git/rebase-merge/done 
pick 786139e lrg
edit 668b8a6 ktio
$ 

我现在正在交互式地重新编辑“ktio”补丁。

如果没有正在进行的重新编辑,它会看起来像这样:

$ cat .git/rebase-merge/done 
cat: .git/rebase-merge/done: No such file or directory
$ 

4

从bash命令行:

ls `git rev-parse --git-dir` | grep rebase

如果存在rebase文件夹,它将返回退出码0(成功),并将rebase文件夹输出到STDOUT。如果您处于rebase的过程中,则不会输出任何内容并返回非0退出码。因此,您甚至可以执行以下操作:

ls `git rev-parse --git-dir` | grep rebase || echo no rebase

2
如果你有EasyGiteg status会告诉你:
$ eg status
(Not currently on any branch.)
(YOU ARE IN THE MIDDLE OF A INTERACTIVE REBASE; RUN 'eg help topic middle-of-rebase' FOR MORE INFO.)
Changes ready to be committed ("staged"):
    modified:   .gitmodules
    renamed:    config_loader.rb -> code/config_loader.rb
Newly created unknown files:
    vendor/
(YOU ARE IN THE MIDDLE OF A INTERACTIVE REBASE; RUN 'eg help topic middle-of-rebase' FOR MORE INFO.)

在彩色终端中,通知非常显眼:

<code>eg status</code> middle-of-rebase demonstration screenshot

"

(eg help topic middle-of-rebase 显示文档“如何解决或中止未完成的变基”。)

"
(注:该句为程序代码和注释,意为运行指令“eg help topic middle-of-rebase”会显示关于如何解决或中止未完成变基的文档。其中link1为一个链接,具体内容需要上下文来确定)

0

我还没有看到清晰的表述,所以在这里说明一下:

在 rebase 过程中,如果有一个正在进行中,那么 git status 现在已经足够了,因为它会提供信息(作为参考,我使用的示例分支名为 masterrbBr):

interactive rebase in progress; onto 5f8e534
Last command done (1 command done):
   pick 1b7a450 BRANCH: another comment
No commands remaining.
You are currently rebasing branch 'rbBr' on '5f8e534'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
        both modified:   User.java

no changes added to commit (use "git add" and/or "git commit -a")

在解决冲突之前显示,解决冲突后它会显示:

interactive rebase in progress; onto 5f8e534
Last command done (1 command done):
   pick 1b7a450 BRANCH: another comment
No commands remaining.
You are currently rebasing branch 'rbBr' on '5f8e534'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   User.java

PS C:\my_git_repos\learning_git> git rebase --continue                                                                                                                                                                                       [detached HEAD 9645135] BRANCH: another comment
 1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/rbBr.

真实,但不适用于脚本:解析/grepping git status的输出将不是一个好的做法,正如在https://dev59.com/iW865IYBdhLWcg3wOb9h#B7mkEYcBWogLw_1bccG9中所评论的那样。 - VonC
好的。只需要添加--porcelain--porcelain=v2,使其更适合自动化脚本。 - Ted

-2

我正在使用这个命令 is_rebase=$(git status | grep "rebasing" | wc -l)


5
有一个问题:如果你有一个脏文件,其中包含“重新定位(rebasing)”一词,它会打印出你正在重新定位,尽管你并没有这样做。 - CLOVIS

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