14 KiB
Raw Blame History

Git

Git

Basic configuration

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

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

Setting Up Personal Information and Preferences

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

[user]
	email = lucien@phundrak.com
	name = Lucien Cartier-Tilet
	signingkey = BD7789E705CB8DCA

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

Lets 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

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

/phundrak/config.phundrak.com/media/commit/d4ec04f9759a12e7566efd512172b8f1961938ef/docs/img/git/diff-default.png

Not really readable, I think youll 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, lets turn on the histogram algorithm on:

/phundrak/config.phundrak.com/media/commit/d4ec04f9759a12e7566efd512172b8f1961938ef/docs/img/git/diff-histogram.png

Immediately, we have a much clearer picture of what happened! But Ill 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!

/phundrak/config.phundrak.com/media/commit/d4ec04f9759a12e7566efd512172b8f1961938ef/docs/img/git/diff-moved.png

Ill 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 whats new upstream.

[pull]
	rebase = true

However, there is a problem with gits 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 were at it, lets 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! Im 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:

/phundrak/config.phundrak.com/media/commit/d4ec04f9759a12e7566efd512172b8f1961938ef/docs/img/git/merge-default.png

To this:

/phundrak/config.phundrak.com/media/commit/d4ec04f9759a12e7566efd512172b8f1961938ef/docs/img/git/merge-zdiff3.png

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

[merge]
	conflictstyle = zdiff3

Finally, once were good to go, we may want to push our changes to the remote repository. Sometimes, git is confused and isnt sure where it should push your branch. Lets 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 dont want to push separately my tags, so lets push them with any other push.

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

Making Git Look Better

First, lets 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, lets 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. Lets 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. Lets 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

abbreviation equivalent
a add --all
aca !git add --all && git commit --amend
acan !git add --all && git commit --amend --no-edit
abbreviation equivalent
b branch
bd branch -d
bdd branch -D
abbreviation equivalent
c commit -S
ca commit -Sa
can commit -Sa --no-edit
cm commit -Sm
cam commit -Sam
abbreviation equivalent
co checkout
cob checkout -b
cod checkout develop
abbreviation equivalent
cl clone
cl1 clone --depth 1
abbreviation equivalent
f fetch
fp fetch --prune
abbreviation equivalent
ps push
psf push --force-with-lease
pso push origin
psfo push --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
abbreviation equivalent
pl pull
pb pull --rebase
abbreviation equivalent
r rebase
ra rebase --abort
rc rebase --continue
rd rebase develop
ri rebase -i
abbreviation equivalent
rmf rm -f
rmd rm -r
rmdf rm -rf
abbreviation equivalent
sm submodule
sms submodule status
sma submodule add
smu submodule update
smui submodule update --init
smuir submodule update --init --recursive
abbreviation equivalent
st stash
stc stash clear
stp stash pop
stw stash show
abbreviation equivalent
u reset --
unstage reset --
abbreviation equivalent
d diff -w
l log --oneline --graph --decorate
s status
staged diff --cached
      a = add --all
      aca = !git add --all && git commit --amend
      acan = !git add --all && git commit --amend --no-edit
[alias]
<<abbrev-gen(abbrevs=git-add-abbrev)>>
<<abbrev-gen(abbrevs=git-branch-abbrev)>>
<<abbrev-gen(abbrevs=git-commit-abbrev)>>
<<abbrev-gen(abbrevs=git-checkout-abbrev)>>
<<abbrev-gen(abbrevs=git-clone-abbrev)>>
<<abbrev-gen(abbrevs=git-fetch-abbrev)>>
<<abbrev-gen(abbrevs=git-push-abbrev)>>
<<abbrev-gen(abbrevs=git-pull-abbrev)>>
<<abbrev-gen(abbrevs=git-rebase-abbrev)>>
<<abbrev-gen(abbrevs=git-rm-abbrev)>>
<<abbrev-gen(abbrevs=git-submodule-abbrev)>>
<<abbrev-gen(abbrevs=git-stash-abbrev)>>
<<abbrev-gen(abbrevs=git-unstage-abbrev)>>
<<abbrev-gen(abbrevs=git-single-abbrev)>>

Tools

Sendemail

[sendemail]
	smtpserver = mail.phundrak.com
	smtpuser = lucien@phundrak.com
	smtpencryption = tls
	smtpserverport = 587
[credentials "smtp://lucien@phundrak.com@mail.phundrak.com:587"]
	helper = "secret-tool lookup password email_lucien-phundrak-com"

Magit

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

GPG

[gpg]
	program = gpg2
[commit]
	gpgsign = true

Merge

[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://phundrak@github.com"]
	insteadOf = https://github.com

[url "https://phundrak@labs.phundrak.com"]
	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, lets just ignore dotenv files and direnvs directories.

.env
.direnv/

Now, lets ignore files generated by Emacs.

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

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

Finally, lets ignore some files we generally do not want.

,*.out
,*.o
,*.so

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

,*.log
,*.sqlite

dist/