Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically printing git revision and checking for uncommitted changes

Tags:

git

To ensure that my scientific analysis is reproducible, I'd like to programmatically check if there are any modifications to the code base that aren't checked in, and if not, print out what commit is being used.

For example, if there are uncommitted changes, it should output

Warning: uncommitted changes made. This output may not be reproducible.

Else, produce

Current commit: d27ec73cf2f1df89cbccd41494f579e066bad6fe

Ideally, it should use "plumbing", not "porcelain".

like image 346
Andrew Grimm Avatar asked Apr 29 '10 01:04

Andrew Grimm


People also ask

How do I see git modifications?

Find what file changed in a commit To find out which files changed in a given commit, use the git log --raw command. It's the fastest and simplest way to get insight into which files a commit affects.

Which of the following command show you any uncommitted changes in your local repo?

The "status" commmand helps you understand the current state of your local Working Copy. It will display any modifications in your local files that you haven't committed to the repository, yet.


2 Answers

The bits of Git plumbing you need are diff-index, rev-parse --verify and maybe rev-parse --show-cdup with ls-files --others.

The following shell program uses those Git plumbing commands, has adjustable untracked/ignored handling, and is fairly careful about all the possible error cases.

#!/bin/sh

# warn-unclean: print a warning if the working tree and index are not clean

#  For utmost strictness, set check_untracked=yes and check_ignored=yes.
#  When both are 'yes', verify that working tree and index are identical to HEAD.
#  When only check_untracked is yes, extra ignored files are allowed.
#  When neither is yes, extra untracked files and ignored files are allowed.

check_untracked=yes
check_ignored=yes

warn() {
    echo 'Warning: '"$*" \
        'This output may not be reproducible.'
}

# Compare HEAD to index and/or working tree versions of tracked files
git diff-index --quiet HEAD
case $? in
    0)
        if test "$check_untracked" != yes; then
            clean=yes
        else
            # Still need to check for untracked files

            or_ignored=''
            exclude=--exclude-standard
            if test "$check_ignored" = yes; then
                or_ignored=' or ignored'
                exclude=''
            fi

            (
                # Move to top level of working tree
                if up="$(git rev-parse --show-cdup)"; then
                    test -n "$up" && cd "$up"
                else
                    echo 'error running "git rev-parse --show-cdup"'
                    exit 129
                fi

                # Check for untracked files
                git ls-files --others $exclude --error-unmatch . >/dev/null 2>&1
                case $? in
                    0)  # some untracked/ignored file is present
                        warn 'some untracked'"$or_ignored"' file is present.'
                        exit 1
                    ;;
                    1)  # no untracked files
                        exit 0
                    ;;
                    *)
                        echo 'error running "git diff-index"!'
                        exit 129
                    ;;
                esac

            )
            case $? in
                0) clean=yes ;;
                1) clean=no ;;
                *) exit $? ;;
            esac
        fi

        test "$clean" = yes &&
        if c="$(git rev-parse --verify HEAD)"; then
            echo 'Current commit: '"$c"
        else
            echo 'error running "git rev-parse --verify"!'
        fi
    ;;
    1)
        warn 'some tracked file has an uncommitted change.'
    ;;
    *)
        echo 'error running "git diff-index"!'
        exit 129
    ;;
esac

You might sprinkle in some more exits if you want its exit code to be meaningful in all cases.

If you do not care for all the error handling or the untracked/ignored handling, then something short might suffice:

if git diff-index --quiet; then
    printf 'Current commit: %s\n' "$(git rev-parse --verify HEAD)
else
    echo 'Warning: …'
fi

You can also check for untracked files (which could be tweaked for ignored etc) in a terse way, without error handling:

git ls-files --others --exclude-standard --error-unmatch \
    "./$(git rev-parse --show-cdup)" >/dev/null 2>&1
like image 104
Chris Johnsen Avatar answered Nov 15 '22 08:11

Chris Johnsen


This uses porcelain, but git diff --exit-code exits with 1 if there are differences to existing files, and 0 if there are no differences to existing files. It doesn't check for untracked files, unfortunately.

This answer to How to retrieve the hash for the current commit in Git? advocates git rev-parse --verify HEAD to print the current commit.

like image 41
Andrew Grimm Avatar answered Nov 15 '22 09:11

Andrew Grimm