Phundrak's Dotfiles
Source
Source
  • Index
  • About this website
  • Emacs
    • Basic Configuration
    • Custom Elisp
    • Package Manager
    • Keybinding Managers
    • Autocompletion
    • Applications
    • Editing
    • Emacs built-ins
    • Making my life easier
    • LaTeX
    • Org-mode
    • Programming
    • Visual Configuration
    • Misc
    • Keybindings
  • Custom Scripts
  • Desktop
  • General Shell Configuration
  • Fish
  • Git
  • Hyprland
  • MPD
  • Tmux
  • Deprecated Configs
    • AwesomeWM
    • Bootstrap Script
    • EXWM (Deprecated)
    • i3
    • Nano
    • Neofetch (Deprecated)
    • Picom (deprecated)
    • Polybar
    • Spacemacs
    • StumpWM
      • Basic Configuration
      • Colours
      • Mode-Line
      • Groups and Placement
      • Theme
      • Commands
      • Keybindings
      • Utilities

Git

Basic configuration

Just to make Emacs follow the convention in terms of indentation, I’m forcing it to use tabs.

# -*- indent-tabs-mode: t; -*-

Setting Up Personal Information and Preferences

Let’s set some of my personal information, namely my name, my email, and which GPG key I sign my commits with.

[user]
        email = [email protected]
        name = Lucien Cartier-Tilet
        signingkey = ~/.ssh/id_ed25519.pub

In terms of core configuration, I simply set Emacs as my default Git editor. I also have my global gitignore file, described below in Global gitignore file.

[core]
        editor = emacsclient -c -a emacs
        excludesfile = ~/.config/git/global-ignore

Let’s not forget to tell Git to use the main branch by default.

[init]
        defaultBranch = main

This is entirely a matter of personal preferences, but I like to use Zen, a Firefox fork with really nice features.

[web]
        browser = zen-browser

Better Diffing

Git’s diffing algorithm evolved and improved over time, but its default algorithm did not. Take this example, from this Gitbutler article:

img

Not really readable, I think you’ll agree. I mean, you can sort of see what happens, but really, we just moved the h2 styling below the .event styling. Git seems to think otherwise. However, let’s turn on the histogram algorithm on:

img

Immediately, we have a much clearer picture of what happened! But I’ll let you on another secret: you can make it even clearer by using the colorMoved option to color differently lines that were moved from lines that were actually modified!

img

I’ll also add a configuration to make it easier to see what is being compared using mnemonicPrefix. As per man git-config:

git diff
    compares the (i)ndex and the (w)ork tree;

git diff HEAD
    compares a (c)ommit and the (w)ork tree;

git diff --cached
    compares a (c)ommit and the (i)ndex;

git diff HEAD:<file1> <file2>
    compares an (o)bject and a (w)ork tree entity;

git diff --no-index <a> <b>
    compares two non-git things <a> and <b>.

That means you can see I was comparing to objects not tracked by git in my screenshot above.

Finally, renames set to copies not only better detects file renames, but also file copies.

[diff]
        algorithm = histogram
        colorMoved = plain
        mnemonicPrefix = true
        renames = copy

Better Fetching, Pulling, Rebasing, and Pushing

By default, when I pull new commits, I do not want to create a merge commit, but rather to rebase my commits on what’s new upstream.

[pull]
        rebase = true

However, there is a problem with git’s default behaviour: it wont allow me to pull changes or perform a rebase as long as my worktree is dirty. I either have to commit or stash my changes before I can do something. And you know what? Git can auto stash your changes for you before performing a rebase. In fact, while we’re at it, let’s also automatically squash commits that need to be squashed, and update all refs.

[rebase]
        autoSquash = true
        autoStash = true
        updateRefs = true

And oh, buggers, you have a merge conflict! I’m used to it, but since git 2.3, there is a new feature that adds some context to git conflicts: zdiff3 (which stands for zealous diff3). Not only will it show you the conflicting incoming and HEAD changes, but it will also show you what the code was before either modified the conflicting area. Not a must-have feature, but a nice one to have. Compare this:

img

To this:

