24sp ver.

Note: this is for the Spring 2024 iteration of CSE 391. Looking for a different quarter? Please visit https://courses.cs.washington.edu/courses/cse391/.

  1. What are the four different phases of git that we’ve learned? What commands do you know to move changes from one phase to the next? Is there ever more than one way to move a change from one phase to another?

    Solution

    The four git phases are the working directory, the staging area, the local repository, and the remote repository. git add/git stage moves changes from the working directory to the staging area (note both commands do the same thing). git commit moves changes from the staging area to the local repository.git push` moves changes from the local repository to the remote repository.

  2. What is the difference between git status and git log?

    Solution

    git status displays changes in the working directory and staging area, whereas git log displays the history of changes in the local repository.

  3. One popular “version control” that you’ve probably used is Google Drive/Docs. How is this similar to git? How is it different?

    Solution

    As for similarities, both Google Drive and git are designed to facilitate collaboration (multiple people can work on the same project) and they keep track of changes made over time. They vary in the type content as google drive focuses on documents, spreadsheets, forms, etc. while git is used for source code and text-based files. Additionally, in git, users have to push or create merge requests to update a project (as they’ll have a copy of the project on their local machine), while in Google Drive, users can directly edit the project.

  4. Let’s git some practice! Start by downloading some files:

    wget https://courses.cs.washington.edu/courses/cse391/24sp/lectures/4/questions4.zip
    unzip questions4.zip
    

    There should now be a directory questions4/recipes - this is actually a git repository!

    Note

    You don’t typically want to distribute git repos in a zip file (we’ve done this just for convenience). In reality, you should host your git repositories somewhere like GitHub or GitLab and download them via git clone.

    cd into the questions4/recipes repo, and then complete the following tasks:

    • Add a third step to the sundae.txt recipe:

      • Checkout a new branch (give it a descriptive name).
      Solution

      git checkout -b your-descriptive-branch-name

      • Add a third step to sundae.txt with any addition you want to make to the sundae.
      • Stage, and then commit your changes. Normally you’d want to push your branch/changes too, but we will skip this step for this exercise.
      Solution
      • Some variation of git add, e.g. git add sundae.txt
      • Some variation of git commit, e.g. git commit -m "Descriptive message"
      • Merge your branch into main. Make sure you understand which branch you should be on to perform the merge operation. Again, skip pushing your changes.
      Solution

      git merge should be run from the target branch, in this case main:

      • git checkout main
      • git merge your-branch
      • When you are done, you should be able to see main pointing to your new commit, and a parent commit Add initial sundae recipe. What commands can you run to check this?
      Solution

      Likely some variation of git log from main. For example:

      • git checkout main
      • git log --oneline
    • There is a branch add-strawberries with some changes to sundae.txt:

      • Try to merge add-strawberries into your new main
      Solution
      • git checkout main
      • git merge add-strawberries
      • The merge should fail due to a merge conflict. Why does this merge conflict exist? It may be helpful to view the commit graph of the repo (e.g. git log --all --graph --oneline)
      Solution

      add-strawberries changes were based on an older version of main. Our update to sundae.txt that we previously merged into main conflicts with the update that was attempted by add-strawberries. Since the histories have diverged, git doesn’t know which of the changes to sundae.txt are “correct”.

      • Resolve the merge conflict by editing the sundae.txt file. You’ll want to keep both your change and the strawberries change, and update the numbers accordingly. Be sure to remove the merge conflict metadata from the file! Once you’re done editing sundae.txt, make sure you “finish” resolving the merge conflict.
      Solution

      The file should look something like:

      1. Tillamook Cookie Dough
      2. Chocolate sauce
      3. Your recipe updates
      4. Put strawberries on top
      
      Afterwards, you should be sure to stage and commit sundae.txt to finish resolving the merge conflict.

      • If you’re successful, main should be pointing at a commit titled Merge branch 'add-strawberries' (assuming you didn’t modify the default merge commit).
  5. What is the command to show the changes between our working directory and our staging area? How about between our staging area and the local repository?

    Solution

    git diff shows the changes between the working directory and the staging area. git diff --staged shows the changes between the staging area and the local repository.

  6. Suppose you’re in a random directory on your computer and you want to check if it’s a git repository. How might you check this, without using any git commands?

    Solution

    A git repository is managed by the .git directory. So, to see if a given directory is a git repository, you could run ls -a and see if a .git directory exists.

  7. As you grow more experienced with git you’ll find yourself typing a lot of long commands which can be cumbersome. Luckily for us, git allows to alias many of the commands we run so we can rename them. So, for example, let’s say we want to alias status to simply st. If we wanted to do this for all git repositories on our computer, we could type

    git config --global alias.st status
    
    Or, if we want to alias this for just the git repository we’re currently using:
    git config alias.st status
    
    Write your own global alias for commit that makes sense for you!

    Solution

    This is an open ended question. Next week we’ll learn about git checkout, but I think this command is really long and cumbersome. Therefore, I’ve aliased it globally to git co with the command git config --global alias.co checkout.

  8. Caution

    The command we’re about to discuss can be very dangerous. Use this at your own risk, but it can be very useful if used correctly!

    The git reset command allows us to move changes out of a commit and back into the staging area. However, this command can be very dangerous if you’ve already pushed your changes to remote. Can you think of why this would cause problems? What might be a good rule of thumb for when to use something like git reset?

    Solution

    To understand the issue here we need to have a basic understanding of commits. Commits are uniquely identified by their hash, which is just a 40 character long string. If you run git log, the long string you’ll see after commit: is that commit’s hash. When you push, the remote repository tries to build the history by matching the hashes between the commit history that you pushed and the commit history it has saved.

    Consider the following scenario, you have a local commit history which looks like this (the left number is the hash for that commit)

    Local History
    
    abc123   Add file 2
    dnekd2   Add file 1
    fkdiek   Initial commit
    
    Now, you push this to the remote repo. The history on remote now looks the same, i.e.
    Remote History
    
    abc123   Add file 2
    dnekd2   Add file 1
    fkdiek   Initial commit
    
    Now imagine we run git reset, removing our most recent commit from the local history. We now make some more changes and add and commit them with the message Add file 3. Now, our local history looks like this:
    Local History
    
    lmnopq   Add file 3
    dnekd2   Add file 1
    fkdiek   Initial commit
    
    Note that the hash of the new commit has changed, since hashes uniquely idetify each commit. Now, if we try to push this change our changes will be rejected, since the remote repository cannot determine which commit should follow dnekd2.

    Generally we want to avoid changing our commit history because it can cause problems like this. A good rule of thumb is that you should never modify any commits that have already been pushed to the remote repository.

  9. Using the man page, how would you undo (or revert) a commit. Is this what you expected? Why?

    Solution

    One way you can undo or revert a commit is through git revert <commit-hash>, where the commit-hash refers to the most recent commit. What’s happening here is that we’re creating a new commit that undoes the changes introduced by a previous commit.