Homework 4

Version control

This assignment focuses on introducing the git version control system (VCS) by practicing a very frequently-followed workflow: cloning a repository, staging and committing changes, and merging a feature branch into your main branch. While your work for some of the tasks will be submitted as in an sh file to Gradescope just as before, the Gradescope autograder will also check your CSE GitLab repository history and verify the tasks were completed and pushed successfully.

git is a very complex tool. We strongly recommend using only commands introduced in class.

Enrolled students will have received email inviting them to a private repository in CSE GitLab. If you can’t find the email, you should also be able to find the repository by logging into CSE GitLab. If you can’t find your repository after logging in, be sure to ask on the discussion board!

Download the homework files on attu

After logging into attu, download the homework files.

git archive --remote=git@gitlab.cs.washington.edu:cse391/25wi/hw4.git --prefix=hw4/ HEAD | tar -x

In homework4.sh, complete the print_link function so that it prints-out the https URL to your private repository exactly as it appears in your web browser address bar without any trailing # character. The URL should end with your NetID.

For this part only, be sure to keep the echo command so that running print_link will print out your private repository URL.

Our autograder will grade this homework by cloning your private repository. Keep the your private repository page open in your browser since we’ll be using it frequently throughout this assignment.

Task 1: Create, edit, and move files

Let’s setup your repository. All the problems in this task are autograded by examining your remote repository history. You don’t need to edit homework4.sh for the entirety of this task.

Clone your repository and add a README.md

On attu, follow the Command line instructions on your private repository page to Create a new repository. The first command will clone (download) the repository from CSE GitLab, and the second command will change directory into your new, local copy of the repository.

git clone git@gitlab.cs.washington.edu:cse391/25wi/students/YOUR_CSE_NETID.git
cd YOUR_CSE_NETID

The next sequence of commands will create a main branch, write an empty text file called README.md, stage the empty README.md file, commit the staged changes to the local repository, and finally push the new commit to the remote repository.

git switch --create main
touch README.md
git add README.md
git commit -m "add README"
git push --set-upstream origin main

At this point, running ls -a should list the README.md file alongside a hidden .git directory.

README.md
This empty file was just created with the touch command. Most repositories have some sort of README.md file that explains how the repository works. The .md extension stands for Markdown, a language for styling and structuring plain text.
.git
This hidden directory stores important information about your local copy of the repository. git commands like git add and git commit record their changes in specially-formatted files stored in the .git directory. There is usually no reason to make any changes to files inside the .git directory.

After pushing commits from your local repository to the remote repository, if you now refresh your browser tab with your remote repository, you should see the empty README.md file and your commit titled add README.

This question is graded by looking in your repository for a commit that creates a file called README.md. No edits need to be made to homework4.sh.

Add a new Java file to your repository

Now that we’ve setup our local repository, let’s use it to develop software!

Copy the Facts.java file from your hw4 directory into your local repository. Facts.java calculates the factorial of its command line argument: we can calculate 5! by compiling and running it with javac Facts.java && java Facts 5.

Since this is a new file, if we now run git status, the output will explain that it is an untracked file. Stage the new file using the git add command to add only Facts.java.

git add Facts.java

If you previously compiled Facts.java and now have a Facts.class, be sure to only add Facts.java. Do not add or commit any compiled .class files to your repository!

Now that Facts.java has been staged, we can now commit the change. For this problem, be sure that your commit message is exactly "Added Facts.java".

git commit -m "Added Facts.java"

Finally, push the changes in your local repository to the remote repository on GitLab.

git push

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

This question is graded by looking in your repository for a commit that adds the Facts.java file with the exact commit message Added Facts.java.md. No edits need to be made to homework4.sh.

Edit a file in your repository

If you open Facts.java in vim, you’ll notice that it contains no documentation. Adding documentation not only helps explain how to use the program, but it also signals a degree of professionalism about the software: particularly important in helping users make a decision about which implementation to use.

Edit the file Facts.java by adding at least one Java comment to the file. The contents of the comment aren’t graded, but you must add at least one comment using either // or /*.

