HW4 - git (2 points)

Due Tuesday 10/29 at 1:00 pm. No late submissions accepted.

Submission: Gradescope

Specification: Spec


This assignment focuses on using git for version control. In particular, this assignment focuses on using git by yourself: learning how to clone a repository, move files between the “four phases” of git, and create + merge a feature branch into your main branch. This exact workflow is helpful when working on personal projects (or storing your homework for other classes)!

In this homework, you will turn in just one file called homework4.sh. However, you will also make and push changes to a remote GitLab repository; the autograder will be run against your commands in homework4.sh and the history of the repository.

Warning

git is a very complex tool with many ways to do similar things. For this homework, we strongly recommend you use the tools discussed in lecture rather than features that we have not discussed (that you may find online, etc.)

To calculate your final score on this assignment, sum the individual scores from Gradescope.

  • if your score is between [0, 1), you will get 0 points
  • if your score is between [1.0, 1.5), you will get 1 point
  • if your score is between [1.5, 2], you will get 2 points

Info

This autograder is still relatively new. To clarify things, we’ve added πŸ“¬ to explain how we’re evaluating your solution for each problem. Don’t hesitate to post on Ed if you have any issues with the autograder!

Task 0: Setting Up

Using CSE GitLab

First, please follow the steps in Using CSE GitLab (i.e. finish steps 1-3). As a reminder, you should make an ssh key on the computer you are doing the homework from.

Find your GitLab repo

In order to grade this assignment, we have created a GitLab repository for you. You should have gotten an email inviting you to the cse391/24au/hw4 group on GitLab. Your repository should be within that group with the same name as your GitLab username/NetID (e.g. cse391/24au/hw4/dubs2000). Navigate to the homepage for that repository.

If you haven’t received an email, you should also be able to find the repository by visiting https://gitlab.cs.washington.edu/ and looking at your listed projects.

Warning

Can’t find your repo? Please let your instructor know ASAP!

Download homework4.sh

Similar to previous assignments, you will turn in a .sh file to Gradescope; download it to get started:

$ wget https://courses.cs.washington.edu/courses/cse391/24au/homework/hw4/homework4.sh

Note that we will grade this assignment by looking at homework4.sh and the history of your repository.

Our autograder will grade this homework by looking at the contents and history of your repository. To do that, it needs to know where it is.

In homework4.sh, put the URL to the repository (from the address bar in your browser, not “Clone with HTTPS” or “Clone with SSH”). This should start with https:// and should not end with .git.

Caution

Do not remove the echo from this command!! But only for this command!

function print_link {
  # Type your answer to problem #1 below this line
  echo "https://gitlab.cs.washington.edu/cse391/24au/hw4/name-of-your-repository"
}

For example, if Dubs’ UW NetID is dubs2000 (it’s not), the function would look like

function print_link {
  # Type your answer to problem #1 below this line
  echo "https://gitlab.cs.washington.edu/cse391/24au/hw4/dubs2000"
}

Caution

Make sure your URL exactly matches the URL for your repo (not Dubs’)!

Task 1: Create, edit, and move files

All of the problems in this task are autograded by examining the history of your repository; in order for Gradescope to “know” where your repository is, you must finish the print_link setup task above and push your changes to the GitLab repository.

Problem 1: Create a main branch and a README.md

By default, the repository that we’ve created for you is empty. Our first step will be to add a README.md file and create our main branch. To do this, we’ll “clone” (make a local copy of) the GitLab repository to make a local copy, make our changes, and then push them.

To do that, we’ll essentially follow the instructions under “Create a new repository”. In particular, run the following commands on a terminal connected to a computer with your SSH key (replacing your_netid with your GitLab username):

$ git clone git@gitlab.cs.washington.edu:cse391/24au/hw4/your_netid.git
$ cd your_netid
$ git switch -c main
$ touch README.md
$ git add README.md
$ git commit -m "add README"
$ git push -u origin main

Caution

Git should not ask you for a password when running git clone. If you are asked for a password, check that your SSH key is setup properly.

Info

git switch might not exist on older versions of Git (e.g. on vergil). In that case, instead of git switch -c main, use git checkout -b main.

After executing these commands, you should be in a directory named after your project; this is your “working directory” in git terminology. Your working directory is where you will edit and create files to commit in your local repository.

At this point, running ls -a in your working directory should have two interesting files:

