So, we assume that you already know how to use GIT, for the most part. Instead, we need to focus on some particular situations that can arise, and the logic on how to deal with them. This article is mostly written for myself, as I’ve encountered some scenarios and the solution was not that obvious.

Some concepts

Good illustrated tutorials for understanding basic GIT workflow are:

The HEAD

What is the HEAD? The HEAD in Git is the pointer to the current branch reference, which is in turn a pointer to the last commit you made or the last commit that was checked out into your working directory. That also means it will be the parent of the next commit you do. It's generally simplest to think of it as HEAD is the snapshot of your last commit.

The Index (also known as Stage or Cache

The Index is your proposed next commit (snapshot of your next commit.)

The Working Directory (Workspace)

The Working Directory is your scratch space, used to easily modify file content.


Saving changes

  • I want to save all changes to the repository directly (bypass stage step)
    • $ git commit -a
  • I want to stage (prepare to commit) all tracked files at once
    • $ git add -u
      GIT commit workflow

Inspecting the repository

Useful links:

log or rev-list (History between two commits)

Question 1.

What is the history between <since> and <until> for the following scenario? We are interested in the gray area.

Both arguments <since> and <until> can be either a commit ID, a branch name, HEAD, or any other kind of revision reference.
Venn Diagram and commit trees - one branch

The subsequent commands are equivalent in current scenario:

  • “^” prefix means not reachable from marked point:
    • $ git log ^<since> <until>
    • $ git log <until> ^<since>
  • However, this syntax cannot be inverted because the left term is always the hat one (“^”). In this case, the following log syntax is not commutative.
    • $ git log <since>..<until>
  • By branch name on the same branch:
    • $ git log ^master~4 master
    • $ git log master~4..master
  • By branch name compared to another branch:
    • $ git log new-feature..master
    • $ git log ^new-feature master
  • Comparing different versions of HEAD:
    • $ git log ^HEAD~4 HEAD
    • $ git log HEAD~4..HEAD
  • If HEAD is on master branch:
    • $ git log ^HEAD~4 master
    • $ git log HEAD~4..master
    • $ git log ^master~4 HEAD
    • $ git log master~4..HEAD

Results

log two dots results

Question 2.

What is the history between <since> and <until> for the following scenario?
We use "..." with log to represent a union between the 2 committed histories'.
We are interested in the gray area.
Venn Diagram and commit trees - two branches
The subsequent commands are equivalent in current scenario:

  • In this case, the following log syntax is commutative.
    • $ git log <since>…<until>
  • By branch name using on the same branch.
    • $ git log master~4…master
    • $ git log master…master~4
  • By branch name compared to another branch (Union of the 2 branches’ history):
    • $ git log new-feature…master
    • $ git log master…new-feature
  • If HEAD is on master branch (Union of the 2 branches’ history):
    • $ git log HEAD…new-feature
    • $ git log new-feature…HEAD

Results

log three dots results

Diff

Question 1.

What are the file level changes between <since> and <until> in the following scenario?
We use ".." with diff to get all changes on the 2 branches.
We are interested in the gray area.
Commit trees union two branches
The subsequent calls are equivalent from a logical standpoint:

  • Bottom-Up approach, outputting changes that were added:
    • $ git diff <since> <until>
    • $ git diff <since>..<until>
  • Top-Down approach, showing same changes but outputting in a remove fashion “removed”:
    • $ git diff <until> <since>
    • $ git diff <until>..<since>
  • “^” suffix means reachable until marked point (4 of “^” = 4 levels down):
    • $ git diff HEAD^^^^ HEAD
    • $ git diff HEAD^^^^..HEAD
    • $ git diff HEAD HEAD^^^^
    • $ git diff HEAD..HEAD^^^^
  • By branch name compared to another branch (Union of the 2 branches’ changes). Bottom-up until current HEAD. In this scenario, current HEAD is the same as master.
    • $ git diff new-feature master
    • $ git diff new-feature..master
    • $ git diff new-feature HEAD
    • $ git diff new-feature..HEAD
  • By branch name compared to another branch (Union of the 2 branches’ changes). Top-Down version showing changes from master to new-feature. In this scenario, current HEAD is the same as master.
    • $ git diff master new-feature
    • $ git diff master..new-feature
    • $ git diff HEAD new-feature
    • $ git diff HEAD..new-feature

Results

diff two dots results

Question 2.

What are the file level changes between <since> and <until> in the following scenario?
We use "..." with diff to exclude changes from <since>/new-feature.
We are interested in the gray area.
We’ll use three dots “…” between <since> and <until> to reflect the changes made exclusively on <until> branch.
Commit trees one branch
The following calls are equivalent from a logical standpoint:

  • “<since>…<until>” is not commutative using diff
    • $ git diff <since>…<until>
  • By branch name compared to another branch
    • $ git diff new-feature…master
  • By branch name or HEAD, on the same branch
    • $ git diff master~4 master
    • $ git diff master~4…master
    • $ git diff HEAD^^^^ master
    • $ git diff HEAD^^^^ HEAD
    • $ git diff master^^^… HEAD
    • $ git diff master^^^… master

Results

diff three dots results

Final notes:

  1. The “..” and ”…” methods are acting somehow opposite when using it on with log or diff;
  2. Using $ git log <since>..<until> or git diff <since>..<until> Both arguments <since> and <until> can be either a commit ID, a branch name, HEAD, or any other kind of revision reference;
  3. $ git log <since>..<until> is not commutative;
  4. $ git log <since>...<until> is commutative;
  5. $ git diff <since>..<until> is commutative but displays results in an opposite manner;
  6. $ git diff <since>...<until> is commutative;

Disclaimer

The material is based on other people work, gives cred and provides the source. Another thing is that, this article doesn’t want, in any way, to cover all the difficult scenarios that you may confront yourself with. Instead, it closely ties to my problems and experiences.

Completely Ignored

Accessing parent of HEAD, branch syntax:

Git Stash

Git stash is uncovered here, but log or diff can easily be applied to stashed items in the same manner.