Add split description in italia and english and add directory it in levels

This commit is contained in:
Luca Canali 2021-09-06 12:28:35 +02:00
parent 943126647b
commit 2c275424a3
104 changed files with 3510 additions and 38 deletions

43
levels/it/bisect/bisect Normal file
View file

@ -0,0 +1,43 @@
title = Yellow brick road
cards = checkout commit-auto reset-hard bisect-start bisect-good bisect-bad
[description]
(Please zoom out a bit using your mouse wheel! :D)
Oh no! You have lost your key at some point during the day!
Sure, you could look at every single commit in an attempt to find it - but there's a better way: your time machine has a built-in way to find the point in time where things went wrong quickly!
First, play the "bisect start" card. Then, go to a commit where you don't have the key, and play the "bisect bad" card. Likewise, go to a commit early on where you have the key *in your pocket*, and play the "bisect good card".
After you've found the last good commit, reset the main branch to it. What happened to the key after you lost it?
[setup]
echo "You still have your key." > you
for i in {1..30}; do
if test $i -eq 12; then
echo "Your pocket is empty." > you
echo "Is on the ground." > key
fi
if test $i -eq 13; then
echo "Is holding a key in its beak." > bird
rm key
fi
if test $i -eq 14; then
rm bird
fi
git add .
git commit --allow-empty -m "$i"
done
[win]
# Find the last good commit
test "$(git log --pretty=%s main | head -1)" -eq 11
[congrats]
Well done! :) The only problem is that you now have to walk all the way back home, again...

View file

@ -0,0 +1 @@
bisect

View file

@ -0,0 +1,44 @@
title = Creating branches
cards = checkout commit-auto branch branch-delete reset-hard
[description]
You were invited to two parties! At one of them, your favorite band is playing - and the other one is your best friend's birthday party. Where should you go? No worries - as a time travel agent in training, you can go to both parties!
To make it easier to tell which timeline is which, you can create time portals! (We call these "branches".)
[cli]
Branches also make it really easy to travel between different places using the command line! As soon as you have a branch called "birthday", you can type `git checkout birthday` to travel to it!
[setup]
echo "You wrap the birthday present, and grab your concert ticket." > you
git add .
git commit -m "Evening preparations"
echo "You go to the birthday party!" >> you
git add .
git commit -m "Go to the birthday"
git checkout HEAD~1
echo "You go to the concert!" > you
git add .
git commit -m "Go to the concert"
git checkout HEAD~1
git branch -D main
[win]
# Create a branch called 'birthday' that points to the birthday timeline.
git show birthday | grep 'to the birthday'
# Create a branch called 'concert' that points to the concert timeline.
git show concert | grep 'to the concert'
[congrats]
Now you can travel between those branches easily (using `git checkout`) - try it!
Your friend is happy that you made it to the birthday party and you also got your concert ticket signed. Yay!

View file

@ -0,0 +1,47 @@
title = Deleting branches
cards = checkout commit-auto reset-hard branch-delete
[description]
Life is full of dangers, right? Even when walking to school, it seems like there's a lot of risks!
This Monday is especially bad. You made it to school, but there's some timelines you definitely don't want to keep around.
[setup]
echo You leave your house and start walking to school. > you
git add .
git commit -m "Good morning!"
echo You walk on the right side of the street. >> you
git commit -am "Right side"
echo You jump over an manhole in the walkway, and arrive at school on time. >> you
git commit -am "Jump"
git checkout HEAD^ -b friend
echo Suddenly, you fall down, splash into stinking water, and are eaten by an alligator. >> you
git commit -am "A new friend"
git checkout HEAD~2 -b music
echo You walk on the left side of the street. >> you
git commit -am "Left side"
echo Because you\'re kind of late, you start running. Someone throws a piano out of their windows, and it smashes you. >> you
git commit -am "Sounds nice"
git checkout HEAD^ -b ice-cream
echo You\'re not in a hurry, and walk slowly. You even get some ice cream on your way. You arrive at school too late, your teacher is angry, and you are expelled. >> you
git commit -am "Yum"
git branch -M main leap
git checkout leap^^
[win]
# Find the bad branches and delete them. Keep only the best one.
test "$(git show-ref --heads | cut -f2 -d' ')" = "$(echo refs/heads/leap)"
[congrats]
On second thought, maybe you even prefer the ice cream timeline to the main one? :)

View file

@ -0,0 +1,43 @@
title = Moving through time
cards = checkout commit-auto
[description]
The yellow boxes are frozen points in time, we call them "commits"! You can travel between them using the "checkout" card! (Try it!)
Can you find out what happened here? Then, while on the last commit, edit the files to fix the problem, and make a new commit!
[cli]
To checkout a specific commit, type `git checkout`, then a space, and then right click on the commit you want!
This will insert the commit's unique identifier!
[setup]
echo "This piggy bank belongs to the big sister.
It contains 10 coins." > piggy_bank
git add .
git commit -m "The beginning"
echo "A young girl with brown, curly hair." > little_sister
git add .
git commit -m "Little sister comes in"
echo "Has 10 coins." >> little_sister
echo "This piggy bank belongs to the big sister.
It is empty." > piggy_bank
git add .
git commit -m "Little sister does something"
git checkout HEAD^^
git branch -df main
[win]
# Restore sisterly peace.
{ git show HEAD:piggy_bank | grep "10 coins"; } && { git show HEAD:little_sister | grep -v "10 coins"; } && { git rev-parse HEAD^^^; }
[congrats]
Wonderful! Now that you're getting familiar with the time machine, let's look at some more complicated situations...

65
levels/it/branches/fork Normal file
View file

@ -0,0 +1,65 @@
title = Make parallel commits
cards = checkout commit-auto
[description]
Did you know that creating parallel timelines is perfectly legal and safe? It's true!
Can you find out when things went wrong in this zoo? Then, go back to the last good commit and create a parallel universe where everyone is happy!
[cli]
The blue animal represents a concept known as the "HEAD pointer" in Git: It shows you which commit is the current one.
Here's a cool trick to go to the previous commit:
git checkout HEAD^
You can also go back two commits by typing, for example:
git checkout HEAD~2
[setup]
mkdir cage
echo "Looks very hungry." > cage/lion
echo "A small child.
It really loves cats!" > child
git add .
git commit -m "The beginning"
echo "It's holding a lollipop." >> child
git commit -am "The child buys something"
mv child cage
git add .
git commit -m "The child climbs somewhere"
git rm cage/child
echo "Looks happy. :)" > cage/lion
git add .
git commit -m "Oh no"
echo "It's sleeping." > cage/lion
git add .
git commit -m "Nap time!"
git checkout --detach
git branch -d main
[win]
# Make sure that the child is happy.
git ls-tree --name-only -r HEAD | grep child
# Make sure that the lion gets something to eat.
git show HEAD:cage/lion | grep -v "very hungry"
[congrats]
Whew, good job! This seems like a *much* better outcome.
Feel free to add more parallel timelines, or make them longer.
If you're ready, our next mission is already waiting...

49
levels/it/branches/grow Normal file
View file

@ -0,0 +1,49 @@
title = Branches grow with you!
cards = checkout commit-auto branch branch-delete reset-hard
[description]
Note that there are two options to "travel to the end of a timeline":
First, you can directly travel to the commit, like we've done it before.
And second, you can travel to the branch label. In this case, when you make a new commit, the branch will grow with you, and still point at the end of the timeline!
[cli]
To travel to a branch, type `git checkout name_of_the_branch`.
And to travel to the last commit, type `git checkout --detach name_of_the_branch`.
[setup]
echo "You wrap the birthday present, and grab your concert ticket." > you
git add .
git commit -m "Evening preparations"
echo "You go to the birthday party!" >> you
git add .
git commit -m "Go to the birthday"
git branch birthday
git checkout HEAD~1
echo "You go to the concert!" > you
git add .
git commit -m "Go to the concert"
git branch concert
git checkout HEAD~1
git branch -D main
[win]
# Travel directly to the last yellow commit of the birthday timeline, make a change to 'you', and make a commit
for commit in $(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep 'commit$' | cut -f1 -d' '); do
if test $(git rev-parse $commit^) = $(git rev-parse birthday); then
return 0
fi
done
return 1
# Travel to the blue 'concert' branch, make a change to 'you', and a commit.
git show concert^ | grep "Go to the concert"