$ ls -a
. .. .git README.md
  1. The README.md should be empty (this was just created with the touch command). Most repositories have some sort of README file that explains how the repository works; the .md extension stands for Markdown, a language used to quickly style and structure text.
  2. The .git directory stores all the information about the local copy of the repository. You should not cd into the .git directory or modify this directory directly. Instead, you’ll interact with git via commands (e.g. git add or git commit).

If you visit the GitLab homepage for your repository (and refresh), you should see that an empty README.md is now there and pushed to the repository with a commit titled add README.

πŸ“¬ This question is graded by looking in your repo for a commit that creates a file called README.md.

Problem 2: Create and add a new file to your repo

For the rest of this homework, you’ll interact with a toy program called Facts.java that calculates the factorial of its command line argument. You can test it by compiling and running it, e.g. with javac Facts.java && java Facts 5.

Copy the Facts.java file from the course website into your working directory, using:

$ wget https://courses.cs.washington.edu/courses/cse391/24au/homework/hw4/Facts.java

Now, try typing git status; notice that Facts.java is listed as an “untracked file” (and shown in red). This is in the “working directory” phase; we can move it to the staging area by using git add:

$ git add Facts.java

Warning

If you were testing Facts.java and have a Facts.class, please do not add/commit it to your repository!

Now, using git status again will now list Facts.java as a file ready to be committed (and shown in green).

We can now commit our change (and moving it to the next “phase” of git). For this problem, you should make sure that your commit message is exactly "Added Facts.java".

There are two ways you can do this: either with the -m flag, which allows you to specify a short commit message:

$ git commit -m "Added Facts.java"

Or, by opening up your editor of choice:

$ git commit

Finally, let’s push the changes in your local copy of the repo to the remote repo on GitLab.

$ git push

On GitLab, if you refresh the files, you should see that Facts.java is now there.

Run git log in your directory to see recent commit history.

πŸ“¬ This question is graded by looking in your repo for a commit which adds this file and has the exact commit message "Added Facts.java".

Problem 3: Edit a file in the repo

You may notice that Facts.java has no comments in it. While it’s a pretty simple program, a comment or two wouldn’t hurt!

