Useful GitHub Tricks
1. Introduction
This short note collects three GitHub habits that keep repos clean and builds reliable: .gitignore, pre-commit, and a minimal GitHub Actions workflow. The goal is fewer accidental commits and more consistent checks.
2. .gitignore
.gitignore only ignores files that are not yet tracked by Git. If a file is already in history, remove it from tracking with git rm --cached <file> before the ignore rules take effect. Start from a template and then trim it down for your project.
Below is a common starter template (Linux + Python). You can generate a custom one with the toptal gitignore generator:
1### Linux ###2*~34# temporary files which can be created if a process still has a handle open of a deleted file5.fuse_hidden*67# KDE directory preferences8.directory910# Linux trash folder which might appear on any partition or disk11.Trash-*1213# .nfs files are created when an open file is removed but is still being accessed14.nfs*1516### Python ###17# Byte-compiled / optimized / DLL files18__pycache__/19*.py[cod]20*$py.class2122# C extensions23*.so2425# Distribution / packaging26.Python27build/28develop-eggs/29dist/30downloads/31eggs/32.eggs/33lib/34lib64/35parts/36sdist/37var/38wheels/39share/python-wheels/40*.egg-info/41.installed.cfg42*.egg43MANIFEST4445# PyInstaller46# Usually these files are written by a python script from a template47# before PyInstaller builds the exe, so as to inject date/other infos into it.48*.manifest49*.spec5051# Installer logs52pip-log.txt53pip-delete-this-directory.txt5455# Unit test / coverage reports56htmlcov/57.tox/58.nox/59.coverage60.coverage.*61.cache62nosetests.xml63coverage.xml64*.cover65*.py,cover66.hypothesis/67.pytest_cache/68cover/6970# Translations71*.mo72*.pot7374# Django stuff:75*.log76local_settings.py77db.sqlite378db.sqlite3-journal7980# Flask stuff:81instance/82.webassets-cache8384# Scrapy stuff:85.scrapy8687# Sphinx documentation88docs/_build/8990# PyBuilder91.pybuilder/92target/9394# Jupyter Notebook95.ipynb_checkpoints9697# IPython98profile_default/99ipython_config.py100101# pyenv102# For a library or package, you might want to ignore these files since the code is103# intended to run in multiple environments; otherwise, check them in:104# .python-version105106# pipenv107# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.108# However, in case of collaboration, if having platform-specific dependencies or dependencies109# having no cross-platform support, pipenv may install dependencies that don't work, or not110# install all needed dependencies.111#Pipfile.lock112113# poetry114# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.115# This is especially recommended for binary packages to ensure reproducibility, and is more116# commonly ignored for libraries.117# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control118#poetry.lock119120# pdm121# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.122#pdm.lock123# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it124# in version control.125# https://pdm.fming.dev/#use-with-ide126.pdm.toml127128# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm129__pypackages__/130131# Celery stuff132celerybeat-schedule133celerybeat.pid134135# SageMath parsed files136*.sage.py137138# Environments139.env140.venv141env/142venv/143ENV/144env.bak/145venv.bak/146147# Spyder project settings148.spyderproject149.spyproject150151# Rope project settings152.ropeproject153154# mkdocs documentation155/site156157# mypy158.mypy_cache/159.dmypy.json160dmypy.json161162# Pyre type checker163.pyre/164165# pytype static type analyzer166.pytype/167168# Cython debug symbols169cython_debug/170171# PyCharm172# JetBrains specific template is maintained in a separate JetBrains.gitignore that can173# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore174# and can be added to the global gitignore or merged into this file. For a more nuclear175# option (not recommended) you can uncomment the following to ignore the entire idea folder.176#.idea/177178### Python Patch ###179# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration180poetry.toml181182# ruff183.ruff_cache/184185# LSP config files186pyrightconfig.json
3. Pre-commit
Use pre-commit to run checks automatically before each commit. Here I use prek, a Go-based pre-commit runner.
Install prek (pick one method):
1# Using uv (recommended)2uv tool install prek34# Using uvx (install and run in one command)5uvx prek67# Adding prek to the project dev-dependencies8uv add --dev prek910# Using pip11pip install prek1213# Using pipx14pipx install prek
Basic usage:
1# Run all hooks against all files2prek run -a34# Update hook versions5prek auto-update67# Run hooks on every commit8prek install910# Uninstall the git hook11prek uninstall1213# Clean up unused repos, hook envs and tool versions from prek cache14prek cache gc
Create a .pre-commit-config.yaml in the repo root:
.pre-commit-config.yaml
1# Let all hooks run so you see the full set of issues in one pass.2fail_fast: false34exclude: "^.github/workflows/"56repos:7 # 1. Basic file cleanup and checks (Standard hooks)8 - repo: https://github.com/pre-commit/pre-commit-hooks9 rev: v6.0.010 hooks:11 - id: trailing-whitespace # Removes trailing whitespace12 - id: check-added-large-files # Prevents committing giant files13 - id: check-case-conflict # Checks for case conflicts (important for Windows/Mac)14 - id: end-of-file-fixer # Ensures files end with a newline15 - id: fix-byte-order-marker # Removes UTF-8 BOM16 - id: check-json # Validates JSON syntax17 - id: check-toml # Validates TOML syntax18 - id: check-yaml # Validates YAML syntax (checks only, no formatting)19 - id: check-xml # Validates XML syntax20 - id: mixed-line-ending # Enforces consistent line endings (LF/CRLF)21 - id: check-symlinks # Checks for broken symlinks22 - id: check-merge-conflict # Checks for leftover merge conflict markers23 - id: detect-private-key # Checks for private keys24 # - id: no-commit-to-branch # (Commented out) Prevents committing to main branch25 - id: check-executables-have-shebangs # Ensures executables have a valid shebang26 - id: pretty-format-json # Formats JSON files27 args: [--autofix, --no-sort-keys] # Autofix enabled, preserves key order2829 # 2. Spell checker (Catches typos in variable names)30 - repo: https://github.com/crate-ci/typos31 rev: v1.42.132 hooks:33 - id: typos34 # Fast dictionary-based spell check; configurable via `typos.toml`.3536 # 3. Python linting and formatting (Ruff - Extremely fast)37 - repo: https://github.com/astral-sh/ruff-pre-commit38 rev: v0.14.1339 hooks:40 - id: ruff-format # Formats Python code (like Black)41 - id: ruff # Lints and fixes Python logic (like Flake8/Isort)42 args: [--fix] # Auto-fix lint; CI remains green after fixes4344 # 4. Security scan (Secrets detection)45 - repo: https://github.com/gitleaks/gitleaks46 rev: v8.30.047 hooks:48 - id: gitleaks49 # Scans for hard-coded secrets; honors `.gitleaks.toml` if present.5051 # 5. Markdown formatting52 - repo: https://github.com/hukkin/mdformat53 rev: 1.0.054 hooks:55 - id: mdformat56 language: python57 additional_dependencies:58 - mdformat-gfm # GitHub Flavored Markdown support (tables, etc.)59 - mdformat-black # Formats Python code blocks inside Markdown60 - mdformat-mkdocs61 - mdformat-footnote62 # Keep Markdown consistent across docs and READMEs.6364 - repo: https://github.com/abravalheri/validate-pyproject65 rev: v0.24.166 hooks:67 - id: validate-pyproject # Validate pyproject.toml against PEP 621/5176869 - repo: https://github.com/igorshubovych/markdownlint-cli70 rev: v0.47.071 hooks:72 - id: markdownlint # Auto-fix Markdown style issues where possible73 args: [--fix, --disable=MD013, --disable=MD041]7475 - repo: https://github.com/rbubley/mirrors-prettier76 rev: v3.8.177 hooks:78 - id: prettier79 types_or: [yaml, toml]
A better way is to create 'prek.toml' and configure hooks there.
1fail_fast = false23[[repos]]4repo = "https://github.com/pre-commit/pre-commit-hooks"5rev = "v6.0.0"6hooks = [7 { id = "trailing-whitespace" },8 { id = "check-added-large-files" },9 { id = "check-case-conflict" },10 { id = "end-of-file-fixer" },11 { id = "fix-byte-order-marker" },12 { id = "check-json" },13 { id = "check-toml" },14 { id = "check-yaml" },15 { id = "check-xml" },16 { id = "mixed-line-ending" },17 { id = "check-symlinks" },18 { id = "check-merge-conflict" },19 { id = "detect-private-key" },20 { id = "check-executables-have-shebangs" },21 {22 id = "pretty-format-json",23 args = [24 "--autofix",25 "--no-sort-keys"26 ]27 }28]2930[[repos]]31repo = "https://github.com/crate-ci/typos"32rev = "v1.43.3"33hooks = [34 { id = "typos" }35]3637[[repos]]38repo = "https://github.com/astral-sh/ruff-pre-commit"39rev = "v0.15.0"40hooks = [41 { id = "ruff-format" },42 {43 id = "ruff",44 args = ["--fix"]45 }46]4748[[repos]]49repo = "https://github.com/gitleaks/gitleaks"50rev = "v8.30.0"51hooks = [52 { id = "gitleaks" }53]5455[[repos]]56repo = "https://github.com/hukkin/mdformat"57rev = "1.0.0"58hooks = [59 {60 id = "mdformat",61 language = "python",62 additional_dependencies = [63 "mdformat-gfm",64 "mdformat-black",65 "mdformat-mkdocs",66 "mdformat-footnote"67 ]68 }69]7071[[repos]]72repo = "https://github.com/abravalheri/validate-pyproject"73rev = "v0.25"74hooks = [75 { id = "validate-pyproject" }76]7778[[repos]]79repo = "https://github.com/igorshubovych/markdownlint-cli"80rev = "v0.47.0"81hooks = [82 { id = "markdownlint-fix" }83]8485[[repos]]86repo = "https://github.com/rbubley/mirrors-prettier"87rev = "v3.8.1"88hooks = [89 {90 id = "prettier",91 types_or = [92 "yaml",93 "toml"94 ]95 }96]97
After you write the config, always run prek auto-update to fetch the latest hook versions.
We can ignore some folder or rules in toml file
1[tool.ruff]2exclude = [3 "..."4]56[tool.ruff.lint]7ignore = ["..."]89[tool.typos.files]10extend-exclude = ["..."]
4. GitHub Actions
To keep local and CI checks consistent, add a simple workflow that runs the same pre-commit hooks on every push and pull request. The action below does two passes: first it runs hooks and allows fixes, then it runs again to verify everything is clean. If fixes were made, it can auto-commit them back to the branch.
.github/workflows/pre-commit.yml
1name: pre-commit23on:4 pull_request:5 push:6 branches: [main]78jobs:9 prek:10 runs-on: ubuntu-latest11 permissions:12 contents: write13 steps:14 - uses: actions/checkout@v615 with:16 ref: ${{ github.head_ref || github.ref_name }}17 - uses: actions/setup-go@v618 with:19 go-version: "stable"20 - name: pre-commit run (fix first pass)21 id: prek_fix22 uses: j178/prek-action@v123 continue-on-error: true24 - name: pre-commit run (verify second pass)25 uses: j178/prek-action@v126 - name: Detect changes27 id: diff28 run: |29 if git diff --quiet; then30 echo "changed=false" >> $GITHUB_OUTPUT31 else32 echo "changed=true" >> $GITHUB_OUTPUT33 fi34 - name: Auto-commit fixes35 if: steps.diff.outputs.changed == 'true'36 uses: stefanzweifel/git-auto-commit-action@v737 with:38 commit_message: "Apply pre-commit fixes"