ECE297 · Software Design and Communication

Version Control and git

Why do we need version control?

“Remember that time when everybody quit?” - Anon

A Motivating Case

“Any organization that designs a system will produce a design whose structure is a copy of the organization's communication structure.” — Melvin Conway, 1967

A Human Version Control System!

That just walked out the door...

  • Tracking history
    • Who changed the code and when?
  • Resolving conflicts
    • What if 2 people edit the same file?
  • Change visibility
    • Who's code is "live" and when?

This is tricky, frustrating, and expensive work for a human!!

Tracking History

  • Make a sequence of changes to a program
  • Discover it is broken
  • Figure out which change broke it

How do we go back to a previous version?

Simple History Solution

  • Regularily make a copy (backup) of all the files
  • Restore the backups 1 by 1 until the problem is gone
  • Problems with this soution
    • How often do you backup? Every 5 minutes?
      (Lots of storage!)
    • How long will it take you to find the problem
      (Hundreds of backups a day!)
    • Will you be diligent, or will you get bored/forget?
      (Defeats the purpose!)

Resolving Conflicts

  • Tilly edits and saves file1.cpp
  • Cowboy edits and saves file1.cpp
  • Tilly's changes are lost!

Simple Resolve Conflict Solution

  • Email the team when you're editing
    • Subject: I'm editing file1.cpp! ← When you start
    • Subject: I'm done with file1.cpp! ← When you're done
  • Problems with this solution
    • Someone doesn't read the email
    • 2 people send a file1.cpp email at the same time
    • The team is 150 engineers
      Your inbox is now just "I'm editing" emails!

We need a Version Control System

  • Tracks Revision History
    • Can rewind the codebase to an earlier point in time and show who changed what
  • Resolves Conflicts
    • Can identify and handle multiple users editing the same file
  • Controls Change Visibility
    • Allows users to control when their changes become visible to others

In this course we use git!

Global Repository, Local Copies

The key idea

  • Code is stored in a remote repository
  • Users use git commands to
    • make a local working copy when they want to make changes
    • send or receive changes to the remote repository when they're ready

Revision History

Revision History : git log

Listing changes

Revision History : git show/diff

Examining Changes

Revision History: git revert

Undoing Changes

Revision History : Takeaways

  • Doesn't this take up lots of storage?
    • No! git only stores changes
    • Even with a million line codebase
      each change is (usually) small
  • How often should I commit?
    • Often! Commits are cheap!
    • Suggestion:
      • Commit every time you make a working change towards your goal
    • Warning:
      • Always compile and run before every commit!
      • Treat each commit like a "save point" you can return to

Resolving Conflicts

    There are two basic approaches
  • Lock-Based
    • Like our email idea, but enforced by a program
    • You lock a file before editing, preventing others from editing
    • Used by some legacy systems (rcs, vcs)
  • Merge-Based
    • Users have working copies of the same file
    • Conflicts are resolved when users choose to
      • see other users changes
          git pull
      • make their changes visible to others
          git push

Resolving Conflicts

Different Files

Resolving Conflicts

Different Files

Resolving Conflicts

Same File, Different Lines

Resolving Conflicts

Same File, Same Lines

Resolving Conflicts

Same File, Same Lines - Editing the conflicted file

Resolved version

Resolving Conflicts

Same File, Same Lines - Marking the conflict resolved

Change Visibility

Remote Repos, Local Repos, and Working Copies

    • git clone
      makes local copy of remote repo
      and an editable working copy
    • git commit
      creates new revision in local repo
      from working copy edits
    • git pull
      gets revisions from remote repo
      applies changes to local copy
    • git push
      sends local revisions to remote repo

The Development Loop

  1. git pull -r to ensure your repo is up to date
  2. Fix a bug, add a feature, improve tests
  3. Build
  4. Test
  5. git commit
  6. git pull -r to ensure your repo is up to date
  7. Resolve conflicts (if any)
  8. git push to publish your changes

Branching

A Motivating Example for an Optional Advanced Version Control Feature

  • Tilly is just wrapping up Milestone 1
    • Mostly working, just adding polish and fixing minor bugs
  • Cowboy wants to get a head start on Milestone 2
    • Milestone 1 submission is soon!
    • Code needs to stay stable, working, with all tests passing
    • Half finished Milestone 2 features could mess up live demo
  • Solution?
    • Make a branch!

Branching

  • What is a ref?
    • A human readable, named pointer to a revision,
      instead of a hash like 3ad5e6f
  • What is a branch?
    • A ref that always points to the latest revision (the tip)
    • Updated by git commit
  • What is the default branch?
    • Most important branch, usually master or main
    • What you get when you git clone
  • HEAD
    • A special ref that points to the current branch

Branching

Creating the branch

  • Both Tilly and Cowboy start on master
  • Tilly runs git checkout -b milestone1
    • A new branch ref is created
    • Tilly's HEAD changes
  • Cowboy stays on master, working on the future

Branching

Working independently

  • Cowboy's commits go to master
  • Tilly's commits go to milestone1
  • They work independently

Branching

Merging in changes

  • Tilly's polish and bugfixes should end up in master
    • git checkout master - switch local branch
    • git pull -r - bring master up to date with Cowboy's work
    • git merge milestone1 - creates new commit joining both histories, with changes from both

Branching

Rebase vs merge

  • merge joins two histories
  • We can avoid branches in the history by rebasing
    • Replays commits one at a time, like git pull -r
    • Keeps the history linear and easier to understand
    • Can make conflict resolution very painful

Branches

Use Cases

  • Master/Main/Trunk
    • The latest tested and working version of your code
    • Only completed working features allowed
  • Feature Branches
    • For adding a specific new feature
    • Develop, test, commit, repeat...
    • git pull -r origin master often to avoid merge conflicts
    • Merge to Master when done
  • Release Branches
    • Matches a specific version (eg. on the app store)
    • Before release: for stabilization and testing (no new features!)
    • After release: for emergency bugfixes to the live app

Summary

Version Control Systems solve three problems: history, conflicts, visibility

  • History: Every commit is a save point
    • git commit to save
    • git log/show/diff to inspect
    • git revert to undo
  • Visibility and Conflicts: Integrating changes
    • git pull -r to get other's changes
    • git push to publish your own changes
    • git add, git rebase --continue to resolve conflicts
  • Branches: Working independently
    • git checkout -b branchname to start
    • git checkout master, git merge branchname to finish
  • The loop: pull → change → build → test → commit → pull → push