In your working directory, edit the file Facts.java by adding at least one Java comment to the file. The contents of the comment can be whatever you like, but you must add at least one comment (using either // or /*) while also not changing the behaviour of the code.

To double-check your work, you can use the commands git status and git diff. You can also check if your Facts.java file still works properly by verifying that javac Facts.java && java Facts 10 outputs 3628800.

Once you are ready, use the commands we’ve learned from class to commit your changes and push them to the remote repository. You may pick whatever commit message you like.

πŸ“¬ This question is graded by looking in your repo for a commit which modifies Facts.java by adding at least one line that contains (// or /*, representing a Java comment).

Problem 4: Rename a file (and class) in the repo

We have decided that Facts.java is an ambiguous name (since you may also want to make a program that gives out fun facts). In order to accomodate for this in our repository, we want to rename Facts.java to Factorial.java. In addition, we should rename the class declared inside the Java program to be Factorial rather than Facts (if you don’t, your code will no longer compile).

(want to check if your new file works properly? javac Factorial.java && java Factorial 10 should output 3628800)

After making these changes, use the appropriate commands to stage your new Factorial.java file, then commit and push your changes to the remote repo. You may pick whatever commit message you like.

πŸ“¬ This question is graded by looking in your repo for a commit that renames Facts.java to Factorial.java.

Task 2: Exploring git commands

This next task asks you to explore some git commands and answer questions for common operations. We encourage you to try practicing them in your repository, but you do not need to commit any changes to complete this task; instead, write your answers within the corresponding functions in homework4.sh.

For these problems, the following commands will be relevant:

  • git status
  • git diff
  • git log
  • git blame

You will want to look at the man page for each of these commands and experiment with them (especially git blame, which we did not cover in the videos).

Problem 1

What command provides more information about just the most recent commit?

Hint: you will need to pass a flag to one of the aforementioned commands.

Problem 2

What command outputs the differences between the most recent commit and its grandparent (2 commits prior)?

Hint: the most recent commit is often referred to as HEAD; a commit n commits before the most recent commit is denoted by HEAD~n.

Problem 3

What command tells you who most recently changed each line of Factorial.java (and when)?

Hint: the command you’re looking for is not git log.

Task 3: Make and resolve a merge conflict

This final task simulates a part of the “git workflow”: creating a new branch, make some code changes (in this case, refactoring), resolving a merge conflict, and then merging it into main.

Problem 1: Go to a new branch

First, we will create a new branch to make our change. From the main branch, create a new branch that is exactly called refactor-factorial:

$ git checkout -b "refactor-factorial"

This command uses git checkout and the -b flag to create a new branch called refactor-factorial and then check it out (i.e. move to that branch).

You will know that you’re successful when git status indicates that you are on the refactor-factorial branch, not the main branch.

Problem 2: Refactor the code

Note

The emphasis of this class is not on writing complicated Java code, so we are picking an intentionally small refactor and providing you with the code.

Now that you’re in the branch, we’re ready to make some changes. In this case, your boss has decided that the actual logic that calculates the factorial should live in its own method.

So, create a new method called factorial that “pulls” out the factorial logic, like so:

public static int factorial(int num) {
  int fact = 1;
  for (int i = 1; i <= num; i++) {
    fact *= i;
  }

  return fact;
}

Then, in the main method, call factorial instead and print out its return value:

public static void main(String[] args) {
  // ...
  int num = 0;
  try {
    // ...
  } catch {
    // ...
  }

  System.out.println(factorial(num));
}

Before you add and commit your changes, verify that this new refactor still works as intended; e.g., after recompiling your code,

  • java Factorial 0 should print out 1
  • java Factorial 1 should print out 1
  • java Factorial 5 should print out 120
  • java Factorial 10 should print out 3628800

Now, use the appropriate git commands to stage and commit this refactor to the refactor-factorial branch. In particular, you should not add the Factorial.class file — just the Factorial.java file. We suggest the commit message exactly Refactor factorial to its own method.

After committing your changes, push your branch to GitLab:

$ git push --set-upstream origin refactor-factorial

You can then check that your branch exists on GitLab. If you don’t push the branch the autograder won’t be able to grade your submission properly, resulting in a potential loss of points.

πŸ“¬ This question is graded by examining your refactor-factorial branch, and making sure that you have defined the appropriate new method without changing the behaviour of the file.

Problem 3: Bugfixes and merge conflicts

Note

For this problem, we have you commit to main to introduce a merge conflict. This is for simplicity’s sake, but in real software development you’d want to make this change on a branch too!

First, switch back to the main branch of the repository.

$ git checkout main

(note that this should not have any of the changes you made on your refactor-factorial branch)

Your boss has now separately pointed out that the Factorial program gives the wrong output for some inputs, such as java Factorial 20 (which outputs -2102132736 — the wrong answer due to integer overflow).

This is mission critical, so your boss says you need to commit the bugfix to main ASAP. In particular, he suggests changing the fact variable to a long. In your main method, make that change:

public class Factorial {
  public static void main(String[] args) {
-      int fact = 1;
+      long fact = 1;
  }
}

Making just this change should resolve the bug; confirm that by recompiling your program and verifying that java Factorial 20 now outputs 2432902008176640000.

Now, using the appropriate git commands, stage and commit your changes to the main branch (taking extra care to not commit any .class files). We suggest the commit message Fixes integer overflow bug.

Finally, you remember that you need to merge in your changes from refactor-factorial. Run:

$ git merge refactor-factorial

At this point, git should tell you that there is a merge conflict. To fix this conflict, you will need to edit Factorial.java with your text editor of choice.

This merge conflict is particularly nasty, since it’s not just a syntax change; you need to make the code represent the merge of the intention of the previous two commits. In particular, your final code should:

  • not suffer from the int overflow error (at least, on java Factorial 20)
  • and, refactor the factorial logic into its own method called factorial
    • hint: you will have to change the method signature to match with fact now being a long
  • still compile and run properly on the examples we’ve mentioned in the spec (e.g. 0, 1, 5, 10, and 20)
    • note that this requires you to remove the <<<<<< HEAD, =======, and >>>>>> sort-menu lines

Once you have resolved the merge conflict, test your code and make sure that it still compiles and runs. Then, add your changes and commit them. For this commit, we suggest that you don’t change the default commit message; simply save and exit the editor. Then, push your changes to remote.

πŸ“¬ This part is graded by looking in your repo for a merge commit in main, as well as the final main branch providing the correct output for java Factorial on 0, 1, 5, 10, and 20.