GIT commands move data between four areas of the object database. This article explores the four areas and the common commands that affect them.

See the earlier post on How GIT stores information for information on the GIT object database.

What are the four areas GIT uses?

  1. The Working Area stores project source files updated directly by a code editor
  2. The Index (or Staging Areas) tracks which files from the working area included in the next commit
  3. The Repository (or Repo) is the most important area, where GIT stores snapshots of the tracked files, called commits
  4. The Stash is a temporary area, a bit like a clipboard, that can store and retrieve a saved copy of the working area and index

Understanding git requires understanding how commands move data between these four areas.

FourAreas

GIT STATUS

git status is one of the most important commands. It shows the status of the working area and index. The most common output shows untracked files and modified files.

❯ git status
On branch master
nothing to commit, working tree clean

New files

When a file is created or copied into the project, it only exists in the working area. git status will show the file as untracked. It has not been added to the index (staging) area and will not be part of the next commit until added. The status command shows the list of new files and suggests how to add them to the index.

❯ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        consolidate.py

nothing added to commit but untracked files present (use "git add" to track)

Modified files

Files added to the index are tracked by GIT. When a tracked file is updated or modified, git status shows the it as modified and not yet staged for commit. The working area version has changed, but GIT is only tracking the previous version in the index. The updated file needs to be added to the index to be included in the next commit. The status command shows the modified files and suggests actions to take.

❯ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   consolidate.py

no changes added to commit (use "git add" and/or "git commit -a")

Changes not committed

git status also shows changes in the index but not yet committed to the repo. These could be new and/or modified files.

❯ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   consolidate.py

Remote

A remote is a linked repository, for example, a central source repo that the local repo was originally cloned from. GIT maintains the link to the remote and tracks differences. By default, the remote is named origin. git status will show if the remote repo is ahead or behind the current local commit.

❯ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

GIT ADD

The git add command updates the index (staging) area to track new files or add new versions of already tracked files. The most common parameters are as follows:

❯ git add mynewfile.txt # stage a specific file in the index
❯ git add folder1/ # stage all new and modified files in folder1
❯ git add -A # stage all new and modified files in the entire project
❯ git add . # same as above
❯ git add -i # interactive mode. Prompts for a decision on a file-by-file basis

GIT DIFF

git diff shows differences between the GIT areas, such as between the working area and index, or between the index and repo. Differences are displayed at the command line. git diff is convenient for quick checks and small changes. Graphical tools may be better suited for complex comparisons.

❯ git diff # shows differences between the working area and index
❯ git diff --cached # shows differences between the index and repo

diff --git a/consolidate.py b/consolidate.py
index de10111..97f66ce 100644
--- a/consolidate.py
+++ b/consolidate.py
@@ -1 +1,2 @@
 import sys
+print (sys.version)

In the example output above, there is a difference between the index and the repo. A line has been added in the index version, indicated by the “+” symbol.

GIT COMMIT

The git commit command creates a point-in-time snapshot of tracked files in the repo. New and modified files from the index are added to the repo as new objects. Unchanged files are just referenced by a link to the existing object in the repo. The commit itself is an object in the repository, pointing to a tree and any parent commit.
A commit is named using a SHA1 hash. It can be referenced in commands using just the first few characters of the hash (enough that it is not ambiguous).

❯ git commit -m "Enabled handling of user input"

[main b9b6064] Enabled handling of user input
 1 file changed, 1 insertion(+), 1 deletion(-)

In the output above, a new commit is created on the main branch with partial SHA1 hash b9b6064

GIT BRANCH

A branch is just a reference to a commit. Creating a branch does not actually change objects in the repo, it just creates a named pointer to an existing commit. If you are on the main branch and create a new branch called dev, GIT adds a new dev object in the .git/refs folder pointing to the current commit. Initially both branches are pointing to the same commit.
The git branch command shows the current branches or creates a new branch, but does not switch to it. The asterisk in the output below shows that after creating a new dev branch, main is still the current branch:

