Git Commit References, History, Branching, and Stashing

Commit References

Git provides multiple ways to reference commits in the repository
history.

Common references:

  • HEAD --- the latest commit on the current branch
  • Commit hash --- e.g., af4564
  • Branch name --- e.g., master

Relative references:

  • Parent commit: HEAD^
  • Grandparent: HEAD^^
  • Great‑grandparent: HEAD^^^

Use ~ with a number to move further back:

  • HEAD~1 = HEAD^
  • HEAD~3
  • HEAD~5

0_MAGT7w8fYdCjEBtZ_1.width-800.png


Browsing Commit Snapshots

Referencing a commit allows you to inspect the repository state at that
time.

List Files in a Commit

In Git terminology:

  • tree = directory
  • blob = file

Examples:

git ls-tree HEAD

List files in the repository at HEAD.

git ls-tree master assets/

List contents of the assets directory in master.

git ls-tree master^ assets/

List contents of assets in the previous commit of master.

git ls-tree 4c56f2

Inspect files from an older commit using its hash.


Working with the Git Log

Get documentation for any command:

git help <command>

Example:

git help log

Common Log Queries

git log --oneline -3

Show the last three commits.

git log --since="2012-05-05"
git log --since="2 weeks ago" --until="3 days ago"

Filter commits by time.

git log --author="osama abuomar"

Filter by author.

git log --grep="temp"

Filter by commit message.

git log 45648fd..dsafd456 --oneline

Show commits within a range.

git log cdfs32.. index.html

Show changes affecting index.html since a specific commit.

Detailed Logs

git log -p

Show patches (line additions and deletions).

git log --stat --summary

Show summary statistics of changes without full diffs.


Formatting Log Output

git log --format=oneline

Similar to --oneline but shows the full hash.

git log --graph

Display commit history as a graph.

A practical combined view:

git log --oneline --graph --all --decorate

Many developers create an alias for this command.

Example alias:

git log2 = git log --oneline --graph --all --decorate

Viewing Commits

Inspect a commit and its changes:

git show <hash>

Compact format:

git show --format=oneline HEAD^
git show --format=oneline HEAD~3

View a File from a Past Commit

git show <commit_hash>:<path>

Example:

git show e4d1e94:.gitignore

View all files in a commit:

git show <commit_hash>:

Comparing Commits

Git compares directories or files using git diff.

Examples:

git diff <hash>

Compare working directory with a commit.

git diff <hash> index.html

Compare index.html with its version in a commit.

git diff hash1..hash2

Compare entire repository between two commits.

git diff hash1..hash2 index.html

Compare a single file between commits.

Compact summary:

git diff -w --stat hash1..hash2 index.html

Options:

  • -w ignore whitespace changes
  • --stat show summary statistics

Example output:

foo.txt | 6 ++++++
1 file changed, 6 insertions(+)

Branching

Branches allow parallel development contexts.

Branches are stored in:

.git/refs/heads/

List Branches

git branch

The current branch is highlighted.

Always verify the current branch before committing.

Create a Branch

git branch <branch_name>

This creates the branch but does not switch to it.

Switch Branch

git checkout new_feature

This moves HEAD to the new branch.

Switching branches immediately updates the working directory.

Create and Switch in One Step

git checkout -b fix_bug_x

The new branch is created from the current branch.

Always switch to the correct base branch before creating a new one.

0_vmPNU-pCys4CTA8m_1.width-800.png


HEAD Behavior

HEAD always points to the latest commit on the current branch.


Branches with Uncommitted Changes

Switching branches requires a clean working directory.

Uncommitted changes may be overwritten.

Options before switching:

Discard changes:

git checkout -- <file>

Commit changes.

Or stash them.

Create a branch from a specific commit:

git checkout -b testing_something <commit_sha>

Comparing Branches

Compare branch tips:

git diff master..new_feature

More complex references are allowed:

git diff master^..new_feature~3

Branch names act as references to their latest commits.

Check Which Branches Are Merged

git branch --merged

Example output:

master
new_feature
* shorten_title

This indicates master and new_feature are fully merged into
shorten_title.


Renaming Branches

git branch -m new_feature seo_title

Deleting Branches

git branch -d branch_to_delete

Git checks:

  • The branch is not currently checked out
  • The branch is merged

Force deletion:

git branch -D branch_to_delete

Branches often end by merging back into their base branch. Temporary
branches can simply be deleted.


Merging Branches

Switch to the receiving branch first:

git checkout master

Then merge:

git merge new_feature

0_mM2RzjoLlPjc5YLE_1.width-800.png

After merging, the branches may contain identical history.

git diff master..new_feature

This will return no differences.

The merged branch can then be deleted.

Always ensure the working directory is clean before merging.


Fast‑Forward vs True Merge

Fast‑Forward Merge

Occurs when the receiving branch has no new commits since the feature
branch diverged.

Git simply moves the branch pointer forward.

0_vgwEAK46iN_HC3IV_1.width-800.png

No merge commit is required.

To force a merge commit:

git merge --no-ff branch_name

True Merge

A real merge occurs when both branches have new commits.

Git creates a new merge commit combining both histories.

0_p991mqAlYT2OTS7Z_1.width-800.png

Command:

git merge new_feature

Git usually decides the appropriate merge strategy automatically.


Merge Conflicts

Conflicts occur when two commits modify the same line in a file.

Git cannot determine which change should win.

Manual resolution is required.


Resolving Merge Conflicts

When a conflict occurs, the shell prompt changes:

(master|MERGING)

Available actions:

  • Abort the merge
  • Resolve manually
  • Use a merge tool

Abort the Merge

git merge --abort

Manual Resolution

Conflicting files contain markers:

<<<<<<< HEAD
changes from current branch
=======
changes from merged branch
>>>>>>> branch_name

Steps:

  1. Choose the correct change.
  2. Remove conflict markers.
  3. Commit the result.
git commit

Using Merge Tools

git mergetool --tool=<tool_name>

Most IDEs provide integrated conflict resolution tools.


Reducing Merge Conflicts

Recommended practices:

  • Keep lines short.
  • Keep commits small and focused.
  • Avoid unnecessary whitespace changes.
  • Merge frequently.
  • Keep feature branches updated with master.

0_hu-2gYR05WETfOwJ_1.width-800.png
0_sVP3ITX5LNkuGZPd_1.width-800.png

Notes:

  • Branches can be created from any branch.
  • Branches can be merged into any branch.
  • A merged branch still exists until deleted.
  • Work can continue on a merged branch.

Stashing

Stashing temporarily saves changes without committing them.

The stash is separate from Git's three main trees.

Stashed changes behave like commits but do not have hashes.

Typical use case:

  • You have uncommitted changes.
  • You need to switch branches.
  • You are not ready to commit.

Creating a Stash

git stash save "message"

This stores changes from:

  • Working directory
  • Staging index

The working directory becomes clean.


Listing Stashes

git stash list

Example output:

stash@{0}: On master: trying to fix a bug
stash@{1}: On feature_branch: updating styles

Display stash changes:

git stash show -p stash@{0}

Retrieving Stashed Changes

Apply a stash:

git stash apply stash@{0}

Apply and remove the stash:

git stash pop stash@{0}

After applying a stash, the working directory contains changes again.

You can continue editing or create a commit.


Deleting Stashes

Delete a specific stash:

git stash drop stash@{0}

Remove all stashes:

git stash clear

Use caution when clearing the stash.