Compare commits

..

No commits in common. "918bf6cc49a544fea96ba0b5923c63a6d19df277" and "31c04c09c4d9cf738d5595ff8e74917d8ebc4f51" have entirely different histories.

2 changed files with 67 additions and 166 deletions

View file

@ -1,69 +1,34 @@
# dotGit ::: 🪄 dotfiles + 🧸 bare git repo + 🐚 shell aliases
# dotGit - 🐚 shell aliases + 🪄 dotfiles + 🧸 bare git repo
There are a lot of ways to manage your dotfiles. dotGit implements an idea that has been floating around on the internet for a while: a bare git repo for storing your dotfiles. A quick search finds [this post](https://news.ycombinator.com/item?id=11070797), but there may be older sources. dotGit combines this with some convenient shell aliases, a couple of functions, and FZF's matching magic to track your dotfiles files with ease.
There are a lot of ways to manage your dotfiles. dotGit implements an idea that has been floating around on the internet for a while: a bare git repo for storing your dotfiles. A quick search finds [this post](https://news.ycombinator.com/item?id=11070797), but there may be older sources.
dotGit has modest aims:
- 🏡 keep configuration files where tools expect them in `$HOME`
- 🏡 keep config files where tools expect them in `$HOME`
- 🐚 stay as light and close to git and the shell as possible
- 🚀 reduce friction and make configuration changes quick and convenient
- 🚀 reduce friction and make config changes quick and convenient
dotGit gives you a handful of shell aliases (tested with `zsh`🐚 and `bash`) to make dotfile management quick and easy. The shortcuts mimic a subset of those found in the [oh-my-zsh](https://github.com/ohmyzsh/ohmyzsh) [git](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git) plugin.
## usage
- `.g` is the alias for running `git` with correct `--git-dir` and `--work-tree`
- `.ga` runs `git add`
- `.gc` runs `git commmit`
- `.gco` runs `git checkout`
- `.gd` runs `git diff`
- `.gss` shows the `git status --short`
- `.gp` will `git push` the changes to the origin
- `.gl` will `git pull` changes from the origin
- `.glo` runs `git log --oneline --decorate `
- `.glg` runs `git log --stat`
- `.glgp` runs `git log --stat --patch`
- `.gg` runs `git grep` on your dotfiles. If [FZF](https://github.com/junegunn/fzf) is installed it will be used to present the matches, and make it easy open your `$EDITOR` on the right line (works with vi, emacs, nano, micro, and any editor that accepts the `+<number>` syntax to indicate the line number).
- `.ge` (requires [FZF](https://github.com/junegunn/fzf)) lists all files using FZF and opens the selected file in your `$EDITOR`
- `.lazygit` (requires [lazygit](https://github.com/jesseduffield/lazygit)) will run `lazygit` with the correct `-g` and `-w`
- `.gitui` (requires [gitui](https://github.com/extrawurst/gitui)) will run `gitui` with the correct `-d` and `-w`
Most of dotGit is just some aliases that point to the `--git-dir` and `--work-tree`.
The real daily winners for me are the "edit" (`.ge`) and "grep" (`.gg`) aliases. They get me to where I need to be fast.
### a normal workflow for making configuration changes
1. `.gl` - pull changes from origin
2. make some changes. Try:
- `.ge zshrc` - presents all files with `zshrc` in the name
- `.gg PATH` - runs `git grep` across your dotfiles and presents the results
4. `.gc -m 'commit comment' .zshrc` - will commit the changes
5. `.gp` - pushes the changes to the origin
### a list of all aliases defined
| alias | action | note |
| --- | --- | --- |
| .git | `git --git-dir=${DOT_REPO} --work-tree=${DOT_HOME}` | |
| .g | `.git` | |
| .ga | `.git add` | |
| .gc | `.git commit` | |
| .gco | `.git checkout` | |
| .gd | `.git diff` | |
| .ge | calls the `_dotgit_ge` helper function | the dotGit edit feature [^fzf] |
| .gg | calls the `_dotgit_gg` helper function | grep your dotfiles, and jump to correct line [^line] |
| .gss | `.git status --short` | |
| .glo | `.git log --oneline --decorate` | |
| .glg | `.git log --stat` | |
| .glgp | `.git log --stat --patch` | |
| .gbl | `.git blame -w` | |
| .gb | `.git branch` | |
| .gba | `.git branch --all` | |
| .gbd | `.git branch --delete` | |
| .gbD | `.git branch --delete --force` | |
| .gm | `.git merge` | |
| .gma | `.git merge --abort` | |
| .gmc | `.git merge --continue` | |
| .gc! | `.git commit --verbose --amend` |
| .gcm | `.git commit --message` | |
| .gcp | `.git cherry-pick` | |
| .gcpa | `.git cherry-pick --abort` | |
| .gcpc | `.git cherry-pick --continue` | |
| .gclean | `.git clean --interactive -d` | |
| .ginit | `git init --bare "${DOT_REPO}"; .git config --local status.showUntrackedFiles no` | [^untracked] |
| .gp | `.git push` | requires `DOT_ORIGIN` be set |
| .gl | `.git pull` | requires `DOT_ORIGIN` be set
| .gclone | `git clone --bare "${DOT_ORIGIN}" "${DOT_REPO}"; .git config --local status.showUntrackedFiles no` | |
| .lazygit | `lazygit -g ${DOT_REPO}/ -w ${DOT_HOME}` | requires `lazygit` be installed |
| .gitui | `gitui -d ${DOT_REPO}/ -w ${DOT_HOME}` | requires gitui to be installed |
[^line]: This works with vi, emacs, nano, micro, and any editor that accepts the line number to open the file to.
[^untracked]: Also set git's `status.showUntrackedFiles` to `no`. This prevents every file in `$DOT_HOME` from showing as "untracked" by git.
[^fzf]: requires [FZF](https://github.com/junegunn/fzf)
There are two additional aliases used to (re)set up the bare git setup.
- `.ginit` creates the bare git repository in `$DOT_FILES` directory.
- `.gclone` will clone the repository set in `$DOT_ORIGIN` into the `$DOT_FILES` directory
Both of these aliases also set git's `status.showUntrackedFiles` to `no`. This prevents every file in `$DOT_HOME` from showing as "untracked" by git.
## requirements
@ -76,11 +41,11 @@ The real daily winners for me are the "edit" (`.ge`) and "grep" (`.gg`) aliases.
## installation
1. clone this repository or simply copy the [dotgit.sh](./dotgit.sh)
2. add some configuration sauce to your shell initialization (.i.e. `.zshrc` or `.bashrc`). The `DOT_REPO` and `DOT_HOME` variables **must be set** for the dotgit.sh to load!
1. clone this repository or simply copy the [dotGit.sh](./dotGit.sh)
2. add some config sauce to your shell initialization (.i.e. `.zshrc` or `.bashrc`). The `DOT_FILES` and `DOT_HOME` variables **must be set** for the dotGit.sh to load!
```bash
export DOT_REPO="${HOME}/.dotfiles" # this is where the repo will live
export DOT_HOME="${HOME}" # this is generally the same as `$HOME`
export DOT_FILES="${HOME}/.dotfiles"
export DOT_HOME="${HOME}"
export DOT_ORIGIN="git@github.com:user/your-dotfiles-repo.git" # optional
source <path to dotGit.sh>`
```
@ -91,7 +56,7 @@ The real daily winners for me are the "edit" (`.ge`) and "grep" (`.gg`) aliases.
## initial clone cleanup
Existing configuration files will prevent checking out the files. To list the files causing the checkout to fail, run the following.
Existing config files will prevent checking out the files. To list the files causing the checkout to fail, run the following.
```bash
.g checkout 2>&1|grep -E '^\s'|cut -f2-|xargs -I {} echo "{}"
@ -99,10 +64,6 @@ Existing configuration files will prevent checking out the files. To list the fi
To remove all the conflicting files, simply change the `echo` in the above command to `rm`. **This will delete files, so be sure you want to remove them.** Once the files are removed the checkout will succeed.
## future features
- command line completion
- manage system configuration files
## alternatives

134
dotgit.sh
View file

@ -1,108 +1,48 @@
#!/usr/bin/env bash
[[ ! "$DOT_REPO" ]] && echo "NOT setting dotgit aliases, since DOT_REPO not set." && return
[[ ! "$DOT_HOME" ]] && echo "NOT setting dotgit aliases, since DOT_HOME not set." && return
[[ ! "${DOT_FILES}" ]] && echo "NOT setting dotGit aliases, since DOT_FILES not set." && return
[[ ! "${DOT_HOME}" ]] && echo "NOT setting dotGit aliases, since DOT_HOME not set." && return
[[ -n "$DEBUG" ]] && echo loading dotgit aliases
alias .g='git --git-dir=${DOT_FILES} --work-tree=${DOT_HOME}'
alias .ga='.g add'
alias .gc='.g commit'
alias .gco='.g checkout'
alias .gd='.g diff'
alias .gss='.g status --short'
alias .gp='.g push'
alias .gl='.g pull'
alias .glo='.g log --oneline --decorate'
alias .glg='.g log --stat'
alias .glgp='.g log --stat --patch'
[[ -z "$DOTGIT_MULTI_LIMIT" ]] && DOTGIT_MULTI_LIMIT=2
[[ -z "$DOTGIT_MULTI_ACCEPT" ]] && DOTGIT_MULTI_ACCEPT='{1}'
[[ -z "$DOTGIT_PREVIEW" ]] && DOTGIT_PREVIEW='bat -p --color=always'
# the master alias
alias .git='git --git-dir=${DOT_REPO} --work-tree=${DOT_HOME}'
# the short one
alias .g='.git'
# and all the shortcuts
alias .ga='.git add'
alias .gc='.git commit'
alias .gco='.git checkout'
alias .gd='.git diff'
alias .gss='.git status --short'
alias .glo='.git log --oneline --decorate'
alias .glg='.git log --stat'
alias .glgp='.git log --stat --patch'
alias .gbl='.git blame -w'
alias .gb='.git branch'
alias .gba='.git branch --all'
alias .gbd='.git branch --delete'
alias .gbD='.git branch --delete --force'
alias .gm='.git merge'
alias .gma='.git merge --abort'
alias .gmc='.git merge --continue'
alias .gc!='.git commit --verbose --amend'
alias .gcm='.git commit --message'
alias .gcp='.git cherry-pick'
alias .gcpa='.git cherry-pick --abort'
alias .gcpc='.git cherry-pick --continue'
alias .gclean='.git clean --interactive -d'
alias .ginit='git init --bare "${DOT_REPO}"; .git config --local status.showUntrackedFiles no'
# only set up push and pull if DOT_ORIGIN is set
if [[ -n "$DOT_ORIGIN" ]]; then
alias .gp='.git push'
alias .gl='.git pull'
alias .gclone='git clone --bare "${DOT_ORIGIN}" "${DOT_REPO}"; .git config --local status.showUntrackedFiles no'
else
alias .gp='echo "error: must first configure DOT_ORIGIN"'
alias .gl='echo "error: must first configure DOT_ORIGIN"'
alias .gclone='echo "error: must first configure DOT_ORIGIN"'
fi
# if lazygit or gitui are available, we set up a .lazygit and .gitui
[[ $(command -v lazygit) ]] &&
alias .lazygit='lazygit -g ${DOT_REPO}/ -w ${DOT_HOME}'
[[ $(command -v gitui) ]] &&
alias .gitui='gitui -d ${DOT_REPO}/ -w ${DOT_HOME}'
# if fzf is installed we can have nice things
# https://github.com/junegunn/fzf
read -r -d '' FZF_HEADER<<EOF
[enter] open/edit [ctrl-/] toggle preview [ctrl-w] toggle wrap
EOF
# shellcheck disable=SC2142,SC215
alias .ge='_dotgit_ge(){
cd ${DOT_HOME}
FILE=$( Q="$@"; .g ls-files --full-name |
fzf --preview "bat -n --color=always {}" -q "${Q}")
[[ "$FILE" ]] && $EDITOR "${FILE}"
cd ${OLDPWD}
}; _dotgit_ge'
if [[ $(command -v fzf) ]]; then
fzf_opts=(--multi="$DOTGIT_MULTI_LIMIT" --ansi -0
# shellcheck disable=SC2142
alias .gg='_dotgit_gg(){
cd ${DOT_HOME}
.g grep --full-name --color=always -n "$@" |
fzf -0 --ansi -d ":" --bind "enter:execute($EDITOR +{2} {1})" \
--preview "bat -n -H {2} --color=always {1}" \
--preview-window "right,60%,<60(down,75%),+{2}/2"
--header "$FZF_HEADER"
--bind 'ctrl-z:ignore'
--bind 'ctrl-/:toggle-preview'
--bind 'ctrl-w:toggle-preview-wrap'
)
_dotgit_ge() {
local gitdir
local files
gitdir=$(.git rev-parse --show-toplevel)
files=$(cd "$gitdir" && .git ls-files --full-name |
fzf "${fzf_opts[@]}" \
--preview "$DOTGIT_PREVIEW {1}" \
--bind "enter:accept-non-empty" \
-q "${@:-}" | paste -sd' ')
[[ -n "$files" ]] && sh -c "cd \"$gitdir\" && \"$EDITOR\" $files"
}
alias .ge='_dotgit_ge'
_dotgit_gg() {
local gitdir
local files
gitdir=$(.git rev-parse --show-toplevel)
files=$(cd "$gitdir" && .git grep --full-name --color=always -n "$@" |
fzf "${fzf_opts[@]}" -d ":" \
--preview "$DOTGIT_PREVIEW -H{2} {1}" \
--accept-nth "$DOTGIT_MULTI_ACCEPT" | paste -sd' ')
[[ -n "$files" ]] && sh -c "cd \"$gitdir\" && \"$EDITOR\" $files"
}
alias .gg='_dotgit_gg'
cd ${OLDPWD}
}; _dotgit_gg'
else
# simplified grep but no "interactive file select"
alias .gg='.git grep'
alias .gg='.g grep'
fi
[[ -n "$DEBUG" ]] && echo dotgit aliases loaded
alias .ginit='git init --bare "${DOT_FILES}"; .g config --local status.showUntrackedFiles no'
[[ -n "$DOT_ORIGIN" ]] && alias .gclone='git clone --bare "${DOT_ORIGIN}" "${DOT_FILES}"; .g config --local status.showUntrackedFiles no'
# and to make general aliases available, we source this file again, but set
# the aliases by removing the leading `.` and changing all instances of the
# string 'dotgit' to 'anygit'
# shellcheck source=/dev/null
# the line above makes the source below not complain
[[ "$DOTGIT_ANYGIT" == 'yes' ]] && \
sed '/alias \.g.*DOT_REPO/d; s/\.g/g/g; s/dotgit/anygit/g' < "$0" | source /dev/stdin
# if lazygit or gitui are avaiable, we set up a .lazygit and .gitui
[[ $(command -v lazygit) ]] &&
alias .lazygit='lazygit -g ${DOT_FILES}/.dotfiles/ -w ${DOT_HOME}'
[[ $(command -v gitui) ]] &&
alias .gitui='gitui -d ${DOT_FILES}/.dotfiles/ -w ${DOT_HOME}'