How to know if there is a git rebase in progress?
Asked Answered
V

8

82

When I start a git rebase -i, I can issue commands like git rebase --continue, or git rebase --abort. Those commands only work if a rebase is in progress.

How can I know if there is a rebase in progress?

(I would greatly appreciate some details on how rebase works internally; what does git do to a repo that gives it the "rebase in progress" status,?)

Vagina answered 13/10, 2010 at 6:58 Comment(0)
A
53

Update 2021:

As I mentioned in "git stash is slow on windows", with Git for Windows 2.19 (Sept. 2018), git stash (and git rebase) are no longer script-only, but actually a binary compiled with git.exe.

Tim's answer illustrates how it is still difficult to ascertain if a rebase is in progress.

That was discussed in the mailing list, leading to patch like "status: rebase and merge can be in progress at the same time":

Since git rebase -r was introduced, that is possible.
But our machinery did not think that possible, and failed to say anything about the rebase in progress when in the middle of a merge.

There was a case of "rebase in progress" detection before that (2016), with "worktree.c: check whether branch is rebased in another worktree"

This function find_shared_symref() is used in a couple places:

  1. in builtin/branch.c: it's used to detect if a branch is checked out elsewhere and refuse to delete the branch.
  2. in builtin/notes.c: it's used to detect if a note is being merged in another worktree
  3. in branch.c, the function die_if_checked_out() is actually used by "git checkout" and "git worktree add" to see if a branch is already checked out elsewhere and refuse the operation.

In cases 1 and 3, if a rebase is ongoing "HEAD" will be in detached mode.
find_shared_symref() fails to detect it and declares "no branch is checked out here", which is not really what we want.


Original answer: 2010

For one thing, there is a ORIG_HEAD in place during a rebase (but that is not limited to the rebase command)

But you can also look at the 2010 Git 1.7.0 git-rebase.sh script itself (which is as "internal" as you can get ;) ).
Lines like those can give you another clue:

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

sabgenton comments:

  • The folder rebase-apply seems to appear with rebase,
  • but a folder rebase-merge shows up only with with rebase -i.

And hippy also comments, in 2017, that:

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 suggests in the comments:

(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.

That is because the git rev-parse --git-path <path>: does resolve "$GIT_DIR/<path>".

And Elizandro - SparcBR adds in the comments:

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+ (Q3 2015) will print more information during a rebase:

See commit 592e412, commit 84e6fb9 (06 Jul 2015), commit 84e6fb9 (06 Jul 2015), and commit df25e94, commit 05eb563 (30 Jun 2015) by Guillaume Pagès (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 178d2c7, 03 Aug 2015)

status: give more information during rebase -i

git status gives more information during rebase -i, about the list of commands that are done during the rebase.
It displays:

  • the last two commands executed and
  • the next two lines to be executed.

It also gives hints to find the whole files in .git directory.


Trying and detect the prompt won't work with Git 2.26+, as shown in commit 6d04ce7

"git rebase" has learned to use the merge backend (i.e. the machinery that drives "rebase -i") by default, while allowing "--apply" option to use the "apply" backend (e.g. the moral equivalent of "format-patch piped to am").
(The rebase.backend configuration variable can be set to customize.)

See 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), and commit a9ae8fd, commit 22a69fd (16 Jan 2020) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster -- in commit 8c22bd9, 02 Mar 2020)

git-prompt: change the prompt for interactive-based rebases

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".


Since Git 2.17 (March 2018), you also have:

git rebase --show-current-patch

It shows the content of .git/REBASE_HEAD during an interactive rebase which can be paused during conflict.