To double-check your work, use 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.

Stage your changes, commit them, and push the changes to your remote repository with any descriptive commit message.

This question is graded by looking in your repository for a commit that modifies Facts.java by adding at least one line that contains // or /*, representing a Java comment. No edits need to be made to homework4.sh.

Rename a file (and class) in your repository

Facts.java is great for computing factorials, but not so great for generating fun facts.

In order to accomodate both goals, rename Facts.java to Factorial.java so that we can later write a Facts.java program that generates fun facts. Be sure to rename the class declared inside the Java program to Factorial rather than Facts too: if you don’t, the code will no longer compile!

Stage your changes, commit them, and push the changes to your remote repository with any descriptive commit message.

This question is graded by looking in your repository for a commit that renames Facts.java to Factorial.java. No edits need to be made to homework4.sh.

Task 2: Exploring git commands

In homework4.sh, write your answer to the following questions using only git status, git diff, git log, or git blame. It’s not necessary to run any commands in your local repository; instead, write your answers within the corresponding functions in homework4.sh. Read the man page for each command and experiment with them (especially git blame, which we did not cover in the prework).

  1. Which command provides more information about just the most recent commit? Read the man pages to identify the necessary flag.
  2. Which command outputs the differences between the most recent commit and its grandparent (2 commits prior)? The most recent commit is HEAD; a commit k commits before the most recent commit is denoted by HEAD~k.
  3. Which command tells you who most recently changed each line of Factorial.java (and when)? Don’t use git log.

Task 3: Make and resolve a merge conflict

In real-world collaborative software development, we’ll often create a new branch, make some code changes, resolve a merge conflict, and then merge the new branch back into the main branch. Specifically, we’ll focus on refactoring code, or reorganizing the program to improve code quality without affecting its behavior.

Switch to a new branch and refactor the code

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

git switch -c refactor-factorial

In the main method, remove the existing factorial calculation code:

-  int fact = 1;
-  for (int i = 1; i <= num; i++) {
-    fact *= i;
-  }
-
-  System.out.println(fact);

Then, copy the following factorial method and paste it inside the Factorial class.

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

Finally, call the factorial function at the end of the main method.

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

Before you add and commit your changes, check that your refactored code still works as intended.

  • 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

Be sure not to commit the Factorial.class file!

After committing your changes, push your branch to GitLab:

git push --set-upstream origin refactor-factorial

This question is graded by looking in your repository for a refactor-factorial branch for a refactored Factorial.java program that still works as intended. No edits need to be made to homework4.sh.

Fixing an integer overflow bug

Since we’ve finished refactoring the code, it’s time to switch back to the main branch so that we can keep up to date with everyone’s changes.

git switch main

Factorial.java should no longer contain your refactored code. But we might realize that our Factorial program gives the wrong answer for some larger numbers, such as java Factorial 20, which outputs the negative number -2102132736 due to integer overflow. To fix this issue, change the type of the fact variable to long.

-      int fact = 1;
+      long fact = 1;

Recompile the program and check that java Factorial 20 now outputs 2432902008176640000. Stage your changes, commit them, and push the changes to your remote repository with any descriptive commit message.

Be sure not to commit the Factorial.class file!

Merge the refactor back to main

Now that we’ve addressed the bug in the main branch, it’s time to merge the refactor-factorial branch back to the main branch. From the main branch:

git merge refactor-factorial

git should report a merge conflict! To fix this conflict, edit the Factorial.java file so that the resulting code merges the ideas from both branches:

  • The resulting code addresses the integer overflow problem at least on java Factorial 20.
  • The resulting code refactors the math logic into its own method called factorial. Remember to update the method signature to return a long rather than an int!
  • The resulting code compiles and runs properly on all previous examples.
    • 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
    • java Factorial 20 should print out 2432902008176640000

Stage your changes, commit them, and push the changes to your remote repository. For this commit, we suggest keeping the default commit message; simply save and exit the editor. Then, push your changes to remote.

This question is graded by looking in your repository 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. No edits need to be made to homework4.sh.