img

We have a new line beginning with ||||||| with the original line below. Also, it’s nice to see Emacs supports this syntax out of the box!

[merge]
        conflictstyle = zdiff3

Finally, once we’re good to go, we may want to push our changes to the remote repository. Sometimes, git is confused and isn’t sure where it should push your branch. Let’s tell it to simply push your current branch to the branch with the same name on the remote with push.default. If the upstream branch is not set yet, you can automatically set it up with push.autoSetupRemote. Finally, I don’t want to push separately my tags, so let’s push them with any other push.

[push]
        default = simple
        autoSetupRemote = true
        followTags = true

Making Git Look Better

First, let’s activate colors in git by default when we are in a terminal.

[color]
        ui = auto

Getting a raw list of things –branches, tags, …– is not nice. So, let’s make it a bit nicer and split these lists in columns.

[column]
        ui = auto

Simply using the column.ui option sets everything to use columns when using a terminal. If you want more granularity, you can instead use column.branch, column.status, etc… Look up man git-config for more info.

Better Sorting Branches and Tags

By default, branches are sorted alphabetically. This may be fine for most people, but I prefer something else: sorting them by how recently they were comitted to. This is actually quite easy to configure:

[branch]
        sort = -committerdate

Sorting tags is not nice by default. For instance, git will show you version 11 before version 2, because 11 is technically before 2 alphabetically speaking. Let’s fix that.

[tag]
        sort = version:refname

Did You Mean “Commit”?

Sometimes, I fat finger my git commands and white a subcommand that does not exist, like git pul or git comitt. By default, git will simply tell you that, no, that subcommand does not exist, but will be kind enough to suggest a few commands that may be what you are looking for. Let’s make git not only suggest these, but also ask you if you want to run the one you most likely wanted to run.

[help]
        autocorrect = prompt

Aliases

abbreviationequivalent
aadd --all
aca!git add --all && git commit --amend
acan!git add --all && git commit --amend --no-edit
abbreviationequivalent
bbranch
bdbranch -d
bddbranch -D
abbreviationequivalent
ccommit -S
cacommit -Sa
cancommit -Sa --no-edit
cmcommit -Sm
camcommit -Sam
abbreviationequivalent
cocheckout
cobcheckout -b
codcheckout develop
abbreviationequivalent
clclone
cl1clone --depth 1
abbreviationequivalent
ffetch
fpfetch --prune
abbreviationequivalent
pspush
psfpush --force-with-lease
psopush origin
psfopush --force-with-lease origin
pushall!git remote \vert{} xargs -L1 git push
psl!git remote \vert{} xargs -L1 git push
pullall!git remote \vert{} xargs -L1 git pull
pll!git remote \vert{} xargs -L1 git pull
abbreviationequivalent
plpull
pbpull --rebase
abbreviationequivalent
rrebase
rarebase --abort
rcrebase --continue
rdrebase develop
rirebase -i
abbreviationequivalent
rmfrm -f
rmdrm -r
rmdfrm -rf
abbreviationequivalent
smsubmodule
smssubmodule status
smasubmodule add
smusubmodule update
smuisubmodule update --init
smuirsubmodule update --init --recursive
abbreviationequivalent
ststash
stcstash clear
stpstash pop
stwstash show
abbreviationequivalent
ureset --
unstagereset --
abbreviationequivalent
ddiff -w
llog --oneline --graph --decorate
sstatus
stageddiff --cached
a = add --all
aca = !git add --all && git commit --amend
acan = !git add --all && git commit --amend --no-edit
[alias]
        a = add --all
        aca = !git add --all && git commit --amend
        acan = !git add --all && git commit --amend --no-edit
        b = branch
        bd = branch -d
        bdd = branch -D
        c = commit -S
        ca = commit -Sa
        can = commit -Sa --no-edit
        cm = commit -Sm
        cam = commit -Sam
        co = checkout
        cob = checkout -b
        cod = checkout develop
        cl = clone
        cl1 = clone --depth 1
        f = fetch
        fp = fetch --prune
        ps = push
        psf = push --force-with-lease
        pso = push origin
        psfo = push --force-with-lease origin
        pushall = !git remote | xargs -L1 git push
        psl = !git remote | xargs -L1 git push
        pullall = !git remote | xargs -L1 git pull
        pll = !git remote | xargs -L1 git pull
        pl = pull
        pb = pull --rebase
        r = rebase
        ra = rebase --abort
        rc = rebase --continue
        rd = rebase develop
        ri = rebase -i
        rmf = rm -f
        rmd = rm -r
        rmdf = rm -rf
        sm = submodule
        sms = submodule status
        sma = submodule add
        smu = submodule update
        smui = submodule update --init
        smuir = submodule update --init --recursive
        st = stash
        stc = stash clear
        stp = stash pop
        stw = stash show
        u = reset --
        unstage = reset --
        d = diff -w
        l = log --oneline --graph --decorate
        s = status
        staged = diff --cached

