Git efficiency

In a Git repository

Rote commands drive my use of git too much. It's far better for me if I understand the database directly, and then use those commands as a toolset.

SHA-1 hash
A cryptographic key value computed for objects of the git repository

Each Blob, Tree, and Commit is static, and therefore has a fixed reference or id for storing and retrieving each object.

Contents of a file stored in a git repository

A blob is a static object without a name nor a change history. Each file is a blob in context of a commit, so change history may be approximated heuristically. Blobs are stored by various techniques of compression.

Directory list of a folder stored in a git repository

Each tree is a list of tree and blob references. Each item in the list has the file or folder name, access permissions, and the ref. This structure of trees allows each blob or tree to have home in multiple trees of different names.

A record representing a complete state of a git repository

Each commit has the following properties: a tree reference, parent references (commit, merge commit), author (name/email/date), committer (name/email/date), and free-form text (log description). The parent properties build a commit graph. I can directly reference commits by the first few digits of its id. I can indirectly reference commits by assigning a tag name or branch name. I can relatively reference commits by using a combination of postfix modifiers.

A pointer with a name that maps to a specific commit

I can indirectly reference a specific commit by assigning a tag name. I can further that indirection by appending the following postfix modifiers to reference relatives in the commit graph.

Nth-great parent commit following first-parent lineage (tilde is depth-wise)
1st parent (caret is breadth-wise)
2nd parent (the merge parent)

I can also affect an indirection by use of prefix or infix modifiers as follows. Some commands operate on a set of commits, such as git log and git diff. For these commands it usually helps to trim the graph.

^id1 id2
set difference from id1 to id2
The set of commits in the parent graph of id2 and not in that of id1
symmetric difference of id1 and id2
The set of commits from both the parent graphs that do not overlap between that of id1 and that of id2 (commits which are not common ancesters)
A pointer with a name that maps to a specific commit timeline

A branch is like a tag, but has a history beyond the commit genealogy which I call the commit timeline. The HEAD is a special branch which references the current commit and its timeline formed by switching between commits by series of check-out (typically, moving branches) and check-in (creating new commits). A detached HEAD occurs when you checkout a commit other than a branch. Besides the postfix modifiers allowed for commit ids and tags, additional postfix modifiers are allowed on branches.

Nth previous commit value of a branch
"HEAD@{5 minutes ago}"
Previous value of a branch at a specified time
The git help reference for rev-parse shows more examples of postfix tag/branch/id modifiers.
A connected git repository for collaboration

Most repositories are cloned from another git repository. The default clone operation creates a new local repository and sets its default remote for push and fetch operations. The default remote is called origin. The clone, fetch, and push operations combine to facilitate collaboration of independently maintained repositories. Each collaborator has his or her own repository with commits, trees, and blobs, and with branches and tags that navigate them. Each remote reflects this same repository data as hosted on a shared server or provided by other collaborators. The fetch command will update the reflection of the remote stored locally. The push command will apply changes from a local branch back to the remote branch after fetch.

Git can bury its data

Here's some ways to browse the data of a git repository without changing the HEAD pointer.

git log --first-parent
When I want to trim the branches from the log
git log directory/or/file
When I want to see the log filtered to specific files
git log --name-only
When I want to see the files changed in the log
git log -M
When I want to files across renames
git rev-parse id-tag-branch-etc
When I want to show the full Ref based upon input of a tag name, branch name, commit id, HEAD, or relative id
git cat-file -p id
When I want to walk through and show contents of each of the git objects by id
git remote -v
When I want to show a list of each remote connection

And git can be slow

Well, I simply got tired of some slow git commands, and so begun this list of efficiency improvements.

git status -uno
When I don't need to scan folders for untracked files
git status --ignore-submodules
git diff --ignore-submodules
When I have a large submodule which is infrequently modified
git submodule deinit my/big/module
When a large submodule is completely unused for long periods
git add -p .
When I want a single commit from changes across many files, interspersed among many other changes I want to withhold (without commit)


  • y = Yes (add)
  • n = No (skip)
  • s = split (re-ask in smaller chunks)
  • e = edit (change the changeset in vi)
  • q = quit
  • ? = tell me my choices
git reset -p file
When I want to partially reverse an added file or partially unindex
Subcommands are essentially the same as with partially indexing except reversed in direction.
git diff --cached
When I want to review the staged files before commit
git diff HEAD files
When I want to see the staged and unstaged changes since the last commit
git diff -M
When I want to review changes between moved files
git reset --soft HEAD~1
When I want to undo the last commit
git checkout filename
When I want to revert a single file, throwing away the uncommitted changes

But I am still learning

Some git commands linger in my learning queue.

git stash ...
When I want to get all changes out of the way while temporarily I work on the repository or other changes

A conflict can occur when restoring the stash (pop), causing a "merge-like" situation, with all but the conflicting files in the index. But I don't know why because I don't want to commit the stash quite yet (else why did I stash it?). It seems if I attempted a pop when the index was populated, I might lose the work of building the index. I can save the index first, but I haven't figured out all the workflows yet.