Git

git

git (plural gits) (British, Ireland, Australia, New Zealand, slang, derogatory) A silly, incompetent, stupid, or annoying person (usually a man).

“the stupid content tracker”

What is git?

A distributed version control system.

Version control system — a system for tracking different versions of a set of files.

Distributed — there’s no central server; every developer has a complete history of the code on their computer.

What is Github?

A service that hosts git repositories and provides functionality on top of git for managing collaborations.

Github model is extremely good for open-source software where anyone might want to contribute to any project yet project owners need a way to manage potential contributions.

Fundamental git concepts

  • Repositories

  • Commits

  • Branches

  • Merging

Repository

A collection of files with their complete history.

Every repository is a multiverse of different timelines that split and merge.

Commit

A unique point in the history of the multiverse.

Most commits represent a change to one or more files in the repository.

Commits also have a relationship to all the commits that came before them in whatever timeline (or timelines) that they are part of.

Two sides of a commit

  • A commit identifies the contents of the repository at that point

  • A commit represents the set of all commits that they depend on.

Note that while a commit determines the state of the repository contents there can be different commits that put the repository into the same state, i.e. that got to the same place via a different series of commits.

Branch

A particular named timeline in the multiverse.

At any given moment a branch points to a particular commit but when you make a new commit, the current branch is updated to point to that new commit.

Branching

The process of creating a branch.

Usually from whatever commit the current branch is at but can be from any existing commit.

When you create a branch in the normal way, at the point the branch is created the new branch and the old branch point to the same commit.

After that, new commits are added to the new branch and the old branch is unchanged.

Merging

The process of combining two timelines into one.

If you have two commits (probably named by branches) representing divergent timelines in your repo, you can make a new commit that depends on both of those commits, unifying the timelines.

A picture

Each circle represents a commit.

Lines represent branches.

Merging files

Merging two commits also requires that we merge the contents of the files in the repository as they exist in each of those commits to produce a new set of files that represents how we want to combine all the changes.

Merge conflicts

Git will help with combining the contents of the files from the commits you are merging.

Conflicts arise when unrelated commits make changes to the same part of the code.

Git will recognize this and force you to resolve them.

Merge example:

Let’s start with this file in main:

public class Foo {

  private int x = 42;

}

Make a branch

git switch -c branch-1

Change the file

Change the initial value of x to 43:

public class Foo {

  private int x = 43;

}

And commit

git commit -am "42 -> 43"

Back on main

git switch main

Change the file there

Add a new line right below the old line:

public class Foo {

  private int x = 42;
  private int y = 100;

}

And commit

git commit -am "Add y"

Now branch-1 and main have unrelated commits to Foo.java

Let’s merge!

$ git merge branch-1
Auto-merging Foo.java
CONFLICT (content): Merge conflict in Foo.java
Automatic merge failed; fix conflicts and then commit the result.

What’s in Foo.java now:

public class Foo {

<<<<<<< HEAD
  private int x = 42;
  private int y = 100;
=======
  private int x = 43;
>>>>>>> branch-1

}

Markers show us the conflicting sections.

HEAD is a special name for “the commit we are currently on”. A.k.a. main in the current scenario.

Resolving the conflict

public class Foo {

  private int x = 43;
  private int y = 100;

}

We take the new value of x from branch-1 and the new variable y from main.

Note, it’s up to us to determine the right resolution. Maybe that change from 42 to 43 doesn’t actually make sense in the context of how we’re merging the two branches. Only a human can know.

Silent conflicts

So if there’s no conflicts, everything is fine, right?

Well, not necessarily.

Suppose in one branch you rename a method from foo to bar and change all the places that call it.

In another branch, made before the name change, you add a new call to foo.

There’s no textual conflict but if you merge those two branches but the code will not compile.

So be a bit careful

You do need to exercise some care when merging to make sure the result of the merge is actually what you want. I.e. it does compile cleanly, passes whatever tests you have, etc.

On the other hand, it’s just another change—you can always see exactly what happened in the merge and fix things up if need be by making a new commit.

Fancy pants git maneuvers

You can make a branch from any commit. And you can merge any commit into a branch.

This lets you go back in time (make a branch from some old commit and pretend you’re living in the past.)

It also lets you combine development branches before you merge them to main.

Don’t go nuts with this though.

Git on the command line

git add add a file to be committed
git mv rename a file so git knows about it
git commit commit the currently added files
git pull fetch and merge commits for the current branch
git merge merge a branch

Learn more

Git documentation

git help

man git-commit, etc.

Oh Shit, Git!?!

https://ohshitgit.com/