sanmai
sanmai

Reputation: 30891

Track branch changes from a Makefile

For the purposes of Makefile, how do I find out that HEAD of the current branch has changed?

I'm looking for something like this, but for a generic current branch:

all: report.txt

report.txt: .git/refs/heads/master
    touch report.txt

Upvotes: 3

Views: 919

Answers (3)

Austin Shin
Austin Shin

Reputation: 11

One of enhancement to @ndec suggested, which do not care of "detached HEAD".

Insert this before the target

subdir := ./                                    # can be ./src in different location 
subdep := $(subdir)/.git/HEAD                   # may have SHA-1 (detached HEAD) 
gitref := $(word 2, $(shell cat $(subdep)))     # may be a ref HEAD (for any branch/tag) 
ifneq "$(gitref)" ""                            # append it if referenced HEAD
    subdep += $(subdir)/.git/$(gitref)          # e.g. HEAD & refs/heads/master 
endif 

Then you can add $(subdep) to the target dependency, e.g.

report.txt: $(subdep)
    @touch $@

Then the target will be built if branch or commit changes.

Upvotes: 1

Etan Reisner
Etan Reisner

Reputation: 80931

SHELL:=/bin/bash

all: report.txt

report.txt: up-to-date
        @echo 'Updating $@'
        @touch report.txt

up-to-date: force
        @cmp -s '$@' <(git rev-parse @{0}) || git rev-parse @{0} > '$@'

force: ;

The up-to-date target compares the contents of the up-to-date file against the current revision of the HEAD ref (@{0} is the 0-th previous reflog entry for the current ref).

When that comparison indicates a difference it puts the new revision into the file, thus updating it and triggering make to rebuild report.txt which depends on it. When the comparison indicates the files are the same the file does not get updated and make sees no reason to rebuild report.txt.

The force target forces make to always consider up-to-date as needing to be built. You might have thought to use .PHONY: up-to-date instead of force but the semantics of phony targets when used as prereqs would make this not work as intended (the rule for report.txt would always be run).

Upvotes: 2

ndec
ndec

Reputation: 156

.git/HEAD gives the ref of the current branch, so you can derefence .git/HEAD, to get the actual current branch ref.

all: report.txt

current := $(shell cut -c6- .git/HEAD)

report.txt: .git/${current}
        touch report.txt

note that if you switch branch, you will detect a change even if the new branch is on the same commit as the previous branch.

Upvotes: 3

Related Questions