❯ git branch dev # create a new branch. 
❯ git branch # show branches
  dev
* main

GIT SWITCH

git switch is a relatively new command that switches between branches. It does not make changes to the repo, but it does affect the working area and index. When you switch to another branch, the GIT HEAD reference is updated to point to the selected branch. The branch refers to a commit and the files and folders in the working area and index are replaced by the files in this commit.

❯ git switch dev
Switched to branch 'dev'
❯ git branch
* dev
  main

You can create a branch and switch to it with the -c option

❯ git switch -c feature
Switched to a new branch 'feature'

GIT CHECKOUT

When it comes to moving between branches, git checkout is almost identical to git switch. The checkout command has been around for much longer and has options that perform other actions. The variety of uses for the checkout command was deemed confusing and switch was introduced to focus purely on moving between branches.

❯ git checkout dev # change to the dev branch
Switched to branch 'dev'
❯ git branch # show 'dev' is now the current branch
* dev
  feature
  main
❯ git checkout -b feature2 # create a new branch and switch to it
Switched to a new branch 'feature2'
❯ git branch # show 'feature2' is not the current branch
  dev
  feature
* feature2
  main

GIT LOG

git log shows the history of commits and branches. It does not make any changes to the repo, index or working area. Use the –graph option to see a basic diagram of branches and merges:

❯ git log --oneline --graph --decorate
*   a7d531d (HEAD -> main) Merge Feature2, resolve conflict in orders.py
|\
| * d0773eb (feature2) Adds input validation to orders.py
* | bba3001 Modifies output in orders.py
|/
* 460ce0e Enables user input
* b9b6064 Creates orders.py

GIT RESET

git reset is used to rollback to a previous commit. It can affect the repo, the index and the working area depending on the parameters.
A common use case is to abandon some changes that have been committed and revert to a previous version of the project. Another is to abandon changes in the working area and revert to the last commit in the repo.

The reset command will move the current branch to the specified commit. By default, it will also overwrite the index with the contents of the commit. If you want to completely remove all traces of the unwanted change, you can also overwrite the working area using the –hard option

> git log --oneline # show the history of commits
848eae0 (HEAD -> main) Adds search to 404 page
364b33f Changes format of 404 page
d4ff0dc Modifies position of search box 
c55dbb1 Enables comments
cccb986 Adds home page, header and footer
4478398 Initial commit
>
> git reset --hard d4ff0dc  # Rollback the repo two commits, overwriting the index and working area
HEAD is now at d4ff0dc Modifies position of search box

Other options are:

> git reset --mixed d4ff0dc # Rollback the repo two commits but only overwrite the index. The working area is not touched. This is also the default if no options are specified.
> git reset --soft d4ff0dc # Rollback the repo two commits, but don't touch the index or working area

HEAD RESET

git reset HEAD is a quick way to return the index/working area to the committed state of the repo. This is an unsual reset as it doesn’t actually change anything in the repo.

HEAD is usually poiting to the latest commit on the current branch. Resetting the repo to HEAD changes nothing in the repo, but by default it will perform a mixed reset, overwriting the index. We can also use the –hard option to overwrite both the index and working area:

> git reset --hard HEAD

GIT STASH

The Stash is a temporary storage area to save the working area and index when you need to working on another feature. You don’t want to lose or commit what you are currently working on, so you stash the changes, work on something else and then retrieve them later. Its a bit like saving something in a clipboard.

When you run git stash, GIT copies tracked files in the working area and index that aren’t in the current commit and saves them to the stash. It then checks out the current commit (overwriting the working area and index so they match the repo).

When ready to restore the stashed files, run git stash apply.

> git stash --include-untracked  # Save changes to the stash including untracked files
>
> git stash list # List the contents of the stash. This is an array of saves starting with zero
>
> git stash apply # Copies the latest entry in the stash to the working area and index. You can also specify an array element number if you don't want the latest



This article was originally posted on Write-Verbose.com