gitstatestatus

How to ask git if the repository is in a conflict stage?


There are a lot of ways to see, as a human, whether the repository has conflicts that need to be resolved or not.

However, I am looking for a way to check this in a script. That is, to check whether the repository is at a good shape to start doing something to it, or it is at a stage where the user has to fix the conflicts.

I can think of a way such as the following:

__git_ps1 "%s" | grep MERGING > /dev/null 2>&1 && echo "In merge state"

However, I suspect this is not a recommended method. First because __git_ps1 starts with __ and as a C programmer I tend to think it's not for my use, and second that I'm guessing there is a more proper way like:

git repo-status --is-merging

which would have the return value, or something like that.

So, how do I ask git (as a script) if the repository is at a merging state?


Solution

  • Using git status or similar will be slow on a large repository, as it needs to check the entire working copy's status, as well as the index. We're only interested in the index, so we can use much quicker commands that will just check the index state.

    Specifically, we can use git ls-files --unmerged. That command will produce no output if there are no files in a conflicted state, and something like the below if there are:

    $ git ls-files --unmerged
    100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 1       filename
    100644 4a58007052a65fbc2fc3f910f2855f45a4058e74 2       filename
    100644 65b2df87f7df3aeedef04be96703e55ac19c2cfb 3       filename
    

    So we can just check if that file produces any output: [[ -z $(git ls-files --unmerged) ]]. That command will give a return code of zero if the repository is clean, and non-zero if the repository has conflicts. Replace -z with -n for the inverse behaviour.

    You could add the following to your ~/.gitconfig:

    [alias]
        conflicts = ![[ -n $(git ls-files --unmerged) ]]
        list-conflicts = "!cd ${GIT_PREFIX:-.}; git ls-files --unmerged | cut -f2 | sort -u"
    

    This will give behaviour like the following:

    $ git st
    # On branch master
    nothing to commit (working directory clean)
    
    $ git conflicts && echo 'Conflicts exist' || echo 'No conflicts'
    No conflicts
    
    $ git merge other-branch
    Auto-merging file
    CONFLICT (content): Merge conflict in file
    Automatic merge failed; fix conflicts and then commit the result.
    
    $ git conflicts && echo 'Conflicts exist' || echo 'No conflicts'
    Conflicts exist
    
    $ git list-conflicts
    file
    

    (The cd ${GIT_PREFIX:-.} part of the second alias means you only get a list of the conflicting files in the current directory, not for the entire repository.)