Exercise solutions

Solutions - Git first steps

Exercise 1 - Your first commit

  1. After initializing a new Git repository with git init, we run git status: what we can see is that, at this point, all files are untracked. The next step will therefore be to add some of the files to the git index so they can then be committed.
cd exercise_1   # To intialize a new git repository, we must first enter the repository in which
                # we want to track changes.
tree .          # This command is just to list the files present in a directory.
git init        # Create a new Git repository.
git status      # At this point, all files are untracked.
  1. Stage all files except test_results.out, then check the status of the repository again.
git status         # Files that we just added are displayed as "new file".
                   # They have been added to the Git index (aka, "staging area")
                   # and are ready to be committed.
  1. Make a first commit.
git commit -m "Initial commit for fake stringr package"
git log        # Shows commit history.
git show       # Shows content of the last commit.
git status     # There is now only 1 untracked files left: test_results.out
  1. Since we want the test_results.out file to be ignored by all copies of the repository, the correct location to exclude it is in .gitignore. After having created a new .gitignore file that contains the text "test_results.out", we still have one untracked file: the .gitignore file itself! This file is meant to be tracked by Git, so that it can be shared with others. Therefore we add it to the git index and then commit it.
echo "test_results.out" >> .gitignore
git status                             # There is still one untracked
                                       # file left: .gitignore !!

git add .gitignore                     # Stage the .gitignore file.
git commit -m "Add gitignore file"
git status                             # Now there are no more untracked
                                       # files displayed.
  1. Edit the README file to add the package author and URL information. Then commit the changes:
vim README.md          # Edit author and URL manually.
git add README.md
git commit -m "README: add author and URL info"
# Shortcut for the above 2 lines:
#  git commit -m "README: add author and URL info" README.md
  1. Explore different ways to display a Git repository's history:
git log
git log --pretty=oneline
git log --oneline
git log --all --decorate --oneline --graph
  1. Create an "adog" alias Git command and test it:
git config --global alias.adog "log --all --decorate --oneline --graph"
git adog
  1. Run the commands given in the instructions to create 3 new files and modify 2 existing files. When running git status you should see that 2 files are modified, and 3 are untracked (actually, the entire large_data directory will be shown as untracked).
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   DESCRIPTION
    modified:   README.md

Untracked files:
  (use "git add <file>..." to include in what will be committed)

no changes added to commit (use "git add" and/or "git commit -a")
  1. Explore the difference between git add -u and git add --all. First let's see what "add -u" does: it updates the Git index with the new version of all files that are already tracked by Git (in our case DESCRIPTION and README.md), but it does not stage any new, untracked files (in our case, personal_notes.txt and the files in large_data remain untracked).
git status
git add -u
git status

git reset HEAD     # Remove the staged changes for `DESCRIPTION` and `README.md`
                   # so we can test the "add --all" option.

Now let's test what "add -all" does: it updates the Git index with all modified and untracked files. As can be seen, our 5 files (modified and new) have now been staged:

git status
git add --all
git status

Changes to be committed:
    modified:   DESCRIPTION
    modified:   README.md
    new file:   large_data/large_1.csv
    new file:   large_data/large_2.csv
    new file:   personal_notes.txt

The difference between git add -u (-u is a shortcut for --update) and git add --all is that using --update will only add files that are already tracked in Git, while -all will add all files (except ignored files), whether they are already tracked (modified) for not (untracked). In a sense, --update is safer because it prevents you from adding completely new files to the Git repo by mistake.

  1. let's unstage each of our 3 files with one of the possible command to remove content from the git index:
git restore --staged personal_notes.txt
git reset HEAD large_data/large_1.csv
git rm --cached large_data/large_2.csv

The difference between git rm --cached and the two other commands is that git rm --cached will unstage the entire file, not just the new changes that were made to it since the last commit.
The reason why in this particular case git rm --cached does exactly the same as git restore --staged and git reset HEAD is because the 3 files that we unstaged are new and have never been added to the Git repo before. There is thus no difference between removing them completely, or just resetting them back in the index to their version from the latest commit (since they are all absent from the latest commit).

  1. Since the content of large_data should be ignored by all copies of the repository, we ignore it using the .gitignore file.
    personal_notes.txt, on the other hand, should only be ignored only by the local instance of the Git repo, and must therefore be added to .git/info/exclude.
echo "large_data" >> .gitignore
echo "personal_notes.txt" >> .git/info/exclude
git status
  1. Commit all remaining changes:
git add .gitignore
git status
git commit -m "Update DESCRIPTION and README"
git status
git log --oneline

Exercise 2 - The git reference web page

Change into the exercise_2 directory, and look at the current status of the git repository.

cd exercise_2
git log
git log --oneline     # There are 3 commits in the repo.
git branch            # There is 1 branch: master.
git status            # There is one tracked file with
                      # unstaged changes: references.html

A) Fix the broken "ProGit" link.

Make a new commit with any non-committed changes:

git diff
git add references.html
git commit -m "Add Git logo placeholder to the Git reference webpage"
# Shortcut for the above 2 lines:
#  git commit -m "Add Git logo placeholder to the Git reference webpage" references.html
#  or
#  git commit -am "Add Git logo placeholder to the Git reference webpage"

git status   # There are no more uncommitted changes.

Fix the "ProGit" link in a temporary fix branch. After testing that the HTML page works correctly, commit the change.

git branch fix
git checkout fix     # Alternatively, you can also use "git switch fix"
# Shortcut for the above 2 lines: "git checkout -b fix" or "git switch -c fix"

