www.alxm.org

Git Notes

Contents

Shell#

Show the Time and Git Branch on the Shell Prompt#

I set up my Bash prompt to show the current time, and if inside a Git repo path, to also show the name of the checked-out branch. The following goes at the end of ~/.bashrc, to override any previously set PS1 (the environment variable for the shell prompt's format string):

1
2
3
4
5
6
git_branch() {
    branch_name=$(git symbolic-ref --short HEAD 2>/dev/null)
    [ $? -eq 0 ] && echo "[$branch_name]"
}

export PS1='\t \u@\h \w$(git_branch) \$ '

The shell prompt should look something like this now:

1
2
3
18:44:06 alex@laptop ~ $ mkdir project && cd project
18:44:10 alex@laptop ~/project $ git init
18:44:20 alex@laptop ~/project[master] $

Convenient Single-Letter Aliases#

I keep a few short shell aliases in ~/.bashrc for the Git commands I use the most day to day. All of them are for read-only actions though, muscle memory can be dangerous when you're tired...

1
2
3
4
5
6
alias b="git branch -a -vv"
alias d="git diff"
alias ds="git diff --staged"
alias h="git show"
alias l="git log --graph --decorate=full --pretty=medium"
alias s="git status"

Colored Text in the Terminal#

Add to ~/.gitconfig:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[color]
    ui = true
[color "branch"]
    current = yellow reverse
    local = yellow bold
    remote = green bold
[color "diff"]
    meta = magenta bold
    frag = magenta bold
    old = red bold
    new = green bold
[color "status"]
    added = blue bold
    changed = green bold
    untracked = cyan bold

Repo Management#

Push to Multiple URLs#

Git remotes can be configured to push to multiple URLs, which is great for having backups and keeping things distributed. You can add extra addresses with git remote set-url --add --push origin git@host2:project.git or edit the project's .git/config directly:

1
2
3
4
5
[remote "origin"]
    url = git@host1:project.git
    pushurl = git@host1:project.git
    pushurl = git@host2:project.git
    pushurl = git@host3:project.git

Remotes should look something like this now:

1
2
3
4
5
$ git remote -v
origin  git@host1:project.git (fetch)
origin  git@host1:project.git (push)
origin  git@host2:project.git (push)
origin  git@host3:project.git (push)

Merge Two Separate Git Repos#

I create a new Git repo for every game jam project, but afterwards I merge it to a single archive repo that has all my past jam entries, preserving the original commit history of each.

Starting with the new game's repo at ~/newgamerepo, I first move everything from the project root to a subfolder:

1
2
3
4
$ cd ~/newgamerepo
$ mkdir newgame
$ git mv * newgame/
$ git commit -m "Move everything to the newgame subfolder."

Then I merge the game repo to the archive repo at ~/gamejams:

1
2
3
4
$ cd ~/gamejams
$ git remote add newgameremote ~/newgamerepo
$ git fetch newgameremote
$ git merge --allow-unrelated-histories newgameremote/master

The new game lands at ~/gamejams/newgame/. The --allow-unrelated-histories flag lets us merge Git histories with no common ancestors, in other words distinct repos.

Filter Changes of a Particular File by Keywords#

This lists commits that added or removed occurences of MyKeyword in a file:

1
git log -S "MyKeyword" -- path/to/file.txt

Repo Upkeep#

Remove All Files Not Part of the Repo#

1
git clean -dfx

Fix Issues Identified by git fsck#

One day I learned about this Git command and tried it out in one of my repos:

1
2
3
4
5
6
$ git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (6088/6088), done.
error: <object-id>: invalid sha1 pointer in resolve-undo
dangling commit 7cc415930bfcb31cd1c0501f54c2a452fb411156
Verifying commits in commit graph: 100% (694/694), done.

The following fixed everything, beware losing any uncommitted changes:

1
2
3
4
git reflog expire --expire=now --all
git gc --aggressive --prune=now
rm .git/index
git reset