Homework 1

Due Thursday, September 12th 2019 at 11:59 PM.

Topics

Part 1: Course Survey

Part 2: Basics

Part 1 [10 pts]: Course Survey

Problem 1 [10 pts]

Take the following survey: CS207 Introductory Survey.

Part 2 [90 pts]: Basics

A short example of the absolutely essential Unix commands can be found at the end of this notebook: Some essential Unix commands.

Problem 2: Unix

For these problems you will submit the single Unix command that outputs the desired result. Note that there are many different ways to do these problems.

Note on submission: For exercises A through D in this section, please submit the commands in a text file called P2.sh. Each line should correspond to a command representing the solution in order (ie line 1 problem A, line 2 problem B, etc.) Hence you're file should be 4 lines only looking something like

ls -ltr

cp p1.py p2.py

grep -v

wc p1.py

Exercise E should be submitting in a file called p2E.sh

Example Problem: Use two Unix commands (on a single line) to count the number of words in a file.

Example Solution: example_solution

A [5 pts]: You are provided with apollo.txt. Write a command that writes the number of lines in the file that contain a numerical digit to an output file called `apollo_out.txt' Your command should assume that the text file is in the current directory.

For example, if the provided text file was

a9
2c
abd
939

Then the resulting command should output a file with $3$.

B [5 pts]: Write a command that ouputs a single line that tells what the -c option does in grep.

(Hint: For git bash/Linux users You might need the results of grep --help. For Mac users you will need to use the output of man and potentially clean it up with col (man grep | col -b might be a good starting point). See http://www.softpanorama.org/Tools/col.shtml)

For example, to look for the --V command the output should look like

-V, --version display version information and exit.

C [5 pts]: Write a command that counts the total number of .py files in your current directory.

For example, suppose the following files are in the current directory,

p1.py

Documents/

checkGrades.c

rejected_hard_problem.py

Then output of the command should be $2$.

D [5 pts]: Write a command that counts the number the files/directory that "others" DO NOT have read/write access to.

For example, if the directory contains 10 files and only and 6 of them have read/write permissions for "others", then the output should be 4.

E [10 pts]: Write a bash script that counts and prints the number of lines of each file in the current directory along with its name. Your resulting file should be called p2E.sh.

For example, if the directory contains the files,

p1.py

Documents/

checkGrades.c

rejected_hard_problem.py

then the output might look like

p1.py 10

checkGrades.c 100

rejected_hard_problem.py 10000.

Problem 3: Git crash course

A vital part of software development is being able to manage changes and the entire workflow of a project. Version Control Systems (VCS) are the primary tool used to keep track of actual changes to code. Git is the most common VCS used and it is what we will use for this course.

Grading on this problem will be based on the edits you make to your branch as well as a screenshot that we'll ask for during the assignment.

Part A [10 pts]: Getting Started

Before we make changes we're first going to start working off an existing git repository (repo). Go to https://github.com/dsondak/playground. There will be a green button that says Clone or Download. The website will give you a URL.

updated_README Copy that URL. In either your terminal or Git Bash go to your homework directory for this assignment.

In the command line type:

git clone

Now you'll see an entirely set up git repo for you with all the content.

The problem with this approach is that you do not have push access to this public repo. Therefore, when you try to do the next exercises and push your changes, you will get a permission denied error. There are two ways to solve this:

  1. Have the repository owner give you push access --- This will be challenging with a course this size.
  2. Create your own fork of the repository and make a pull request (PR) back to the original repository when you've made all the changes. This is the approach that you will take in this assignment.

To use the forking workflow, use the following steps:

  1. Fork the repo by clicking the fork button in the upper right hand corner fork
  2. Now you have a forked copy of the repository! From this forked repo, copy the repo link (as discussed above) and type git clone into your command line. Now you have a local copy of the forked repository.
  3. Complete Part B on your fork. When you've made your changes, make a PR into the master branch of dsondak/playground. We will review your work through the PR.

Note that Part C requires you to set up a fork. You've already done that in this step. However, part C goes one step further and discusses remotes so make sure you still complete that part.

Part B [25 pts]: Branches and Merge Conflicts

One of the most fundamental concepts in git is the concept of a branch.

A branch is an area from which code can be updated or modified and continually branched. It's good practice to NEVER make changes directly on master but create a branch to work off of during development. To see a list of branches type

git branch --list

If you've started this assignment early, you may only see a few branches. If you started after others you may see many other branches! To switch to the TF branch type git checkout TFtestbranch

git checkout moves you from one branch to another.

If you type ls you'll see that there's an extra file on this branch. Different branches can contain different files in addition to different content in exisiting files.

Next you will make your own branch. First switch back to master - type git checkout master.

Now you're ready to create your first branch (you should name it firstname_lastname) git branch firstname_lastname.

To move to this branch use git checkout firstname_lastname.

And ta-da you've created your own branch!

Create one more branch. You can use a single command git checkout -b firstname_lastname_changes.

(This is simply doing a combination of branch and checkout in one line)

Now update the README.md. Open up README.md and add your name to the top of the file. Use Markdown format. Save and close the file. Note: You may use your text editor of choice to edit the file. DO NOT use Word or Google Docs.

In the same terminal, type git status. This is how you see changes to the repo.

git status will summarize everything that is going on in your branch and is immensely useful (running git status is almost always a good thing to do). A good practice is to use git status after every git action you take.

Now we'll actually add the file. Type git add README.md.

This lets git know that you are preparing to commit README.md (formally this is called staging). After that if you try git status you should see something like:

git_add

Now type git commit.

You'll see a texteditor pop up. Don't get worried by the stuff already there - on the first line add a description of what this commit is doing (i.e updating the README with your name). Note: Depending on your system, git commit may open different kinds of text editors. In general, the default text editor is vim (or vi). You can change the default if you prefer. For now, if you're not familiar with vim, simply type enter the following commands:

  • Type the letter i for insert. This opens insert mode.
  • Enter your message.
  • Press the escape button, esc. This exits insert mode.
  • Type :wq. The : enters command mode. w means write and q means quit.

Congrats! You've made your first commit.

(You can also do git commit -m "YOUR COMMIT MESSAGE" to avoid the texteditor popping up.)

If you type git status you'll see git telling you there's nothing new to commit. git_commit

However, this has only changed your history locally! You still need to let the world (that is remote/github) know that you've made these changes. To accomplish this, enter

git push

in the terminal.

But when you do that you'll get a funny error message

fatal: The current branch has no upstream branch

It'll also tell you how to resolve the issue. For my branch

git push --set upstream origin aditya_karan_2

What this is doing is it's telling git which remote repo it needs to push to. By default if you type in "origin" it will reference the remote repo that you clone/pulled from originally (each time you add a new branch you'll have to set the upstream if you want to push it to the remote. ).

Follow those instructions and then push. (If you haven't set up authentication you'll have to type in your github username/password) git_push

After that it'll be updated in remote (Github). Your collaboraters (and your TFs if you gave them access) will now be able to pull from your branch!

Now let's try something else. Let's go back to your branch "firstname_lastname": git checkout firstname_lastname.

If you open up the README - you'll see that your name isn't on the README. This is expected as you only made changes on a different branch.

Now we'll update this README - instead of your name add some of the courses you're planning on taking this semester and commit (don't push!) like above.

Now we'd like our current branch to reflect the changes from the branch we made earlier (branch firstname_lastname_changes). To combine branches while on branch "firstname_lastname" type git merge firstname_lastname_changes.

You should notice in your terminal AUTOMATIC merge failed; fix conflicts and then commit. git_merge1

Don't worry - this is expected! What has happened is the history of these two branches have diverged and git doesn't know what the result should be (should it keep your changes or your colleagues changes? which one is correct?). In some cases (if the changes are distinct enough) git is smart enough to do the merge. However, in this case it cannot and there is a merge conflict. Git keeps both changes and provides annotations to help you decide which one to keep. We'll walk you through resolving the merge conflict in this exercise.

Type git status - it should tell you which files neeed to be merged.

Lets open up the README.

git_merge2

Take a screenshot of this file similar to one above and call it P3_merge.png (don't add the red text though..). Commit/push this file as well.

You need to go in and manually update it to reflect the final state you want (and then remove the <<<<<, =====, >>>>> symbols).

git_merge3

You can see that in git status there are unmerged paths.

git_merge4

Once you're ready you should have a clean file to commit. Go ahead and add the file and commit with a message that says you've resolved the merge conflict.

Push to remote and congrats for solving the merge conflicts!

Connecting back to lecture

Recall the meaning of the symbols:

  • The content between <<<<<<< HEAD and ======= shows what the current state of the HEAD is. You can think of this as what existed before you tried to merge your changes. This is the "head" of the current branch; the most recent change.
  • The content between ======= and >>>>>>> xxxxxxx shows what changes are trying to be merged in. This is essentially the conflict. The xxxxxxx will usually be the conflicting branch name of the conflicting commit hash.
  • Your job is to decide which thing to keep. In practice, you might need to call up your colleague to discuss. In the current exercise you can just do this yourself because you know which change to keep.

Don't be afraid of merge conflicts!

Let's add one more feature.

In your firstname_lastname branch add another line that says what year you are (G1, junior, whatever it is). Follow the usual add - commit - push cycle to get the changes to the branch on the remote repo.

Now suppose you want to revert this change (or any change really). The magic of version control is that it's relatively straight forward to go back to a previous version!

To revert a commit - first identify the commit you want to rollback. To do this type

git log

git_log

You'll see several commits - the commit "hash" or id is the long string (in this example my latest commit starts with 87b......)

Here you want to revert my last commit. To accomplish this, just type

git revert LONGHASH.

All this does is add a new commit, which is just restoring to the state that occured before the above commit.

To push the change simply git push. Now everyone can see the most up to date version of this branch which will be your version of the file without your year and just your name/courses.

Note that we didn't "delete" the offending commit. Instead we added a new commit on top of the offending commit - that way there's still a history of all the changes that occured. git revert is history preserving in that the history stored in git is never modified.

You may also want to revert changes that you've committed locally but haven't push to remote. This is what git reset will do.

Recap and Deliverables

That was a lot of stuff! At this point, working from you firstname_lastname branch, issue a pull request back to the original repository. A member of the teaching staff will approve and merge your PR. Your branch should include an updated README.md file and a file P3_merge.png. We will also be able to see your commit history to make sure you followed all the steps.

Part c [15 pt]: Forking and setting up remote

In the last section we were mostly working off of branches. Branches are great but sometimes we need to be able to fully change a given project. Often times a project might be spun off an existing repo and take on a life of its own (ex: Ubuntu is a fork of the Linux project). The fork may still contribute back to the original project from time to time, but it is usually meant to be an entirely new project. Branches on the other hand are meant to be confined within a single repo.

git_fork

To fork click the button above and choose your personal username.

This creates an entire copy of the original repo under your username. In this forked version you have complete control of the project and can make whatever changes you want.

Clone this repo into a new directory on your local machine.

Sometimes even with a forked version we would like to track another project (for example the original repo).

To check the status of the remote you can do

git remote -v

You'll see two lines that both point to your current forked version. git_remote1

To set an upstream version you can type

git remote add upstream ORIGINAL GIT Repo.git

Now if you do git remote -v you'll see that upstream is set to the original repo. git_remote2

Take a screenshot of this file similar to one above and same it P3_remote.png and commit/push as well.

The diagram you've created is essentially this (poorly) done cartoon:

git_remote_cartoon

You have two remote repos from which you can fetch (receive changes from remote) and push (make changes to remote). There are often situations where you might fetch from one remote (say a fully tested and reflecting the latest good build) and push to another (a QA remote). You can specify which remote you wish to pull/push from (ex git pull origin master vs git pull upstream master)


Problem 4: Updating GitHub

Warning: Note that if you do not do the following we won't be able to grade. So there won't be points assigned to this problem but failure to do so can result in a 0 overall.

Please do the following:

  1. Some of you named your course repo cs207work. Please rename it cs207_firstname_lastname. If you have already done this, then you're done and you can skip to Step 2. If not, here's how you can rename your repo:
    1. Go to your GitHub repo and click on the Settings tab. Change the name under Repository name.
    2. Now go to the local copy of your repository (remember, we cloned this last time). It's probably named cs207work if you're doing these steps.
    3. Type git remote set-url origin where will be something like https://github.com/github_username/cs207_firstname_lastname.git. What you just did was change the url of the remote repository. Recall that origin is the short name of your remote repository.
    4. As a sanity check, type git remote -v. It should list the correct url now.
    5. Finally, your directory should be updated to avoid any future confusion.
      • To navigate up one directory, type cd ...
      • Type mv cs207work cs207_firstname_lastname. You just renamed the directory!
  2. Give the teaching staff access to your private repository:
    1. Go to your private repository again on GitHub.
    2. Go to Settings again.
    3. Click on Collaborators on the left side.
    4. Add the TFs and me. Our GitHub usernames are:
      • dsondak
      • adityakaran
      • bhavenp
      • feiyu-chen96
      • lindseysbrown

Now you're ready to create your first commit to the master branch. Set up a homeworks/ directory with the following steps (assuming you're in the root directory of the repository):

  1. mkdir homeworks/
  2. cd homeworks/
  3. echo # Homework Directory > README.md
  4. git add README.md
  5. git commit -m "Setting up homeworks directory."
  6. git push

WARNING: This is likely the only time you will make a commit directly to the master branch.

These steps will become second nature to you after this homework and the next few lectures. What you've done here is create a homework directory using some common Unix commands, generated a README file also using a common Unix command, and following the usual git workflow of staging (via git add), commiting changes to your local repo (via git commit), and pushing to the remote repo (called origin). Note that the -m option to git commit allows you to specify a commit message directly from the command line rather than via your system's default text editor (e.g. vim).


Problem 5 [10pt]: Write some Markdown

The task in this problem is to re-write the README.md document in the homeworks/ directory. This will be done with the Markdown language.

Markdown is a very easy language to work with. Here's a Markdown cheatsheet with everything you need: Markdown Cheatsheet.

The task is to write a short Markdown document. Your Markdown document must have at least one of the following:

  • Two different types of headers
  • A List
  • A table
  • A link

You can include other features if you want.


Some Unix References and Examples

This extra set of exercises is for your reference in case you don't have much experience with Unix. Please do your best to become comfortable with the command line throughout the semester. There are plenty of resources available on learning how to use the command line efficiently. Here is one to get you started: http://linuxcommand.org/lc3_learning_the_shell.php#contents.

Macs come with a command line app (terminal.app) and since Macs are loosely similar to Unix the terminal commands are pretty much the same as those in Linux distributions. Windows is a bit different, and because of this, I had you install git BASH if you are using a Windows machine. What this means is that, even if you are using a Windows OS, you can still use the nice Unix commands as long as you are in the git BASH terminal.

It is true that there are various options for using git from the Desktop (e.g. see GitHub Desktop). However, it is more useful for you to be able to do things from the command line. The reasons for this are that the command line is not going anywhere any time soon and that I can't predict what GUI your future company/group will want you to use. You'll be much more versatile using the command line.

What this means is that you need to learn a little bit about how to navigate with the command line. There are a few essential commands that you absolutely must know. You'll pick up the rest as you go through your life. Here are the essential ones:

  • ls: list the contents of the current directory
  • cd: change to a new directory
  • mv: rename a directory or file OR move a directory or file to a new location
  • cp: copy a directory or file
  • pwd: print the working directory
  • mkdir: create a new directory
  • rm: remove a file (you can remove a directory with rm -r)

Let's try to work with these a bit. In the following steps, you should hit the return key after typing each command.

  1. Open up a terminal and type pwd. The output should be your home directory.
  2. Next type ls. You should see all the files and directories in your home directory. Notice that if you type ls -l you get a list with more information where the files and directories are ordered alphabetically. Typing ls -lt sorts the list by date/time created with the most recent file/directory at the top. ls -ltr just reverses the order of the sort; now the most recent file/directory is at the bottom.
  3. Now type mkdir mydir. Voila! You have just created a new directory. Try ls again. Do you see the new directory?
  4. To enter that directory type cd mydir. You just changed into your new directory. Type pwd to see where you are.
  5. Now that you're inside your new directory, let's create a file in there.
    • Type echo 'Hello world!' > newfile.txt
    • Type ls. You should see the next text file!
    • To see the contents of the file, type cat newfile.txt.
  6. Suppose you now want to rename newfile.txt to README.txt. Just execute mv newfile.txt README.txt. Type ls again if you wish.
  7. Maybe you really wanted to keep a copy of newfile.txt. Just do cp README.txt newfile.txt. As usual, ls will show you what you want to see.
  8. What if newfile.txt should actually be in a different directory? Let's do the following:
    • mkdir newdir
    • mv newfile.txt newdir\
    • Altneratively, you could give the entire path of the new directory (not necessary here). Here's how you would do that:
      • pwd (just to see the current path)
      • mv newfile.txt path_from_pwd/newdir/
  9. That was fun, but this directory is completely useless to use now. Let's delete it.
    • First, you need to get out of the current directory. You can't delete a directory from within it!
    • To go up one directory, just type cd ...
      • Unix Note: In Unix, . stands for the current directory and .. stands for the parent directory (that is, the directory containing the current directory. Hence, cd ../ changes to the parent directory of the current directory.
      • Unix Note: If you want to go up two directories, just do cd ../../. You can use the same pattern for $n$ directories.
    • Now type rm mydir. You should see the message rm: mydir/: is a directory. rm cannot be used to remove directories as-is. It can only remove files.
    • To remove the directory type rm -rv mydir. The -r option says to recursively remove the directory and any contents. The -v option says to be verbose while removing files. You don't really need the -v option, but I like use it so I can see progress.

That was a whirlwind tour through a few of the more useful Unix commands. It won't take you long to use them effectively, but you must use them.

Note: If you want more information about any command, just type man into the terminal. This will bring up the manual page for that command. You will see all sorts of information. To scroll down, just hit the space bar. To exit the man page just type q (for quit). Here's an example of a portion of the man page for the rm command: rm man page

Bonus Command

Suppose you want to copy a file from a different location to your current directory. Well, recall that the current directory is represented by the . object. Here are a few things you can do:

  • cp path_to_file/file .: Will copy file to your current location
  • cp path_to_file/file ./sub_dir: Will copy file to the directory sub_dir in your current location
  • cp ../file .: Will copy file from the parent directory to your current location There are other, similar patterns to accomplish roughly the same thing. You'll ../figure them out as you go through life.