regit: put a lost .git back, without touching the files¶
The problem¶
A folder gets copied without its .git: a sync that skips dot-folders, a
flattened project tree, a zip, a file-by-file restore. The files survive; the
history and the remote do not. The copy may also hold edits that exist nowhere
else. Cloning fresh and copying over mixes in deleted files; reset --hard
destroys the edits; committing everything and merging buries what differs.
The method¶
Load upstream into the index, never the working tree. read-tree makes
git believe the folder is a checkout of upstream's tip while not one byte on
disk moves. git add -A then stages exactly the difference.
- Nothing differs: point upstream's branch at the tip and switch to it. A clean checkout, tracking set, files untouched.
- Something differs: secrets scan, then one commit on a new branch whose parent is upstream's tip. Upstream's branch is never moved; nothing is pushed.
- Ask the server for the default branch (
ls-remote --symref): a fresh fetch never setsorigin/HEAD, so reading it guessesmainand fails onmasterortrunk. - Name the git dir on every call, so a folder inside another repo is not
judged, or staged, by the parent's
.git.
Sample¶
git init -q "$dir"
git -C "$dir" remote add origin "$url"
git -C "$dir" fetch -q origin "+refs/heads/$branch:refs/remotes/origin/$branch"
sha=$(git -C "$dir" rev-parse "origin/$branch")
env GIT_INDEX_FILE="$idx" git -C "$dir" read-tree "$sha" # index only
env GIT_INDEX_FILE="$idx" git -C "$dir" add -A # stage the difference
env GIT_INDEX_FILE="$idx" git -C "$dir" diff-index --cached --quiet "$sha" \
&& echo identical || echo "commit on local-$(date +%F)"
env rather than GIT_INDEX_FILE=... myfunc: in POSIX sh an assignment in
front of a shell function may outlive the call, and the later commit reads a
missing index and records an empty tree.
Use it:
regit --dry-run myproject https://example.com/me/myproject.git # writes nothing
regit myproject https://example.com/me/myproject.git
Limits¶
- Only for folders with no history: a
.gitwith commits is refused. - An existing remote with another URL is refused, not overwritten.
- Ignored files are neither compared nor committed.
Code¶
methods/regit/ in the methods repository: POSIX sh and
git, a README and a 50-check test (bash's sh mode and dash). Tried live on a
copy of a public repo with no .git: 27 local differences became one commit on
local-2026-11-01 whose parent is the published tip; the published branch was
not touched.