Fix scope and observe three references
The complete laboratory below creates a bare remote and two clones, A and B, inside a temporary directory. It permits only file transport, ignores global and system configuration and uses an empty hooks directory. It does not use the project origin or a hosted service. A creates O; B obtains O, creates C and publishes C to the local remote. Before any fetch, A origin/main still points to O. A then creates L from O. Draw O with two descendants, C and L, and identify A HEAD, A origin/main and remote main at each moment. The drawing avoids treating three references as one reality. Save the code as run.py and execute with Python 3.13 in the stated environment. The runner requires /usr/bin/git reporting version 2.50.1 Apple Git-155.
Measure rejection and the effect of fetch
The ordinary push of L is rejected because the remote already contains C. The runner checks the exit status and reads the remote reference again to confirm C remains intact. It then fetches in A: origin/main moves to C, but HEAD and value.txt remain at L. The main...origin/main symmetric-difference count is one exclusive commit on each side. These results do not imply a textual conflict or assess either change quality. They only describe divergence precisely before choosing integration. In a fictional support situation, one operator may have a hotfix ready while another has published a batch change. A useful first step is identifying both contents and their consumers rather than repeatedly attempting the same push. The functional decision remains outside the object-transfer mechanism.
Distinguish concurrency condition and preservation
The exercise then tries an explicit lease against O even though fetch has updated origin/main to C. The attempt is rejected and the remote remains at C. To demonstrate the protection boundary, the script authorizes a rewrite only on its disposable remote, supplying C as the expected value. The update to L is accepted. Immediately afterward, an ancestry query confirms C is not an ancestor of L. Accepting the condition therefore does not establish inclusion of replaced work. In the Anchor case, a review against O does not automatically cover C. If the reference changed, review the new history before renewing the decision. Do not merely change the expected value to eliminate the error. A hosted service also has permissions, protection rules and checks that this laboratory does not execute.
Clean references with explicit scope
The final collaboration section creates temporary on the remote. B fetches the reference, creates retained locally and saves a local-only tag. After temporary is deleted remotely, B still sees origin/temporary until fetch --prune runs. With the normal clone refspec used here, the tracking reference disappears; retained and local-only still point to O. Do not generalize this result to options adding tag pruning or to mirror configurations. The Cedar case asks for precisely that scope review. The runner ends with twenty-four checks that also include the bisect experiments in the next lesson. It removes temporary repositories on exit. Observations apply to the executed binary; current inspected documentation belongs to the 2.56 line. No testing involved authentication, server hooks, branch protection or real applications.
"""DR original local Git experiments. Python 3.13 and Apple Git 2.50.1.
Run: python3 run.py
All repositories, remote refs and rewrites are disposable and local.
No project repositories, network hosts, credentials or personal Git config.
"""
import hashlib
import json
import os
from pathlib import Path
import subprocess
import sys
import tempfile
GIT = '/usr/bin/git'
version = subprocess.check_output([GIT, '--version'], text=True).strip
assert version == 'git version 2.50.1 (Apple Git-155)', version
checks = []
def check(name, value):
assert value, name
checks.append(name)
with tempfile.TemporaryDirectory(prefix='dr-git-diagnosis-') as directory:
root = Path(directory)
hooks = root / 'empty-hooks'
hooks.mkdir
template = root / 'empty-template'
template.mkdir
env = {k: v for k, v in os.environ.items if not k.startswith('GIT_')}
env.update(GIT_CONFIG_NOSYSTEM='1', GIT_CONFIG_GLOBAL=os.devnull,
GIT_ALLOW_PROTOCOL='file', GIT_TERMINAL_PROMPT='0',
GIT_AUTHOR_NAME='DR Synthetic', GIT_AUTHOR_EMAIL='lab@example.test',
GIT_COMMITTER_NAME='DR Synthetic', GIT_COMMITTER_EMAIL='lab@example.test',
GIT_AUTHOR_DATE='2026-10-03T12:00:00+00:00',
GIT_COMMITTER_DATE='2026-10-03T12:00:00+00:00', LC_ALL='C')
base = [GIT, '-c', 'core.hooksPath=' + str(hooks), '-c', 'commit.gpgSign=false',
'-c', 'tag.gpgSign=false', '-c', 'init.templateDir=' + str(template),
'-c', 'core.autocrlf=false', '-c', 'core.fsmonitor=false']
def command(repo, *args, ok=True):
result = subprocess.run(base + list(args), cwd=repo, env=env,
capture_output=True, text=True, timeout=15)
if ok and result.returncode:
raise AssertionError((args, result.returncode, result.stdout, result.stderr))
return result
def text(repo, *args):
return command(repo, *args).stdout.strip
def commit(repo, value, message):
(repo / 'value.txt').write_text(value + '\n')
command(repo, 'add', 'value.txt')
command(repo, 'commit', '-m', message)
return text(repo, 'rev-parse', 'HEAD')
remote = root / 'remote.git'
command(root, 'init', '--bare', '--initial-branch=main', str(remote))
a = root / 'a'
b = root / 'b'
command(root, 'clone', str(remote), str(a))
original = commit(a, 'base', 'initial synthetic state')
command(a, 'push', 'origin', 'main')
command(root, 'clone', str(remote), str(b))
concurrent = commit(b, 'concurrent', 'colleague synthetic change')
command(b, 'push', 'origin', 'main')
check('remote: tracking ref remains stale until fetch', text(a, 'rev-parse', 'origin/main') == original)
local = commit(a, 'local', 'independent synthetic change')
rejection = command(a, 'push', 'origin', 'main', ok=False)
check('remote: ordinary divergent push is rejected', rejection.returncode!= 0)
check('remote: rejected push preserves remote tip', text(remote, 'rev-parse', 'main') == concurrent)
command(a, 'fetch', 'origin')
check('fetch: remote-tracking ref advances', text(a, 'rev-parse', 'origin/main') == concurrent)
check('fetch: current branch and worktree remain local',
text(a, 'rev-parse', 'HEAD') == local and (a / 'value.txt').read_text == 'local\n')
check('fetch: symmetric difference contains one commit per side',
text(a, 'rev-list', '--left-right', '--count', 'main...origin/main').split == ['1', '1'])
stale = command(a, 'push', '--force-with-lease=refs/heads/main:' + original,
'origin', 'HEAD:refs/heads/main', ok=False)
check('lease: explicit old expectation rejects after fetch', stale.returncode!= 0)
check('lease: stale expectation leaves colleague tip intact', text(remote, 'rev-parse', 'main') == concurrent)
# Deliberately authorized rewrite of only this disposable local remote.
command(a, 'push', '--force-with-lease=refs/heads/main:' + concurrent,
'origin', 'HEAD:refs/heads/main')
check('lease: matching expectation permits this local rewrite', text(remote, 'rev-parse', 'main') == local)
check('lease: accepted rewrite need not include overwritten commit',
command(a, 'merge-base', '--is-ancestor', concurrent, local, ok=False).returncode == 1)
command(a, 'branch', 'temporary', original)
command(a, 'push', 'origin', 'temporary')
command(b, 'fetch', 'origin')
command(b, 'branch', 'retained', 'origin/temporary')
command(b, 'tag', 'local-only', original)
command(a, 'push', 'origin', '--delete', 'temporary')
check('prune: deleted remote branch initially remains in tracking refs',
text(b, 'rev-parse', 'origin/temporary') == original)
command(b, 'fetch', '--prune', 'origin')
check('prune: default clone refspec removes stale remote-tracking ref',
command(b, 'show-ref', '--verify', '--quiet', 'refs/remotes/origin/temporary', ok=False).returncode == 1)
check('prune: local branch remains', text(b, 'rev-parse', 'retained') == original)
check('prune: local-only tag remains without tag refspec', text(b, 'rev-parse', 'local-only') == original)
history = root / 'history'
command(root, 'init', '--initial-branch=main', str(history))
commits = []
for n in range(9):
(history / 'sample.json').write_text(json.dumps({'revision': n, 'result': 'bad' if n >= 5 else 'good'}))
command(history, 'add', 'sample.json')
command(history, 'commit', '-m', 'synthetic revision ' + str(n))
commits.append(text(history, 'rev-parse', 'HEAD'))
oracle = root / 'oracle.py'
oracle.write_text("import json,sys\nfrom pathlib import Path\nr=json.loads(Path('sample.json').read_text)\n"
"mode=sys.argv[1]\n"
"if mode=='abort': sys.exit(128)\n"
"if mode=='skip' and r['revision'] in (4,5,6): sys.exit(125)\n"
"sys.exit(1 if r['result']=='bad' else 0)\n")
good_result = subprocess.run([sys.executable, str(oracle), 'normal'], cwd=history,
capture_output=True)
check('bisect: bad endpoint fails original oracle', good_result.returncode == 1)
command(history, 'switch', '--detach', commits[0])
good_result = subprocess.run([sys.executable, str(oracle), 'normal'], cwd=history,
capture_output=True)
check('bisect: good endpoint passes original oracle', good_result.returncode == 0)
command(history, 'switch', 'main')
command(history, 'bisect', 'start', commits[8], commits[0])
command(history, 'bisect', 'run', sys.executable, str(oracle), 'normal')
check('bisect: stable oracle identifies revision five', text(history, 'rev-parse', 'refs/bisect/bad') == commits[5])
log = text(history, 'bisect', 'log')
check('bisect: log records observed endpoints and conclusion', commits[0] in log and commits[8] in log and commits[5] in log)
logfile = root / 'bisect.log'
logfile.write_text(log + '\n')
command(history, 'bisect', 'reset')
check('bisect: reset returns to original branch and tip',
text(history, 'symbolic-ref', '--short', 'HEAD') == 'main' and text(history, 'rev-parse', 'HEAD') == commits[8])
command(history, 'bisect', 'replay', str(logfile))
check('bisect: replay reconstructs recorded conclusion', text(history, 'rev-parse', 'refs/bisect/bad') == commits[5])
command(history, 'bisect', 'reset')
command(history, 'bisect', 'start', commits[8], commits[0])
skipped = command(history, 'bisect', 'run', sys.executable, str(oracle), 'skip', ok=False)
output = skipped.stdout + skipped.stderr
candidates = [n for n, oid in enumerate(commits) if oid in output]
# The unresolved boundary contains skipped revisions 4,5,6 and tested-bad 7.
check('bisect: skipping boundary prevents a unique conclusion', skipped.returncode!= 0 and 'first bad commit could be any of' in output)
check('bisect: ambiguous output includes actual culprit and adjacent candidates',
all(commits[n] in output for n in (4,5,6,7)))
command(history, 'bisect', 'reset')
command(history, 'bisect', 'start', commits[8], commits[0])
aborted = command(history, 'bisect', 'run', sys.executable, str(oracle), 'abort', ok=False)
check('bisect: oracle status 128 aborts automation', aborted.returncode!= 0 and '128' in aborted.stdout + aborted.stderr)
command(history, 'bisect', 'reset')
check('bisect: final worktree is clean and main restored',
text(history, 'status', '--porcelain') == '' and text(history, 'symbolic-ref', '--short', 'HEAD') == 'main')
print(json.dumps({'version': version, 'checks_passed': len(checks), 'checks': checks,
'scope': 'Disposable local repositories and a file-transport bare remote only. '
'No network hosting, credentials, production application, branch protection, '
'server hooks or Git 2.56 runtime tested.',
'sourceSha256': hashlib.sha256(Path(__file__).read_bytes).hexdigest}, indent=2))
After fetch, A keeps L and observes C at origin/main. A lease against O fails; a lease against C permits a replacement that does not include C.
Common pitfalls
Updating a lease without reviewing the new commit; treating fetch as integration; generalizing normal pruning to tags; confusing a local remote with real hosting.
Related topics: States and index · Integration and backports · Reproducible diagnosis
Compare references before and after the operation and record the content the decision intends to preserve.
Reference: Git manual and original DR local experiment evidence · Git 2.56; workflow concepts compatible with modern Git 2.x