How do I programmatically determine if there are uncommited changes?

In a Makefile, I’d like to perform certain actions if there are uncommited changes (either in the working tree or the index). What’s the cleanest and most efficient way to do that? A command that exits with a return value of zero in one case and non-zero in the other would suit my purposes.

I can run git status and pipe the output through grep, but I feel like there must be a better way.

  • Git (windows); P4merge as mergetool error
  • Git - Cherry picking with ours/theirs strategy
  • git -Lost everything before comitting, is there hope for recovery
  • Git move commits to different branch, and make master same as upstream master branch
  • Find committer of a force push on github
  • Using private Composer VCS Git repo
  • How to push my changes back to the source code in git
  • How do I reverse a specific hunk of a commit in git?
  • Using SVN commands alongside git-svn: Possible? Advisable?
  • git how to find commit hash where branch originated from
  • Git Push to Teamcity CI
  • Git merge all but one file, and that file be a (full) conflicted file
  • 7 Solutions collect form web for “How do I programmatically determine if there are uncommited changes?”

    UPDATE: the OP Daniel Stutzbach points out in the comments that this simple command git diff-index worked for him:

    git diff-index --quiet HEAD --
    

    You can then see “How to check if a command succeeded?” if you are using it in a bash script:

    git diff-index --quiet HEAD -- || echo "untracked"; // do something about it
    

    Note: as commented by Anthony Sottile

    git diff-index HEAD ... will fail on a branch which has no commits (such as a newly initialized repository).
    One workaround I’ve found is git diff-index $(git write-tree) ...


    “Programmatically” means never ever rely on porcelain commands.
    Always rely on plumbing commands.

    See also “Checking for a dirty index or untracked files with Git” for alternatives (like git status --porcelain)

    You can take inspiration from the new “require_clean_work_tree function” which is written as we speak 😉 (early October 2010)

    require_clean_work_tree () {
        # Update the index
        git update-index -q --ignore-submodules --refresh
        err=0
    
        # Disallow unstaged changes in the working tree
        if ! git diff-files --quiet --ignore-submodules --
        then
            echo >&2 "cannot $1: you have unstaged changes."
            git diff-files --name-status -r --ignore-submodules -- >&2
            err=1
        fi
    
        # Disallow uncommitted changes in the index
        if ! git diff-index --cached --quiet HEAD --ignore-submodules --
        then
            echo >&2 "cannot $1: your index contains uncommitted changes."
            git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2
            err=1
        fi
    
        if [ $err = 1 ]
        then
            echo >&2 "Please commit or stash them."
            exit 1
        fi
    }
    

    While the other solutions are very thorough, if you want something really quick and dirty, try something like this:

    [[ -z $(git status -s) ]]
    

    It just checks if there is any output in the status summary.

    git diff --exit-code will return nonzero if there are any changes; git diff --quiet is the same with no output. Since you want to check for the working tree and the index, use

    git diff --quiet && git diff --cached --quiet
    

    Or

    git diff --quiet HEAD
    

    Either one will tell you if there are uncommitted changes that are staged or not.

    As pointed in other answer, as simple as such command is sufficient:

    git diff-index --quiet HEAD --
    

    If you omit the last two dashes, the command would fail if you have a file named HEAD.

    Example:

    #!/bin/bash
    set -e
    echo -n "Checking if there are uncommited changes... "
    trap 'echo -e "\033[0;31mFAILED\033[0m"' ERR
    git diff-index --quiet HEAD --
    trap - ERR
    echo -e "\033[0;32mAll set!\033[0m"
    
    # continue as planned...
    

    Word of caution: this command ignores untracked files.

    Expanding on @Nepthar’s answer:

    if [[ -z $(git status -s) ]]
    then
      echo "tree is clean"
    else
      echo "tree is dirty, please commit changes before running this"
      exit
    fi
    

    With Python and GitPython:

    git.Repo(path).is_dirty(untracked_files=True)
    

    Returns True if repository is not clean

    Here is the best, cleanest way.

    function git_dirty {
        text=$(git status)
        changed_text="Changes to be committed"
        untracked_files="Untracked files"
    
        dirty=false
    
        if [[ ${text} = *"$changed_text"* ]];then
            dirty=true
        fi
    
        if [[ ${text} = *"$untracked_files"* ]];then
            dirty=true
        fi
    
        echo $dirty
    }
    
    Git Baby is a git and github fan, let's start git clone.