Yujin Boby
Yujin Boby

Reputation: 313

git pull check if a file changed bash

I run following bash script in cronjob to update my web site

#!/bin/bash

cd /home/username/public_html
git pull origin master

This cronjob is run every 5 minutes, so if i commit changed to git repo, it get pulled to live web site.

What i want to do is, each time this script run, check if a particular file is changed, run a curl/wget command if the file is changed.

The file i need to track for changes are style.css and script.js

What i am doing is, if these file is changed, update revision number of the script in my web site template, so cache is cleared and latest changed css and js file is loaded.

<link href="/css/style.css?REVISION_NUMBER_HERE" rel="stylesheet" type="text/css">

I can increase JS/CSS revision number easily with a curl request as it is stored in mysql DB.

Here is a sample git pull result, so we can grep for that style.css/script.js in the result

 * branch            master     -> FETCH_HEAD
Updating cbd0d46..36aeed6
Fast-forward
 admin/cf.php         |   16 ++++++++++++++++
 css/style.css        |   47 +++++++++++++++++++++++++++--------------------
 include/common.php   |    1 +
 templates/header.tpl |    4 ++--
 templates/index.tpl  |   13 ++++++-------
 5 files changed, 52 insertions(+), 29 deletions(-)

EDIT

Thanks @torek for the reply.

I need some more help with BASH scripting, now here is my test git command.

[root@server70 public_html]# git diff --name-only 8613bd3ed718b27ca680bdf33e0a4b32b0f58b8c HEAD | egrep '.css|.js|.tpl'
css/style.css
templates/header.tpl
templates/index.tpl
templates/user/delete.tpl
[root@server70 public_html]#

I put hard coded git rev number for testing. My bash script

[root@server70 public_html]# sh 1.sh
File changed css/style.css
File changed templates/header.tpl
File changed templates/index.tpl
File changed templates/user/delete.tpl
[root@server70 public_html]# cat 1.sh
#!/bin/bash


CSS_JS_CHANGED=0

git diff --name-only 8613bd3ed718b27ca680bdf33e0a4b32b0f58b8c HEAD | egrep '.css|.js|.tpl' |
while read name; do
   CSS_JS_CHANGED=1
   echo "File changed $name"
done

if [ "$CSS_JS_CHANGED" = "1" ]; then
    echo expression evaluated as true
fi

[root@server70 public_html]#

If i run my script inside while, it get executed multiple times if multiple files changed. I only need to run my script once per change.

So i Need to set a variable CSS_JS_CHANGED, set its value to 0. Then if a file change is detected, set its value to 1. Then run my script if value of CSS_JS_CHANGED is 1.

But for some reason, i can't set value of CSS_JS_CHANGED to 1 inside the while loop. Anything to do with variable scope ?

** EDIT 2 **

I find why i can't set variable from inside while loop here

Being a bash noob, can someone get my script working please :)

EDIT 3

Got it working with out CSS_JS_CHANGED variable.

[root@server70 public_html]# cat update
#!/bin/bash
# */5 * * * * /home/USERNAME/public_html/update >/dev/null 2>&1


cd /home/USERNAME/public_html
OLD_HEAD=$(git rev-parse HEAD)
git pull origin master
NEW_HEAD=$(git rev-parse HEAD)

[ $OLD_HEAD = $NEW_HEAD ] && exit 0

git diff --name-only $OLD_HEAD $NEW_HEAD | egrep '.css|.js' |
while read name; do
   touch /tmp/css_js_update
done

if [ -f "/tmp/css_js_update" ]
then
    /usr/bin/curl 'http://mywebsite.com/admin/cf.php?js_version_update=mywebsite'
    rm -f /tmp/css_js_update
fi
[root@server70 public_html]#

Now waiting for a .css/.js file commit :)

Thanks again @torek

Upvotes: 5

Views: 4658

Answers (1)

torek
torek

Reputation: 488193

Any time you do this sort of thing you should ask: "changed with respect to what?"

If you're deploying stuff to a web server, presumably you mean "changed from the version the server read". In which case, start by saving something about the version the server read, such as "the contents", or—in the case of git, where this is easy—a unique-identifier for the version the server read.

It seems like you're doing a git pull directly on the server (which has some drawbacks but let's just run with that). Rather than attempting to interpret git merge output, it would seem to be simpler to capture some SHA-1 values. For instance, you could grab those for the two file blobs you're interested in:

OLD_STYLE_ID=$(git rev-parse HEAD:css/style.css)
OLD_SCRIPT_ID=$(git rev-parse HEAD:script.js) # fix path here if/as needed

After that you can do the fetch-and-merge / pull operation, then get the new SHA-1s:

git pull origin master
NEW_STYLE_ID=$(git rev-parse HEAD:css/style.css)
NEW_SCRIPT_ID=$(git rev-parse HEAD:script.js) # again, fix path if needed

Now if the new IDs match the old IDs, those files are unchanged; any IDs that do not match represent a change in those files.

Alternatively, save the IDs for the old and new HEAD values, and if those change, do something with the interesting path(s), e.g.:

OLD_HEAD=$(git rev-parse HEAD)
git pull origin master
NEW_HEAD=$(git rev-parse HEAD)
[ $OLD_HEAD = $NEW_HEAD ] && exit 0 # no change to repo = no change to any files

At this point there are many options, such as:

git diff --name-only ${OLD_HEAD} ${NEW_HEAD} -- css/style.css script.js |
while read name; do
    ...
done

or simply check whether git diff --name-only, restricted to those paths (as above), prints anything at all.

Upvotes: 7

Related Questions