Git Tips and Tricks

Image of Author
March 15, 2022 (last updated September 11, 2023)

Help

-h shows quick inline help, while --help shows the full man page. It will work with aliases as well.

git branch -h
g br -h

git help branch
git branch --help
g br --help

Here are some tips and tricks in other locations:

How to manipulate your commit history

A robust way to manipulate your commit history is with the interactive rebase. For example, to manipulate your last five commits, you can do the following,

git rebase -i HEAD~5

You are then presented with an editor of those commits and allowed to select from a variety of actions, like pick, drop, squash, etc. You can then force push your changes.

Obligatory warning: messing with commit history is dangerous so be careful.

Stashing only unstaged content

git stash --keep-index

As a reminder, the index is where the staged changes "live" until committed. See Git Working Directory and Index for more. This means you are keeping the staged (yellow) code, and stashing the unstaged (red) code.

Tags

It seems that tags created locally are not automatically pushed up to remote. To do so, run git push --tags. You can then do things like create a github release, etc, based on that tag. Pushing tags automatically populates github tags, which is nice for users who want to download zips, etc.

Branches

  • g bra, git branch --all

    List every branch

  • g br -dr b1 b2, git branch --delete --remote b1 b2

    Deletes multiple branches "safely", i.e., only fully merged branches. Often fails for certain workflows. g br -Dr b1 b2, or g br -drf b1 b2 will force the deletion. If you've already removed the remote-tracking branch, e.g., g remote prune origin, you will need to drop the -r, since git will not run the command if it fails to find the remote-tracking branch. So, g br -df b1 b2.

Remote-tracking branches

From the git docs on remote branches

Remote-tracking branches are references to the state of remote branches. They’re local references that you can’t move; Git moves them for you whenever you do any network communication, to make sure they accurately represent the state of the remote repository. Think of them as bookmarks, to remind you where the branches in your remote repositories were the last time you connected to them.

Keep in mind that remote-tracking branches are local references. This is why the git remote command doesn't actually do anything to the remote repository. What it does is interact with your local reference of the remote repository. For example, git remote prune origin gets rid of local references to stale remote branches.

Accidentally committed files you should have gitignored?

Use git rm --cached -r .

--cached will only remove cached files, which are files in the index, and not the working tree. (Remember, working tree is the red stuff, so that is not messed with here.) The -r flag is for 'recursive', so it will remove nested files from the cache as well.

Now, update your .gitignore to include the files and directories you should have ignored to begin with. You should now be able to run git add . and only have the files you want.

Reset to remote branch without concern for local?

For example, you want to reset your local main to remote main.

git fetch
git reset --hard origin/main

Misc

  • git revert [sha]

    Reverts the commit. E.g., git revert HEAD will revert the last commit. If you have not pushed to a remote branch, use git reset instead.

  • git cat-file -p [sha]

    -p stands for "pretty print". Will print out the internal "value" associated with the SHA "key", the content of which depends on what the SHA refers to. For a commit it will show things like the tree, parent, author, commit message, etc. Trees contain blobs, and blobs contain file text, all of which can be recursively inspected with the same command. Run git help cat-file to learn more

  • git push [origin] --delete [branch_name]

    Delete the remote version of a branch. (Though I often feel safer doing it via the remote repo GUI.)

  • git remote prune origin or git remote update [origin] --prune

    Prune stale branches from your remote cache

  • git clean -fd

    Removes untracked files and directories from the working tree. I.e., it deletes the red stuff. -f is to force the clean. I think that they make you type it because it's a destructive action. -d is to recursively clean directories. Effectively, that means it deletes directories as well.

Syntax

  • HEAD is the commit upon which you are basing your current changes in the working tree. (docs)
  • @ is an alias for HEAD
  • <rev> is a generic term that specifies a "revision". This is typically a commit SHA. Another type of revision is a refname, which points to a SHA. (docs)
  • <ref>, or <refname>, is a reference to a revision (or, <rev>). These are the most commonly used revisions, e.g., master, branch-name, HEAD, etc. (docs)
  • <ref>~<n>, e.g., HEAD~3, is syntactic sugar which refers to the 3rd (or nth) ancestor commit to HEAD. So, like, 3 commits back, not including the HEAD commit.