Tools

Sendemail

With git, it is possible to directly send commits as patches to a mailing list by email. However, it needs to know how. I’ll just configure my mail server here.

[sendemail]
        smtpserver = mail.phundrak.com
        smtpuser = [email protected]
        smtpencryption = tls
        smtpserverport = 587

Git also needs to know my password for my email address. Obviously, I won’t share it here, but I am using a helper which will itself return my password to git.

[credentials "smtp://[email protected]@mail.phundrak.com:587"]
        helper = "secret-tool lookup password email_lucien-phundrak-com"

Magit

This configuration is specific for what I consider to be the best git client out there, Magit. Not just because it is an Emacs git client, but also because it is quite transparent in terms of what happens with the command line, but it also lets you see so much more easily what happens with so many niceties. Rebases, including interactive rebases, are a breeze with Magit.

I also can interact with some Git forges, including GitHub. Here are some configurations recommended by Magit for Git.

[magithub]
        online = true
[magithub "status"]
        includeStatusHeader = true
        includePullRequestsSection = true
        includeIssuesSection = true

GPG

[gpg]
        format = ssh
[gpg "ssh"]
        allowedSignersFile = "~/.ssh/allowed_signers"
[commit]
        gpgsign = true

Merge

I like to use Emacs for everything (is it surprising?). Let’s declare the merge tool ediff and use it in my git configuration.

[merge]
        tool = ediff
[mergetool.ediff]
        cmd = emacs --eval \" (progn (defun ediff-write-merge-buffer () (let ((file ediff-merge-store-file)) (set-buffer ediff-buffer-C) (write-region (point-min) (point-max) file) (message \\\"Merge buffer saved in: %s\\\" file) (set-buffer-modified-p nil) (sit-for 1))) (setq ediff-quit-hook 'kill-emacs ediff-quit-merge-hook 'ediff-write-merge-buffer) (ediff-merge-files-with-ancestor \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$BASE\\\" nil \\\"$MERGED\\\"))\"

Git forges

[github]
        user = phundrak
[url "https://[email protected]"]
        insteadOf = https://github.com

[url "https://[email protected]"]
        insteadOf = https://labs.phundrak.com

[url "https://github.com/RustSec/advisory-db"]
    insteadOf = https://github.com/RustSec/advisory-db

LFS

[filter "lfs"]
        required = true
        clean = git-lfs clean -- %f
        smudge = git-lfs smudge -- %f
        process = git-lfs filter-process

Global gitignore file

This is my global gitignore file, specifying files that will always be ignored by Git, as described in Basic configuration.

You may see some lines beginning with ,*. Just read it as a simple *, this is done in order to avoid org-mode being confused by a line-initial * usually marking headings.

First, let’s just ignore dotenv files and direnv’s directories.

.env
.direnv/

Now, let’s ignore files generated by Emacs.

*~
\#*\#
*.elc
auto-save-list
.\#*
*_flymake.*
/auto/
.projectile
.dir-locals.el

# Org mode files
.org-id-locations
*_archive

Finally, let’s ignore some files we generally do not want.

*.out
*.o
*.so

# Archives
*.7zz
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip

*.log
*.sqlite

dist/
Prev
Fish
Next
Hyprland