From 35b4dc098a0978fe5d777459556b39ec11429863 Mon Sep 17 00:00:00 2001 From: Sebastian Morr Date: Tue, 15 Sep 2020 22:35:14 +0200 Subject: [PATCH] Rework levels, and add some new ones --- levels/blob-create/description | 4 ++++ levels/blob-remove/description | 5 +++++ levels/blob-remove/goal | 1 + levels/blob-remove/start | 3 +++ levels/blob-remove/win | 3 +++ levels/commit-parents/description | 4 +++- levels/commit-parents/goal | 1 + levels/commit-parents/start | 1 - levels/index-add/description | 10 ++++++++++ levels/index-add/goal | 4 ++++ levels/index-add/start | 0 levels/index-add/win | 1 + levels/index-remove/description | 5 +++++ levels/index-remove/goal | 3 +++ levels/index-remove/start | 4 ++++ levels/index-remove/win | 1 + levels/index-update/description | 9 +++++++++ levels/index-update/goal | 2 ++ levels/index-update/start | 4 ++++ levels/index-update/win | 1 + levels/ref-create/description | 4 ++-- levels/ref-move/description | 5 +++++ levels/ref-move/goal | 3 +++ levels/ref-move/start | 10 ++++++++++ levels/ref-move/win | 1 + levels/ref-remove/description | 5 +++++ levels/ref-remove/goal | 3 +++ levels/ref-remove/start | 10 ++++++++++ levels/ref-remove/win | 1 + levels/symref-create/description | 4 +--- levels/symref-create/goal | 4 +++- levels/symref-create/start | 4 ---- levels/symref-create/win | 2 +- levels/symref-no-deref/description | 7 +++++++ levels/symref-no-deref/goal | 1 + levels/symref-no-deref/start | 4 ++++ levels/symref-no-deref/win | 2 ++ levels/tree-create/description | 20 +++----------------- levels/tree-create/goal | 4 ---- levels/tree-create/start | 5 ++++- levels/tree-create/win | 2 +- levels/tree-nested/description | 6 +++--- levels/tree-read/description | 5 +++++ levels/tree-read/goal | 1 + levels/tree-read/start | 15 +++++++++++++++ levels/tree-read/win | 1 + levels/welcome/description | 7 +++++++ 47 files changed, 163 insertions(+), 39 deletions(-) create mode 100644 levels/blob-remove/description create mode 100644 levels/blob-remove/goal create mode 100644 levels/blob-remove/start create mode 100644 levels/blob-remove/win create mode 100644 levels/index-add/description create mode 100644 levels/index-add/goal create mode 100644 levels/index-add/start create mode 100644 levels/index-add/win create mode 100644 levels/index-remove/description create mode 100644 levels/index-remove/goal create mode 100644 levels/index-remove/start create mode 100644 levels/index-remove/win create mode 100644 levels/index-update/description create mode 100644 levels/index-update/goal create mode 100644 levels/index-update/start create mode 100644 levels/index-update/win create mode 100644 levels/ref-move/description create mode 100644 levels/ref-move/goal create mode 100644 levels/ref-move/start create mode 100644 levels/ref-move/win create mode 100644 levels/ref-remove/description create mode 100644 levels/ref-remove/goal create mode 100644 levels/ref-remove/start create mode 100644 levels/ref-remove/win create mode 100644 levels/symref-no-deref/description create mode 100644 levels/symref-no-deref/goal create mode 100644 levels/symref-no-deref/start create mode 100644 levels/symref-no-deref/win create mode 100644 levels/tree-read/description create mode 100644 levels/tree-read/goal create mode 100644 levels/tree-read/start create mode 100644 levels/tree-read/win create mode 100644 levels/welcome/description diff --git a/levels/blob-create/description b/levels/blob-create/description index d8a3e86..15437bd 100644 --- a/levels/blob-create/description +++ b/levels/blob-create/description @@ -9,3 +9,7 @@ Let's create some blobs! To do that, create a file with the desired content, and The flag -w means "write", and tells Git to actually write the new blob to the disk. Create three new blobs! + +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 diff --git a/levels/blob-remove/description b/levels/blob-remove/description new file mode 100644 index 0000000..a2fbc3b --- /dev/null +++ b/levels/blob-remove/description @@ -0,0 +1,5 @@ +There's a simple command to remove all blobs that are not connected to anything: + + $ git prune + +Remove all blobs in this repository. diff --git a/levels/blob-remove/goal b/levels/blob-remove/goal new file mode 100644 index 0000000..b47980f --- /dev/null +++ b/levels/blob-remove/goal @@ -0,0 +1 @@ +git prune diff --git a/levels/blob-remove/start b/levels/blob-remove/start new file mode 100644 index 0000000..2251495 --- /dev/null +++ b/levels/blob-remove/start @@ -0,0 +1,3 @@ +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 diff --git a/levels/blob-remove/win b/levels/blob-remove/win new file mode 100644 index 0000000..0d5ab21 --- /dev/null +++ b/levels/blob-remove/win @@ -0,0 +1,3 @@ +OBJECT_COUNT=$(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | wc -l) + +test "$OBJECT_COUNT" -eq 0 diff --git a/levels/commit-parents/description b/levels/commit-parents/description index 9eda844..e52de96 100644 --- a/levels/commit-parents/description +++ b/levels/commit-parents/description @@ -2,4 +2,6 @@ When using the commit-tree command, you can optionally specify a parent: $ git commit-tree -m "Description" -p -Can you make a string of three commits? We placed an empty tree in your repo to get you started. +Make a string of three commits! + +Hint: What would be the easiest way to get a tree object? diff --git a/levels/commit-parents/goal b/levels/commit-parents/goal index d80163a..28249f9 100644 --- a/levels/commit-parents/goal +++ b/levels/commit-parents/goal @@ -1,3 +1,4 @@ +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/') diff --git a/levels/commit-parents/start b/levels/commit-parents/start index 7654925..e69de29 100644 --- a/levels/commit-parents/start +++ b/levels/commit-parents/start @@ -1 +0,0 @@ -git write-tree diff --git a/levels/index-add/description b/levels/index-add/description new file mode 100644 index 0000000..197f750 --- /dev/null +++ b/levels/index-add/description @@ -0,0 +1,10 @@ +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 permissions. + +Even though it is possible to add an entry directly to the index, it's much more convenient to do it 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"? diff --git a/levels/index-add/goal b/levels/index-add/goal new file mode 100644 index 0000000..ea458d5 --- /dev/null +++ b/levels/index-add/goal @@ -0,0 +1,4 @@ +echo "file 1" > file1 +echo "file 2" > file2 +echo "file 3" > file3 +git add . diff --git a/levels/index-add/start b/levels/index-add/start new file mode 100644 index 0000000..e69de29 diff --git a/levels/index-add/win b/levels/index-add/win new file mode 100644 index 0000000..419655c --- /dev/null +++ b/levels/index-add/win @@ -0,0 +1 @@ +test "$(git ls-files | wc -l)" -ge 3 diff --git a/levels/index-remove/description b/levels/index-remove/description new file mode 100644 index 0000000..3ba8f7b --- /dev/null +++ b/levels/index-remove/description @@ -0,0 +1,5 @@ +To remove an entry from the index, use a command like this: + + $ git update-index --force-remove + +Remove all entries from the index! diff --git a/levels/index-remove/goal b/levels/index-remove/goal new file mode 100644 index 0000000..b92645e --- /dev/null +++ b/levels/index-remove/goal @@ -0,0 +1,3 @@ +git update-index --force-remove file1 +git update-index --force-remove file2 +git update-index --force-remove file3 diff --git a/levels/index-remove/start b/levels/index-remove/start new file mode 100644 index 0000000..ea458d5 --- /dev/null +++ b/levels/index-remove/start @@ -0,0 +1,4 @@ +echo "file 1" > file1 +echo "file 2" > file2 +echo "file 3" > file3 +git add . diff --git a/levels/index-remove/win b/levels/index-remove/win new file mode 100644 index 0000000..43787fa --- /dev/null +++ b/levels/index-remove/win @@ -0,0 +1 @@ +test "$(git ls-files | wc -l)" -eq 0 diff --git a/levels/index-update/description b/levels/index-update/description new file mode 100644 index 0000000..7ad098b --- /dev/null +++ b/levels/index-update/description @@ -0,0 +1,9 @@ +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 + +This will create a new blob, and update the hash of the entry to that blob. + +Update an entry in the index! diff --git a/levels/index-update/goal b/levels/index-update/goal new file mode 100644 index 0000000..ffeadf6 --- /dev/null +++ b/levels/index-update/goal @@ -0,0 +1,2 @@ +echo "new content" > file1 +git update-index file1 diff --git a/levels/index-update/start b/levels/index-update/start new file mode 100644 index 0000000..ea458d5 --- /dev/null +++ b/levels/index-update/start @@ -0,0 +1,4 @@ +echo "file 1" > file1 +echo "file 2" > file2 +echo "file 3" > file3 +git add . diff --git a/levels/index-update/win b/levels/index-update/win new file mode 100644 index 0000000..43787fa --- /dev/null +++ b/levels/index-update/win @@ -0,0 +1 @@ +test "$(git ls-files | wc -l)" -eq 0 diff --git a/levels/ref-create/description b/levels/ref-create/description index 097ae6b..f9aeabc 100644 --- a/levels/ref-create/description +++ b/levels/ref-create/description @@ -1,9 +1,9 @@ -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. +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/ -Make sure to start a ref's name with "refs/"! That's a convention that helps Git find all refs you create. +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! diff --git a/levels/ref-move/description b/levels/ref-move/description new file mode 100644 index 0000000..1063cc0 --- /dev/null +++ b/levels/ref-move/description @@ -0,0 +1,5 @@ +You can point refs to a new location using the same command you use to create them: + + git update-ref refs/ + +As an exercise, make all refs in this repository point to the tree object! diff --git a/levels/ref-move/goal b/levels/ref-move/goal new file mode 100644 index 0000000..a412880 --- /dev/null +++ b/levels/ref-move/goal @@ -0,0 +1,3 @@ +for REF in $(git for-each-ref --format='%(refname)'); do + git update-ref "$REF" "$TREE" +done diff --git a/levels/ref-move/start b/levels/ref-move/start new file mode 100644 index 0000000..c7fabda --- /dev/null +++ b/levels/ref-move/start @@ -0,0 +1,10 @@ +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" diff --git a/levels/ref-move/win b/levels/ref-move/win new file mode 100644 index 0000000..14ed974 --- /dev/null +++ b/levels/ref-move/win @@ -0,0 +1 @@ +test "$(git show-ref -s | uniq)" = "c7863f72467ed8dd44f4b8ffdb8b57ca7d91dc9e" diff --git a/levels/ref-remove/description b/levels/ref-remove/description new file mode 100644 index 0000000..a8fd88a --- /dev/null +++ b/levels/ref-remove/description @@ -0,0 +1,5 @@ +To delete a ref, use + + git update-ref -d refs/ + +Delete all refs! :P diff --git a/levels/ref-remove/goal b/levels/ref-remove/goal new file mode 100644 index 0000000..12b94d4 --- /dev/null +++ b/levels/ref-remove/goal @@ -0,0 +1,3 @@ +for REF in $(git for-each-ref --format='%(refname)'); do + git update-ref -d "$REF" +done diff --git a/levels/ref-remove/start b/levels/ref-remove/start new file mode 100644 index 0000000..c7951e3 --- /dev/null +++ b/levels/ref-remove/start @@ -0,0 +1,10 @@ +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" diff --git a/levels/ref-remove/win b/levels/ref-remove/win new file mode 100644 index 0000000..af29797 --- /dev/null +++ b/levels/ref-remove/win @@ -0,0 +1 @@ +test "$(git show-ref | wc -l)" -eq 0 diff --git a/levels/symref-create/description b/levels/symref-create/description index 836a7b7..474b184 100644 --- a/levels/symref-create/description +++ b/levels/symref-create/description @@ -4,6 +4,4 @@ When that happens, they are called "symbolic refs". You can create or update a s git symbolic-ref -Usually, you will only encounter a special symbolic ref called "HEAD". This ref is special in that it doesn't start with "refs/"! You might already have seen it in the other levels - it's the only thing that's always there! - -Try pointing HEAD to the refs in this repository! +Create a symbolic ref called "refs/rainbow"! diff --git a/levels/symref-create/goal b/levels/symref-create/goal index e137603..c0c3531 100644 --- a/levels/symref-create/goal +++ b/levels/symref-create/goal @@ -1 +1,3 @@ -git symbolic-ref HEAD refs/best_commit +BLOB=$(git hash-object -w --stdin) +git update-ref refs/double "$BLOB" +git symbolic-ref refs/rainbow refs/double diff --git a/levels/symref-create/start b/levels/symref-create/start index d1373ab..e69de29 100644 --- a/levels/symref-create/start +++ b/levels/symref-create/start @@ -1,4 +0,0 @@ -TREE=$(git write-tree) -COMMIT=$(git commit-tree $TREE -m "Initial commit") -git update-ref refs/best_commit $COMMIT -git update-ref refs/worst_commit $COMMIT diff --git a/levels/symref-create/win b/levels/symref-create/win index 2dab745..5c8e5cf 100644 --- a/levels/symref-create/win +++ b/levels/symref-create/win @@ -1 +1 @@ -git symbolic-ref HEAD | grep _commit +git symbolic-ref refs/rainbow diff --git a/levels/symref-no-deref/description b/levels/symref-no-deref/description new file mode 100644 index 0000000..dec5e69 --- /dev/null +++ b/levels/symref-no-deref/description @@ -0,0 +1,7 @@ +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? diff --git a/levels/symref-no-deref/goal b/levels/symref-no-deref/goal new file mode 100644 index 0000000..8a8bf8c --- /dev/null +++ b/levels/symref-no-deref/goal @@ -0,0 +1 @@ +git update-ref --no-deref refs/fries "$BLOB2" diff --git a/levels/symref-no-deref/start b/levels/symref-no-deref/start new file mode 100644 index 0000000..d881ece --- /dev/null +++ b/levels/symref-no-deref/start @@ -0,0 +1,4 @@ +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 diff --git a/levels/symref-no-deref/win b/levels/symref-no-deref/win new file mode 100644 index 0000000..3b11531 --- /dev/null +++ b/levels/symref-no-deref/win @@ -0,0 +1,2 @@ +git symbolic-ref refs/fries && exit 1 +test "$(git show-ref -s refs/fries)" = "035e2968dafeea08e46e8fe6743cb8123e8b9aa6" diff --git a/levels/tree-create/description b/levels/tree-create/description index 0ddfc7a..a5b96ce 100644 --- a/levels/tree-create/description +++ b/levels/tree-create/description @@ -1,21 +1,7 @@ -Blobs just have some content and an ID. It would be convenient to be able to give names to a blob, right? +After carefully building the index we want, it would be nice to save a permanent snapshot of it, right? -The second type of Git object is called a "tree" - a tree points a bunch of blobs, and gives each of them a name! - -How can we build our own trees? Introducing: the index! - -The index is like a "work in progress" version of a tree, where we can add and remove blobs. When we're happy with what we have built, we can make it into a real tree object! - -We can use - - $ git update-index --add - -to make the file's content into a blob, and to add that blob to the index using the file's name. - -When we're happy with out index, we can convert it into a tree using +This is what the second type of objects is for: trees! You can convert the index into a tree using $ git write-tree -That command will output the ID of the newly crated tree. - -Build a tree containing just the 'noises' file, which we conveniently placed in your current directory! :) +Try it! :) diff --git a/levels/tree-create/goal b/levels/tree-create/goal index 99b538d..7654925 100644 --- a/levels/tree-create/goal +++ b/levels/tree-create/goal @@ -1,5 +1 @@ -git update-index --add noises git write-tree - -rm noises -git update-index --remove noises diff --git a/levels/tree-create/start b/levels/tree-create/start index f2bfbe9..ea458d5 100644 --- a/levels/tree-create/start +++ b/levels/tree-create/start @@ -1 +1,4 @@ -echo 'meow' > noises +echo "file 1" > file1 +echo "file 2" > file2 +echo "file 3" > file3 +git add . diff --git a/levels/tree-create/win b/levels/tree-create/win index 40bc605..cc00b1c 100644 --- a/levels/tree-create/win +++ b/levels/tree-create/win @@ -1 +1 @@ -git cat-file -p c099013035060f20e8d8f5db69e158213fbec519 +git cat-file -p 21a638f28022064c1f1df20844278b494d197979 diff --git a/levels/tree-nested/description b/levels/tree-nested/description index 8a30ffc..b456b16 100644 --- a/levels/tree-nested/description +++ b/levels/tree-nested/description @@ -1,5 +1,5 @@ -Trees can also point to other trees! This way, they can basically describe nested directory structures. +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 automatically do the correct thing. +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, and to a tree that points to two blobs. +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. diff --git a/levels/tree-read/description b/levels/tree-read/description new file mode 100644 index 0000000..b4683c2 --- /dev/null +++ b/levels/tree-read/description @@ -0,0 +1,5 @@ +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 + +Try switching between the trees in this repository! diff --git a/levels/tree-read/goal b/levels/tree-read/goal new file mode 100644 index 0000000..886a13a --- /dev/null +++ b/levels/tree-read/goal @@ -0,0 +1 @@ +git read-tree "$TRIPLE_TREE" diff --git a/levels/tree-read/start b/levels/tree-read/start new file mode 100644 index 0000000..990418e --- /dev/null +++ b/levels/tree-read/start @@ -0,0 +1,15 @@ +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" diff --git a/levels/tree-read/win b/levels/tree-read/win new file mode 100644 index 0000000..15bbb04 --- /dev/null +++ b/levels/tree-read/win @@ -0,0 +1 @@ +test "$(git ls-files | wc -l)" -gt 0 diff --git a/levels/welcome/description b/levels/welcome/description new file mode 100644 index 0000000..6ab0432 --- /dev/null +++ b/levels/welcome/description @@ -0,0 +1,7 @@ +To the left, you see an empty Git repository! + +The only thing that's always there is the HEAD reference - we'll look at what that is later. + +You can drag and drop all nodes on the left, and reorder them how you want! + +You can enter Bash commands in the line at the bottom.