vim references.html           # Edit the HTML page... then verify
                              # in the browser that it works.
git add references.html
git commit -m "Fix broken ProGit link"
# Shortcut for the above 2 lines:
#  git commit -m "Fix broken ProGit link" references.html
#  or
#  git commit -am "Fix broken ProGit link"

Merge the changes into branch master and delete branch fix.

git checkout master
git merge fix         # Note: no additional commit is created by the merge,
                      # because this is a "fast-forward" merge.
git log --all --decorate --oneline --graph

git branch -d fix     # Delete the "fix" branch, as we no longer need it.
git branch            # Verify "fix" branch is gone.
git log --all --decorate --oneline --graph    # Show repo history again.

B) Add an image and new links to the HTML page.

Add new links to webpage:

git checkout -b dev            # Alternatively, "git switch -c dev".
vim references.html            # Edit HTML page to add the new links...

# After having checked that the two new links are working, stage and commit the changes:
git diff
git diff --cached
git add references.html
git diff
git diff --cached
git commit -m "Add two new links to Git reference page"

Add Git logo to webpage:

vim references.html             # Edit HTML page to add logo...
git commit -m "Add git logo" references.html

Merge changes into master, delete branch dev:

git checkout master
git merge dev
git log --all --decorate --oneline --graph

git branch -d dev      # Delete "dev" branch.

Exercise 3 - The crazy peak sorter script

Clone the peak sorter project from GitHub, test run the peak sorter script and display the Git repository's history.

cd exercise_3/
git clone https://github.com/sibgit/exercise_3.git
cd peak_sorter
git log --all --decorate --oneline --graph

A) Add a fix to the master branch

Apply Jimmy's fix using cherry-pick on a temporary hotfix branch

git checkout -b hotfix                       # Alternative: git switch -c hotfix
git log --all --decorate --oneline --graph   # search for the commit of Jimmy's fix: 1c695d9
git cherry-pick 1c695d9
git log --all --decorate --oneline --graph   # Verify the commit was properly cherry-picked.
git show HEAD                                # Have a look at changes introduced by the cherry-pick.
./peak_sorter.sh                             # Test run the script to verify nothing is broken.

Merge the fix back into master.

git checkout master
git merge hotfix
git log --all --decorate --oneline --graph
./peak_sorter.sh                            # Test run: check the script is still working.
git branch -d hotfix                        # Delete hotfix branch, as we no longer need it.

B) Add the Dahu count feature to the master branch

Checkout the feature-dahu branch. Run the script to test that it works. Then rebase it on master.

git checkout feature-dahu

Rebase feature-dahu on master. As there are conflicts, we need manually resolve them by opening the conflicted file in an editor, resolving the conflict, then running git add peak_sorter.sh and git rebase --continue.

git rebase master

# There are 3 conflicts, so repeat the steps below 3 times.
vim peak_sorter.sh           # Solve the conflict in an editor.
git add peak_sorter.sh
git rebase --continue

./peak_sorter.sh             # Test run to see if everything is
                             # still working after the rebase.

We are now ready to merge the new feature into master:

git checkout master
git merge feature-dahu       # This is now a fast-forward merge.
./peak_sorter.sh             # Test run to see if everything is
                             # still working after the merge.

Note: trying to delete the local branch feature-dahu with the safe -d option will not work, because changes on the branch have not been pushed to the upstream branch 'origin/feature-dahu'.

Exercise 4 - The Awesome Animal Awareness Project

A) Organize your team

Clone the repo.

cd exercise_4/
git clone https://github.com/sibgit/sibgit.github.io.git
cd sibgit.github.io

The team leader creates the main development branch for the team and pushes it to the remote repository on GitHub. The example here is for the team "yeti"

git checkout -b yeti-dev
git push -u origin yeti-dev       # note: -u is the short option for --set-upstream-to

Other team members can now pull the new yeti-dev branch and create a local copy of it by checking-it out.

git fetch
git checkout yeti-dev

B) Add content for your awesome animal

Each team member creates his personal work branch. The example here is for Alice, working in team Yeti. She edits the yeti.html page in her favorite editor. When she is done, she load the page in her browser to make sure the rendering is looking good. Then she can commit he changes.

git checkout -b yeti-alice
git add yeti.html
git commit -m "Add habitat and distribution info to yeti page."

C) Merge your branch with your team's animal-dev branch

Each member of the team must now add the changes they made on their personal branch to the team branch branch. Let's assume that Alice is the last of the team to make changes.

git checkout yeti-dev
git pull
git checkout yeti-alice

git rebase yeti-dev        # Conflicts will appear, so Alice must solve them manually.
git add yeti.html
git rebase --continue

Now that the rebase is completed, Alice can merge her branch into yeti-dev. Then she pushes the updated yeti-dev branch to the remote.

git checkout yeti-dev
git merge alice-dev           # This is now a simple fast-forward merge.
git push -u origin yeti-dev

D) Create a pull request for the top-level management to verify and approve your work.

Now that the yeti page is completed, the team leader can make a pull request to the owner of the project on GitHub (i.e. one of the class teachers).
When the request is accepted, this will merge the changes in yeti-dev into the master branch of the project.
All members of the team can now view their work at [https://sibgit.github.io/tiger.html], and update their local git repo:

git fetch
git checkout yeti-dev
git pull
git checkout master
git pull

Last modified: Tuesday, 26 January 2021, 5:13 PM