Final StretchOrdered learning track

Local Templates and Repository Bootstrap

Learn Git In Action - Part 104

Designing local Git templates and repository bootstrap flows that install consistent hooks, config, defaults, and team guardrails.

10 min read1923 words
PrevNext
Lesson 104126 lesson track104–126 Final Stretch
#git#version-control#developer-experience#automation+1 more

Local Templates and Repository Bootstrap

Repository bootstrap adalah proses membuat repository baru atau clone baru langsung berada dalam state yang aman, konsisten, dan siap dipakai.

Banyak tim memperlakukan bootstrap sebagai “clone repo, lalu baca README”. Itu terlalu rapuh. Repository yang baik harus punya mekanisme eksplisit untuk mengatur:

  • default branch behavior;
  • local Git config;
  • hooks path;
  • commit message template;
  • aliases/include config;
  • sparse/partial clone profile jika repo besar;
  • LFS/submodule setup;
  • dependency bootstrap;
  • local validation command;
  • security guardrails.

Git menyediakan satu mekanisme awal bernama template directory. Tapi penting memahami batasnya:

Git template directory mengisi struktur internal $GIT_DIR saat git init atau clone tertentu membuat repository. Ia bukan scaffolding project source tree.

Untuk bootstrap production-grade, template directory hanyalah satu bagian. Sisanya perlu script dan policy yang versioned.


1. Apa Itu Git Template Directory?

Saat git init membuat repository, Git membuat struktur seperti .git/objects, .git/refs/heads, .git/refs/tags, dan file/directory internal lain. Git juga bisa menyalin isi template directory ke $GIT_DIR.

Template directory biasanya berisi:

hooks/
info/
  exclude

Default Git installation sering membawa sample hooks di template directory. Sample hooks ini biasanya disabled karena memiliki suffix .sample.

Contoh lokasi umum:

git --exec-path

Atau cek config:

git config --show-origin --get init.templateDir

Jika config tidak ada, Git memakai default template directory dari instalasi Git.


2. Template Directory Bukan Project Template

Ini kesalahan umum.

Git template directory disalin ke $GIT_DIR, bukan ke working tree.

Artinya template directory cocok untuk:

  • default hooks;
  • .git/info/exclude;
  • internal metadata awal;
  • hook helper files;
  • custom template untuk repository internals.

Tidak cocok untuk:

  • README.md;
  • .gitignore project;
  • source folder;
  • CI workflow files;
  • package manifest;
  • application scaffolding.

Untuk project template, gunakan generator lain:

  • repository template;
  • cookiecutter;
  • internal CLI;
  • monorepo workspace generator;
  • framework generator;
  • scaffolding script.

Mermaid mental model:


3. Setting init.templateDir

Buat template directory:

mkdir -p ~/.config/company/git-template/hooks
mkdir -p ~/.config/company/git-template/info

Tambahkan global config:

git config --global init.templateDir ~/.config/company/git-template

Cek:

git config --global --get init.templateDir

Saat repository baru dibuat:

mkdir demo
cd demo
git init

Git akan menyalin isi template ke .git/.


4. Minimal Template Directory Layout

Baseline:

~/.config/company/git-template/
  hooks/
    pre-commit
    commit-msg
  info/
    exclude

Contoh info/exclude:

# Local editor files
*.swp
*.swo
*~
.DS_Store

# Local scratch
.local/
.tmp/

Perbedaan info/exclude dan .gitignore:

FileScopeVersioned?Cocok Untuk
.gitignoreProjectYaArtifact project yang semua orang harus ignore.
.git/info/excludeLocal repoTidakPreferensi lokal atau machine-specific ignore.
core.excludesFileUser globalTidakIgnore global seperti OS/editor files.

Jangan taruh ignore project penting hanya di template info/exclude. Engineer lain atau CI bisa berbeda.


5. Hook Bootstrap via Template

Contoh pre-commit sederhana:

#!/usr/bin/env bash
set -euo pipefail

# Avoid committing unresolved conflict markers.
if git diff --cached --check; then
  :
else
  echo "pre-commit: whitespace/conflict-marker check failed" >&2
  exit 1
fi