Axseed answered 13/10, 2010 at 8:29 Comment(19)
shouldn't git-status tell you this?Sexology
As of git version 1.7.3.1, git status doesn't say anything about the rebase status.Vagina
However, EasyGit’s eg status does tell you.Decide
Interpreting the git-rebase.sh code in this answer, Git knows there is a rebase in progress if, inside the .git folder at the root of the repo, either of the directories rebase-merge or rebase-apply exist.Decide
@RoryO'Kane that sounds about right, and +1 on your answer with EasyGit.Axseed
Do you really need the dotest variable ?Bib
@Bib probably not, it was just how the script was initially written.Axseed
thanks, I was just checking if I was missing something, as I intend to reuse this elsewhere...Bib
The master link for git-rebase.sh now does not have the quoted code. VonC, please use this link which is tag: v1.7.0-rc1. The coding guidelines discourage the usage of -o (see github.com/git/git/blob/…) so the correct way now is (test -d ".git/rebase-merge" || test -d ".git/rebase-apply") || die "No rebase in progress?".Evangelize
@Evangelize Thank you. I have updated this 7 years-old question accordingly, adding a link to the exact commit which made that change.Axseed
In Git 2.7 and maybe earlier, you can use something like (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.Dispersal
@Dispersal Thank you, good point. I have included your comment in the answer for more visibility.Axseed
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"Tergiversate
@Elizandro-SparcBR Interesting, thank you. I have included your comment in the answer for more visibility.Axseed
How about .git/REBASE_HEAD ? It contains a hash. Could that also be reliable? It's similar to MERGE_HEAD, in the case of a git merge.Tergiversate
@Elizandro-SparcBR It is a marker, to indicate at what commit the rebase is at in case of conflict. I would therefore use git rebase --show-current-patch (git-scm.com/docs/git-rebase#Documentation/…)Axseed
I don't understand this answer. Is the 2021 update providing some new command or just adding additional information about git internals? Is (test -d "$(git rev-parse --git-path rebase-merge)" || \ test -d "$(git rev-parse --git-path rebase-apply)" ) the recommended way?Gregale
test -d ... was the old answer. The 2021 update is to point out the answer is not as easy as using git rev-parse output. Tim's answer illustrates that.Axseed
--show-current-patch Show the current patch in an interactive rebase or when rebase is stopped because of conflicts. Not "interactive rebase which can be paused" - this is a significant under-information.Stopover
G
24

You can also check how such detection is done in __git_ps1 function in contrib/completion/git-prompt.sh, which can be used for git-aware bash prompt:

                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
Garica answered 13/10, 2010 at 10:12 Comment(0)
L
9

There are some bad answers here. git doesn't really have a specification for how it should work so the only answer is "how does git do it?". The code is here:

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;
}

It basically checks if these few files/directories exist (note !stat() means "does the file exist"). am is git am which is for applying patches from a mailbox which I doubt anyone except the Linux developers use.

  • 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

I guess if you want to know if any kind of rebase/am is happening just check if .git/rebase-apply or .git/rebase-merge exist.

Lustrate answered 24/4, 2021 at 16:26 Comment(2)
How should this be modified if .git is a file with a path to the actual git folder?Gregale
If you're in a worktree and .git is a file then you need to parse the file (e.g. it might contain gitdir: /path/to/repo/.git/worktrees/worktreename) and then check for /path/to/repo/.git/worktrees/worktreename/rebase-apply etc.Lustrate
R
4

If there’s an interactive rebase in progress, this will tell you where you are in the process:

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

Right now I’m editing the “ktio” patch in an interactive rebase.

If there’s no rebase going on, it will look like this:

$ cat .git/rebase-merge/done 
cat: .git/rebase-merge/done: No such file or directory
$ 
Rendon answered 8/8, 2012 at 13:32 Comment(0)
R
4

From a bash command line:

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

That will return exit code 0 (success) if there is a rebase folder, and it will output the rebase folder to STDOUT. If you are not in the middle of a rebase, then it will output nothing and return non-0 exit code. So you could even do something like this:

ls `git rev-parse --git-dir` | grep rebase || echo no rebase
Roee answered 24/4, 2014 at 18:45 Comment(0)
C
2

If you have EasyGit, eg status will tell you:

$ 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.)

In a colored terminal, the notification is very prominent:

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

(eg help topic middle-of-rebase displays the documentation “How to resolve or abort an incomplete rebase”.)

Cordovan answered 23/8, 2012 at 18:48 Comment(0)
A
0

I have not seen it stated clearly, so here it is:

during rebasing process, if there is one under way, git status is now sufficient, as it gives information (for reference, I head smaple branches named master and 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")

This is shown before resolving conflicts, after resolving conflicts it shows:

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.
Axinomancy answered 19/8, 2020 at 4:35 Comment(2)
True, but not applicable for a script: parsing/grepping the git status output would not be a good practice, as commented in #3921909Axseed
Good one. Just add --porcelain or --porcelain=v2 to make it more suitable for automated scripts.Raynor
I
-2

I am using this command is_rebase=$(git status | grep "rebasing" | wc -l)

Invertase answered 23/5, 2018 at 16:1 Comment(1)
This is broken: if you have a dirty file that contains 'rebasing', it will print that you are rebasing even though you aren't.Welladvised

© 2022 - 2024 — McMap. All rights reserved.