David Gomes
David Gomes

Reputation: 5825

Makefile target to check for clean git diff

I am trying to write a Makefile target that checks for no uncomitted changes in the git repository where it is ran after running another target.

This is what I have so far:

check-git-clean: other-target
ifneq ($(shell git diff-index --quiet HEAD; echo $$?), 0)
    $(error "There are uncomitted changes after running make other-target")
endif

However, what I am experiencing is that if the other-target causes uncommitted changes, the ifneq will not catch it. On the other hand, if there were already uncommitted changes before I run make check-git-clean, then the ifneq does catch it.

So, in a way, it's almost as if the ifneq is running "before" the make other-target but the CLI output (echo) I get are in the right order.

I'm wondering how I can do this right.

Upvotes: 1

Views: 2247

Answers (3)

Johan Boulé
Johan Boulé

Reputation: 2090

If you want the condition to be executed when the rule is executed rather than when the makefile is parsed, you need to use the if function.

# This function tests whether both arguments are equals
equals = $(and $(findstring $1,$2),$(findstring $2,$1))

check-git-clean: other-target
    $(if $(call equals,0,$(shell git diff-index --quiet HEAD; echo $$?)),, \
        $(error There are uncomitted changes after running make $?) \
    )

However, you may prefer to use a more natural approach to error out:

check-git-clean: other-target
    git diff-index --quiet HEAD

Upvotes: 3

jthill
jthill

Reputation: 60295

In libexec/git-core there's a git-sh-setup set of common utility routines for git commands and hooks, including require_clean_worktree. The meat of that is

git update-index -q --ignore-submodules --refresh
git diff-files --quiet --ignore-submodules
git diff-index --cached --quiet --ignore-submodules HEAD --

where the index refresh is a safety play to deal with the chance you've just finished restoring your worktree from a backup or something, diff-files compares indexed content against worktree content and diff-index compares arbitrary repo content against indexed (in this case, because of --cached) content. The return codes on those last two commands are what you're after.

Upvotes: 1

phd
phd

Reputation: 94502

May I recommend to use git diff --exit-code directly?

.PHONY: check-git-clean
check-git-clean: other-target
    git diff --quiet

or

.PHONY: check-git-clean
check-git-clean: other-target
    git diff-index --quiet HEAD

Upvotes: 6

Related Questions