Install:

cat > ~/.config/company/git-template/hooks/pre-commit <<'SCRIPT'
#!/usr/bin/env bash
set -euo pipefail

git diff --cached --check
SCRIPT
chmod +x ~/.config/company/git-template/hooks/pre-commit

Repository baru akan mendapat hook ini di .git/hooks/pre-commit.

Tetapi ada batas serius:

Hooks di .git/hooks tidak ikut ter-clone dan tidak versioned bersama source tree.

Template membantu repo baru di mesin user, tetapi tidak menjamin semua clone di semua mesin memiliki hook yang sama.


6. Prefer core.hooksPath untuk Hooks yang Versioned

Untuk repository penting, lebih baik version hooks di working tree:

repo/
  .githooks/
    pre-commit
    commit-msg
    pre-push
  scripts/
    git-hooks/
      check-commit-message.sh
      check-sensitive-paths.sh

Lalu set local config:

git config core.hooksPath .githooks

Kelebihan:

  • hook scripts versioned;
  • perubahan hook bisa direview;
  • bisa dites di CI;
  • semua engineer bisa install via bootstrap;
  • tidak bergantung pada template machine-specific.

Kekurangan:

  • user harus menjalankan bootstrap minimal sekali;
  • malicious repo dapat menyediakan hook jika user mengaktifkan core.hooksPath, jadi trust boundary harus jelas;
  • hook client-side tetap bypassable.

Template directory dan core.hooksPath bisa digabung:

Contoh dispatcher:

#!/usr/bin/env bash
set -euo pipefail

root=$(git rev-parse --show-toplevel 2>/dev/null || true)

if [ -n "$root" ] && [ -x "$root/.githooks/pre-commit" ]; then
  exec "$root/.githooks/pre-commit" "$@"
fi

# Generic fallback
git diff --cached --check

7. Bootstrap Script: The Real Control Plane

Template directory hanya berlaku saat init. Untuk clone existing repo, onboarding, atau update hook, butuh bootstrap script.

Contoh layout:

repo/
  scripts/
    bootstrap-git.sh
    git-doctor.sh
  .githooks/
    pre-commit
    commit-msg
    pre-push
  .gitconfig.local.example

scripts/bootstrap-git.sh:

#!/usr/bin/env bash
set -euo pipefail

root=$(git rev-parse --show-toplevel)
cd "$root"

echo "Configuring repository-local Git settings..."

git config core.hooksPath .githooks
git config pull.ff only
git config fetch.prune true
git config rebase.autosquash true
git config rerere.enabled true