View file

@ -0,0 +1,89 @@
title = Moving branches around
cards = checkout commit-auto merge reset-hard
[description]
One of your colleagues messed up here, and put the branches in the wrong timelines!
You could delete and re-create these branches - but you can also directly move them to different commits, by using
git checkout
on the branch names, and then using
git reset --hard
on the commit where you want the branch to be.
The donut branch is in the right place, but the timeline is still incomplete - make you actually *eat* the donut in that branch!
[setup]
echo "You do not have a baguette.
You do not have coffee.
You do not have a donut." > you
git add .
git commit -m "The Beginning"
git checkout -b coffee
echo "You have a baguette.
You do not have coffee.
You do not have a donut." > you
git add .
git commit -m "You buy a baguette"
echo "You ate a baguette.
You do not have coffee.
You do not have a donut." > you
git add .
git commit -m "You eat the baguette"
git checkout -b baguette main
echo "You do not have a baguette.
You have coffee.
You do not have a donut." > you
git add .
git commit -m "You buy some coffee"
echo "You do not have a baguette.
You drank coffee.
You do not have a donut." > you
git add .
git commit -m "You drink the coffee"
git checkout -b donut main
echo "You do not have a baguette.
You do not have coffee.
You have a donut." > you
git add .
git commit -m "You buy a donut"
git checkout --detach main
[win]
# Did you eat a baguette on the baguette branch?
git show baguette:you | grep "You ate.*baguette"
# Did you drink a coffee on the coffee branch?
git show coffee:you | grep "You drank.*coffee"
# Did you eat a donut on the donut branch?
git show donut:you | grep "You ate.*donut"
[actions]
test "$(git rev-parse HEAD^)" = "$(git rev-parse donut)" && hint "Remember to checkout the blue branch tag when you want it to grow with the timeline."

View file

@ -0,0 +1,6 @@
checkout-commit
fork
branch-create
grow
branch-remove
reorder

View file

@ -0,0 +1,86 @@
title = Rebasing
cards = checkout commit-auto reset-hard rebase
[description]
Okay - turns out that saving time in the morning by utilizing parallel universes is against the regulations of the International Time Travel Association. You'll have to do your tasks in sequence after all.
See the "rebase" card? When you drag it to a commit, it will copy the events in your current timeline after the specified one! This way, make a clean, linear timeline where you visit all three shops.
Again, we want to make that our base reality - the "main" branch should point to that timeline!
[setup]
echo "You do not have a baguette.
You do not have coffee.
You do not have a donut." > you
git add .
git commit -m "The Beginning"
git checkout -b baguette main
echo "You have a baguette.
You do not have coffee.
You do not have a donut." > you
git add .
git commit -m "You buy a baguette"
echo "You ate a baguette.
You do not have coffee.
You do not have a donut." > you
git add .
git commit -m "You eat the baguette"
git checkout -b coffee main
echo "You do not have a baguette.
You have coffee.
You do not have a donut." > you
git add .
git commit -m "You buy some coffee"
echo "You do not have a baguette.
You drank coffee.
You do not have a donut." > you
git add .
git commit -m "You drink the coffee"
git checkout -b donut main
echo "You do not have a baguette.
You do not have coffee.
You have a donut." > you
git add .
git commit -m "You buy a donut"
echo "You do not have a baguette.
You do not have coffee.
You ate a donut." > you
git add .
git commit -m "You eat the donut"
git checkout --detach main
[win]
# Order all tree branches into one and move the main branch ref
{ git show main:you | grep "You ate.*baguette"; } && { git show main:you | grep "You drank.*coffee"; } && { git show main:you | grep "You ate.*donut"; } && { test "$(git log main --oneline | wc -l)" -eq 7; }
[congrats]
Notice how the other timelines and commits are still there - if anything goes wrong, you can also travel back to them.
It's really hard to actually *destroy* stuff with your time machine.

View file

@ -0,0 +1,78 @@
title = Reordering events
cards = checkout commit-auto reset-hard rebase-interactive cherry-pick
[description]
Oops, looks like there's something messed up here. Can you put the events back into their correct order?
There are two ways to do this: You can drag the "interactive rebase" card to the commit before the one you want to change, then reorder the lines in the file that opens, and save it.
Or you can reset the main tag to the very first commit, and then cherry-pick single commits in the order you want. You have cards for both approaches!
[setup]
echo "You just woke up.
You are NOT wearing underwear.
You are NOT wearing pants.
You are NOT wearing a shirt.
You are NOT wearing shoes." > you
git add .
git commit -m "The Beginning"
echo "You just woke up.
You are NOT wearing underwear.
You are NOT wearing pants.
You are NOT wearing a shirt.
You are wearing shoes." > you
git commit -am "Put on shoes"
echo "You just woke up.
You are NOT wearing underwear.
You are wearing pants.
You are NOT wearing a shirt.
You are wearing shoes." > you
git commit -am "Put on pants"
echo "You just woke up.
You are wearing underwear.
You are wearing pants.
You are NOT wearing a shirt.
You are wearing shoes." > you
git commit -am "Put on underwear"
echo "You just woke up.
You are wearing underwear.
You are wearing pants.
You are wearing a shirt.
You are wearing shoes." > you
git commit -am "Put on shirt"
[win]
# Reorder the commits to dress yourself in the correct way
{ git log main --oneline | perl -0777 -ne'exit(1) if not /shoes[\s\S]*pants[\s\S]*underwear/'; } && { test "$(git log main --oneline | wc -l)" -eq 5; }
[congrats]
Feel free to reset the level and try the other strategy! Which one do you like better?

View file

@ -0,0 +1,2 @@
rebase
reorder

32
levels/it/files/files-add Normal file
View file

@ -0,0 +1,32 @@
title = Interior design
cards = file-new file-delete
[description]
Now that your room looks tidy, you can start to unpack your stuff. You brought two new pieces of furniture with you and with a bright smile,
you see that their colors match the color of your bed!
Build up your two pieces of furniture by playing the touch card.
Then name your furniture - you can choose whatever you like.
Make sure the colors match! You can find the bed's color in its description.
Don't forget to add a color and description to your new furnitures, too!
[setup]
echo A yellow cozy bed. > bed
[win]
# Add two more pieces of furniture
NUM_FILES="$(ls | wc -l)"
test "$NUM_FILES" -ge 3
# Make sure the colors match your bed's color.
NUM_FILES="$(ls | wc -l)"
YELLOW_FILES="$(grep -li yellow * | wc -l)"
test "$NUM_FILES" -ge 2 && test "$YELLOW_FILES" = "$NUM_FILES"
[congrats]
Don't you immediately feel more at home?

View file

@ -0,0 +1,36 @@
title = Unexpected Roommates
cards = file-delete
[description]
The first day at Time Travel School comes to an end and you receive the key to your room.
Full of excitement you open the door just to find... spider webs! Spider webs everywhere!
Remove all the spider webs you can find with the remove card!
[cli]
On the command line, you can easily delete all files ending in -web using this command:
rm *web
[setup]
echo A tiny spider web is next to your window. > tiny_web
echo A big spider web sticks above your bed. > big_web
echo A cozy bed. > bed
echo An extra thick spider web is right beside your door. > thick_web
[win]
# Remove all spider webs.
! ls | grep thick_web &&
! ls | grep big_web &&
! ls | grep tiny_web
# But make sure you keep your bed!
ls | grep bed
[congrats]
Your room looks now very tidy and cozy! Time to unpack your stuff!

3
levels/it/files/sequence Normal file
View file

@ -0,0 +1,3 @@
files-delete
files-add

38
levels/it/index/add Normal file
View file

@ -0,0 +1,38 @@
title = Updating files in the index
cards = add commit checkout
[description]
So you start working, and make changes to your files! Git lets you choose which of these changes you want to put in the next commit. This is like updating the index version of that file to the new version.
This allows you to have smaller commits, that describe better what you changed!
The command for this is the same - `git add`!
[setup]
echo a > a
echo b > b
echo c > c
git add .
git commit -m "Initial commit"
[win]
# Make changes to all files!
test "$(cat a)" != "a" &&
test "$(cat b)" != "b" &&
test "$(cat c)" != "c"
# Add only the changes of a and c, and make a commit! Finally, make a commit which captures the changes in b!
test "$(git show main:a)" != "a" &&
test "$(git show main:b)" != "b" &&
test "$(git show main:c)" != "c" &&
test "$(git show main^:a)" != "a" &&
test "$(git show main^:b)" == "b" &&
test "$(git show main^:c)" != "c"
[congrats]
Well done! Try tavelling between the commits using `git checkout`, so you can look at their contents again!

31
levels/it/index/change Normal file
View file

@ -0,0 +1,31 @@
title = Update files in the index
cards = add commit
[description]
When we change files, the index won't change on its own. We have to use `git add` to update the index to the changed version of the file.
Let's try that!
The icons in the file browser show you when the actual file (white) and the version in the index (blue) are different, and when they are the same!
[win]
Good! The index is sometimes also called the "staging area" - it contains exactly what ends up in the next commit when you use `git commit`!
[setup]
echo "The candle is burning with a blue flame." > candle
git add .
git commit -m "The beginning"
[win]
# Make a change to the candle.
test "$(git diff --name-only)" = "candle" || file -f .git/candle-changed && touch .git/candle-changed
# Add the candle.
test "$(git diff --cached --name-only)" = "candle" || file -f .git/candle-added && touch .git/candle-added
# Make a commit.
test "$(git diff --name-only HEAD HEAD^)" = "candle"

25
levels/it/index/checkout Normal file
View file

@ -0,0 +1,25 @@
title = Checking out files from the index
cards = add reset-file checkout-file commit
[description]
So you've made changes to your files, but you decide that you don't want to keep them! You can use `git checkout` for that!
What happens if you have already update the index, like in file c? You have to reset the index first!
[setup]
echo a > a
echo b > b
echo c > c
git add .
git commit -m "Initial commit"
echo x > a
echo x > b
echo x > c
git add c
[win]
# Remove all changes in your local files!
test "$(git diff --name-only | wc -l)" -eq 0

51
levels/it/index/compare Normal file
View file

@ -0,0 +1,51 @@
title = Step by step
cards = checkout commit-auto
[description]
Welcome to today's lesson! We're going to learn how to make commits with more precision!
Have a look at these two timelines. They have exactly the same outcome. But one of them makes it much easier to figure out what happened.
[win]
# Right! Having each change in its own commit makes it easier to understand what's going on! Let's learn how to do that!
git branch --show-current | grep step-by-step
[setup]
echo "A small, but heavy glass ball." > ball
echo "A thin book, that's standing upright." > book
echo "A candle, burning with a blue flame." > candle
echo "A smoke detector. It's absolutely silent." > smoke_detector
git add .
git commit -m "The beginning"
git branch -M all-at-once
echo "The ball is now touching the book." > ball
echo "The book has fallen over." > book
echo "The candle has been blown out." > candle
git commit -am "The end"
git checkout HEAD^
git checkout -b step-by-step
echo "The ball is now touching the book." > ball
git commit -am "The ball rolls towards the book"
echo "The book has fallen over." > book
git commit -am "The book falls over"
echo "The candle has been blown out." > candle
git commit -am "The book blows out the candle"
git checkout HEAD~3
[win]
# Pick the timeline that's clearer, and make the alarm go off!
git show step-by-step:smoke_detector | tail -n 1 | grep -v "absolutely silent"

28
levels/it/index/new Normal file
View file

@ -0,0 +1,28 @@
title = Add new files to the index
cards = add commit
[description]
So far, when we made a commit, we've always recorded the current status of all objects, right?
But Git allows you to pick which changes you want to put in a commit!
To learn how that works, we need to learn about the "index"! In the index, we can prepare what will be in the next commit. In this game, the index is represented by a blue aura around icons in the file browser!
Initially, the index is empty. To make a commit that contains a new file, we need to add it!
[cli]
You can use tab completion in the terminal! Start typing a filename, then press the tab key to complete its name. This will often save you some time!
[setup]
echo "The candle is burning with a blue flame." > candle
[win]
# Add the candle.
test "$(git diff --cached --name-only)" = "candle" || file -f .git/candle-added && touch .git/candle-added
# Make a commit.
test "$(git ls-tree --name-only HEAD)" = "candle"

37
levels/it/index/reset Normal file
View file

@ -0,0 +1,37 @@
title = Resetting files in the index
cards = add reset-file commit
[description]
See the dark shadow behind the icons? That's the version of the file in the last commit!
For example, these candles have been blown out, and that change has been added.
But you decide that this was a mistake! You only want to blow out the red candle in the next commit!
If you already have updated the index to a changed file, but want to reset it, you can use `git reset`!
[setup]
echo "It's burning!" > red_candle
echo "It's burning!" > green_candle
echo "It's burning!" > blue_candle
git add .
git commit -m "The beginning"
echo "It's been blown out." > red_candle
echo "It's been blown out." > green_candle
echo "It's been blown out." > blue_candle
git add .
[win]
# Reset the changes in the green and blue candles!
git show :green_candle | grep burning &&
git show :blue_candle | grep burning &&
git show :red_candle | grep -v burning
# And make a commit!
git show main:green_candle | grep burning &&
git show main:blue_candle | grep burning &&
git show main:red_candle | grep -v burning

24
levels/it/index/rm Normal file
View file

@ -0,0 +1,24 @@
title = Delete a file in the next commit
cards = add reset-file checkout-file rm file-delete commit
[description]
If you want to remove a file in the next commit, you can use `git rm`! This will both delete the file locally, and in the index.
If a file is modified, you'll need to reset these changes first/reset the files.
[setup]
echo a > a
echo x > b
echo x > c
git add .
git commit -m "Initial commit"
echo x > a
echo b > b
git add b
[win]
# Make a commit where all files are deleted ¯\_(^_^)_/¯
test "$(git ls-tree main | wc -l)" -eq 0

5
levels/it/index/sequence Normal file
View file

@ -0,0 +1,5 @@
compare
new
change
reset
steps

53
levels/it/index/steps Normal file
View file

@ -0,0 +1,53 @@
title = Adding changes step by step
cards = add reset-file commit
[description]
The index is really useful, because it allows us to be precise about which changes we want to include in each commit!
[setup]
echo "A hammer, balancing on its handle." > hammer
echo "A bottle, containing a clear liquid." > bottle
echo "A white sugar cube." > sugar_cube
git add .
git commit -m "The beginning"
[win]
# Make changes to all three objects, to form a logical sequence of events!
test "$(git diff --name-only | wc -l)" -eq 3 || file -f .git/candle-changed && touch .git/candle-changed
# Only add one of these changes!
test "$(git diff --cached --name-only | wc -l)" -eq 1 || file -f .git/candle-added && touch .git/candle-added
# And make a commit.
COUNT=0
for commit in $(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep 'commit$' | cut -f1 -d' '); do
if test "$(git diff --name-only $commit $commit^ | wc -l)" -eq 1; then
COUNT=$((COUNT+1))
fi
done
test "$COUNT" -ge 1
# Make a second commit that only records a single change.
COUNT=0
for commit in $(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep 'commit$' | cut -f1 -d' '); do
if test "$(git diff --name-only $commit $commit^ | wc -l)" -eq 1; then
COUNT=$((COUNT+1))
fi
done
test "$COUNT" -ge 2
# And a third one.
COUNT=0
for commit in $(git cat-file --batch-check='%(objectname) %(objecttype)' --batch-all-objects | grep 'commit$' | cut -f1 -d' '); do
if test "$(git diff --name-only $commit $commit^ | wc -l)" -eq 1; then
COUNT=$((COUNT+1))
fi
done
test "$COUNT" -ge 3

27
levels/it/intro/cli Normal file
View file

@ -0,0 +1,27 @@
title = La line di comando
cards =
[description]
Queste carte da gioco sono state disegnate per essere usate e ricordate facilmente! Ti consigliamo di attenerti a loro se non hai molta esperienza di Git!
[cli]
Ma c'è un'altra via per interagire con Git:
Prova a digitare `git init` nel terminale qui sotto e premere il pulsante Enter!
[setup]
rm -rf .git
[win]
# Inizializza la macchina del tempo!
test -d .git
[congrats]
Perfetto! Al posto di usare le carte da gioco, puoi anche fare tutto dalla line di comando!
La line di comando e piuttosto potente! A volte, puoi usarla per risolvere le attività più velocemente che con l'interfaccia grafica.

32
levels/it/intro/commit Normal file
View file

@ -0,0 +1,32 @@
title = Il tuo primo commit!
cards = commit-auto
[description]
Puoi usare la tua macchina del tempo per scattare istantanee degli oggetti intorno a te! Qui puoi metterlo in pratica!
(Il tuo insegnante versa un pò di acqua nel bicchiere)
[cli]
Nuovamente, al posto di usare le carte, puoi scrivere i comandi, che sono stampati sulle carte, nel terminale in basso!
Questo è totalmente opzionale! Ma questa è una conoscenza super utile nel mondo reale - e ti farà avere un distintivo scintillante! :)
[setup]
echo "Il bicchiere è pieno di acqua." > glass
[win]
# Crea un'istantanea del bicchiere (un "commit")
git rev-parse HEAD
# Cambia il contenuto del bicchiere!
! test "$(cat glass)" = "Il bicchiere è pieno di acqua."
# E crea un secondo "commit"!
git rev-parse HEAD^ && ! test "$(git show main:glass)" = "Il bicchiere è bieno di acqua."
[congrats]
Perfetto! Puoi provare a creare altri "commit". Quando ti sentirai a posto, premi su "Next Level".

42
levels/it/intro/copies Normal file
View file

@ -0,0 +1,42 @@
title = Crea una copia
cards =
[description]
Questa volta, stai facendo molte copie di backup - puoi guardarli cliccandoci sopra!
[congrats]
Okay, questo è un modo di lavorare.
Ma sei preoccupato che ti ritroverai con centinaia di copie di questo modulo e sarà difficile tenerne traccia nel tempo.
Specialmente quando lavori con altre persone, inviare copie avanti ed indietro non sembra l'ideale.
Fermati, devi provare questa macchina del tempo!
[setup]
rm -rf .git
echo "~ Perchè voglio imparare Git ~
(Devo ancora scriverlo.)" >> form.txt
echo "~ Perchè volgio imparare Git ~
- Così posso annullare gli errori" >> form2.txt
echo "~ Perchè volgio imparare Git ~
- Così posso annullare gli errori
- Per tracciare i mie progetti attraverso il tempo" >> form2_final.txt
cp form2_final.txt form2_really_final.txt
[win]
# Aggiungi una nuova line al file form2_really_final.txt!
test "$(cat form2_really_final.txt | wc -l )" -ge 5

24
levels/it/intro/init Normal file
View file

@ -0,0 +1,24 @@
title = Entra nella machina del tempo
cards = init
[description]
Sei stato accettato nella scuola della macchina del tempo! Questo è il tuo primo giorno! Il tuo insegnate ti spiega:
"Per fare qualsiasi cosa con una macchina del tempo, devi prima inizializzarla!"
Trascina quella carta blu verso l'alto per usarla!
[setup]
rm -rf .git
[win]
# Inizializzazione della macchina del tempo
test -d .git
[congrats]
Perfetto! Vedi quel piccolo animale che è apparso? Sarà il tuo compagno e ti mostrerà dove ti trovi nel tempo!

52
levels/it/intro/remote Normal file
View file

@ -0,0 +1,52 @@
title = Dai lavoriamo tutti assieme
cards = pull commit-auto push
[description]
Aggiungi il tuo nome nella nostra lista di studenti!
Ho già un secondo "commit" nella mia macchina del tempo - Dai lavoriamo tutti assieme!
[cli]
Per tornare in dietro alle vecchie istruzioni, puoi premere la freccia in alto o in basso. In questo modo non devi digitare, nuovamente, le istruzioni.
[congrats]
Benvenuto nella scuola del viaggio nel tepo! :) Ci vediamo domani per la tua prima lezione!
[setup]
echo "~ Lista degli attuali studenti ~" > students
git add .
git commit -m "Versione iniziale"
git push -u teacher main
git update-ref -d refs/remotes/teacher/main
[setup teacher]
git reset --hard main
echo "
- Sam
- Alex" >> students
git add .
git commit -m "Aggiunti due studenti"
[win]
# Ottieni il secondo "commit" dal tuo insegnante usando `git pull`.
test "$(git log --oneline teacher/main | wc -l)" -ge 2
# Aggiungi il tuo nome alla lista degli studenti.
test "$(cat students |wc -l)" -ge 5
# Crea un'istantanea dei risultati.
test "$(git show main:students |wc -l)" -ge 5
[win teacher]
# E usa `git push` per inviarlo al tuo insegnante!
test "$(git show main:students |wc -l)" -ge 5

42
levels/it/intro/risky Normal file
View file

@ -0,0 +1,42 @@
title = Vivere è pericoloso
cards =
[description]
Quindi hai deciso di fare domanda per la scuola di viaggio nel tempo, per usare la macchina del tempo chiamata "Git"!
Che emozione!
Hai quasi concluso le scartoffie! Devi solamente inserire un motivo per il quale vuoi imparare Git.
[congrats]
All'improvviso, il tuo gatto salta sul tavolo, strappa via il modulo, e scappa via! Oh no. Tutto il tuo duro lavoro, andato!
Devi trovare una buona soluzione.
(Premi "Next Level" appena sei pronto!)
[setup]
rm -rf .git
echo "~ Perchè voglio imparare Git ~
- Così posso cancellare gli errori
- Per seguire il mio progetto attraverso il tempo" >> form.txt
[actions]
test "$(cat form.txt | wc -l )" -ge 5 && echo "(E' stato rubato dal tuo gatto.)
" > form.txt
[win]
# Aggiungi un'altra line a form.txt!
test "$(cat form.txt | wc -l )" -ge 5

6
levels/it/intro/sequence Normal file
View file

@ -0,0 +1,6 @@
risky
copies
init
cli
commit
remote

View file

@ -0,0 +1,38 @@
title = Benvenuto nella scuola del viaggio nel tempo!
cards = config-name commit-auto checkout
[description]
Sei ancora confuso da tutto quello che sta succedendo. Il giorno seguente, decidi di iscriverti nella scuola del viaggio nel tempo!
Il tuo insegnante del viaggio nel tempo ti saluta: "Ciao come va! Vuoi dirci il tuo nome?"
[setup]
git config --global user.name "TU"
echo "~ Chi vuole imparare come si usa la macchina del tempo? ~
[ ] Per essere sicuro che il mio gatto non mangi il mio lavoro.
[ ] Così non devo tenere copie di tutti i miei saggi.
[ ] Per collaborare con altri studenti del viaggio nel tempo.
[ ] Altro, perfavore specifica:" > form
[actions]
test "$(git config user.name)" != "TU" && cat form | grep -v Signature && echo "
Firma: $(git config user.name)" >> form
[win]
# Presentati.
test "$(git config user.name)" != "TU"
# Compila l'iscrizione e inviala!
git show main:form | grep '\[[xX]\]'
[congrats]
"Siamo lieti di averti con noi!
Git puoi aiutarti a correggere i problemi del passato! Ti aiuta a collaborare con gli studenti del viaggio nel tempo! E' davvero potente e e popolare! Ci vediamo domani per la tua prima lezione!"

View 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"

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View file

@ -0,0 +1,41 @@
[description]
Delete all objects in this repository using git commands only!
Useful commands:
git prune
git reflog expire
[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

View file

@ -0,0 +1,28 @@
[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
git cat-file -p $TREE | cut -f1 | cut -f3 -d" "
done)
NUMBER_OF_CHILDREN=$(echo "$ALL_TREE_CHILDREN" | wc -l)
UNIQUE_CHILDREN=$(echo "$ALL_TREE_CHILDREN" | sort -u | wc -l)
test "$NUMBER_OF_CHILDREN" -gt "$UNIQUE_CHILDREN"

View file

@ -0,0 +1,34 @@
[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
if [ "$(git cat-file -p $TREE | wc -l)" -eq 1 ]; then
if [ "$(git cat-file -p $TREE | cut -f1 | grep tree | wc -l)" -eq 1 ]; then
# So the tree has exactly one child, and it is a tree!
TREE2=$(git cat-file -p $TREE | cut -f1 | grep tree | cut -f3 -d" ")
if [ "$(git cat-file -p $TREE2 | wc -l)" -eq 1 ]; then
if [ "$(git cat-file -p $TREE2 | cut -f1 | grep tree | wc -l)" -eq 1 ]; then
# Same for its child! \o/
return 0
fi
fi
fi
fi
done
return 1

View 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"

View 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"

View 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

View file

@ -0,0 +1,18 @@
welcome
basics
blob-create
blob-remove
index-add
index-remove
index-update
tree-create
tree-read
tree-nested
commit-create
commit-parents
commit-rhombus
ref-create
ref-move
ref-remove
symref-create
symref-no-deref

View file

@ -0,0 +1,21 @@
[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
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

View 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"

View 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

View file

@ -0,0 +1,38 @@
[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
NUMBER_OF_BLOB_CHILDREN=$(git cat-file -p $OUTER_TREE | cut -f2 -d" " | grep blob | wc -l)
NUMBER_OF_TREE_CHILDREN=$(git cat-file -p $OUTER_TREE | cut -f2 -d" " | grep tree | wc -l)
if [ $NUMBER_OF_BLOB_CHILDREN -eq 2 -a $NUMBER_OF_TREE_CHILDREN -eq 1 ]; then
TREE_CHILD=$(git cat-file -p $OUTER_TREE | cut -f1 | grep tree | cut -d" " -f3)
NUMBER_OF_BLOB_CHILDREN_OF_TREE_CHILD=$(git cat-file -p $TREE_CHILD | cut -f2 -d" " | grep blob | wc -l)
if [ $NUMBER_OF_BLOB_CHILDREN_OF_TREE_CHILD -eq 2 ]; then
return 0
fi
fi
done
return 1

View 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

View file

@ -0,0 +1,33 @@
[description]
This is prototype #1 for the Git learning game by @bleeptrack and @blinry. Thanks for checking it out! <3
You can interact with the repository labelled "yours" by typing Bash commands in the terminal below! The visualization will show you its internal status.
Let's get started by initializing an empty Git repository in the current directory by typing:
git init
[congrats]
Well done!
An empty Git repository is... well, quite empty. The only thing that always exists is a reference called "HEAD" - we'll learn what that is later!
But first, let's look at some basics!
(Click "Next Level" as soon as you're ready!)
[setup]
rm -rf .git
[setup goal]
rm -rf .git
git init
[win]
test -d .git

47
levels/it/merge/conflict Normal file
View file

@ -0,0 +1,47 @@
title = Contradictions
cards = checkout commit-auto merge reset-hard
[description]
Sometimes, timelines will contradict each other.
For example, in this case, one of our clients wants these timelines merged, but they ate different things for breakfast in both timelines.
Try to merge them together! You'll notice that there will be a conflict! The time machine will leave it up to you how to proceed: you can edit the problematic item, it will show you the conflicting sections. You can keep either of the two versions - or create a combination of them! Remove the >>>, <<<, and === markers, and make a new commit to finalize the merge!
Let your finalized timeline be the "main" one.
[setup]
echo "Just woke up. Is hungry." > sam
git add .
git commit -m "The beginning"
git checkout -b pancakes
echo "Had blueberry pancakes with maple syrup for breakfast." > sam
git add .
git commit -m "Pancakes!"
echo "
Is at work." >> sam
git commit -am "Go to work"
git checkout -b muesli main
echo "Had muesli with oats and strawberries for breakfast." > sam
git add .
git commit -m "Muesli!"
echo "
Is at work." >> sam
git commit -am "Go to work"
git checkout main
[win]
# Make a breakfast compromise in the 'main' branch.
git rev-parse main^ && test "$(git rev-parse main^1^^)" = "$(git rev-parse main^2^^)"
[congrats]
Yum, that sounds like a good breakfast!

82
levels/it/merge/merge Normal file
View file

@ -0,0 +1,82 @@
title = Merging timelines
cards = checkout commit-auto merge
[description]
Here's a trick so that you can sleep a bit longer: just do all your morning activities in parallel universes, and then at the end, merge them together!
[setup]
echo "You do not have a baguette.
You do not have coffee.
You do not have a donut." > you
git add .
git commit -m "The Beginning"
echo "You have a baguette.
You do not have coffee.
You do not have a donut." > you
git add .
git commit -m "You buy a baguette"
echo "You ate a baguette.
You do not have coffee.
You do not have a donut." > you
git add .
git commit -m "You eat the baguette"
git checkout HEAD~2
echo "You do not have a baguette.
You have coffee.
You do not have a donut." > you
git add .
git commit -m "You buy some coffee"
echo "You do not have a baguette.
You drank coffee.
You do not have a donut." > you
git add .
git commit -m "You drink the coffee"
git checkout HEAD~2
echo "You do not have a baguette.
You do not have coffee.
You have a donut." > you
git add .
git commit -m "You buy a donut"
echo "You do not have a baguette.
You do not have coffee.
You ate a donut." > you
git add .
git commit -m "You eat the donut"
git checkout --detach
git branch -D main
[win]
# Build a situation where you consumed a baguette, a coffee, *and* a donut.
{ git show HEAD:you | grep "You ate.*baguette"; } && { git show HEAD:you | grep "You drank.*coffee"; } && { git show HEAD:you | grep "You ate.*donut"; }
# Be on a merge commit.
test "$(git log --pretty=%P -n 1 HEAD | wc -w)" -ge 2
[congrats]
I wonder if you're more relaxed when you *sleep* in parallel timelines...

View file

@ -0,0 +1,54 @@
title = Abort a merge
cards = checkout commit-auto merge merge-abort
[description]
Sometimes you want to merge two commits, but a merge conflict occurs that you currently don't want to resolve.
In these situations you can abort the merge to merge later. Use
git merge --abort
when you are in a merge process.
Try to merge both commits and abort the merge afterwards.
[setup]
echo "A new day is starting" > you
git add .
git commit -m "Start"
echo "Walking down the Main Lane." >> you
git add .
git commit -m "Main Lane"
git checkout HEAD~1
echo "Walking down the Side Lane." >> you
git add .
git commit -m "Side Lane"
git checkout HEAD~1
git branch -D main
[actions]
if test -f .git/MERGE_HEAD; then
touch .git/secretfile
fi
[win]
# You tried to merge?
test -f .git/secretfile
# You aborted to merge?
test -f .git/secretfile && ! test -f .git/MERGE_HEAD && ! git rev-parse HEAD^^
[congrats]
Aaah, let's merge later...

2
levels/it/merge/sequence Normal file
View file

@ -0,0 +1,2 @@
merge
conflict

47
levels/it/remotes/friend Normal file
View file

@ -0,0 +1,47 @@
title = Friend
cards = pull push commit-auto checkout
[description]
Your friend added another line to your essay! Get it, add a third one and send it to them!
Take turns until you have five lines!
[setup yours]
echo "Line 1" > essay
git add .
git commit -m "One line"
git push -u friend main
[setup friend]
git checkout main
echo "Line 2, gnihihi" >> essay
git commit -am "Another line"
[actions friend]
if test "$(git log --oneline | wc -l)" -eq 3; then
git reset --hard main # Necessary because the working directory isn't updated when we push to the friend.
echo "Line 4, blurbblubb" >> essay
git commit -am "Final line"
hint "Oh nice, I added a fourth line!"
fi
[win]
# Got the second line from your friend
git show HEAD:essay | grep gnihihi
# Got the fourth line from your friend.
git show HEAD:essay | grep blurbblubb
[win friend]
# The friend got a third line from you
test "$(git show HEAD:essay | wc -l)" -ge 3
# The friend got a fifth line from you
test "$(git show HEAD:essay | wc -l)" -ge 5

View file

@ -0,0 +1,33 @@
title = Problems
cards = checkout add pull push commit-auto merge
[description]
Both you and your friend have been working on the file, and want to sync up!
[setup yours]
echo "The bike shed should be ???" > file
git add .
git commit -m "initial"
git push -u friend main
echo "The bike shed should be green" > file
[setup friend]
git checkout main
echo "The bike shed should be blue" > file
git commit -a -m "friends version"
[win]
# Commit your local changes.
test "$(git status -s)" = ""
[win friend]
# Look at your friend's suggestion, make a compromise, and push it back.
git rev-parse main^ && test "$(git rev-parse main^1^)" = "$(git rev-parse main^2^)"

View file

@ -0,0 +1,2 @@
friend
problems

7
levels/it/sandbox/empty Normal file
View file

@ -0,0 +1,7 @@
title = Empty sandbox
[description]
This is an empty sandbox you can play around in.
[setup]

22
levels/it/sandbox/remote Normal file
View file

@ -0,0 +1,22 @@
title = Sandbox with a remote
cards = checkout commit-auto pull fetch push
[description]
Here's a sandbox with a remote! Try pulling, fetching, or pushing!
How can you push tags and branches on a remote? How can you delete them again?
[setup yours]
echo "Line 1" > essay
git add .
git commit -m "Initial commit"
git push -u friend main
[setup friend]
git checkout main
echo "Line 2" >> essay
git commit -am "Another line"

View file

@ -0,0 +1,3 @@
empty
remote
three-commits

View file

@ -0,0 +1,26 @@
title = Sandbox with three commits
cards = checkout add reset-file checkout-file commit merge rebase
[setup]
echo "You wake up." > you
git add .
git commit -m "The beginning"
echo "You drink coffee." >> you
git commit -am "First things first"
echo "You hear a knock on the door." >> you
git commit -am "Who's there?"
git branch not_main
[description]
Here's a sandbox you can play around in.
You can use both the playing cards, as well as the terminal. This is a real Git terminal! Fun things to try:
- Make a commit that merges three timelines together at once!
- Create and delete some tags!
- Make a timeline that's completely independent of the rest!

13
levels/it/sequence Normal file
View file

@ -0,0 +1,13 @@
intro
files
branches
merge
index
remotes
changing-the-past
shit-happens
workflows
bisect
stash
tags
sandbox

View file

@ -0,0 +1,30 @@
title = Undo a bad commit
cards = reset commit-a
[description]
Oh no, we made a bad commit! How can we undo making the commit, and go back to a point where we can try again?
The answer is using `git reset [commit]`, which does two things:
- It resets the current branch ref to the commit you specify.
- And it resets the index to that commit.
It does not change your working directory in any way, which means that after that, you can try making the commit you want again.
[setup]
echo "1 2 3 4" > numbers
git add .
git commit -m "Initial commit"
echo "1 2 3 4 5 6 7 8 9 11" > numbers
git commit -am "More numberrrrrs"
[win]
# In the last main commit, the numbers file contains the numbers from 1 to 10.
test "$(git show main:numbers)" = "1 2 3 4 5 6 7 8 9 10"
# The commit message of that commit is "More numbers".
git log -1 --oneline | grep "More numbers"
# The commit with the typo is not part of the main branch anymore.
git log --oneline | grep -v "rrrrr"

View file

@ -0,0 +1,54 @@
title = I pushed something broken
cards = revert push
[description]
We were talking about how to undo a commit, and fix it. This only helps when you haven't already pushed it to a remote. When that has happened, and you want to undo the effects of the commit completely, your best option is `git revert`
[setup]
echo "this is fine
?
?
?" > text
git add .
git commit -m fine
echo "this is fine
this is also fine
?
?" > text
git commit -am "also fine"
echo "this is fine
this is also fine
this is very bad
?" > text
git commit -am "very bad"
echo "this is fine
this is also fine
this is very bad
this is fine again" > text
git commit -am "fine again"
git push team main
git branch -u team/main main
[setup team]
[win team]
# The team's main branch no longer contains the bad thing.
! { git show main:text | grep -q "very bad"; }
# And the history has not been modified.
git show main^:text | grep -q "very bad"

View file

@ -0,0 +1,26 @@
title = Go back to where you were before
cards = checkout reflog
[description]
Say you were looking at something in the past, and then switched back to the main branch.
But then, you got reaaally distracted, and after your lunch break, you can't remember on which commit in the past you were before. How can you find out?
There's a convenient command that shows you all the places your HEAD did point to in the past:
git reflog
[setup]
for i in {1..10}; do
git commit --allow-empty -m $i
git branch $i
done
git checkout 3
git checkout main
[win]
# Find out where you've been before, and go back there!
test "$(git rev-parse HEAD)" = "$(git rev-parse 3)"

View file

@ -0,0 +1,22 @@
title = Restore a deleted file
cards = checkout
[description]
Oops - you deleted the "essay" file, which you worked on all night!
Luckily, Git is here to help! You can use `git checkout` to restore the file!
[setup]
echo important > essay
git add .
git commit -m "Initial commit"
echo "important content" > essay
git commit -am "Improve essay"
rm essay
[win]
# Restore the essay to contain "important content"
test "$(cat essay)" = "important content"

View file

@ -0,0 +1,21 @@
title = Restore a file from the past
cards = checkout checkout-from commit
[description]
Here's a similar problem: you really liked the essay from the very first commit, and want to have it back! Well, checkout can also restore things from older commits, Here's how:
git checkout [commit] [file]
[setup]
echo "good version" > essay
git add .
git commit -m "Initial commit"
echo "bad version" > essay
git commit -am "\"Improve\" essay"
[win]
# Get the first version of your essay, and make a new commit with it.
test "$(git show main:essay)" = "good version"

View file

@ -0,0 +1,5 @@
restore-a-file
restore-a-file-from-the-past
bad-commit
pushed-something-broken
reflog

5
levels/it/stash/sequence Normal file
View file

@ -0,0 +1,5 @@
stash
stash-pop
stash-clear
stash-branch
stash-merge

45
levels/it/stash/stash Normal file
View file

@ -0,0 +1,45 @@
title = Stashing
cards = checkout commit-auto merge reset-hard
[description]
You will encounter situations in which you are working on your project but you need to
put your current changes aside temporarily. To do so, you can use the stash function. Use
git stash push
to add your current changes to the stash stack.
---
tipp1
---
tipp2
---
tipp3
[setup]
echo "Apple Pie:" > recipe
git add .
git commit -m "creating a recipe"
echo "- 4 Apples" >> recipe
git add .
git commit -m "Adding ingredients"
echo "- 500g Flour" >> recipe
git checkout main
[win]
# Did you stash the current changes?
test "$(git stash list | wc -l)" -ge 1
[actions]
[congrats]
Nice stash you got there! :)

View file

@ -0,0 +1,48 @@
title = Branch from stash
cards = checkout commit-auto merge reset-hard
[description]
If you want to keep your changes but they don't belong to the main branch, you can easily
create a new branch from your stashed changes. Just use
git stash branch <branchname> <stash>
If you just want to use the latest stash entry, you can leave the <stash> option empty.
Create a new branch from the stashed changes!
---
tipp1
---
tipp2
---
tipp3
[setup]
echo "Apple Pie:" > recipe
git add .
git commit -m "creating a recipe"
echo "- 4 Apples" >> recipe
git add .
git commit -m "Adding ingredients"
echo "- 500g Flour" >> recipe
git stash push
git checkout main
[win]
# Did you create a new branch from the stashed changes?
test "$(git branch --list| wc -l)" -ge 2
[actions]
[congrats]
Stashed changes are in a new branch! :)

View file

@ -0,0 +1,57 @@
title = Clear the Stash
cards = checkout commit-auto merge reset-hard
[description]
If you want to inspect your stash stack, use the command
git stash list
Oh, you don't want to keep your stashed changes? There are way too many? Then go ahead and clear the stack with
git stash clear
If you only want to discard a certain stash entry, you can use
git stash drop <stash>
Clear your stash stack!
---
tipp1
---
tipp2
---
tipp3
[setup]
echo "Apple Pie:" > recipe
git add .
git commit -m "creating a recipe"
echo "- 4 Apples" >> recipe
git add .
git commit -m "Adding ingredients"
echo "- 500g Flour" >> recipe
git stash push
echo "- 200g Sugar" >> recipe
git stash push
echo "- Pinch of Salt" >> recipe
git stash push
git checkout main
[win]
# Did you clear your stash stack?
test "$(git stash list | wc -l)" -eq 0
[actions]
[congrats]
All clear! :)

View file

@ -0,0 +1,54 @@
title = Merging popped stash
cards = checkout commit-auto merge reset-hard
[description]
When you want to reapply your changes but you already continued working on your file, you might get
a merge conflict! Let's practise this situation.
Pop the changes from the stash with
git stash pop
and resolve the merge conflict. Commit the resolved changes and clear the stash stack afterwards.
---
tipp1
---
tipp2
---
tipp3
[setup]
echo "Apple Pie:" > recipe
git add .
git commit -m "creating a recipe"
echo "- 4 Apples" >> recipe
git add .
git commit -m "Adding ingredients"
echo "- 500g Flour" >> recipe
git stash push
echo "- Pinch of Salt" >> recipe
git checkout main
git add recipe
[win]
# Did you resolve the confict and commit?
{ git show HEAD | grep "Flour"; } && { git show HEAD | grep "Salt"; }
# Did you clear stash stack?
test "$(git stash list | wc -l)" -eq 0
[actions]
[congrats]
Yay, you got your changes back! :)

46
levels/it/stash/stash-pop Normal file
View file

@ -0,0 +1,46 @@
title = Pop from Stash
cards = checkout commit-auto merge reset-hard
[description]
When you stashed your changes and you want to apply them back to your current working directory, you can use
git stash pop
This will remove the changes from the stash stack. If you also want to keep the changes on the stash stack, use
git stash apply
---
tipp1
---
tipp2
---
tipp3
[setup]
echo "Apple Pie:" > recipe
git add .
git commit -m "creating a recipe"
echo "- 4 Apples" >> recipe
git add .
git commit -m "Adding ingredients"
echo "- 500g Flour" >> recipe
git stash push
git checkout main
[win]
# Did you pop the changes from the stash stack?
test "$(git stash list | wc -l)" -eq 0
[actions]
[congrats]
Yay, you got your changes back! :)

53
levels/it/tags/add-tag Normal file
View file

@ -0,0 +1,53 @@
title = Creating tags
cards = checkout commit-auto merge reset-hard
[description]
Some of your commits may be special commits. Maybe you reached a milestone or a new version number.
You can mark these commits with a special flag called 'tag'.
Write
git tag <tag-name>
to tag your commit.
---
tipp1
---
tipp2
---
tipp3
[setup]
echo "event 1" > feature-list
git add .
git commit -m "Adding feature 1"
echo "event 2" >> feature-list
git add .
git commit -m "Adding feature 2"
echo "event 3" >> feature-list
git add .
git commit -m "Adding feature 3"
git checkout --detach main
[win]
# Did you create a new tag?
test "$(git tag -l | wc -l)" -ge 1
[actions]
[congrats]
Nice! You tagged your first commit :)

View file

@ -0,0 +1,50 @@
title = Tagging later
cards = checkout commit-auto merge reset-hard
[description]
But what happens if you forgot to tag your current commit?
No Prob! You can also tag older commits via
git tag <tag-name> <commit-hash>
Tag the commit "Adding feature 2" with the name "v1"!
---
tipp1
---
tipp2
---
tipp3
[setup]
echo "event 1" > feature-list
git add .
git commit -m "Adding feature 1"
echo "event 2" >> feature-list
git add .
git commit -m "Adding feature 2"
echo "event 3" >> feature-list
git add .
git commit -m "Adding feature 3"
git checkout --detach main
[win]
# Did you create a new tag?
test "$(git show v1 -s --format=%h)" = "$(git show HEAD~1 -s --format=%h)"
[actions]
[congrats]
Well done :)

58
levels/it/tags/remote-tag Normal file
View file

@ -0,0 +1,58 @@
title = Remote Tags
cards = pull push commit-auto checkout
[description]
When you work with remote repositories, tags are not pushed or pulled automatically.
You can push a tag with
git push <remote> <tag-name>
Or all tags with:
git push <remote> --tags
Deleting tags on your remote works with:
git push <remote> --delete <tag-name>
You can also sync
git fetch <remote> --prune --prune-tags
Add a tag named "v2" to the last commit and push it to the remote. Also pull the v1 tag to your local repository.
[setup yours]
git checkout main
git checkout main
echo "toothbrush sharing" > project-ideas
git add .
git commit -m "First idea"
echo "Is my phone upside down? App" >> project-ideas
git commit -am "Another idea"
git push friend main
git branch -u friend/main main
[setup friend]
[actions friend]
git tag v1 HEAD~1
[win]
# v1 tag in your repo
test "$(git show v1 -s --format=%h)" = "$(git show HEAD~1 -s --format=%h)"
# v2 tag in your repo
test "$(git show v2 -s --format=%h)" = "$(git show HEAD -s --format=%h)"
[win friend]
# v2 tag in the remote
test "$(git show v2 -s --format=%h)" = "$(git show HEAD -s --format=%h)"

53
levels/it/tags/remove-tag Normal file
View file

@ -0,0 +1,53 @@
title = Removing tags
cards = checkout commit-auto merge reset-hard
[description]
You added way too many tags? No prob! Delete them with
git tag -d <tag-name>
Remove all tags in this repo!
---
tipp1
---
tipp2
---
tipp3
[setup]
echo "event 1" > feature-list
git add .
git commit -m "Adding feature 1"
echo "event 2" >> feature-list
git add .
git commit -m "Adding feature 2"
echo "event 3" >> feature-list
git add .
git commit -m "Adding feature 3"
git tag v1 HEAD~2
git tag v2 HEAD~1
git tag v3
git checkout --detach main
[win]
# Did you remove all tags?
test "$(git tag -l | wc -l)" -eq 0
[actions]
[congrats]
Well done :)

4
levels/it/tags/sequence Normal file
View file

@ -0,0 +1,4 @@
add-tag
remove-tag
add-tag-later
remote-tag

31
levels/it/unused/checkout Normal file
View file

@ -0,0 +1,31 @@
title = Getting the last version
cards = checkout-file
[description]
You've been working on your essay for a while. But - ughh! Now your cat walks over your keyboard and "helps you", so now it's all messed up! :/
But Git is here to help! To discard all changes your cat made, and go back to the version in the last commit, use `checkout`!
[setup]
echo "A" >> essay.txt
git add .
git commit -m "Initial commit"
echo "B" >> essay.txt
git commit -a -m "Improved version"
echo "C" >> essay.txt
git commit -a -m "Even better version"
echo "D" >> essay.txt
git commit -a -m "Marvelous version"
echo "blarg
blaaaargh" > essay.txt
[win]
# Restore the version from the last commit.
cat essay.txt | grep D

20
levels/it/unused/clone Normal file
View file

@ -0,0 +1,20 @@
title = Cloning a repo
cards = clone commit-auto pull push
[description]
Get your friend's repo using clone, change something, push it back.
[setup]
rm -rf .git
[setup friend]
echo hi > file
git add .
git commit -m "Initial commit"
[win friend]
test "$(git show main:file)" != hi

27
levels/it/unused/commit Normal file
View file

@ -0,0 +1,27 @@
title = Make a commit \o/
cards = add reset checkout commit
[description]
For practice, make a commit where all files contain an "x"!
[setup]
echo a > a
echo x > b
echo x > c
git add .
git commit -m "Initial commit"
echo x > a
echo b > b
git add b
echo c > c
[win]
# File a contains "x" in the last main commit.
test "$(git show main:a)" = x
# File b contains "x" in the last main commit.
test "$(git show main:b)" = x
# File c contains "x" in the last main commit.
test "$(git show main:c)" = x

26
levels/it/unused/commit-a Normal file
View file

@ -0,0 +1,26 @@
title = Make a commit, but faster!
cards = add reset checkout commit commit-a
[description]
There is a time-saving trick, where instead of a plain `git commit`, you can use
git commit -a
This will automatically add all changes you made to local files! Very convenient.
[setup]
echo a > a
echo b > b
echo c > c
git add .
git commit -m "Initial commit"
echo x > a
echo x > b
echo x > c
[win]
# Make a commit where all files contain "x".
test "$(git show main:a)" = x && test "$(git show main:b)" = x && test "$(git show main:c)" = x

35
levels/it/unused/fetch Normal file
View file

@ -0,0 +1,35 @@
title = Fetching from remotes
cards = checkout fetch commit-auto
[description]
Here, you already have two remotes configured! You can list them using `git remote`.
Fetch from both, and look at the suggestions.
Then, make a new commit on top of your original one that introduces a compromise.
[setup]
echo "The bikeshed should be ???" > proposal
git add .
git commit -m "What do you think?"
[setup friend1]
git pull yours main
echo "The bikeshed should be green" > proposal
git commit -am "Green"
[setup friend2]
git pull yours main
echo "The bikeshed should be blue" > proposal
git commit -am "Blue"
[win]
# Your proposal is acceptable for friend1.
git show main:proposal | git grep green
# Your proposal is acceptable for friend2.
git show main:proposal | git grep blue

View file

@ -0,0 +1,27 @@
title = No sleep required
cards = file-new file-delete file-rename
[description]
Actually, you decide that you don't need any sleep.
Because of that, you won't require a bed, and can build some other piece of furniture from the wood!
[setup]
echo A yellow cupboard with lots of drawers. > cupboard
echo A really big yellow shelf. > shelf
echo A comfortable, yellow bed with yellow cushions. > bed
[win]
# Rename the bed into something else, and give it a new description!
NUM_FILES="$(ls | wc -l)"
! test -f bed && test "$NUM_FILES" -ge 3 && ! grep -r "yellow bed" .
[congrats]
Neat! It even still looks a bit comfortable!
You head out, eager for your first lesson at time travel school!

26
levels/it/unused/index-mv Normal file
View file

@ -0,0 +1,26 @@
title = Rename a file in the next commit
cards = add reset-file checkout-file mv commit
[description]
Other times, you might want to rename a file in the next commit. Use
git mv [file] [new name]
for that. The effect is very similar as if you had created a copy with a new name, and removed the old version.
[setup]
echo a > a
echo SPECIAL > b
echo x > c
git add .
git commit -m "Initial commit"
echo x > a
echo b >> b
git add b
[win]
# Make a commit where you rename the file b to "x".
test "$(git ls-tree --name-only main)" = "$(echo -e "a\nc\nx")"

14
levels/it/unused/init Normal file
View file

@ -0,0 +1,14 @@
title = Welcome!
cards = init
[description]
[setup]
rm -rf .git
[win]
# Again, initialize your time machine!
test -d .git

View file

@ -0,0 +1,51 @@
title = Helping each other
cards = checkout commit-auto reset-hard pull push
[description]
The events and timelines you see are always only what your own time machine knows about!
Of course, time agents don't have to work alone! Here, your sidekick has already prepared a merge for you! You can use the "pull" card to transfer it to your own time machine.
Then, add another event on top (what does Sam have for dinner?), and `push` the result, to transfer it back to your sidekick!
You can only ever manipulate things in your own time machine (the one on the bottom).
[setup yours]
echo "Just woke up. Is hungry." > sam
git add .
git commit -m "The beginning"
git checkout -b pancakes
echo "Had blueberry pancakes with maple syrup for breakfast." > sam
git add .
git commit -m "Pancakes!"
git checkout -b muesli main
echo "Had muesli with oats and strawberries for breakfast." > sam
git add .
git commit -m "Muesli!"
git checkout main
git push -u sidekick main pancakes muesli
[setup sidekick]
git checkout main
git merge pancakes
git merge muesli
echo "Had pancakes with strawberries for breakfast." > sam
git add .
git commit -m "Let's make this breakfast compromise" --author="Sidekick <sidekick@example.com>"
[win sidekick]
# Below main's parent, there is a rhombus:
git rev-parse main^^ && test "$(git rev-parse main^^1^)" = "$(git rev-parse main^^2^)"
[congrats]
In reality, in many cases, a lot of time agents work together to build a really good future together! :)

View file

@ -0,0 +1,33 @@
title = Adding a remote
cards = checkout
[description]
Let's work together with others! Your friend has their own repo at the URL `../friend` - you can add it using
git remote add [name] [URL]
where `[name]` is an arbitrary, short name you pick for the remote.
When you've done that, you can get all commits from that remote using
git pull friend
There's a letter for you!
[setup]
git remote remove friend
[setup friend]
echo "I'm really committed to our friendship! <3" > love_letter
git add .
git commit -m "Write a letter"
[win]
# Add a remote that points to ../friend.
git remote -v | grep '../friend'
# Pull from the remote.
git show HEAD:love_letter | grep committed

View file

@ -0,0 +1,23 @@
title = Deleting and renaming a remote
cards = checkout
[description]
Here, you already have two remotes configured! You can list them using `git remote`.
[setup]
git remote rename friend frend
[setup friend]
[setup enemy]
[win]
# Rename the remote with the typo (using `git remote rename [old name] [new name]`)
git remote | grep friend
# The remote with the typo is gone.
! grep 'frend' <(git remote)
# Delete the remote you don't want to keep (using `git remote remove [remote]`)
! grep 'enemy' <(git remote)

28
levels/it/unused/restore Normal file
View file

@ -0,0 +1,28 @@
title = Looking into the past
cards = checkout-from
[description]
You've been working on your essay for a while. But you're not happy with the changes you've made recently. You want to go back to the version called "Best version"!
No problem, you can use the `checkout` card to restore your essay from an older commit!
[setup]
echo "Initial version" > essay.txt
git add .
git commit -m "Initial commit"
echo "Improved version" > essay.txt
git commit -a -m "Improved version"
echo "Best version" > essay.txt
git commit -a -m "Best version"
echo "Less-good version" > essay.txt
git commit -a -m "Less-good version"
[win]
# For nostalgic reasons, restore the very first backup you made!
diff essay.txt <(echo "Best version")

26
levels/it/unused/split Normal file
View file

@ -0,0 +1,26 @@
title = Split a commit!
cards = checkout commit reset-hard reset add rebase-interactive rebase-continue show
[description]
Here, both changes happened in one commit! Split them to be in two commits instead.
[setup]
echo something > file1
echo something else > file2
git add .
git commit -m "Initial commit"
echo this should happen first >> file1
echo and this should happen after that >> file2
git commit -am "Both together"
echo this is some other change >> file1
echo this is some other change >> file2
git commit -am "Something else"
[win]
test "$(git diff-tree --no-commit-id --name-status -r main^)" = "M file2" &&
test "$(git diff-tree --no-commit-id --name-status -r main~2)" = "M file1"

23
levels/it/unused/steps Normal file
View file

@ -0,0 +1,23 @@
title = One step after another
cards = checkout commit reset-hard add
[description]
Sometimes, you might want to record the order in which things changed, instead of making a single commit.
What happened here? Make two commits from the changes (using the "add" card), in an order that makes sense!
[setup]
echo something > file1
echo something else > file2
git add .
git commit -m "Initial commit"
echo this should happen first >> file1
echo and this should happen after that >> file2
[win]
test "$(git diff-tree --no-commit-id --name-status -r main)" = "M file2" &&
test "$(git diff-tree --no-commit-id --name-status -r main^)" = "M file1"

View file

@ -0,0 +1,23 @@
title = Nice to meet you!
cards = config-name config-email
[description]
Introduce yourself using
git config --global user.name Firstname
git config --global user.email "your@mail.com"
[setup]
[actions]
test "$(git config user.name)" != "You" && hint "Hey $(git config user.name), nice to meet you!"
[win]
# Have a name configured.
test "$(git config user.name)" != "You"
# Have an email address configured.
test "$(git config user.email)" != "you@time.agency"

View file

@ -0,0 +1,18 @@
title = Ignoring files
[description]
That chicken is running around a lot, and changing often. We don't want to have it in our commits.
Add it to the file .gitignore, and try using `git add .`!
[setup]
touch .gitignore
echo important > important
git add important
git commit -m "Initial commit"
[actions]
echo "$RANDOM" > chicken

25
levels/it/workflows/pr Normal file
View file

@ -0,0 +1,25 @@
title = Cloning a repo
cards = clone commit-auto reset-hard checkout file-new branch
[description]
Your friend has a problem! Clone the repo, create a branch called "solution", and fix the problem in this branch. When you're ready, make a "Pull Request" by using `git tag pr`.
[setup]
rm -rf .git
[setup friend]
echo "2 + 3 = " > file
git add .
git commit -m "Initial commit"
[actions friend]
git ls-remote yours | grep pr && git fetch yours && git merge yours/solution
git show main:file | grep 5 && hint "Thanks!"
[win friend]
git show main:file | grep 5

Some files were not shown because too many files have changed in this diff Show more