如何知道是否有一个正在进行的 git rebase?

当我启动 git rebase -i时,我可以发出诸如 git rebase --continuegit rebase --abort之类的命令。这些命令只有在 rebase 正在进行时才有效。

如何知道是否有正在进行的 rebase?

(关于 rebase 在内部是如何工作的,我非常希望了解一些细节; git 如何处理给予其“ rebase in process”状态的回购?)

35886 次浏览

2021年最新情况:

正如我在“ git stash在窗户上运行缓慢”中提到的,使用 适用于 Windows 2.19的 Git(2018年9月) ,git stash(和 git rebase)不再只是脚本,而实际上是用 git.exe编译的二进制文件。

Tim 的 回答说明了为什么仍然很难确定 rebase 是否在进行中。

邮件列表中讨论了这个问题,导致了像“ ABC0: ABC1和 merge可以同时进行”这样的补丁:

由于引入了 git rebase -r,这是可能的。
但是我们的机器认为这是不可能的,并且在合并过程中没有提到任何关于正在进行的重新基地的事情。

在此之前(2016年)有一个“正在进行中的 rebase”检测案例,其中“ worktree.c: 检查分支是否重新基于另一个工作树

这个函数 find_shared_symref()可以用在以下几个地方:

  1. builtin/branch.c中: 它用于检测某个分支是否在其他地方签出并拒绝删除该分支。
  2. builtin/notes.c中: 它用于检测一个音符是否被合并到另一个工作树中
  3. branch.c中,“ git checkout”和“ git worktree add”实际上使用函数 die_if_checked_out()来查看某个分支是否已在其他地方签出并拒绝操作。

在案例1和案例3中,如果一个基地正在进行“头”将在分离模式
find_shared_symref()未能检测到它并声明“ no branch is checked out here”,这并不是我们真正想要的。


原始答案: 2010年

首先,在 rebase 期间 有一个 ORIG_HEAD就位(但这不限于 rebase 命令)

但是您也可以查看2010 Git 1.7.0 翻译: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对: 奇芳校对:本身(这是最“内部”的;)。
这样的句子可以给你另一条线索:

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

萨根顿 评论:

  • 文件夹 rebase-apply似乎与 rebase一起出现,
  • 但是一个文件夹 rebase-merge显示只与 rebase -i

嬉皮士也是 评论,在2017年:

编码指南不鼓励使用 -o(参见 Documentation/CodingGuidelines) ,因此正确的 现在(2017年,但也自2011年以来,Git 1.7.6)方法是:

(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)" )

这样可以正确地处理工作树以及没有 .git目录的异常或非标准布局,并且允许您从工作目录的子目录中运行这个测试。

这是因为 git rev-parse --git-path <path>: 确实解析了“ $GIT_DIR/<path>”。

Elizandro-SparcBR增加了 在评论中:

也可以将错误重定向为 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年第三季度)将在重建基础期间打印更多信息:

第五季,第412集犯罪现场调查,第八季,第6集(2015年7月6日) ,犯罪现场调查,第八季,第6集(2015年7月6日)和 提交 df25e94第五季,第563集(2015年6月30日)。
(由 朱尼奥 · C · 哈马诺 gitster于2015年8月3日在 犯下178d2c7合并)

rebase -i期间提供更多信息

git statusrebase -i期间提供了更多信息,关于在 rebase 期间执行的命令列表。
它显示:

  • 执行的最后两个命令和
  • 接下来要执行的两行。

它还提供了在 .git目录中查找整个文件的提示。


第六季第四集所示,在 Git 2.26 + 中尝试和检测 提示将无法工作

git rebase”已经学会默认使用合并后端(即驱动“ rebase -i”的机器) ,同时允许“ --apply”选项使用“ apply”后端(例如道德上相当于“ format-patch piped to am”)。
(可以将 rebase.backend配置变量设置为自定义。)

参见 提交10cdb9f犯下2ac0d62提交8295ed6提交76340c8犯下980b482提交 c2417d3第六季第四集第52章第738节犯下8af14f0提交10cdb9f0,提交10cdb9f1,提交10cdb9f2,提交10cdb9f3,提交10cdb9f4,提交10cdb9f5,提交10cdb9f6,提交10cdb9f7,提交10cdb9f8(2020年2月15日)和 犯下2ac0d621的 提交10cdb9f9,犯下2ac0d620(2020年1月16日)。
(由 朱尼奥 · C · 哈马诺 gitster提交8c22bd9合并,2020年3月2日)

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

过去,对于不同类型的 rebase,我们有不同的提示:

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

不清楚为什么这种区分是必要的或有帮助的; 在提交 E752019中添加了提示符(“改进 bash 提示符以检测 各种状态,比如未完成的合并”,2007-09-30,Git v1.5.5-rc0) ,它只是添加了这三种不同的类型。
也许当时还有一个有用的目的,但现在已经有了一些变化:

  • 合并后端在交互式后端之上实现后被删除,导致基于合并的 rebase 提示从 REBASE-m更改为 REBASE-i
  • 交互式后端用于多种不同类型的非交互式 rebase,因此提示符的“ -i”部分并不真正意味着它过去的意思。
  • 基地后端获得了更多的能力,并有大量的重叠,有时很难区分他们。
  • 后端之间的行为差异也已得到消除。
  • 我们希望将默认的后端从 am 改为交互式,这意味着如果我们不改变提示符,人们将在默认情况下获得“ REBASE-i”,只有当他们指定 --am--whitespace-C时,他们才会获得“ REBASE”提示符。
  • 在未来,我们计划有“ --whitespace”,“ -C”,甚至“ --am”运行交互式后端一旦它可以处理一切的 am-backend可以。

出于所有这些原因,将任何类型的 rebase 的提示符设置为“ REBASE”。


自 Git 2.17(2018年3月) 以来,您还拥有:

git rebase --show-current-patch

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

您还可以检查这种检测是如何在 ABC1中的 __git_ps1功能中完成的,ABC1中的 __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

如果有一个正在进行的交互式 rebase,它会告诉你在这个过程中你处于什么位置:

$ cat .git/rebase-merge/done
pick 786139e lrg
edit 668b8a6 ktio
$

现在我正在一个交互式的 rebase 中编辑“ ktio”补丁。

如果没有重新建立基础,它将看起来像这样:

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

如果你有 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显示文档“ 如何解决或中止不完整的重建基础”。)

从 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

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

我没有看到它清楚地说明,所以它是这样的:

在重新定基的过程中,如果有一个正在进行,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.

这里有一些不好的答案。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是否存在。