echo "Checking hook executability..."
chmod +x .githooks/*

echo "Git bootstrap complete."

Usage:

./scripts/bootstrap-git.sh

Idempotency invariant:

Bootstrap script may be run repeatedly without corrupting state.

Jangan membuat bootstrap yang hanya aman dijalankan sekali.


8. Repository-Local Config: What to Set and What Not to Set

Repository-local config hidup di .git/config, tidak versioned. Bootstrap bisa mengisinya.

Contoh useful local config:

git config pull.ff only
git config fetch.prune true
git config rebase.autosquash true
git config rerere.enabled true
git config core.hooksPath .githooks

Tapi hati-hati dengan config yang terlalu personal.

ConfigCocok Local Repo?Catatan
core.hooksPathYaUntuk versioned hooks.
pull.ff onlyYaJika tim setuju pull harian harus ff-only.
fetch.prune trueYaBiasanya aman, tapi pahami remote refs.
rerere.enabled trueTergantungBerguna untuk rebase/backport berat.
user.nameTidak biasanyaPersonal identity.
user.emailTergantungBisa repo-specific untuk work/personal separation.
commit.gpgsignTergantungJika repo wajib signed commits.
core.autocrlfHati-hatiLebih baik kombinasikan dengan .gitattributes.

Config yang menyangkut team invariant sebaiknya juga didokumentasikan dan dicek oleh git doctor.


9. Commit Message Template Bootstrap

Untuk tim yang butuh commit discipline, gunakan commit template.

File versioned:

.gitmessage

Contoh:

<type>(<scope>): <summary in imperative mood>

Why:
- 

What changed:
- 

Risk / rollback:
- 

Refs:
- 

Bootstrap:

git config commit.template .gitmessage

Ini membantu, tetapi jangan jadikan template terlalu panjang hingga engineer hanya menghapus bagian tanpa berpikir. Template harus mengarahkan context, bukan menjadi form birokratis.

Untuk regulated systems, template bisa berisi trailer guidance:

Risk-Level:
Change-Request:
Reviewed-By:

Namun enforcement trailer harus di server/CI jika benar-benar wajib.


10. Branch Naming and Default Branch Bootstrap

Default branch untuk repo baru bisa dikonfigurasi:

git config --global init.defaultBranch main

Repository bootstrap juga bisa validasi branch naming.

Client-side pre-push example:

#!/usr/bin/env bash
set -euo pipefail

branch=$(git branch --show-current)

case "$branch" in
  main|master|develop|release/*|hotfix/*|feature/*|fix/*|chore/*)
    exit 0
    ;;
  *)
    echo "Invalid branch name: $branch" >&2
    echo "Allowed: feature/*, fix/*, chore/*, release/*, hotfix/*" >&2
    exit 1
    ;;
esac

Tetap ingat: client-side hook bisa bypass. Server-side branch protection/ruleset adalah enforcement boundary.


11. Large Repository Bootstrap

Large repository tidak cukup dengan git clone default.

Bootstrap decision matrix:

Repo TypeRecommended Clone Profile
Small repoFull clone.
Large history, normal working treePartial clone --filter=blob:none.
Monorepo, small workspacePartial clone + sparse checkout.
CI release buildUsually full enough history/tags for release correctness.
Forensic/audit cloneAvoid shallow/partial unless explicitly acceptable.

Example bootstrap for monorepo:

git clone --filter=blob:none --sparse git@example.com:company/monorepo.git
cd monorepo
git sparse-checkout set services/enforcement libs/workflow docs/architecture
./scripts/bootstrap-git.sh

Do not blindly use shallow clone for developer work if engineers need:

  • merge-base analysis;
  • release range changelog;
  • bisect;
  • tag verification;
  • full blame archaeology.

12. LFS Bootstrap

If repository uses Git LFS:

git lfs install
git lfs pull

Bootstrap should detect LFS pointer files that were not hydrated.

Example check:

if command -v git-lfs >/dev/null 2>&1; then
  git lfs install --local
  git lfs pull
else
  echo "Git LFS is required for this repository." >&2
  exit 1
fi

LFS must be treated as dependency boundary, not invisible implementation detail.


13. Submodule Bootstrap

If repository uses submodules:

git submodule update --init --recursive

Bootstrap should detect missing submodule commits:

git submodule status --recursive

Submodule guardrail:

if git submodule status --recursive | grep -q '^-'; then
  echo "Some submodules are not initialized." >&2
  exit 1
fi

Production rule:

A release build must record superproject commit and every submodule commit.

14. Bootstrap for Hooks and Policy Checks

Example .githooks/commit-msg:

#!/usr/bin/env bash
set -euo pipefail

msg_file=$1
subject=$(head -n 1 "$msg_file")

if [ ${#subject} -gt 72 ]; then
  echo "Commit subject too long: ${#subject} > 72" >&2
  exit 1
fi

case "$subject" in
  feat\(*|fix\(*|chore\(*|docs\(*|test\(*|refactor\(*|perf\(*)
    exit 0
    ;;
  *)
    echo "Commit subject should start with type(scope): summary" >&2
    exit 1
    ;;
esac

This is feedback, not absolute truth. Some commits may need exceptions. If exceptions matter, build an explicit bypass process and server-side validation.


15. Bootstrap for Security-sensitive Repositories

Security-sensitive repo bootstrap should set up local feedback for:

  • secret scanning;
  • sensitive path warning;
  • commit signing check reminder;
  • dependency lockfile check;
  • forbidden file pattern;
  • generated credential files;
  • local config sanity.

Example pre-commit secret pattern check:

#!/usr/bin/env bash
set -euo pipefail

if git diff --cached --name-only | grep -E '(\.pem$|\.key$|id_rsa|secrets?\.ya?ml$)' >/dev/null; then
  echo "Potential secret-like file staged. Review before commit." >&2
  exit 1
fi

This is intentionally conservative. For real secret scanning, use a tested scanner in pre-commit and CI.


16. git doctor as Bootstrap Verification

Bootstrap should end with verification.

scripts/git-doctor.sh:

#!/usr/bin/env bash
set -euo pipefail

root=$(git rev-parse --show-toplevel)
cd "$root"

fail=0

check() {
  name=$1
  shift
  echo "== $name =="
  if "$@"; then
    echo "ok"
  else
    echo "failed" >&2
    fail=1
  fi
  echo
}

check "hooks path" test "$(git config --get core.hooksPath || true)" = ".githooks"
check "pull ff only" test "$(git config --get pull.ff || true)" = "only"
check "fetch prune" test "$(git config --get fetch.prune || true)" = "true"
check "working tree status" git status --short

exit "$fail"

Run:

./scripts/git-doctor.sh

Expose as alias:

git config alias.doctor '!./scripts/git-doctor.sh'

17. Bootstrap State Machine

A clean bootstrap lifecycle:

This state machine is more useful than prose onboarding because it defines exit criteria.


18. Bootstrap Idempotency and Safety Rules

Bootstrap scripts must follow rules:

  1. Do not overwrite user identity without explicit confirmation.
  2. Do not auto-delete branches.
  3. Do not auto-clean untracked files.
  4. Do not force-push or rewrite history.
  5. Do not install opaque hooks from untrusted source.
  6. Print config changes being made.
  7. Support re-run.
  8. Fail loudly if required tools are missing.
  9. Keep destructive remediation as separate explicit command.
  10. Prefer repository-local config for repository-specific policy.

Bad bootstrap:

rm -rf .git/hooks
cp -r hooks .git/hooks
git config --global user.email dev@company.com
git clean -fdx

Good bootstrap:

git config core.hooksPath .githooks
git config pull.ff only
git config fetch.prune true
./scripts/git-doctor.sh

19. Cross-platform Bootstrap

If team uses Linux, macOS, and Windows, shell scripts may not be enough.

Options:

ApproachProsCons
BashSimple for Unix-likeWindows friction unless Git Bash/WSL.
PowerShellGood Windows supportUnix friction if not standardized.
Node.jsCommon in frontend/fullstackRequires Node version.
PythonOften available, readableVersion/environment issue.
Go binaryPortable single binaryBuild/release overhead.
Internal CLIBest long-term consistencyNeeds ownership.

For serious engineering orgs, bootstrap often becomes internal CLI:

company dev bootstrap git
company dev doctor git
company dev repair hooks

The CLI can call Git underneath, but user interface remains stable.


20. Bootstrap for New Repository Creation

When creating new repository, combine two layers:

  1. Git template for .git internals.
  2. Project generator for working tree files.

Example internal command:

company repo create service enforcement-api --language java --workflow trunk-release

Under the hood:

mkdir enforcement-api
cd enforcement-api
git init --initial-branch=main
company scaffold service --language java
./scripts/bootstrap-git.sh
git add .
git commit -m "chore(repo): initialize enforcement-api service"

Initial commit should include:

  • README;
  • .gitignore;
  • .gitattributes;
  • CI workflow;
  • CODEOWNERS;
  • branch policy docs;
  • build files;
  • bootstrap scripts;
  • hooks directory if used;
  • release metadata convention.

Git template alone cannot create this source tree.


21. Bootstrap and .gitattributes

Every serious repository should consider .gitattributes early.

Example:

* text=auto

*.sh text eol=lf
*.ps1 text eol=crlf
*.md text
*.png binary
*.jpg binary
*.pdf binary

# Generated lockfiles can have custom diff policy if needed
package-lock.json diff=json

Why bootstrap matters: EOL normalization added late can create huge noisy diffs. Better to define it at repository creation.


22. Bootstrap and Branch Protection

Local bootstrap is not enough. Repository creation should also apply server-side rules:

  • protect main;
  • require PR review;
  • require status checks;
  • require CODEOWNERS for sensitive paths;
  • disable force push to protected branch;
  • protect release tags;
  • require signed tags/commits if policy demands;
  • configure merge queue where appropriate.

This is outside local Git, but belongs in repository bootstrap as an organizational process.

A mature bootstrap pipeline:


23. Migration: Adding Bootstrap to Existing Repo

Existing repositories require careful rollout.

Step plan:

  1. inspect current Git config assumptions;
  2. add .githooks/ but do not enforce immediately;
  3. add scripts/bootstrap-git.sh;
  4. add scripts/git-doctor.sh;
  5. document expected local config;
  6. run dry-run with volunteers;
  7. add CI check equivalent for critical policy;
  8. enable branch protection/rulesets;
  9. announce deprecation of old manual setup;
  10. periodically audit adoption.

Avoid sudden local hooks that block unrelated work without clear remediation.


24. Bootstrap Failure Modes

24.1 Hook Exists but Not Executable

Symptom:

Hook silently does not run or fails depending on environment.

Mitigation:

chmod +x .githooks/*

Doctor check:

test -x .githooks/pre-commit

24.2 User Has Conflicting Global Config

Example:

git config --global pull.rebase true

Repo expects:

git config pull.ff only

Mitigation:

  • set local config explicitly;
  • doctor prints origin of config;
  • educate precedence.

Command:

git config --show-origin --get-regexp '^(pull\.rebase|pull\.ff)'

24.3 Template Updated but Existing Repos Do Not Change

Template directory is copied at init time. Existing repos do not auto-update.

Mitigation:

  • use bootstrap script for existing repos;
  • use core.hooksPath to version hooks;
  • use doctor to detect old setup.

24.4 Bootstrap Becomes Hidden Policy

If policy only exists in bootstrap script, reviewers and CI may not know the rules.

Mitigation:

  • document policy in handbook;
  • enforce critical rules server-side;
  • keep bootstrap as local convenience/feedback.

24.5 Overzealous Hooks Slow Developers

Pre-commit hook running full integration test causes bypass culture.

Mitigation:

  • pre-commit: fast checks;
  • pre-push: medium checks;
  • CI: complete checks;
  • provide explicit command for full validation.

25. Example Complete Bootstrap Package

Recommended repo layout:

repo/
  .gitattributes
  .gitignore
  .gitmessage
  .githooks/
    pre-commit
    commit-msg
    pre-push
  scripts/
    bootstrap-git.sh
    git-doctor.sh
    check-sensitive-paths.sh
    check-commit-msg.sh
  docs/
    engineering/
      git-workflow.md
      release-process.md
  CODEOWNERS

scripts/bootstrap-git.sh:

#!/usr/bin/env bash
set -euo pipefail

root=$(git rev-parse --show-toplevel)
cd "$root"

printf 'Configuring Git for %s\n' "$root"

git config core.hooksPath .githooks
git config pull.ff only
git config fetch.prune true
git config rebase.autosquash true
git config commit.template .gitmessage

if [ -d .githooks ]; then
  chmod +x .githooks/*
fi

if [ -f .lfsconfig ] || git lfs ls-files >/dev/null 2>&1; then
  if command -v git-lfs >/dev/null 2>&1; then
    git lfs install --local
  else
    echo 'Git LFS appears required but git-lfs is not installed.' >&2
    exit 1
  fi
fi

if [ -f .gitmodules ]; then
  git submodule update --init --recursive
fi

./scripts/git-doctor.sh

This bootstrap is explicit, re-runnable, and avoids destructive actions.


26. Summary

Local templates and bootstrap solve different layers:

LayerTool
New .git internal defaultsGit template directory
Versioned hookscore.hooksPath + .githooks/
Repository-local configBootstrap script
Project source scaffoldProject generator/template repo
Policy enforcementBranch protection, server hooks, CI
Ongoing verificationgit doctor

The critical mental model:

Git template initializes repository internals. Bootstrap initializes operational readiness.

Good bootstrap makes the correct Git workflow easy, visible, and repeatable. It does not silently mutate user data, hide policy, or pretend local hooks are enforcement.


References

Lesson Recap

You just completed lesson 104 in final stretch. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.