当我执行git rebase -i
命令后,我可以通过git rebase --continue
或者git rebase --abort
来执行相应的操作,但是这些命令只有在rebase正在进行时才有效。
如何判断是否有一个rebase正在进行?
(我非常希望能够了解rebase内部工作的详细信息;git对存储库做了什么以使其具有“正在进行rebase”的状态?)
当我执行git rebase -i
命令后,我可以通过git rebase --continue
或者git rebase --abort
来执行相应的操作,但是这些命令只有在rebase正在进行时才有效。
如何判断是否有一个rebase正在进行?
(我非常希望能够了解rebase内部工作的详细信息;git对存储库做了什么以使其具有“正在进行rebase”的状态?)
2021年更新:
如我在“git stash
is slow on windows”中提到的,从Git for Windows 2.19(2018年9月)开始,git stash
(和git rebase
)不再是脚本,而是使用git.exe
编译的二进制文件。
Tim的answer说明了如何确定重定基正在进行仍然很困难。
这在邮件列表中得到了讨论,并导致像“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()
函数在以下几个地方被使用:
- 在
builtin/branch.c
中:用于检测分支是否在其他地方被检出,并拒绝删除该分支。- 在
builtin/notes.c
中:用于检测笔记是否正在另一个工作树中合并。- 在
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?"
rebase-apply
似乎只在使用rebase
时出现,rebase-merge
仅在使用rebase -i
时出现。The coding guidelines discourage the usage of
-o
(seeDocumentation/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?"
(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 592e412,commit 84e6fb9(2015年7月6日),commit 84e6fb9(2015年7月6日)和commit df25e94,commit 05eb563(2015年6月30日),由Guillaume Pagès(gitster
)。
(由Junio C Hamano -- gitster
--合并于commit 178d2c7,2015年8月3日)
状态
:在rebase -i
期间提供更多信息git status
在rebase -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
toREBASE-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 theam-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
的内容,可以在冲突期间暂停。
你还可以查看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
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()
意味着“文件是否存在”)。am
是git 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.git
是一个文件,则需要解析该文件(例如,它可能包含gitdir:/path/to/repo/.git/worktrees/worktreename
),然后检查/path/to/repo/.git/worktrees/worktreename/rebase-apply
等。 - Timmmm$ 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
$
从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
eg 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.)
(eg help topic middle-of-rebase
显示文档“如何解决或中止未完成的变基”。)
我还没有看到清晰的表述,所以在这里说明一下:
在 rebase 过程中,如果有一个正在进行中,那么 git status
现在已经足够了,因为它会提供信息(作为参考,我使用的示例分支名为 master
和 rbBr
):
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 status
的输出将不是一个好的做法,正如在https://dev59.com/iW865IYBdhLWcg3wOb9h#B7mkEYcBWogLw_1bccG9中所评论的那样。 - VonC--porcelain
或--porcelain=v2
,使其更适合自动化脚本。 - Ted我正在使用这个命令 is_rebase=$(git status | grep "rebasing" | wc -l)
eg status
命令确实会告诉你其状态信息(详情参见:https://dev59.com/iW865IYBdhLWcg3wOb9h#12098177)。 - Rory O'Kanegit-rebase.sh
代码,Git 可以知道是否存在正在进行的 rebase,如果在存储库根目录下的.git
文件夹内,存在rebase-merge
或rebase-apply
目录,则表示存在 rebase。 - Rory O'Kane(test -d "$(git rev-parse --git-path rebase-merge)" || test -d "$(git rev-parse --git-path rebase-apply)"
的东西。这样可以正确处理工作树和不具有.git目录的非常规或非标准布局,并且还允许您从工作目录的子目录运行此测试。 - Jelaby