Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
34 changes: 34 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
# Local guard against the failure modes that produced the 2026-06-17 incident:
# - direct pushes to main
# - pushing a branch that has diverged from / is not based on origin/main
# (the "unrelated histories" trap)
#
# Enable once per clone:
# git config core.hooksPath .githooks
set -euo pipefail

protected="main"
remote_name="${1:-origin}"

current_branch="$(git rev-parse --abbrev-ref HEAD)"

if [ "$current_branch" = "$protected" ]; then
echo "pre-push: direct push to '$protected' is blocked. Open a PR from a feature branch." >&2
exit 1
fi

# Make sure we know where origin/main is, then require the current branch to be
# a descendant of it (i.e. rebased on top, sharing history).
git fetch -q "$remote_name" "$protected" || {
echo "pre-push: could not fetch $remote_name/$protected; check your remote." >&2
exit 1
}

if ! git merge-base --is-ancestor "$remote_name/$protected" HEAD; then
echo "pre-push: HEAD is not based on $remote_name/$protected (diverged/unrelated history)." >&2
echo " Rebase first: git fetch $remote_name && git rebase $remote_name/$protected" >&2
exit 1
fi

exit 0
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,24 @@ jobs:
- run: python -m pip install --upgrade pip ruff
- run: python -m ruff check python/ --ignore=E501,F401

repo-hygiene:
# Guards cross-platform path safety: long sweep filenames under
# experiments/results once hit 266 chars and broke clones/reset on Windows
# (MAX_PATH 260). The windows leg is a canary: an over-long tracked path
# fails at checkout before the lint even runs.
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- run: python tools/lint_repo_paths.py --max-path 180 --max-name 96

test-python-smoke:
runs-on: ubuntu-latest
timeout-minutes: 15
Expand Down
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,19 @@ experiments/results/gsdc2023_bridge_diag_*.csv

# Generated experiment result artifacts (regenerable via CLIs; force-add
# deliverables you want versioned, e.g. `git add -f <submission>.csv`).
# Already-tracked result files keep being tracked.
# These data artifacts are intentionally NOT tracked (untracked 2026-06-17 to
# fix Windows MAX_PATH breakage from 260+ char sweep filenames). Media and
# paper_assets under experiments/results are still tracked.
experiments/results/*.csv
experiments/results/*.json
experiments/results/*.md
experiments/results/*.pos
experiments/results/*.txt
experiments/results/*.npz
experiments/results/*.html
experiments/results/*.pkl
experiments/results/*.pkl.gz
experiments/results/*.parquet

# GPU / urban-shadow / RF-security lab generated data assets
docs/assets/data/
Expand Down
37 changes: 37 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,43 @@ These come from `internal_docs/decisions.md` and the README's development policy
- **Do not vendor, link, or derive production code/config from GPL-3.0 reference
sources** such as `gici-open`. This repo is Apache-2.0.

## Git workflow & branch protection

`main` mirrors `origin/main` — never commit to it directly. On 2026-06-17 a local
`main` diverged into an *unrelated history* (88 local vs 469 remote commits) and a
`git reset --hard` then failed on Windows because tracked sweep filenames exceeded
the 260-char `MAX_PATH` limit. These rules keep that from recurring.

Per-clone setup (run once):

```bash
git config pull.ff only # never create surprise merge commits on pull
git config fetch.prune true # drop deleted remote branches
git config push.default simple
git config core.hooksPath .githooks # enable the tracked pre-push guard
git config core.longpaths true # tolerate long paths on Windows (belt-and-braces)
```

Day-to-day:

```bash
git fetch --prune origin
git switch main && git reset --hard origin/main # main is read-only; just track origin
git switch -c feat/<topic> # do all work on feature branches
# ... commit ...
git fetch origin && git rebase origin/main # stay based on origin/main
git push -u origin feat/<topic> # then open a PR
```

The tracked `.githooks/pre-push` hook blocks direct pushes to `main` and refuses
to push a branch that isn't a descendant of `origin/main`. Never use
`git pull --allow-unrelated-histories`.

**GitHub settings** (repo admin, Settings → Branches → add rule for `main`):
require a PR before merging, require status checks (`lint`, `repo-hygiene`,
`test-python-smoke`) to pass, require linear history, and disallow force-pushes
and deletions. Apply to administrators too.

## License

By contributing, you agree that your contributions are licensed under the
Expand Down
Loading
Loading