3. “Oh my. Software development sound rather
perilous. I can assure you they will never get me
on one of those dreadful Computers”
- C3PO
4. this -is a command
This is the console output of a command
It can be coloured as well
this completed successfully.
#!/foo/bar
This is the content of a script
[config]
Or the content of a config file
hello=git merge
Conventions
9. Making Git hooks
ls .git/hooks
applypatch-msg.sample commit-msg.sample post-update.sample
pre-commit.sample prepare-commit-msg.sample
pre-rebase.sample pre-applypatch.sample pre-push.sample
update.sample
10. Client side vs server side hooks
precommit
prepare-commit-msg
commit-msg
post-commit
post-checkout
pre-rebase
pre-receive
update
post-receive
11.
12. The truth is out there...
Specifically on master
13.
14. pre-commit hook
● First thing that happens after git commit
● Able to abandon the commit
● We have not got any arguments
15. Where are we at?
git symbolic-ref --short HEAD
master
16. pre-commit hook
#!/bin/bash
# Check where our HEAD is at
if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
echo "This is not the branch you are looking for"
exit 1
fi
exit 0
17. pre-commit hook
#!/bin/bash
# Check where our HEAD is at
if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
echo "This is not the branch you are looking for"
exit 1
fi
exit 0
18. pre-commit hook
#!/bin/bash
# Check where our HEAD is at
if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
echo "This is not the branch you are looking for"
exit 1
fi
exit 0
20. Well, I should be able to commit on master
git checkout master
git commit -n -am “I want to commit this”
[master 5d5308b] I want to commit this
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 foo.md
21.
22. The mission
● I want to reference an issue in my commit messages
● If I do not reference an issue in my repository - abandon my commit
23. Where are our issues?
Git remote show origin
* remote origin
Fetch URL: git@github.com:RandomSort/hooks
Push URL: git@github.com:RandomSort/hooks
HEAD branch: master
Remote branch:
master tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
24. I <3 APIS
curl -s https://api.github.com/repos/$repo/issues/$issue_number
{
"url":
"https://api.github.com/repos/RandomSort/hooks/issues/1",
"repository_url":
"https://api.github.com/repos/RandomSort/hooks",
"labels_url":
"https://api.github.com/repos/RandomSort/hooks/issues/1/labels
{/name}",
....
TONS OF JSON :D
25. commit-msg hook
#!/bin/bash
# $1 is the temp file containing the commit message
issue_number=`cat $1 | xargs | sed 's/.*#([0-9]*).*/1/'`
repo="`git remote show origin | grep "Push" | xargs | sed
's/.*:(.*)/1/'`"
curl -s https://api.github.com/repos/$repo/issues/$issue_number |
grep -q ""Not Found"" > /dev/null
exit $((1 -$?))
26. commit-msg hook
#!/bin/bash
# $1 is the temp file containing the commit message
issue_number=`cat $1 | xargs | sed 's/.*#([0-9]*).*/1/'`
repo="`git remote show origin | grep "Push" | xargs | sed
's/.*:(.*)/1/'`"
curl -s https://api.github.com/repos/$repo/issues/$issue_number |
grep -q ""Not Found"" > /dev/null
exit $((1 -$?))
27. commit-msg hook
#!/bin/bash
# $1 is the temp file containing the commit message
issue_number=`cat $1 | xargs | sed 's/.*#([0-9]*).*/1/'`
repo="`git remote show origin | grep "Push" | xargs | sed
's/.*:(.*)/1/'`"
curl -s https://api.github.com/repos/$repo/issues/$issue_number |
grep -q ""Not Found"" > /dev/null
exit $((1 -$?))
28. commit-msg hook
#!/bin/bash
# $1 is the temp file containing the commit message
issue_number=`cat $1 | xargs | sed 's/.*#([0-9]*).*/1/'`
repo="`git remote show origin | grep "Push" | xargs | sed
's/.*:(.*)/1/'`"
curl -s https://api.github.com/repos/$repo/issues/$issue_number |
grep -q ""Not Found"" > /dev/null
exit $((1 -$?))
29. So now we’ve done something sane ..
● Git hooks can do useful stuff
● Everything in moderation
● (bust the myth, then go all in)
34. The mission
● I want to work on a feature branch never on master
● I want to commit work referencing issues
● I want to be able to run my Continuous Integration setup
● I deliver through ready branches
● Only allow integration if
○ Tests succeed
○ it’s a fast forward merge
35. Where are we at (again)?
git symbolic-ref --short HEAD
ready/foo
git rev-parse --show-toplevel
/home/randomsort/repos/hooks
.. And where’s our stuff?
36. We only want to do fast forward merges
● It’s prettiest
● We prefer to have our automation engine only do trivial merges
C1 C2 C3 C4
Feature#79
master
HEAD
37. We only want to do fast forward merges
● It’s prettiest
● We prefer to have our automation engine only do trivial merges
C1 C2 C3 C4
Feature#79
master
HEAD
38. How fast can we go?
git rev-list --maxcount 1 master..ready/foo
C1 C2 C3 C4
ready/foo
master
HEAD
39. Putting it together
#!bin/bash
if [ not on ready branch ]
do nothing
fi
if [ not fast forwardable ]
cleanup
fi
run tests
if [ successful ]
merge
cleanup
else
cleanup
40. Putting it together
#!bin/bash
if [ not on ready branch ]
do nothing
fi
if [ not fast forwardable ]
cleanup
fi
run tests
if [ successful ]
merge
cleanup
else
cleanup
41. Putting it together
#!bin/bash
if [ not on ready branch ]
do nothing
fi
if [ not fast forwardable ]
cleanup
fi
run tests
if [ successful ]
merge
cleanup
else
cleanup
42. Cleaning up fails
#We can't do a fast forward merge so let's abort this and move some
stuff around
failbranch=`echo $branch | xargs | sed 's/ready/failed/'`
echo "Unable to fast forward master to $branch leaving state on
$failbranch"
git checkout -b $failbranch
git branch -D $branch
43. Cleaning up fails
#We can't do a fast forward merge so let's abort this and move some
stuff around
failbranch=`echo $branch | xargs | sed 's/ready/failed/'`
echo "Unable to fast forward master to $branch leaving state on
$failbranch"
git checkout -b $failbranch
git branch -D $branch
44. Running
git checkout -b ready/feature
Switched to a new branch 'ready/feature'
Running tests
Testing has failed, leaving state on failed/feature
Switched to a new branch 'failed/feature'
Deleted branch ready/feature (was 462b135).
45. Running
git checkout -b ready/feature
Switched to a new branch 'ready/feature'
Running tests
Testing has failed, leaving state on failed/feature
Switched to a new branch 'failed/feature'
Deleted branch ready/feature (was 462b135).
46. Running
git checkout -b ready/feature
Switched to a new branch 'ready/feature'
Running tests
Testing has failed, leaving state on failed/feature
Switched to a new branch 'failed/feature'
Deleted branch ready/feature (was 462b135).
47. Running
git checkout -b ready/feature
Switched to a new branch 'ready/feature'
Running tests
Testing has failed, leaving state on failed/feature
Switched to a new branch 'failed/feature'
Deleted branch ready/feature (was 462b135).
48. Running with successful tests
git checkout -b ready/feature
Switched to a new branch 'ready/feature1'
Running tests
Switched to branch 'master'
Updating e28500e..06a16b1
Fast-forward
temp.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 temp.md
Deleted branch ready/feature1 (was 06a16b1).
49. It works on my machine
"I find your lack of faith disturbing"
51. TATOOINE - LARS OWENS HOMESTEAD
OWEN:
I have no need for a protocol droid.
C3P0:
Sir -- not in an environment such as this -- that's why I've also been
programmed for over thirty secondary functions that...
OWEN:
What I really need is a droid that understands the binary language of
moisture vaporators.
53. Binary is annoying...
git diff wordfile.docx
diff --git a/wordfile.docx b/wordfile.docx
index d24c436..3c4aa59 100644
Binary files a/wordfile.docx and b/wordfile.docx differ
No idea what changed...
54. Teaching git new tricks
Combining two features:
● Git attributes
○ Assign behaviour per file or path
● Custom drivers
○ Define new behaviour
55. Git attributes
Each line in an attributes definition is of form:
pattern attr1 attr2 ...
Where a attribute can be set, unset or assigned a value:
*.txt text
*.jpg -text
*.sh text eol=lf
56. Git attributes - global
Default location:
$XDG_CONFIG_HOME/git/attributes.
Fallback:
$HOME/.config/git/attributes
If you want to set the path you can use:
git config --global core.attributesfile <path>
git config --global core.attributesfile ~/.gitattributes
e.g.
57. Git attributes - local
Just add definitions to a local .gitattributes file.
Can be set in root folder and in subfolders
58. Git attributes
commonly used for changing (force'ing):
● CRLF behaviour
● text / binary behaviour
But that is not Jedi enough ...... so we will skip those
59. Diff driver
Set as a config parameter like diff.foo
[diff "hexify"]
binary = true
textconv = hexdump -v -C
60. Using the new driver is easy
In .gitattributes:
*.bin diff=hexify
Note - we need both:
● Driver definition in config
● Path attribute that tells diff to use it
62. Recipe for success
For each binary type:
1. Find a tool that extracts useful info from a file
2. Set up a diff driver to use it
3. Profit
4. Don't give in to the dark side
64. My brain parses markdown quite fine...
*.docx diff=pandoc2md
[diff "pandoc2md"]
textconv=pandoc --to=markdown
brew install pandoc
For reference:
.gitattributes
config
65. git diff wordfile.docx
diff --git a/wordfile.docx b/wordfile.docx
index d24c436..48249e3 100644
--- a/wordfile.docx
+++ b/wordfile.docx
@@ -1,8 +1,8 @@
-Headline
+Hi Git Merge
This is some simple text
-*and another important paragraph in italic*
+*and another* **important** *paragraph in italic*
Word to MarkDown
66. git diff --word-diff=color wordfile.docx
diff --git a/wordfile.docx b/wordfile.docx
index d24c436..48249e3 100644
--- a/wordfile.docx
+++ b/wordfile.docx
@@ -1,8 +1,8 @@
HeadlineHi Git Merge
This is some simple text
*and another* **important** *paragraph in italic*
Word to MarkDown
68. PDF files
*.pdf diff=pdfconv
[diff "pdfconv"]
textconv=pdftohtml -stdout
brew install pdftohtml
<BODY bgcolor="#A0A0A0" vlink="blue" link="blue">
<A name=1></a>Headline<br>
This is some simple text<br>
-and another paragraph<br>
-and stuff<br>
+and another important paragraph in italic<br>
+stuff goes here<br>
+Greetings from Denmark<br>
<hr>
</BODY>
71. git diff --cached primes.py
...
@@ -0,0 +1,22 @@
+def primes(n):
+ """
+ Compute the sequence of the first n primes.
+ """
+ p = []
+ if n > 0:
+ p = [2, ]
+ for x in range(1, n):
+ q = p[-1] + 1
+ while True:
+ for y in p:
+ if not (q % y):
+ break
+ else:
+ p.append(q)
Syntax highlighted code in diff's
My brain parses coloured python better
Snippet from:
https://github.com/cbcunc/primer (GPL)
73. git diff autostash.md
>"Why can't I pull when I have a dirty workspace, when Mercurial can do this out of the box?"
-I gave the immediate answer that this is just Git's way of protecting the user from possibly
harmful and, more importantly, irreversible changes. Git by default takes a very paranoid
approach to any operations that change dirty files in your file system, when Git itself can't get
you out of those changes again. _This is normally considered a feature_. The known "workaround",
or possible workflow, is to stash any changes before doing a pull (with `git stash save`, and
then unstash them again (`git stash pop`) when done. It seems obvious that it should be easy to
automate this with a git alias, but it turns out that this isn't trivial, as git stash doesn't
fail gracefully when there are no local changes.
+I gave the immediate answer that this is just Git's way of protecting the user from possibly
harmful and, more importantly, irreversible changes. Git by default takes a very paranoid
approach to any operations that change dirty files in your file system, when **Git** itself can't
get you out of those changes again. _This is normally considered a feature_. The known
"workaround", or possible workflow, is to stash any changes before doing a pull (with `git stash
save`, and then unstash them again (`git stash pop`) when done. It seems obvious that it should
be easy to automate this with a git alias but it turns out that this isn't trivial. Git stash
does not fail gracefully when there are no local changes.
.md - Before reformatting
74. git diff autostash.md
@@ -13,13 +13,13 @@ can do this out of the box?"
I gave the immediate answer that this is just Git's way of protecting
the user from possibly harmful and, more importantly, irreversible
changes. Git by default takes a very paranoid approach to any
-operations that change dirty files in your file system, when Git
+operations that change dirty files in your file system, when **Git**
itself can't get you out of those changes again. _This is normally
considered a feature_. The known "workaround", or possible workflow,
is to stash any changes before doing a pull (with `git stash save`,
and then unstash them again (`git stash pop`) when done. It seems
-obvious that it should be easy to automate this with a git alias,
-but it turns out that this isn't trivial, as git stash doesn't fail
+obvious that it should be easy to automate this with a git alias
+but it turns out that this isn't trivial. Git stash does not fail
gracefully when there are no local changes.
.md - after formatting with fmt
78. git diff Yoda-800px.png
diff --git a/Yoda-800px.png b/Yoda-800px.png
index fc8ee0f..8ed738c 100644
--- a/Yoda-800px.png
+++ b/Yoda-800px.png
@@ -1,24 +1,26 @@
-File Size : 35 kB
-File Modification Date/Time : 2017:01:27 17:29:06+01:00
+File Size : 85 kB
+File Modification Date/Time : 2017:01:30 18:52:20+01:00
File Type : PNG
-Image Width : 800
-Image Height : 640
+Image Width : 600
+Image Height : 480
Bit Depth : 8
-Color Type : RGB
+Color Type : RGB with Alpha
Much more useful
Note: manually abbreviated for slide
But do I know what changed?
79. Can we see the difference?
cachetextconv caches the result
[diff "jpg"]
textconv=jp2a --width=80
cachetextconv = true
*.jpg diff=jpg
*.jpeg diff=jpg
Can't quite do holograms yet, but...
brew install jp2a
84. Other quick ones
MP3 file meta data: exiftool can do those too, or try mp3info:
[diff "mp3"]
textconv=mp3info -x
Excel files:
[diff "xlsconv"]
textconv=xls2csv
Zip files:
[diff "zipshow"]
textconv=unzip -c -a
[diff "ziplist"]
textconv=unzip -l
92. Caveat
That was a conceptual demo - probably not production ready.
Git diff gets a bit confused:
● git status now shows ugly.py as modified
● git add - and it disappears :-)