Skip to content

Commit

Permalink
checkout: checkout-index, improve rev-parse, symbolic-ref
Browse files Browse the repository at this point in the history
  • Loading branch information
Joe Mou committed Apr 19, 2019
1 parent 8d97fcd commit 52b1d99
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 15 deletions.
15 changes: 15 additions & 0 deletions checkout
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash -e

if [[ $1 == -b ]]; then
./branch $2
shift
fi
revision=$1
tree=$(./rev-parse $revision^{tree})
./read-tree $tree
./checkout-index
if [[ -f .zit/refs/heads/$revision ]]; then
./symbolic-ref HEAD refs/heads/$revision
else
echo "You are in 'detached HEAD' state." >&2
fi
33 changes: 33 additions & 0 deletions checkout-index
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/python

import os
import struct
import subprocess

# TODO dedup w/ write-tree
index = open('.zit/index').read()
assert index[0:4] == 'DIRC'
assert struct.unpack('>I', index[4:8]) == (2,)
num_entries, = struct.unpack('>I', index[8:12])
entries = []
i = 12
for _ in range(num_entries):
# ignore inode heuristics, file/symlink bit, permissions
i += 40
sha1 = index[i:i+20].encode('hex')
# just use NUL-terminated?
name_length = struct.unpack('>H', index[i+20:i+22])[0] & 0xfff
name = index[i+22:i+22+name_length]
i += (22 + name_length + 8) / 8 * 8
entries.append((name, sha1))

# entry.c:checkout_entry
for filename, sha1 in entries:
assert not filename.startswith('/')
assert '..' not in filename
# TODO unlink directories?
if os.path.exists(filename):
os.unlink(filename)
subprocess.check_call(['mkdir', '-p', './' + os.path.dirname(filename)])
# TODO git 1.0 doesn't seem to unlink deleted files
subprocess.check_call(['./cat-file', 'blob', sha1], stdout=open(filename, 'w'))
11 changes: 11 additions & 0 deletions get-sha1-basic
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash -e

# sha1_name.c:get_sha1_basic
if [[ ${#1} -eq 40 ]]; then
echo $1
else
cat .zit/$(./symbolic-ref $1) 2> /dev/null || \
cat .zit/$(./symbolic-ref refs/$1) 2> /dev/null || \
cat .zit/$(./symbolic-ref refs/tags/$1) 2> /dev/null || \
cat .zit/$(./symbolic-ref refs/heads/$1)
fi
45 changes: 36 additions & 9 deletions rev-parse
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
#!/bin/bash -e
#!/usr/bin/python
# only implements --verify

import subprocess
import sys

# sha1_name.c:get_sha1
def get_sha1(name):
# TODO ^ and ~?
# TODO specialize for tree?
if '^' in name:
name, type = name.rsplit('^', 1)
assert type[0] == '{' and type[-1] == '}'
type = type[1:-1]
while True:
sha1 = get_sha1(name)

# TODO dedup w/ cat-file
import zlib
# sha1_file.c:sha1_file_name
filename = '.zit/objects/{}/{}'.format(sha1[:2], sha1[2:])
decompressed = zlib.decompress(open(filename).read())
header, contents = decompressed.split('\0', 1)
actual_type, length = header.split(' ')

if actual_type == type:
return sha1
elif actual_type == 'commit':
assert int(length) == len(contents)
tree = next(line for line in contents.split('\n')
if line.startswith('tree '))
name = tree.split(' ')[1]
# TODO deref tags?
else:
raise Exception('wrong type')
else:
return subprocess.check_output(['./get-sha1-basic', name])[:-1]

if [[ ${#1} -eq 40 ]]; then
echo $1
else
cat .zit/$(./symbolic-ref $1) 2> /dev/null || \
cat .zit/$(./symbolic-ref refs/$1) 2> /dev/null || \
cat .zit/$(./symbolic-ref refs/tags/$1) 2> /dev/null || \
cat .zit/$(./symbolic-ref refs/heads/$1)
fi
_, name = sys.argv
print get_sha1(name)
17 changes: 11 additions & 6 deletions symbolic-ref
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
#!/bin/bash -e

# refs.c:resolve_ref
path=.zit/$1
while grep -q '^ref: ' $path 2> /dev/null; do
path=.zit/$(cut -d' ' -f2 < $path)
done
echo $path | cut -d/ -f2-
if [[ $# == 2 ]]; then
# refs.c:create_symref
echo "ref: $2" > .zit/$1
elif [[ $# == 1 ]]; then
# refs.c:resolve_ref
path=.zit/$1
while grep -q '^ref: ' $path 2> /dev/null; do
path=.zit/$(cut -d' ' -f2 < $path)
done
echo $path | cut -d/ -f2-
fi

0 comments on commit 52b1d99

Please sign in to comment.