Skip to content

Instantly share code, notes, and snippets.

@kuri65536
Last active April 5, 2018 21:23
Show Gist options
  • Save kuri65536/c16aa31e0bedcef25fa642246b9a3437 to your computer and use it in GitHub Desktop.
Save kuri65536/c16aa31e0bedcef25fa642246b9a3437 to your computer and use it in GitHub Desktop.
An example of git repositories, which are separated release tree and development tree.
#! /bin/bash
lck=git-post-receive.lock
function wait_and_lock() {
for i in {1..10}; do
if ! [ -e $lck ]; then
mkdir -p $lck
return 1
fi
sleep 0.1
done
return 0
}
function release_lock() {
rmdir $lck
}
git="git --git-dir=.git"
(
echo -------------- git push in $(date '+%Y/%m/%d %H:%M:%s') --------------
cd ../release
if wait_and_lock; then
echo script: failed to lock.
exit 1
fi
echo script: work in "'"$(pwd)"'"
if $git status | grep -q -e 'working tree clean'; then
echo "script: local is clean."
else
# regist modified files at the current
echo "script: local changes were detected, save them..."
$git commit -a -m \
"save tempolary files in release_$(date +%Y%m%d_%H%M%S)"
fi
HEAD=$($git rev-parse HEAD)
if ! ($git tag -l --points-at $HEAD | grep -q -e 'release_'); then
# tag release at the date
echo "script: tag this $HEAD to show it was worked actually."
$git tag release_$(date +%Y%m%d_%H%M%S)
else
echo "script: this $HEAD is already show as worked actually."
fi
echo "script: update to deploy."
$git fetch origin
$git push origin -f --tags
$git reset --hard origin/master
release_lock
) 2>&1 >> git-post-receive.log
#! env python3
from __future__ import unicode_literals
from datetime import datetime
import logging
from logging import info
from multiprocessing import Lock
import os
import subprocess
from typing import List, Optional, Text, Tuple
List, Optional, Text, Tuple
path_rel = u"../release"
cmd = ["git", "--git-dir=.git"]
def rungit(*args):
# type: (Text) -> Text
_args = cmd + list(args)
try:
ret = subprocess.check_output(_args)
except subprocess.CalledProcessError:
return "process failed: " + ' '.join(_args)
txt = ret.decode("utf-8") # type: Text
return txt
def wait_and_lock():
# type: () -> Optional[Lock]
ret = Lock()
if not ret.acquire(timeout=0.1): # type: ignore
return None
return ret
def main():
# type: () -> int
os.chdir(path_rel)
info("script: work in '{}'".format(os.getcwd()))
dt = datetime.now().strftime("%Y%m%d_%H%M%S")
ret = rungit("status")
if 'working tree clean' in ret:
info("script: local is clean.")
else:
# regist modified files at the current
info("script: local changes were detected, save them...")
info(rungit("commit", "-a", "-m",
"save tempolary files in release_{}".format(dt)))
HEAD = rungit("rev-parse", "HEAD").strip()
ret = rungit("tag", "-l", "--points-at", HEAD)
if 'release_' not in ret:
# tag release at the date
info("script: tag this $HEAD to show it was worked actually.")
info(rungit("tag", "release_{}".format(dt)))
else:
info("script: this $HEAD is already show as worked actually.")
info("script: update to deploy.")
info(rungit("fetch", "origin"))
info(rungit("push", "origin", "-f", "--tags"))
info(rungit("reset", "--hard", "origin/master"))
return 0
if __name__ == "__main__":
logging.getLogger().setLevel(logging.DEBUG)
lck = wait_and_lock()
if lck is not None:
try:
main()
finally:
lck.release()
# vi: ft=python:et:ts=4:nowrap:fdm=marker

Prepare the repos

$ git clone this/repo develop
$ git clone this/repo release
$ git clone --bare this/repo hosting

hosting repo
$ cd hosting
$ cp git-post-receive hooks/post-receive; chmod 755 hooks/post-receive
or
$ cp git-post-receive.py hooks/post-receive; chmod 755 hooks/post-receive
<check release repo path in 'post-receive' script!>

develop repo
$ cd ../develop
$ sed -i 's/remote "origin"/remote "gist"/' .git/config
$ git remote add origin ../bare

release repo
$ cd ../release
$ sed -i 's/remote "origin"/remote "gist"/' .git/config
$ git remote add origin ../bare

Example

1. push with clean release tree

$ echo 1 >> a
$ git add a; git commit -m 'test 1'
$ git log
...
$ git push origin
$ ls -al ../release
../release/a
$ cat ../release/a
1
$ cd ../release
$ git log
... same as development us

2. push with modified release tree

make some changes in release tree.

$ cd ../release
$ echo exit 0 >> git-post-receive

push new changes from develop tree.

$ cd ../develop
$ echo 1 >> a
$ git add a; git commit -m 'test 1'
$ git push origin
$ git log
...
$ git fetch
$ git log
... (release changes are commited as a sole branch.)

after this example

.--.--.--.--.--.--.  <- new commit in develop tree.
                \
                 .   <- release tree changes, tag: release_YMD_HMS

How does the script work?

under construction.

  • refer: git-hooks

Changelog

  • v1.1: the git-post-receive script looping in push.

TODO

  • new files in release cannot be add automatically. (this is commit -a behavior)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment