mirror of
https://github.com/git-learning-game/oh-my-git.git
synced 2024-11-03 19:04:40 +01:00
Convert "internal" levels to new level format
This commit is contained in:
parent
613b1b9852
commit
53a6885ef9
108 changed files with 727 additions and 382 deletions
26
levels/internals/basics
Normal file
26
levels/internals/basics
Normal file
|
@ -0,0 +1,26 @@
|
|||
[description]
|
||||
|
||||
For this prototype, we assume you have some experience with the command line. Here are some commands that will be useful:
|
||||
|
||||
- ls
|
||||
- echo content > file
|
||||
- cat file
|
||||
- mkdir dir
|
||||
|
||||
Find the riddle in your current directory and put the answer into the file "answer"!
|
||||
|
||||
[congrats]
|
||||
|
||||
Omnomnom!
|
||||
|
||||
For technical reasons, you can't use `cd` in this prototype yet. But there won't be a lot of interaction with the file system anyways. :)
|
||||
|
||||
[setup]
|
||||
|
||||
mkdir riddle
|
||||
echo "ppl p" > riddle/consonants
|
||||
echo "ae ie" > riddle/vowels
|
||||
|
||||
[win]
|
||||
|
||||
cat answer | grep -i "apple \\?pie"
|
|
@ -1,3 +0,0 @@
|
|||
Omnomnom!
|
||||
|
||||
For technical reasons, you can't use `cd` in this prototype yet. But there won't be a lot of interaction with the file system anyways. :)
|
|
@ -1,8 +0,0 @@
|
|||
For this prototype, we assume you have some experience with the command line. Here are some commands that will be useful:
|
||||
|
||||
- ls
|
||||
- echo content > file
|
||||
- cat file
|
||||
- mkdir dir
|
||||
|
||||
Find the riddle in your current directory and put the answer into the file "answer"!
|
|
@ -1,3 +0,0 @@
|
|||
mkdir riddle
|
||||
echo "ppl p" > riddle/consonants
|
||||
echo "ae ie" > riddle/vowels
|
|
@ -1 +0,0 @@
|
|||
cat answer | grep -i "apple \\?pie"
|
38
levels/internals/blob-create
Normal file
38
levels/internals/blob-create
Normal file
|
@ -0,0 +1,38 @@
|
|||
[description]
|
||||
|
||||
At its core, Git is very simple. It stores "objects", which are basically files identified by an "identifier" (short: ID).
|
||||
|
||||
There are four types of objects: blobs, trees, commits, and tags. The simplest type is a "blob", which is just a piece of text.
|
||||
|
||||
Let's create some blobs! To do that, create a file with the desired content, and then use
|
||||
|
||||
git hash-object -w <file>
|
||||
|
||||
The flag -w means "write", and tells Git to actually write the new blob to the disk.
|
||||
|
||||
Create three new blobs!
|
||||
|
||||
[congrats]
|
||||
|
||||
Tip: You can also use a command like this to create a blob in a single line:
|
||||
|
||||
echo "awesome content" | git hash-object -w --stdin
|
||||
|
||||
Did you already notice that you can drag and drop all objects? :)
|
||||
|
||||
[setup]
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo "Hi" > file1
|
||||
echo "Ho" > file2
|
||||
echo "Hu" > file3
|
||||
git hash-object -w file1
|
||||
git hash-object -w file2
|
||||
git hash-object -w file3
|
||||
|
||||
[win]
|
||||
|
||||
BLOB_COUNT=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep blob | wc -l)
|
||||
|
||||
test "$BLOB_COUNT" -gt 2
|
|
@ -1,5 +0,0 @@
|
|||
Tip: You can also use a command like this to create a blob in a single line:
|
||||
|
||||
echo "awesome content" | git hash-object -w --stdin
|
||||
|
||||
Did you already notice that you can drag and drop all objects? :)
|
|
@ -1,11 +0,0 @@
|
|||
At its core, Git is very simple. It stores "objects", which are basically files identified by an "identifier" (short: ID).
|
||||
|
||||
There are four types of objects: blobs, trees, commits, and tags. The simplest type is a "blob", which is just a piece of text.
|
||||
|
||||
Let's create some blobs! To do that, create a file with the desired content, and then use
|
||||
|
||||
git hash-object -w <file>
|
||||
|
||||
The flag -w means "write", and tells Git to actually write the new blob to the disk.
|
||||
|
||||
Create three new blobs!
|
|
@ -1,6 +0,0 @@
|
|||
echo "Hi" > file1
|
||||
echo "Ho" > file2
|
||||
echo "Hu" > file3
|
||||
git hash-object -w file1
|
||||
git hash-object -w file2
|
||||
git hash-object -w file3
|
|
@ -1,3 +0,0 @@
|
|||
BLOB_COUNT=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep blob | wc -l)
|
||||
|
||||
test "$BLOB_COUNT" -gt 2
|
27
levels/internals/blob-remove
Normal file
27
levels/internals/blob-remove
Normal file
|
@ -0,0 +1,27 @@
|
|||
[description]
|
||||
|
||||
There's a simple command to remove all objects that are not referenced by anything:
|
||||
|
||||
git prune
|
||||
|
||||
Remove all blobs in this repository.
|
||||
|
||||
[congrats]
|
||||
|
||||
Generally, `git prune` will be useful if you want to clean up some objects you made.
|
||||
|
||||
Alternatively, you can also click the "Reload" button to restart a level.
|
||||
|
||||
[setup]
|
||||
|
||||
echo "My master password is a1b2c3d4e5" | git hash-object -w --stdin
|
||||
echo "This blob really should not exist" | git hash-object -w --stdin
|
||||
echo "This is a virus" | git hash-object -w --stdin
|
||||
|
||||
[setup goal]
|
||||
|
||||
[win]
|
||||
|
||||
OBJECT_COUNT=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | wc -l)
|
||||
|
||||
test "$OBJECT_COUNT" -eq 0
|
|
@ -1,3 +0,0 @@
|
|||
Generally, `git prune` will be useful if you want to clean up some objects you made.
|
||||
|
||||
Alternatively, you can also click the "Reload" button to restart a level.
|
|
@ -1,5 +0,0 @@
|
|||
There's a simple command to remove all objects that are not referenced by anything:
|
||||
|
||||
git prune
|
||||
|
||||
Remove all blobs in this repository.
|
|
@ -1 +0,0 @@
|
|||
git prune
|
|
@ -1,3 +0,0 @@
|
|||
echo "My master password is a1b2c3d4e5" | git hash-object -w --stdin
|
||||
echo "This blob really should not exist" | git hash-object -w --stdin
|
||||
echo "This is a virus" | git hash-object -w --stdin
|
|
@ -1,3 +0,0 @@
|
|||
OBJECT_COUNT=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | wc -l)
|
||||
|
||||
test "$OBJECT_COUNT" -eq 0
|
37
levels/internals/commit-create
Normal file
37
levels/internals/commit-create
Normal file
|
@ -0,0 +1,37 @@
|
|||
[description]
|
||||
|
||||
So a tree describes a directory structure at a specific point in time.
|
||||
|
||||
It would be nice if we could remember when that state existed, and who authored it, right?
|
||||
|
||||
Enter: commits. They are objects that point to a tree and contain some additional metadata. You can create a commit using
|
||||
|
||||
git commit-tree <tree> -m "Description of your commit"
|
||||
|
||||
Make a commit from the tree in this repository!
|
||||
|
||||
[setup]
|
||||
|
||||
touch empty_file
|
||||
git add .
|
||||
git write-tree
|
||||
|
||||
rm empty_file
|
||||
git update-index --remove empty_file
|
||||
|
||||
[setup goal]
|
||||
|
||||
touch empty_file
|
||||
git add .
|
||||
git write-tree
|
||||
|
||||
rm empty_file
|
||||
git update-index --remove empty_file
|
||||
|
||||
git commit-tree 3185 -m 'Clever commit message'
|
||||
|
||||
[win]
|
||||
|
||||
COMMIT_COUNT=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep commit | wc -l)
|
||||
|
||||
test "$COMMIT_COUNT" -gt 0
|
|
@ -1,9 +0,0 @@
|
|||
So a tree describes a directory structure at a specific point in time.
|
||||
|
||||
It would be nice if we could remember when that state existed, and who authored it, right?
|
||||
|
||||
Enter: commits. They are objects that point to a tree and contain some additional metadata. You can create a commit using
|
||||
|
||||
git commit-tree <tree> -m "Description of your commit"
|
||||
|
||||
Make a commit from the tree in this repository!
|
|
@ -1 +0,0 @@
|
|||
git commit-tree 3185 -m 'Clever commit message'
|
|
@ -1,6 +0,0 @@
|
|||
touch empty_file
|
||||
git add .
|
||||
git write-tree
|
||||
|
||||
rm empty_file
|
||||
git update-index --remove empty_file
|
|
@ -1,3 +0,0 @@
|
|||
COMMIT_COUNT=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep commit | wc -l)
|
||||
|
||||
test "$COMMIT_COUNT" -gt 0
|
31
levels/internals/commit-parents
Normal file
31
levels/internals/commit-parents
Normal file
|
@ -0,0 +1,31 @@
|
|||
[description]
|
||||
|
||||
When using the commit-tree command, you can optionally specify a parent:
|
||||
|
||||
git commit-tree <tree> -m "Description" -p <parent commit>
|
||||
|
||||
Make a string of three commits!
|
||||
|
||||
Hint: You'll need a tree object. What could be the easiest way to obtain one?
|
||||
|
||||
[setup]
|
||||
|
||||
[setup goal]
|
||||
|
||||
git write-tree
|
||||
FIRST_COMMIT=$(git commit-tree 4b82 -m 'First commit :O')
|
||||
SECOND_COMMIT=$(git commit-tree 4b82 -p $FIRST_COMMIT -m 'Second commit :D')
|
||||
THIRD_COMMIT=$(git commit-tree 4b82 -p $SECOND_COMMIT -m 'Third commit \o/')
|
||||
|
||||
[win]
|
||||
|
||||
COMMITS=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep commit | cut -f1 -d" ")
|
||||
|
||||
for COMMIT in $COMMITS; do
|
||||
echo a commit named $COMMIT
|
||||
if [ $(git rev-list $COMMIT | wc -l) -ge 3 ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
|
@ -1,7 +0,0 @@
|
|||
When using the commit-tree command, you can optionally specify a parent:
|
||||
|
||||
git commit-tree <tree> -m "Description" -p <parent commit>
|
||||
|
||||
Make a string of three commits!
|
||||
|
||||
Hint: You'll need a tree object. What could be the easiest way to obtain one?
|
|
@ -1,4 +0,0 @@
|
|||
git write-tree
|
||||
FIRST_COMMIT=$(git commit-tree 4b82 -m 'First commit :O')
|
||||
SECOND_COMMIT=$(git commit-tree 4b82 -p $FIRST_COMMIT -m 'Second commit :D')
|
||||
THIRD_COMMIT=$(git commit-tree 4b82 -p $SECOND_COMMIT -m 'Third commit \o/')
|
|
@ -1,10 +0,0 @@
|
|||
COMMITS=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep commit | cut -f1 -d" ")
|
||||
|
||||
for COMMIT in $COMMITS; do
|
||||
echo a commit named $COMMIT
|
||||
if [ $(git rev-list $COMMIT | wc -l) -ge 3 ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
30
levels/internals/commit-rhombus
Normal file
30
levels/internals/commit-rhombus
Normal file
|
@ -0,0 +1,30 @@
|
|||
[description]
|
||||
|
||||
A commit can have multiple parents! You can specify the -p option multiple times, like this:
|
||||
|
||||
git commit-tree <tree> -m "Description" -p <parent1> -p <parent2>
|
||||
|
||||
Build a rhombus shape from commits, where two commits point to the same parent, and then a fourth commit points to both of them.
|
||||
|
||||
[setup]
|
||||
|
||||
[setup goal]
|
||||
|
||||
TREE=$(git write-tree)
|
||||
SOUTH=$(git commit-tree $TREE -m "South")
|
||||
EAST=$(git commit-tree $TREE -m "East" -p $SOUTH)
|
||||
WEST=$(git commit-tree $TREE -m "West" -p $SOUTH)
|
||||
NORTH=$(git commit-tree $TREE -m "Nort" -p $EAST -p $WEST)
|
||||
|
||||
[win]
|
||||
|
||||
COMMITS=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep commit | cut -f1 -d" ")
|
||||
|
||||
for COMMIT in $COMMITS; do
|
||||
# My first parent's parents has to be the same as my second parent's parent.
|
||||
if [ "$(git rev-parse --verify -q $COMMIT^1^)" = "$(git rev-parse --verify -q $COMMIT^2^)" ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
|
@ -1,5 +0,0 @@
|
|||
A commit can have multiple parents! You can specify the -p option multiple times, like this:
|
||||
|
||||
git commit-tree <tree> -m "Description" -p <parent1> -p <parent2>
|
||||
|
||||
Build a rhombus shape from commits, where two commits point to the same parent, and then a fourth commit points to both of them.
|
|
@ -1,5 +0,0 @@
|
|||
TREE=$(git write-tree)
|
||||
SOUTH=$(git commit-tree $TREE -m "South")
|
||||
EAST=$(git commit-tree $TREE -m "East" -p $SOUTH)
|
||||
WEST=$(git commit-tree $TREE -m "West" -p $SOUTH)
|
||||
NORTH=$(git commit-tree $TREE -m "Nort" -p $EAST -p $WEST)
|
|
@ -1,10 +0,0 @@
|
|||
COMMITS=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep commit | cut -f1 -d" ")
|
||||
|
||||
for COMMIT in $COMMITS; do
|
||||
# My first parent's parents has to be the same as my second parent's parent.
|
||||
if [ "$(git rev-parse --verify -q $COMMIT^1^)" = "$(git rev-parse --verify -q $COMMIT^2^)" ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
43
levels/internals/conflict
Normal file
43
levels/internals/conflict
Normal file
|
@ -0,0 +1,43 @@
|
|||
[description]
|
||||
|
||||
(This is not a real puzzle yet.)
|
||||
|
||||
Try merging the two branches together!
|
||||
|
||||
git merge <otherbranch>
|
||||
|
||||
[setup]
|
||||
|
||||
echo ? > bikeshed_color
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
|
||||
echo green > bikeshed_color
|
||||
git commit -a -m "My suggestion"
|
||||
|
||||
git switch -c alternative HEAD^
|
||||
echo blue > bikeshed_color
|
||||
git commit -a -m "This is way better"
|
||||
|
||||
git switch main
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo ? > bikeshed_color
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
|
||||
echo green > bikeshed_color
|
||||
git commit -a -m "My suggestion"
|
||||
|
||||
git switch -c alternative HEAD^
|
||||
echo blue > bikeshed_color
|
||||
git commit -a -m "This is way better"
|
||||
|
||||
git switch main
|
||||
|
||||
git merge alternative
|
||||
echo blue-green > bikeshed_color
|
||||
git add .
|
||||
git commit -m "Merge"
|
||||
git prune
|
|
@ -1,5 +0,0 @@
|
|||
(This is not a real puzzle yet.)
|
||||
|
||||
Try merging the two branches together!
|
||||
|
||||
git merge <otherbranch>
|
|
@ -1,5 +0,0 @@
|
|||
git merge alternative
|
||||
echo blue-green > bikeshed_color
|
||||
git add .
|
||||
git commit -m "Merge"
|
||||
git prune
|
|
@ -1,12 +0,0 @@
|
|||
echo ? > bikeshed_color
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
|
||||
echo green > bikeshed_color
|
||||
git commit -a -m "My suggestion"
|
||||
|
||||
git switch -c alternative HEAD^
|
||||
echo blue > bikeshed_color
|
||||
git commit -a -m "This is way better"
|
||||
|
||||
git switch main
|
37
levels/internals/index-add
Normal file
37
levels/internals/index-add
Normal file
|
@ -0,0 +1,37 @@
|
|||
[description]
|
||||
|
||||
Blobs usually represent the content of a file. But on their own, they don't have any metadata, not even a name!
|
||||
|
||||
Git has a very powerful concept to store metadata related to blobs: the index! It's a list that relates blobs to filenames and access permissions.
|
||||
|
||||
The most convenient option to add an entry to the index is via an existing file:
|
||||
|
||||
echo "my content" > file
|
||||
git update-index --add file
|
||||
|
||||
Add three entries to the index! For a bonus challenge: can you add a file that is inside of a directory, like "directory/file"?
|
||||
|
||||
[congrats]
|
||||
|
||||
There's another way to add an entry to the index directly:
|
||||
|
||||
git update-index --add --cacheinfo <mode>,<blobhash>,<name>
|
||||
|
||||
The first three numbers of the mode describe the type of the entry, "100" is a regular file.
|
||||
|
||||
The second three number describe the permissions. Only "644" (non-executable) and "755" (executable) are supported.
|
||||
|
||||
You can insert the hash of an object into the terminal by right-clicking on it! :)
|
||||
|
||||
[setup]
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
||||
|
||||
[win]
|
||||
|
||||
test "$(git ls-files | wc -l)" -ge 3
|
|
@ -1,9 +0,0 @@
|
|||
There's another way to add an entry to the index directly:
|
||||
|
||||
git update-index --add --cacheinfo <mode>,<blobhash>,<name>
|
||||
|
||||
The first three numbers of the mode describe the type of the entry, "100" is a regular file.
|
||||
|
||||
The second three number describe the permissions. Only "644" (non-executable) and "755" (executable) are supported.
|
||||
|
||||
You can insert the hash of an object into the terminal by right-clicking on it! :)
|
|
@ -1,10 +0,0 @@
|
|||
Blobs usually represent the content of a file. But on their own, they don't have any metadata, not even a name!
|
||||
|
||||
Git has a very powerful concept to store metadata related to blobs: the index! It's a list that relates blobs to filenames and access permissions.
|
||||
|
||||
The most convenient option to add an entry to the index is via an existing file:
|
||||
|
||||
echo "my content" > file
|
||||
git update-index --add file
|
||||
|
||||
Add three entries to the index! For a bonus challenge: can you add a file that is inside of a directory, like "directory/file"?
|
|
@ -1,4 +0,0 @@
|
|||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
|
@ -1 +0,0 @@
|
|||
test "$(git ls-files | wc -l)" -ge 3
|
29
levels/internals/index-remove
Normal file
29
levels/internals/index-remove
Normal file
|
@ -0,0 +1,29 @@
|
|||
[description]
|
||||
|
||||
To remove an entry from the index, use a command like this:
|
||||
|
||||
git update-index --force-remove <file>
|
||||
|
||||
Remove all entries from the index!
|
||||
|
||||
[setup]
|
||||
|
||||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
||||
|
||||
git update-index --force-remove file1
|
||||
git update-index --force-remove file2
|
||||
git update-index --force-remove file3
|
||||
|
||||
[win]
|
||||
|
||||
test "$(git ls-files | wc -l)" -eq 0
|
|
@ -1,5 +0,0 @@
|
|||
To remove an entry from the index, use a command like this:
|
||||
|
||||
git update-index --force-remove <file>
|
||||
|
||||
Remove all entries from the index!
|
|
@ -1,3 +0,0 @@
|
|||
git update-index --force-remove file1
|
||||
git update-index --force-remove file2
|
||||
git update-index --force-remove file3
|
|
@ -1,4 +0,0 @@
|
|||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
|
@ -1 +0,0 @@
|
|||
test "$(git ls-files | wc -l)" -eq 0
|
33
levels/internals/index-update
Normal file
33
levels/internals/index-update
Normal file
|
@ -0,0 +1,33 @@
|
|||
[description]
|
||||
|
||||
Instead of removing an entry from the index and adding one with the same name, you can also directly update that entry!
|
||||
|
||||
Put the content you want in a file with a matching name, and then run
|
||||
|
||||
git update-index <file>
|
||||
|
||||
This will create a new blob, and update the hash of the entry to that blob.
|
||||
|
||||
Update an entry in the index!
|
||||
|
||||
[setup]
|
||||
|
||||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
||||
|
||||
echo "new content" > file1
|
||||
git update-index file1
|
||||
|
||||
[win]
|
||||
|
||||
# This is not really a good test for the winning condition...
|
||||
test "$(git ls-files -s | git hash-object --stdin)" != "10c4b28623e7e44e09f5a596450a50ab7ac31fbe" -a "$(git ls-files | wc -l)" -eq 3
|
|
@ -1,9 +0,0 @@
|
|||
Instead of removing an entry from the index and adding one with the same name, you can also directly update that entry!
|
||||
|
||||
Put the content you want in a file with a matching name, and then run
|
||||
|
||||
git update-index <file>
|
||||
|
||||
This will create a new blob, and update the hash of the entry to that blob.
|
||||
|
||||
Update an entry in the index!
|
|
@ -1,2 +0,0 @@
|
|||
echo "new content" > file1
|
||||
git update-index file1
|
|
@ -1,4 +0,0 @@
|
|||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
|
@ -1,2 +0,0 @@
|
|||
# This is not really a good test for the winning condition...
|
||||
test "$(git ls-files -s | git hash-object --stdin)" != "10c4b28623e7e44e09f5a596450a50ab7ac31fbe" -a "$(git ls-files | wc -l)" -eq 3
|
44
levels/internals/puzzle-apocalypse
Normal file
44
levels/internals/puzzle-apocalypse
Normal file
|
@ -0,0 +1,44 @@
|
|||
[description]
|
||||
|
||||
Delete all objects in this repository using git commands only!
|
||||
|
||||
Useful commands:
|
||||
|
||||
git prune
|
||||
git fsck
|
||||
git reflog expire
|
||||
|
||||
Note: I'm not sure how to beat this level. :D
|
||||
|
||||
[setup]
|
||||
|
||||
echo foo > foo
|
||||
BLOB=$(git hash-object -w foo)
|
||||
echo bar > bar
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
echo blabber >> bar
|
||||
git commit -a -m "Second commit"
|
||||
git update-ref refs/important HEAD
|
||||
git update-ref refs/interesting "$BLOB"
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo foo > foo
|
||||
BLOB=$(git hash-object -w foo)
|
||||
echo bar > bar
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
echo blabber >> bar
|
||||
git commit -a -m "Second commit"
|
||||
git update-ref refs/important HEAD
|
||||
git update-ref refs/interesting "$BLOB"
|
||||
|
||||
TREE=$(git mktree)
|
||||
git read-tree $TREE
|
||||
rm -rf .git/refs/*
|
||||
rm -rf .git/objects/*
|
||||
|
||||
[win]
|
||||
|
||||
test "$(git cat-file --batch-check --batch-all-objects | wc -l)" -eq 0
|
|
@ -1,9 +0,0 @@
|
|||
Delete all objects in this repository using git commands only!
|
||||
|
||||
Useful commands:
|
||||
|
||||
git prune
|
||||
git fsck
|
||||
git reflog expire
|
||||
|
||||
Note: I'm not sure how to beat this level. :D
|
|
@ -1,4 +0,0 @@
|
|||
TREE=$(git mktree)
|
||||
git read-tree $TREE
|
||||
rm -rf .git/refs/*
|
||||
rm -rf .git/objects/*
|
|
@ -1,9 +0,0 @@
|
|||
echo foo > foo
|
||||
BLOB=$(git hash-object -w foo)
|
||||
echo bar > bar
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
echo blabber >> bar
|
||||
git commit -a -m "Second commit"
|
||||
git update-ref refs/important HEAD
|
||||
git update-ref refs/interesting "$BLOB"
|
|
@ -1 +0,0 @@
|
|||
test "$(git cat-file --batch-check --batch-all-objects | wc -l)" -eq 0
|
|
@ -1,3 +1,21 @@
|
|||
[description]
|
||||
|
||||
Create two trees pointing to the same blob!
|
||||
|
||||
[setup]
|
||||
|
||||
[setup goal]
|
||||
|
||||
BLOB=$(echo "I am precious" | git hash-object -w --stdin)
|
||||
git update-index --add --cacheinfo 100644,$BLOB,a
|
||||
git write-tree
|
||||
git update-index --force-remove a
|
||||
git update-index --add --cacheinfo 100644,$BLOB,b
|
||||
git write-tree
|
||||
git update-index --force-remove b
|
||||
|
||||
[win]
|
||||
|
||||
TREES=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep tree | cut -f1 -d" ")
|
||||
|
||||
ALL_TREE_CHILDREN=$(for TREE in $TREES; do
|
|
@ -1 +0,0 @@
|
|||
Create two trees pointing to the same blob!
|
|
@ -1,7 +0,0 @@
|
|||
BLOB=$(echo "I am precious" | git hash-object -w --stdin)
|
||||
git update-index --add --cacheinfo 100644,$BLOB,a
|
||||
git write-tree
|
||||
git update-index --force-remove a
|
||||
git update-index --add --cacheinfo 100644,$BLOB,b
|
||||
git write-tree
|
||||
git update-index --force-remove b
|
|
@ -1,3 +1,19 @@
|
|||
[description]
|
||||
|
||||
Construct a chain of three trees, which don't point to anything else.
|
||||
|
||||
This is hard! The `git mktree` command might be useful.
|
||||
|
||||
[setup]
|
||||
|
||||
[setup goal]
|
||||
|
||||
git mktree
|
||||
TREE=$(echo -e "040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\tdir" | git mktree)
|
||||
echo -e "040000 tree $TREE\tdir" | git mktree
|
||||
|
||||
[win]
|
||||
|
||||
TREES=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep tree | cut -f1 -d" ")
|
||||
|
||||
for TREE in $TREES; do
|
|
@ -1,3 +0,0 @@
|
|||
Construct a chain of three trees, which don't point to anything else.
|
||||
|
||||
This is hard! The `git mktree` command might be useful.
|
|
@ -1,3 +0,0 @@
|
|||
git mktree
|
||||
TREE=$(echo -e "040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\tdir" | git mktree)
|
||||
echo -e "040000 tree $TREE\tdir" | git mktree
|
42
levels/internals/ref-create
Normal file
42
levels/internals/ref-create
Normal file
|
@ -0,0 +1,42 @@
|
|||
[description]
|
||||
|
||||
Let's take a look at "refs" (short for "references")! Refs are not objects, but rather very simple *pointers* to objects! They can help you keep track of what's where.
|
||||
|
||||
You can create or update a ref with
|
||||
|
||||
git update-ref refs/<refname> <newvalue>
|
||||
|
||||
Make sure to always start a ref's name with "refs/"! That's a convention that helps Git find all refs you create. If you forget the "refs/", you will not see the ref.
|
||||
|
||||
Create refs that point to all objects in this repository!
|
||||
|
||||
[setup]
|
||||
|
||||
echo hello > hello
|
||||
echo world > world
|
||||
BLOB1=$(git hash-object -w hello)
|
||||
BLOB2=$(git hash-object -w world)
|
||||
git add .
|
||||
TREE=$(git write-tree)
|
||||
COMMIT=$(git commit-tree $TREE -m "Initial commit")
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo hello > hello
|
||||
echo world > world
|
||||
BLOB1=$(git hash-object -w hello)
|
||||
BLOB2=$(git hash-object -w world)
|
||||
git add .
|
||||
TREE=$(git write-tree)
|
||||
COMMIT=$(git commit-tree $TREE -m "Initial commit")
|
||||
|
||||
git update-ref refs/a $BLOB1
|
||||
git update-ref refs/b $BLOB2
|
||||
git update-ref refs/c $TREE
|
||||
git update-ref refs/d $COMMIT
|
||||
|
||||
[win]
|
||||
|
||||
OBJECTS=$(git cat-file --batch-check='%(objectname)' --batch-all-objects | sort)
|
||||
REF_TARGETS=$(git show-ref -s | sort | uniq)
|
||||
test "$OBJECTS" = "$REF_TARGETS"
|
|
@ -1,9 +0,0 @@
|
|||
Let's take a look at "refs" (short for "references")! Refs are not objects, but rather very simple *pointers* to objects! They can help you keep track of what's where.
|
||||
|
||||
You can create or update a ref with
|
||||
|
||||
git update-ref refs/<refname> <newvalue>
|
||||
|
||||
Make sure to always start a ref's name with "refs/"! That's a convention that helps Git find all refs you create. If you forget the "refs/", you will not see the ref.
|
||||
|
||||
Create refs that point to all objects in this repository!
|
|
@ -1,4 +0,0 @@
|
|||
git update-ref refs/a $BLOB1
|
||||
git update-ref refs/b $BLOB2
|
||||
git update-ref refs/c $TREE
|
||||
git update-ref refs/d $COMMIT
|
|
@ -1,7 +0,0 @@
|
|||
echo hello > hello
|
||||
echo world > world
|
||||
BLOB1=$(git hash-object -w hello)
|
||||
BLOB2=$(git hash-object -w world)
|
||||
git add .
|
||||
TREE=$(git write-tree)
|
||||
COMMIT=$(git commit-tree $TREE -m "Initial commit")
|
|
@ -1,3 +0,0 @@
|
|||
OBJECTS=$(git cat-file --batch-check='%(objectname)' --batch-all-objects | sort)
|
||||
REF_TARGETS=$(git show-ref -s | sort | uniq)
|
||||
test "$OBJECTS" = "$REF_TARGETS"
|
41
levels/internals/ref-move
Normal file
41
levels/internals/ref-move
Normal file
|
@ -0,0 +1,41 @@
|
|||
[description]
|
||||
|
||||
You can point refs to a new location using the same command you use to create them:
|
||||
|
||||
git update-ref refs/<refname> <object>
|
||||
|
||||
As an exercise, make all refs in this repository point to the tree object!
|
||||
|
||||
[setup]
|
||||
|
||||
echo hello > hello
|
||||
echo world > world
|
||||
BLOB1=$(git hash-object -w hello)
|
||||
BLOB2=$(git hash-object -w world)
|
||||
git add .
|
||||
TREE=$(git write-tree)
|
||||
COMMIT=$(git commit-tree $TREE -m "Initial commit")
|
||||
|
||||
git update-ref refs/a "$BLOB1"
|
||||
git update-ref refs/b "$COMMIT"
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo hello > hello
|
||||
echo world > world
|
||||
BLOB1=$(git hash-object -w hello)
|
||||
BLOB2=$(git hash-object -w world)
|
||||
git add .
|
||||
TREE=$(git write-tree)
|
||||
COMMIT=$(git commit-tree $TREE -m "Initial commit")
|
||||
|
||||
git update-ref refs/a "$BLOB1"
|
||||
git update-ref refs/b "$COMMIT"
|
||||
|
||||
for REF in $(git for-each-ref --format='%(refname)'); do
|
||||
git update-ref "$REF" "$TREE"
|
||||
done
|
||||
|
||||
[win]
|
||||
|
||||
test "$(git show-ref -s | sort -u)" = "c7863f72467ed8dd44f4b8ffdb8b57ca7d91dc9e"
|
|
@ -1,5 +0,0 @@
|
|||
You can point refs to a new location using the same command you use to create them:
|
||||
|
||||
git update-ref refs/<refname> <object>
|
||||
|
||||
As an exercise, make all refs in this repository point to the tree object!
|
|
@ -1,3 +0,0 @@
|
|||
for REF in $(git for-each-ref --format='%(refname)'); do
|
||||
git update-ref "$REF" "$TREE"
|
||||
done
|
|
@ -1,10 +0,0 @@
|
|||
echo hello > hello
|
||||
echo world > world
|
||||
BLOB1=$(git hash-object -w hello)
|
||||
BLOB2=$(git hash-object -w world)
|
||||
git add .
|
||||
TREE=$(git write-tree)
|
||||
COMMIT=$(git commit-tree $TREE -m "Initial commit")
|
||||
|
||||
git update-ref refs/a "$BLOB1"
|
||||
git update-ref refs/b "$COMMIT"
|
|
@ -1 +0,0 @@
|
|||
test "$(git show-ref -s | sort -u)" = "c7863f72467ed8dd44f4b8ffdb8b57ca7d91dc9e"
|
41
levels/internals/ref-remove
Normal file
41
levels/internals/ref-remove
Normal file
|
@ -0,0 +1,41 @@
|
|||
[description]
|
||||
|
||||
And finally, to delete a ref, use
|
||||
|
||||
git update-ref -d refs/<refname>
|
||||
|
||||
Delete all refs! :P (Well, except for HEAD. HEAD is special.)
|
||||
|
||||
[setup]
|
||||
|
||||
echo hello > hello
|
||||
echo world > world
|
||||
BLOB1=$(git hash-object -w hello)
|
||||
BLOB2=$(git hash-object -w world)
|
||||
git add .
|
||||
TREE=$(git write-tree)
|
||||
COMMIT=$(git commit-tree $TREE -m "Initial commit")
|
||||
|
||||
git update-ref refs/best_blob_ever "$BLOB1"
|
||||
git update-ref refs/beautiful_commit "$COMMIT"
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo hello > hello
|
||||
echo world > world
|
||||
BLOB1=$(git hash-object -w hello)
|
||||
BLOB2=$(git hash-object -w world)
|
||||
git add .
|
||||
TREE=$(git write-tree)
|
||||
COMMIT=$(git commit-tree $TREE -m "Initial commit")
|
||||
|
||||
git update-ref refs/best_blob_ever "$BLOB1"
|
||||
git update-ref refs/beautiful_commit "$COMMIT"
|
||||
|
||||
for REF in $(git for-each-ref --format='%(refname)'); do
|
||||
git update-ref -d "$REF"
|
||||
done
|
||||
|
||||
[win]
|
||||
|
||||
test "$(git show-ref | wc -l)" -eq 0
|
|
@ -1,5 +0,0 @@
|
|||
And finally, to delete a ref, use
|
||||
|
||||
git update-ref -d refs/<refname>
|
||||
|
||||
Delete all refs! :P (Well, except for HEAD. HEAD is special.)
|
|
@ -1,3 +0,0 @@
|
|||
for REF in $(git for-each-ref --format='%(refname)'); do
|
||||
git update-ref -d "$REF"
|
||||
done
|
|
@ -1,10 +0,0 @@
|
|||
echo hello > hello
|
||||
echo world > world
|
||||
BLOB1=$(git hash-object -w hello)
|
||||
BLOB2=$(git hash-object -w world)
|
||||
git add .
|
||||
TREE=$(git write-tree)
|
||||
COMMIT=$(git commit-tree $TREE -m "Initial commit")
|
||||
|
||||
git update-ref refs/best_blob_ever "$BLOB1"
|
||||
git update-ref refs/beautiful_commit "$COMMIT"
|
|
@ -1 +0,0 @@
|
|||
test "$(git show-ref | wc -l)" -eq 0
|
|
@ -1,3 +1,5 @@
|
|||
[description]
|
||||
|
||||
Instead of pointing directly to objects, refs can also point to other refs!
|
||||
|
||||
When that happens, they are called "symbolic refs". You can create or update a symbolic ref using
|
||||
|
@ -5,3 +7,15 @@ When that happens, they are called "symbolic refs". You can create or update a s
|
|||
git symbolic-ref <name> <ref>
|
||||
|
||||
Create a symbolic ref called "refs/rainbow"!
|
||||
|
||||
[setup]
|
||||
|
||||
[setup goal]
|
||||
|
||||
BLOB=$(git hash-object -w --stdin)
|
||||
git update-ref refs/double "$BLOB"
|
||||
git symbolic-ref refs/rainbow refs/double
|
||||
|
||||
[win]
|
||||
|
||||
git symbolic-ref refs/rainbow
|
|
@ -1,3 +0,0 @@
|
|||
BLOB=$(git hash-object -w --stdin)
|
||||
git update-ref refs/double "$BLOB"
|
||||
git symbolic-ref refs/rainbow refs/double
|
|
@ -1 +0,0 @@
|
|||
git symbolic-ref refs/rainbow
|
46
levels/internals/symref-no-deref
Normal file
46
levels/internals/symref-no-deref
Normal file
|
@ -0,0 +1,46 @@
|
|||
[description]
|
||||
|
||||
When you have a symbolic ref (a ref pointing at another ref), and you decide you want it to be a regular ref again (pointing to an object), you're in for some trouble! :)
|
||||
|
||||
What happens when you try pointing the symbolic ref directly to the blob using `git update-ref`?
|
||||
|
||||
Oops! Turns out that when you reference a symbolic ref, it acts as if you had specified the ref it points to. To de-symbolic-ize it, use the `--no-deref` option directly after `update-ref`!
|
||||
|
||||
Weird, huh?
|
||||
|
||||
[congrats]
|
||||
|
||||
Whew, we've covered a lot of things: Blobs! The index! Trees! Commits! Refs!
|
||||
|
||||
You now know about almost everything about how Git repositories look like on the inside! We think that's pretty cool! :)
|
||||
|
||||
Everything else is just convention and high-level commands that make interacting with the objects more convenient.
|
||||
|
||||
We haven't covered:
|
||||
|
||||
- tag objects (they are the fourth object type - a bit like refs with a description and an author)
|
||||
- configuration (allows you to specify remote repositories, for example)
|
||||
- working with local files (which is, uh, arguably pretty important :P)
|
||||
|
||||
Thanks for playing! You're welcome to check out the "puzzle" levels in the dropdown, some of them are more advanced!
|
||||
|
||||
[setup]
|
||||
|
||||
BLOB1=$(echo delicious | git hash-object -w --stdin)
|
||||
BLOB2=$(echo very | git hash-object -w --stdin)
|
||||
git update-ref refs/curly "$BLOB1"
|
||||
git symbolic-ref refs/fries refs/curly
|
||||
|
||||
[setup goal]
|
||||
|
||||
BLOB1=$(echo delicious | git hash-object -w --stdin)
|
||||
BLOB2=$(echo very | git hash-object -w --stdin)
|
||||
git update-ref refs/curly "$BLOB1"
|
||||
git symbolic-ref refs/fries refs/curly
|
||||
|
||||
git update-ref --no-deref refs/fries "$BLOB2"
|
||||
|
||||
[win]
|
||||
|
||||
git symbolic-ref refs/fries && return 1
|
||||
test "$(git show-ref -s refs/fries)" = "035e2968dafeea08e46e8fe6743cb8123e8b9aa6"
|
|
@ -1,13 +0,0 @@
|
|||
Whew, we've covered a lot of things: Blobs! The index! Trees! Commits! Refs!
|
||||
|
||||
You now know about almost everything about how Git repositories look like on the inside! We think that's pretty cool! :)
|
||||
|
||||
Everything else is just convention and high-level commands that make interacting with the objects more convenient.
|
||||
|
||||
We haven't covered:
|
||||
|
||||
- tag objects (they are the fourth object type - a bit like refs with a description and an author)
|
||||
- configuration (allows you to specify remote repositories, for example)
|
||||
- working with local files (which is, uh, arguably pretty important :P)
|
||||
|
||||
Thanks for playing! You're welcome to check out the "puzzle" levels in the dropdown, some of them are more advanced!
|
|
@ -1,7 +0,0 @@
|
|||
When you have a symbolic ref (a ref pointing at another ref), and you decide you want it to be a regular ref again (pointing to an object), you're in for some trouble! :)
|
||||
|
||||
What happens when you try pointing the symbolic ref directly to the blob using `git update-ref`?
|
||||
|
||||
Oops! Turns out that when you reference a symbolic ref, it acts as if you had specified the ref it points to. To de-symbolic-ize it, use the `--no-deref` option directly after `update-ref`!
|
||||
|
||||
Weird, huh?
|
|
@ -1 +0,0 @@
|
|||
git update-ref --no-deref refs/fries "$BLOB2"
|
|
@ -1,4 +0,0 @@
|
|||
BLOB1=$(echo delicious | git hash-object -w --stdin)
|
||||
BLOB2=$(echo very | git hash-object -w --stdin)
|
||||
git update-ref refs/curly "$BLOB1"
|
||||
git symbolic-ref refs/fries refs/curly
|
|
@ -1,2 +0,0 @@
|
|||
git symbolic-ref refs/fries && return 1
|
||||
test "$(git show-ref -s refs/fries)" = "035e2968dafeea08e46e8fe6743cb8123e8b9aa6"
|
35
levels/internals/tree-create
Normal file
35
levels/internals/tree-create
Normal file
|
@ -0,0 +1,35 @@
|
|||
[description]
|
||||
|
||||
After carefully building the index we want, it would be nice to save a permanent snapshot of it, right?
|
||||
|
||||
This is what the second type of objects is for: trees! You can convert the index into a tree using
|
||||
|
||||
git write-tree
|
||||
|
||||
Try it! :)
|
||||
|
||||
[congrats]
|
||||
|
||||
Nice!
|
||||
|
||||
Can you make a different tree? Modify the index, then call `git write-tree` again!
|
||||
|
||||
[setup]
|
||||
|
||||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
||||
|
||||
git write-tree
|
||||
|
||||
[win]
|
||||
|
||||
git cat-file -p 21a638f28022064c1f1df20844278b494d197979
|
|
@ -1,3 +0,0 @@
|
|||
Nice!
|
||||
|
||||
Can you make a different tree? Modify the index, then call `git write-tree` again!
|
|
@ -1,7 +0,0 @@
|
|||
After carefully building the index we want, it would be nice to save a permanent snapshot of it, right?
|
||||
|
||||
This is what the second type of objects is for: trees! You can convert the index into a tree using
|
||||
|
||||
git write-tree
|
||||
|
||||
Try it! :)
|
|
@ -1 +0,0 @@
|
|||
git write-tree
|
|
@ -1,4 +0,0 @@
|
|||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
echo "file 3" > file3
|
||||
git add .
|
|
@ -1 +0,0 @@
|
|||
git cat-file -p 21a638f28022064c1f1df20844278b494d197979
|
|
@ -1,3 +1,25 @@
|
|||
[description]
|
||||
|
||||
Trees can also point to other trees! This way, they can describe nested directory structures.
|
||||
|
||||
When you add a file inside of a directory to the index, and then call `git write-tree`, it will create a nested tree for the directory, and attach the blob to it.
|
||||
|
||||
To solve this level, build a little stick figure, as shown on the left - a tree that points to two blobs, as well to a tree that points to two blobs.
|
||||
|
||||
[setup]
|
||||
|
||||
[setup goal]
|
||||
|
||||
echo "I'm the left arm" > arm1
|
||||
echo "I'm the right arm" > arm2
|
||||
mkdir hip
|
||||
echo "I'm the left leg" > hip/leg1
|
||||
echo "I'm the right leg" > hip/leg2
|
||||
git add .
|
||||
git write-tree
|
||||
|
||||
[win]
|
||||
|
||||
TREES=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep tree | cut -f1 -d" ")
|
||||
|
||||
for OUTER_TREE in $TREES; do
|
|
@ -1,5 +0,0 @@
|
|||
Trees can also point to other trees! This way, they can describe nested directory structures.
|
||||
|
||||
When you add a file inside of a directory to the index, and then call `git write-tree`, it will create a nested tree for the directory, and attach the blob to it.
|
||||
|
||||
To solve this level, build a little stick figure, as shown on the left - a tree that points to two blobs, as well to a tree that points to two blobs.
|
|
@ -1,7 +0,0 @@
|
|||
echo "I'm the left arm" > arm1
|
||||
echo "I'm the right arm" > arm2
|
||||
mkdir hip
|
||||
echo "I'm the left leg" > hip/leg1
|
||||
echo "I'm the right leg" > hip/leg2
|
||||
git add .
|
||||
git write-tree
|
51
levels/internals/tree-read
Normal file
51
levels/internals/tree-read
Normal file
|
@ -0,0 +1,51 @@
|
|||
[description]
|
||||
|
||||
As soon as you have some tree objects, you can always read them and set the index exactly to their content! Unsurprisingly, the command is called
|
||||
|
||||
git read-tree <tree>
|
||||
|
||||
For <tree>, you can provide the hash of any tree object - you can right-click one to insert its hash into the terminal!
|
||||
|
||||
Try reading some of the trees in this repository into the index!
|
||||
|
||||
[setup]
|
||||
|
||||
EMPTY_TREE=$(git write-tree)
|
||||
|
||||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
git add .
|
||||
git write-tree
|
||||
|
||||
rm *
|
||||
echo "file A" > fileA
|
||||
echo "file B" > fileB
|
||||
echo "file C" > fileC
|
||||
git add .
|
||||
TRIPLE_TREE=$(git write-tree)
|
||||
|
||||
git read-tree "$EMPTY_TREE"
|
||||
|
||||
[setup goal]
|
||||
|
||||
EMPTY_TREE=$(git write-tree)
|
||||
|
||||
echo "file 1" > file1
|
||||
echo "file 2" > file2
|
||||
git add .
|
||||
git write-tree
|
||||
|
||||
rm *
|
||||
echo "file A" > fileA
|
||||
echo "file B" > fileB
|
||||
echo "file C" > fileC
|
||||
git add .
|
||||
TRIPLE_TREE=$(git write-tree)
|
||||
|
||||
git read-tree "$EMPTY_TREE"
|
||||
|
||||
git read-tree "$TRIPLE_TREE"
|
||||
|
||||
[win]
|
||||
|
||||
test "$(git ls-files | wc -l)" -gt 0
|
|
@ -1,7 +0,0 @@
|
|||
As soon as you have some tree objects, you can always read them and set the index exactly to their content! Unsurprisingly, the command is called
|
||||
|
||||
git read-tree <tree>
|
||||
|
||||
For <tree>, you can provide the hash of any tree object - you can right-click one to insert its hash into the terminal!
|
||||
|
||||
Try reading some of the trees in this repository into the index!
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue