# git exercise. Single developer and local repository.
#
# In this demo/exercise we will develop a toy math-library
# with simple functions: `add`, `sub`, `mul` and `div`
# The functions are trivial, but to understand git, let's assume they were not.
# Each function should be committed seperately.
#
# Hint: the demo and solutions modify all files using command-line tools.
# This allows to automatically run this demo. Feel free to use an editor
# instead.

# -- Setting Up --
# First move to a safe place (e.g. go into the tmp folder with cd /tmp/):
cd /tmp/

# Run the 'git' command and read the output, its a useful summary.
git

# Ask git what it knows about the status of the current directory.
git status

# Introduce yourself to git (set the variables for name and email):
git config --global user.name "Nicola Chiapolini"
git config --global user.email "nicola.chiapolini@physik.uzh.ch"

# Verify that git has correctly stored your config (see 'git help config')
git config user.name
git config user.email
# alternatively use `git config -l`

# Create a directory for this exercise and enter it.
mkdir demo_git_single_local
cd demo_git_single_local

# Create a new git repository within the current directory.
git init

# Verify that you have a brand new ".git/" directory...
ls -al
# ...and its content.
ls -al .git/

# Check the status and compare the output to the one from last time
git status


# -- A First Commit --
# Create a file named simple_math.py with a single function
# ```
# def add(a,b):
#     return a+b
# ```
# (without the ```)
cat > simple_math.py <<EOF
def add(a,b):
    return a+b

EOF
cat simple_math.py

# Check the status and compare the output to the one from last time
git status

# tell git to keep track of simple_math.py (put it in the staging area)
git add simple_math.py
# and check how the status changes
git status

# Now record commit to the repository.
git commit -m "My first commit. A big step for mankind."

# Check status again, it is instructive.
git status


# -- Modifying Files and Committing Changes --
# add a function `subtract(a,b)` calculating a-b to simple_math.py
cat >> simple_math.py <<EOF
def subtract(a,b):
    return a-b

EOF

# See how the status changes accordingly.
git status

# Show the changes between current and staged files.
git diff

# Directly commit simple_math.py (`git commit <filename>` -m ...)
git commit simple_math.py -m "add subtraction"

# And again the status..
git status


# -- Using the Staging Area --
# Add a function `multiply(a,b)` to simple_math.py
cat >> simple_math.py <<EOF
def multiply(a,b):
    return a*b

EOF

# And check the status...
git status

# Add the new changes to staging area
git add simple_math.py

# and check what is going to be committed
git diff --staged

# Oh! We wanted to use 3-letter function names
#
# Rename `mutliply` to `mul`
sed -i 's/multiply(/mul(/' simple_math.py 

# and see how the status changes accordingly.
git status
# Then look at the changes between the 3 different versions.
git diff
git diff --staged

# Update the staging area,
git add simple_math.py

# check status and changes
git status
git diff
git diff --staged

# and finally commit.
git commit -m "add multiplication"


# -- Splitting Changes into several Commits --
# start to work on the division function
#
# add `def div(a,b):` to simple_math.py
echo "def div(a,b):" >> simple_math.py 

# Wait, `subtract` has a wrong name as well.
#
# It should be `sub` not `subtract`. Fix it!
sed -i 's/subtract(/sub(/' simple_math.py 

# Inspect the status and the changes.
git status
git diff

# We are not done with `div` yet but we want to commit the bugfix now.
# In addition, we would like to keep the bugfix in a separate commit:
#
# Add only the bugfix to the staging area. (Hint: use `git add -p`)
git add -p simple_math.py
?
s
y
n

# Check the status and the changes between the 3 different versions.
git status
git diff --staged
git diff

# Commit *only* the bugfix
git commit -m "fix function name of subtraction"
# and see how the status changes accordingly.
git status

# Verify that changes not added to the staging area were not recorded.
git diff

# Finish implementing `div`
echo "    return a/b" >> simple_math.py
echo "" >> simple_math.py

# check the status and the changes
git status
git diff

# and commit the function.
git commit simple_math.py -m "add division"


# -- Changes Affecting Several Files --
# Now we want to add output to each of our functions.
#
# Create a file `logger.py` with content
# ```
# def logger(a,b):
#     print(a,b)
# ```
cat > logger.py <<EOF
def logger(a,b):
    print(a,b)

EOF

# Check the status
git status

# and understand the output of git diff
git diff

# Now add a call to `logger()` to each function in simple_math.py.
# (Don't forget to import the function)
echo -e "from logger import logger\n" | cat - simple_math.py | sponge simple_math.py
sed -i 's/:/:\n    logger(a,b)/' simple_math.py

# Inspect the status.
git status

# Prepare the staging area for this commit.
git add logger.py simple_math.py

# Check that the staged changes include everything
git diff --staged

# Commit
git commit -m "added logging"

# Check that everything looks good.
git status


# -- Looking around --
# See the logs of all commits.
git log

# See the logs of all commits with the git GUI.
qgit

# Show the changes made by the bugfix-commit.
# (get the commit-hash from git log)
git show ...


# -- Unwanted Changes --
# Go crazy.
#
# Remove logger.py
git rm logger.py
# and commit the change.
git commit -m "there you have it!"

# Replace the content of simple_math.py
echo "printttt('I hate you...')" > simple_math.py

# Oh no! What have you done! Shame!
#
# Look at the status and the local changes.
git diff
git status

# Get rid of the untracked changes
git restore simple_math.py

# check that simple_math.py is good now
git status
cat simple_math.py

# We are still missing a file.
#
# Check which commits affected logger.py
git log -- logger.py
git show HEAD

# and revert bad commit.
## (`--no-edit` to prevent opening the editor)
git revert HEAD --no-edit

# Verify that everything is back to normal.
ls
cat logger.py
git status
git diff

#Relax: your work is safe.
