--- license: mit language: - en pipeline_tag: text-classification --- # git-commits-sorter Classify raw git commit messages into categories (`bugfix`, `feature`, `chore`, `docs`, `refactor`, etc.) using a hybrid ML pipeline: TF-IDF + metadata → SVM / RF / CatBoost. ## Features - **Hybrid model** — combines TF-IDF on the message text with numeric features (files changed, additions, deletions, test/doc/src counts) and categorical features (file extensions, directories) - **Multiple classifiers** — LinearSVC, LogisticRegression, RandomForest, CatBoost, XGBoost - **CPU & GPU** — `--gpu` flag enables cuML / CatBoost GPU / XGBoost GPU automatically - **Auto-labeled dataset** — 83% of raw commits automatically labeled via conventional commit prefixes, gitmoji, and keyword heuristics - **Resumable scraping** — GitHub commit scraper with exponential backoff, progress persistence, and connection error resilience ## Pipeline ``` parser.py → GitHub API → commits.jsonl (resilient scraping) build_dataset.py → commits.jsonl → dataset.jsonl (auto-label + feature extraction) train.py → dataset.jsonl → model.joblib (train & save) predict.py → model.joblib → label (inference CLI) commitsorter.py → CommitClassifier class (library API) ``` ## Usage ### CLI ```bash # single prediction python predict.py "fix broad phase crash" 3 45 12 # positional args: message [files_count] [additions] [deletions] python predict.py "bump lodash to 2.1" # batch via stdin echo '{"text":"fix crash","files_count":2} {"text":"add login page","files_count":5,"additions":200}' | python predict.py --stdin ``` ### Library ```python from commitsorter import CommitClassifier clf = CommitClassifier("model.joblib") label, scores = clf.sort("fix renderer crash", files_count=2, additions=10) # → ("bugfix", [("bugfix", 0.77), ("chore", 0.11), ...]) results = clf.sort_batch([ {"text": "update dependencies", "files_count": 1}, {"text": "add user auth", "files_count": 5, "additions": 200}, ]) ``` ### Training ```bash # single model (default: SVM) python train.py svm python train.py lr python train.py rf python train.py cb python train.py xgb # tournament — compare all models python train.py --all # GPU acceleration (requires cuML / CUDA) python train.py svm --gpu python train.py --all --gpu ``` ## Dataset features Each training sample: | Field | Type | Description | |---|---|---| | `text` | string | Commit message (prefix stripped) | | `files_count` | int | Number of files changed | | `additions` | int | Lines added | | `deletions` | int | Lines deleted | | `changed_tests` | int | Test files touched | | `changed_docs` | int | Doc files touched | | `changed_source` | int | Source files touched | | `has_tests` | bool | Any file in a test directory | | `has_docs` | bool | Any file in a docs directory | | `extensions` | [string] | Unique file extensions | | `directories` | [string] | Unique top-level directories | | `label` | string | Target class | ## Model: TF-IDF + metadata ``` commit message ──→ TF-IDF(10k unigrams+bigrams) file metadata ──→ StandardScaler extensions ──→ OneHotEncoder directories ──→ OneHotEncoder ↓ ColumnTransformer ↓ LinearSVC / RF / CatBoost / XGBoost ``` Best result: **LinearSVC at 79% accuracy** on held-out test set. ## Supported labels | Label | Heuristics | |---|---| | `bugfix` | `fix:`, `:bug:`, "crash", "prevent" | | `feature` | `feat:`, `:sparkles:`, "add", "implement" | | `chore` | `chore:`, "bump", "update", "lint" | | `docs` | `docs:`, file-only docs/, `.md` | | `refactor` | `refactor:`, "cleanup", "remove", "rename" | | `test` | `test:`, file-only spec/ or test/ | | `build` | `build:`, "upgrade", dependency changes | | `ci` | `ci:`, CI config changes | | `perf` | `perf:`, "optimize" | | `style` | `style:`, "format", "prettier" | | `revert` | `revert:` | ## Data scraping ```bash # needs GITHUB_TOKEN in .env python parser.py ``` Collects commits from configured repos into `commits.jsonl`. Resumes on interrupt via `progress.json`.