Dotfiles - Git Config with Aliases
Tags: git, alias, productivity, config
Published: 2020-09-06 11:28:14


> Setting up git aliases and core settings in your git config

See my full [Git config](https://github.com/MichaelCurrin/dotfiles/blob/master/.gitconfig.toml) on GitHub.

Most of this post is focused on git aliases, with bit of core settings at the end.

If you are new to git aliases, see this [dev.to post](https://dev.to/konstantin/aliases-git-way-1kjp).


## Setup aliases

Here is the format - add aliases to your `~/.gitconfig` file, which uses TOML format. 

```toml
[alias]
	MY_ALIAS = "GIT_COMMAND"
	MY_ALIAS = "! MY SHELL COMMAND"
```

### Git aliases

Here is a sample based on my [Git config](https://github.com/MichaelCurrin/dotfiles/blob/master/.gitconfig.toml) file.

```toml
[alias]
	st = "status -s -b"
	c = "commit"

	# --all
	# --verbose
	br = "branch -a -v"

	co = "checkout"
	cb = "checkout -b"

	# Short hash, relative date and message.
	logd = "log --pretty='%C(yellow)%h %C(cyan)%ar %Creset%s'"

	# --graph:
	#     Draw a text-based graphical representation of the commit history on
	#     the left hand side of the output.
	# --decorate:
	#     Print out the ref names of any commits that are shown. Defaults to
	#     short optionm such that the name prefixes refs/heads/, refs/tags/ and
	#     refs/remotes/ will not be printed.
	lol = "log --graph --decorate --oneline"
```

Notes on the config:

- You must use **double quotes** if using spaces in an alias value, otherwise you'll get command not found error.
- You don't need to reload your terminal to get changes - git aliases are evaluated fresh each time you run a git command.
- There is a _Better Toml_ extension for VS Code which helps handle this and I find this works better than using the Gitconfig extension and file type in VS Code.

I am going to demonstrate the usage and output of some of my git aliases next.


## View git aliases

As promised from the previous part of this series, here is how to list all aliases that are available.

```sh
$ git alias
st = status -s -b
c = commit
br = branch -a -v
co = checkout
...
```

## Git status

View a summary of your git status.

```
$ git st
## master...origin/master
 M configs/shell/.aliases
 M configs/shell/.commonrc
 M configs/shell/.gitignore
```

That is much quieter than:

```sh
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   configs/shell/.aliases
        modified:   configs/shell/.commonrc
        modified:   configs/shell/.gitignore

no changes added to commit (use "git add" and/or "git commit -a")
```


## Git log oneline

Show one line for each item in git log output.

```sh
$ git lol
* 9103ed0 (HEAD -> master, origin/master, origin/HEAD) Update .gitconfig
* 8a40fdb docs: Add comment
* f750060 feat: Update .gitconfig
```

## Sync local and remote commits and tags

Do a pull with a `--rebase` flag, then push. 

```
$ git sync
Already up to date.
Current branch master is up to date.
Everything up-to-date
```

It is safe to rebase here, since the commits are **unpushed**. Also, if there have been no local commits, the `pull --rebase` will just act as a plain `pull` without rewriting commits.

If you want to fetch all tags and then push all tags, do this:

```
$ git sync-tags
Enumerating objects: 1, done.
...
 * [new tag]         v0.8.0 -> v0.8.0
```

If you want to combine both of the above aliases to pull commits and tags and then push commits and tags, do this:

```sh
$ git sync-all
```

Here is the setup for that last one:

```toml
[alias]
  sync-all = "! git pull --rebase && git push --progress && git push --tags"
```
The `--progress` flag makes pushing quiet but not so quiet as `--quiet`.

I recently discovered this for pushing a commit and tags together:

```sh
$ git push --follow-tags
```

However, it only pushes tags at the current commit, so if you've tagged any older commits then those won't get pushed.

So to ensure all tags get pushes, I went back to this approach:

```sh
$ git push --progress && git push -tags
```

## View git tags

Show git tags using semver ordering, with higher tag numbers first.

```sh
$ git tags
v0.7.0
v0.6.0
v0.5.0
```

Note that `git tag` with no arguments also lists tags. But, will typically show older tags first and the ordering seems weird sometimes as it sorts by text and not by meaning (so `11.0.0` and `1.0.0` could appear side by side). 

So my alias ensures the recent ones are first and they are sorted using semvar.


## Git aliases that invoke the shell

Use an exclamation mark `!` at the start of a command to use a **shell** command without it going through `git`. 

This means you can use `cd` and `find`  for example. And chain shell commands using `&&` or `||`.

```toml
[alias]
	# Go to root of git repo.
	grt = "! cd $(git rev-parse --show-toplevel)"
 
	# Sync local and remote commits.
	sync = "! git pull --rebase && git push"
	# Sync local and remote tags.
	sync-tags = "! git fetch --tags && git push --tags"
	# Sync local and remote commits and tags.
	sync-all = "! git pull --rebase && git push --progress && git push --tags"
```

## Use arguments in a shell alias

Note that you can even reference arguments. Use can use `$1` and `$2` and so on for the position arguments for the aliases.

My use-case for this is limited but here is one that use this approach. Note that the check at the start shows a message if the count of arguments is not equal to one.

```toml
[alias]
	clone-https = "! [ $# -ne 1 ] && echo 'Args: USERNAME/REPO_NAME' || git clone https://github.com/$1.git"
```

Sample usage:

```sh
$ git clone-https
Args: USERNAME/REPO_NAME

$ git clone-https MichaelCurrin/dotfiles
Cloning into 'MichaelCurrin/dotfiles'...
```

Instead of using the forward slash, you could expect two arguments and then substitute them as `$1/$2.git`.

It is also possible to create a shell function instead and to define and invoke it as part of the alias, but I found using the syntax I've covered above cleaner.


## Configure global ignore file

The last part I want to mention on my Git Config part is not an alias but a core setting.

This tells git to use a global git ignore file, if it exists. Note you must used double quotes so that `~` gets expanded.

```toml
[core]
	editor = "nano"
	excludesfile = "~/.gitignore"
```

You must create this file yourself, which I'll cover in the next post.


## Multiple git configs

By the way, I discovered you have have multiple git configs and set it up so that a folder of work repos all use that. 

See this [post](https://dev.to/jma/multiple-gitconfig-409k) by `@jma`.

This sounds great as I use a different email for my work projects and I don't have to remember to set it locally on each repo.


## Share

If you any handy git aliases, please share them in the comments.

## Next

Carry on to [Part 5]( https://dev.to/michaelcurrin/dotfiles-global-git-ignore-38ef).