Hooks, Aliases, Templates, Attributes, and Local Automation: Guided Hands-On Workflow and Core Operations
Create a disposable automation lab with Git aliases, a safe commit-msg hook, core.hooksPath, attributes, ignore diagnostics, local attribute overrides, init templates, and a local bare server receive hook.
Learning objectives
- Configure and inspect local Git aliases and core.hooksPath.
- Observe commit-msg arguments/exit status and prove staged state survives rejection.
- Use git check-attr, git check-ignore, and git ls-files --eol to inspect path behavior.
- Seed harmless repository metadata with an explicit init template.
- Observe a pre-receive hook consuming ref updates on stdin and rejecting one ref.
1. Create a disposable policy-automation lab
The scenario uses a tracked .githooks directory so the
hook script can be reviewed in normal history, but activation
remains local configuration. It also uses a local bare repository
later to demonstrate an authoritative receive hook without any
hosted account.
Git Bash, Bash, or zsh
mkdir git-local-automation-lab
cd git-local-automation-lab
git init -b trunk project
cd project
git config user.name "Automation Lab"
git config user.email "automation-lab@example.invalid"
mkdir -p .githooks docs assets scripts
printf "# Automation Policy Lab\n" > README.md
printf "# Internal notes\n" > docs/internal.md
printf "echo hello\n" > scripts/build.sh
printf "fake-png-payload\n" > assets/logo.png
printf "*.log\n" > .gitignore
cat > .gitattributes <<'EOF'
* text=auto
*.sh text eol=lf
*.png binary
docs/internal.md export-ignore
EOF
PowerShell setup alternative
New-Item -ItemType Directory git-local-automation-lab | Out-Null
Set-Location git-local-automation-lab
git init -b trunk project
Set-Location project
git config user.name "Automation Lab"
git config user.email "automation-lab@example.invalid"
'.githooks','docs','assets','scripts' | ForEach-Object { New-Item -ItemType Directory -Force $_ | Out-Null }
Set-Content README.md '# Automation Policy Lab'
Set-Content docs/internal.md '# Internal notes'
Set-Content scripts/build.sh 'echo hello'
Set-Content assets/logo.png 'fake-png-payload'
Set-Content .gitignore '*.log'
@('* text=auto','*.sh text eol=lf','*.png binary','docs/internal.md export-ignore') | Set-Content .gitattributes
2. Create a non-destructive commit-msg hook
cat > .githooks/commit-msg <<'EOF'
#!/bin/sh
msgfile=$1
gitdir=$(git rev-parse --git-dir)
printf 'hook=commit-msg argc=%s msgfile=%s\n' "$#" "$msgfile" >> "$gitdir/hook-observations.log"
subject=$(sed -n '1p' "$msgfile")
case "$subject" in
"DEMO: "*) exit 0 ;;
*)
echo "commit-msg: subject must start with DEMO: " >&2
exit 1
;;
esac
EOF
chmod +x .githooks/commit-msg
git config --local core.hooksPath .githooks
git config --show-origin --get core.hooksPath
The POSIX chmod command is for filesystems/environments
that expose executable permission bits. Git's hook contract requires
an executable hook; Windows/Git-for-Windows execution details depend
on the filesystem/runtime, so verify actual invocation rather than
assuming POSIX permission behavior maps perfectly.
3. Observe a rejected commit without losing staged content
git add .
git status --short
git commit -m "initial policy lab"
echo "commit exit=$?"
git status --short
cat .git/hook-observations.log
Expected: the hook exits 1, so no commit is
created. The staged snapshot remains staged. The observation log
shows that commit-msg received one argument: the
proposed message-file path.
4. Create a valid commit and prove the ref moved once
git commit -m "DEMO: establish policy automation lab"
git log -1 --oneline --decorate
git status --short --branch
cat .git/hook-observations.log
The branch now points to the new commit. The hook script and
.gitattributes are normal tracked content;
core.hooksPath and the observation log remain local
metadata.
5. Demonstrate why client hooks are not an enforcement boundary
printf "local bypass demonstration\n" > bypass.txt
git add bypass.txt
git commit --no-verify -m "plain subject bypasses client hook"
git log -1 --oneline
The commit succeeds because commit-msg is one of the
hooks that --no-verify can bypass. This is the evidence
for moving mandatory policy to CI/server governance.
6. Configure and inspect simple Git aliases
git config --local alias.st 'status --short --branch'
git config --local alias.last 'log -1 --oneline --decorate'
git config --get-regexp '^alias\.'
git st
git last
These aliases live in this repository's local config. They do not create commits or change refs. They are interactive ergonomics, not project history.
7. Ask Git which attributes apply instead of inferring from patterns
git check-attr --all -- scripts/build.sh
git check-attr --all -- assets/logo.png
git check-attr --all -- docs/internal.md
git ls-files --eol -- scripts/build.sh
Expected: the shell script is text with LF
working-tree intent; the PNG path has the built-in binary macro
effects; the internal document is marked export-ignore.
ls-files --eol helps inspect index/worktree line-ending
state.
8. Debug ignore rules separately from attributes
printf "temporary log\n" > debug.log
git check-ignore -v -- debug.log
git check-attr --all -- debug.log
git status --short
check-ignore -v identifies the source file and matching
pattern. The attribute query may show only broad text policy. One
mechanism decides untracked visibility; the other assigns path
behavior.
9. Demonstrate a repository-local attribute override
printf "local-only.dat -text custom=local\n" > .git/info/attributes
git check-attr text custom -- local-only.dat
The info/attributes rule is not tracked and has high
precedence for this repository. It is appropriate for one
developer's local behavior but not for shared policy.
10. Seed harmless metadata through an init template
cd ..
mkdir -p template-seed
printf "Created from the training template.\n" > template-seed/policy-notice.txt
git init --template=template-seed -b trunk templated
test -f templated/.git/policy-notice.txt
cat templated/.git/policy-notice.txt
The template file is copied into the new repository's
.git directory at initialization. It is not a tracked
working-tree file and does not establish ongoing synchronization
with template-seed.
11. Create a local bare remote with a receive hook that consumes stdin
git init --bare central.git
cat > central.git/hooks/pre-receive <<'EOF'
#!/bin/sh
reject=0
while read old_oid new_oid ref_name
do
printf 'old=%s new=%s ref=%s\n' "$old_oid" "$new_oid" "$ref_name" >> pre-receive.log
if test "$ref_name" = "refs/heads/blocked-demo"
then
echo "server policy: blocked-demo is rejected" >&2
reject=1
fi
done
exit "$reject"
EOF
chmod +x central.git/hooks/pre-receive
git -C project remote add origin ../central.git
git -C project push -u origin trunk
cat central.git/pre-receive.log
Receive hooks run in $GIT_DIR of the bare repository.
Each proposed ref update arrives on standard input as old object ID,
new object ID, and full ref name. Exit 0 allows the accepted
updates.
12. Observe authoritative rejection
git -C project branch blocked-demo
git -C project push origin blocked-demo
echo "push exit=$?"
tail -n 2 central.git/pre-receive.log
Expected: the push is rejected because the
server-side hook exits non-zero for that ref. A client-side
--no-verify cannot disable a hook that executes on the
remote server.
13. Challenge — choose the correct customization layer
- A shorthand is only for your interactive terminal. Git alias, tracked script, or server hook?
-
Every clone should know that
*.pngis binary. Where should that policy live? - Every developer should get fast commit-message feedback, but the rule must also be mandatory. Which two layers should cooperate?
- You want every newly initialized internal repository to start with a local metadata notice. Which mechanism?
- A path is unexpectedly ignored. Which diagnostic command identifies the matching rule source?
14. Cleanup
Git Bash / Bash / zsh
cd ..
pwd
rm -rf git-local-automation-lab
PowerShell
Set-Location ..
Get-Location
Remove-Item -Recurse -Force git-local-automation-lab
15. Knowledge check
Question 1. What state remains after a commit-msg hook rejects a commit?
Question 2. Where are alias.st and
core.hooksPath stored in this lab?
Question 3. What does git check-ignore -v add over
ordinary status?
Question 4. Why can a pre-receive hook enforce a remote rule more strongly than commit-msg?
Question 5. What did the init template copy?
16. Summary
You activated a tracked client hook through local configuration, proved its bypass boundary, configured aliases, inspected attributes and ignore patterns, created a local-only attribute override, seeded repository metadata through a template, and observed a server receive hook's stdin/exit contract.
Authoritative references
githooks
git-config
git-check-attr
git-check-ignore
git-init
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.