Compare commits
2 commits
918bf6cc49
...
d7cc406677
| Author | SHA1 | Date | |
|---|---|---|---|
| d7cc406677 | |||
| 2300bd4549 |
2 changed files with 87 additions and 31 deletions
66
README.md
66
README.md
|
|
@ -8,6 +8,28 @@ dotGit has modest aims:
|
||||||
- 🚀 reduce friction and make configuration changes quick and convenient
|
- 🚀 reduce friction and make configuration changes quick and convenient
|
||||||
|
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. in your .zshrc or .bashrc:
|
||||||
|
export DOT_REPO="${HOME}/.dotfiles"
|
||||||
|
export DOT_HOME="${HOME}"
|
||||||
|
export DOT_ORIGIN="git@github.com:user/dotfiles.git" # optional
|
||||||
|
source /path/to/dotgit.sh
|
||||||
|
|
||||||
|
# 2. initialize a new repo, or clone an existing one
|
||||||
|
.ginit # new repo
|
||||||
|
.gclone # clone from DOT_ORIGIN
|
||||||
|
|
||||||
|
# 3. daily use
|
||||||
|
.ge zshrc # fuzzy-find and edit files matching "zshrc"
|
||||||
|
.gg PATH # grep across dotfiles, jump to result
|
||||||
|
.gss # status
|
||||||
|
.ga .zshrc # stage a file
|
||||||
|
.gc -m 'msg' # commit
|
||||||
|
.gp # push
|
||||||
|
```
|
||||||
|
|
||||||
## usage
|
## usage
|
||||||
|
|
||||||
Most of dotGit is just some aliases that point to the `--git-dir` and `--work-tree`.
|
Most of dotGit is just some aliases that point to the `--git-dir` and `--work-tree`.
|
||||||
|
|
@ -20,8 +42,8 @@ The real daily winners for me are the "edit" (`.ge`) and "grep" (`.gg`) aliases.
|
||||||
2. make some changes. Try:
|
2. make some changes. Try:
|
||||||
- `.ge zshrc` - presents all files with `zshrc` in the name
|
- `.ge zshrc` - presents all files with `zshrc` in the name
|
||||||
- `.gg PATH` - runs `git grep` across your dotfiles and presents the results
|
- `.gg PATH` - runs `git grep` across your dotfiles and presents the results
|
||||||
4. `.gc -m 'commit comment' .zshrc` - will commit the changes
|
3. `.gc -m 'commit comment' .zshrc` - will commit the changes
|
||||||
5. `.gp` - pushes the changes to the origin
|
4. `.gp` - pushes the changes to the origin
|
||||||
|
|
||||||
### a list of all aliases defined
|
### a list of all aliases defined
|
||||||
|
|
||||||
|
|
@ -34,8 +56,9 @@ The real daily winners for me are the "edit" (`.ge`) and "grep" (`.gg`) aliases.
|
||||||
| .gc | `.git commit` | |
|
| .gc | `.git commit` | |
|
||||||
| .gco | `.git checkout` | |
|
| .gco | `.git checkout` | |
|
||||||
| .gd | `.git diff` | |
|
| .gd | `.git diff` | |
|
||||||
|
| .gds | `.git diff --stat` | |
|
||||||
| .ge | calls the `_dotgit_ge` helper function | the dotGit edit feature [^fzf] |
|
| .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] |
|
| .gg | calls the `_dotgit_gg` helper function (falls back to `.git grep` without fzf) | grep your dotfiles and open at the matched line [^line] |
|
||||||
| .gss | `.git status --short` | |
|
| .gss | `.git status --short` | |
|
||||||
| .glo | `.git log --oneline --decorate` | |
|
| .glo | `.git log --oneline --decorate` | |
|
||||||
| .glg | `.git log --stat` | |
|
| .glg | `.git log --stat` | |
|
||||||
|
|
@ -48,20 +71,20 @@ The real daily winners for me are the "edit" (`.ge`) and "grep" (`.gg`) aliases.
|
||||||
| .gm | `.git merge` | |
|
| .gm | `.git merge` | |
|
||||||
| .gma | `.git merge --abort` | |
|
| .gma | `.git merge --abort` | |
|
||||||
| .gmc | `.git merge --continue` | |
|
| .gmc | `.git merge --continue` | |
|
||||||
| .gc! | `.git commit --verbose --amend` |
|
| .gc! | `.git commit --verbose --amend` | |
|
||||||
| .gcm | `.git commit --message` | |
|
| .gcm | `.git commit --message` | |
|
||||||
| .gcp | `.git cherry-pick` | |
|
| .gcp | `.git cherry-pick` | |
|
||||||
| .gcpa | `.git cherry-pick --abort` | |
|
| .gcpa | `.git cherry-pick --abort` | |
|
||||||
| .gcpc | `.git cherry-pick --continue` | |
|
| .gcpc | `.git cherry-pick --continue` | |
|
||||||
| .gclean | `.git clean --interactive -d` | |
|
| .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 |
|
| .gp | `.git push` | requires `DOT_ORIGIN` be set |
|
||||||
| .gl | `.git pull` | 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 |
|
| .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 |
|
| .gitui | `gitui -d ${DOT_REPO}/ -w ${DOT_HOME}` | requires gitui to be installed |
|
||||||
|
| .gclone | `git clone --bare "${DOT_ORIGIN}" "${DOT_REPO}"; .git config --local status.showUntrackedFiles no` | [^untracked] |
|
||||||
|
| .ginit | `git init --bare "${DOT_REPO}"; .git config --local status.showUntrackedFiles no` | |
|
||||||
|
|
||||||
[^line]: This works with vi, emacs, nano, micro, and any editor that accepts the line number to open the file to.
|
[^line]: Opens the editor with `+line file` arguments. Works with vi, emacs, nano, micro, and any editor that accepts a line number via `+N`.
|
||||||
[^untracked]: Also set git's `status.showUntrackedFiles` to `no`. This prevents every file in `$DOT_HOME` from showing as "untracked" by git.
|
[^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)
|
[^fzf]: requires [FZF](https://github.com/junegunn/fzf)
|
||||||
|
|
||||||
|
|
@ -69,7 +92,7 @@ The real daily winners for me are the "edit" (`.ge`) and "grep" (`.gg`) aliases.
|
||||||
|
|
||||||
- `EDITOR` set to your liking
|
- `EDITOR` set to your liking
|
||||||
- [git](https://git-scm.com/)
|
- [git](https://git-scm.com/)
|
||||||
- [bat](https://github.com/sharkdp/bat)
|
- [bat](https://github.com/sharkdp/bat) (optional, default preview command)
|
||||||
- [fzf](https://github.com/junegunn/fzf) (optional)
|
- [fzf](https://github.com/junegunn/fzf) (optional)
|
||||||
- [lazygit](https://github.com/jesseduffield/lazygit) (optional)
|
- [lazygit](https://github.com/jesseduffield/lazygit) (optional)
|
||||||
- [gitui](https://github.com/extrawurst/gitui) (optional)
|
- [gitui](https://github.com/extrawurst/gitui) (optional)
|
||||||
|
|
@ -82,12 +105,31 @@ The real daily winners for me are the "edit" (`.ge`) and "grep" (`.gg`) aliases.
|
||||||
export DOT_REPO="${HOME}/.dotfiles" # this is where the repo will live
|
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_HOME="${HOME}" # this is generally the same as `$HOME`
|
||||||
export DOT_ORIGIN="git@github.com:user/your-dotfiles-repo.git" # optional
|
export DOT_ORIGIN="git@github.com:user/your-dotfiles-repo.git" # optional
|
||||||
source <path to dotGit.sh>`
|
source <path to dotGit.sh>
|
||||||
```
|
```
|
||||||
3. restart your shell or `source ~/.zshrc` or `source ~/.bashrc`
|
3. restart your shell or `source ~/.zshrc` or `source ~/.bashrc`
|
||||||
4. run `.ginit` or `.gclone` (see the *initial clone setup* below, if cloning)
|
4. run `.ginit` to start a new repo, or `.gclone` to clone an existing one
|
||||||
5. `.gc <branch>` to checkout the config files
|
- if cloning: `.gco <branch>` to checkout your config files (see *initial clone cleanup* below if files conflict)
|
||||||
|
- if initializing: start tracking files with `.ga`
|
||||||
|
|
||||||
|
## configuration
|
||||||
|
|
||||||
|
`DOT_REPO` and `DOT_HOME` must be set before sourcing `dotgit.sh`. All other variables are optional.
|
||||||
|
|
||||||
|
| variable | default | description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `DOT_REPO` | *(required)* | path to the bare git repository |
|
||||||
|
| `DOT_HOME` | *(required)* | work tree root, usually `$HOME` |
|
||||||
|
| `DOT_ORIGIN` | *(unset)* | remote URL; enables `.gp`, `.gl`, and `.gclone` |
|
||||||
|
| `DOTGIT_PREVIEW` | `bat -p --color=always` | fzf preview command |
|
||||||
|
| `DOTGIT_MULTI_LIMIT` | `5` | max files selectable at once in `.ge` and `.gg` |
|
||||||
|
| `DOTGIT_OPEN_FMT` | `split` | how `.gg` passes file+line to the editor; `split` uses `+line file` (works with most editors); set to `+e {file}\|{line}` for vim/nvim multi-file line jumping |
|
||||||
|
| `DOTGIT_ANYGIT` | *(unset)* | set to `yes` to also load unprefixed `g*` aliases for any git repo |
|
||||||
|
| `DEBUG` | *(unset)* | set to any value to print load/unload messages |
|
||||||
|
|
||||||
|
### ANYGIT
|
||||||
|
|
||||||
|
Setting `DOTGIT_ANYGIT=yes` causes dotGit to source a transformed copy of itself that registers a parallel set of aliases without the leading `.` — so `.ga` becomes `ga`, `.gc` becomes `gc`, etc. These work against whichever git repo your shell is currently in, like ordinary git aliases.
|
||||||
|
|
||||||
## initial clone cleanup
|
## initial clone cleanup
|
||||||
|
|
||||||
|
|
|
||||||
52
dotgit.sh
52
dotgit.sh
|
|
@ -5,9 +5,9 @@
|
||||||
|
|
||||||
[[ -n "$DEBUG" ]] && echo loading dotgit aliases
|
[[ -n "$DEBUG" ]] && echo loading dotgit aliases
|
||||||
|
|
||||||
[[ -z "$DOTGIT_MULTI_LIMIT" ]] && DOTGIT_MULTI_LIMIT=2
|
[[ -z "$DOTGIT_MULTI_LIMIT" ]] && DOTGIT_MULTI_LIMIT=5
|
||||||
[[ -z "$DOTGIT_MULTI_ACCEPT" ]] && DOTGIT_MULTI_ACCEPT='{1}'
|
|
||||||
[[ -z "$DOTGIT_PREVIEW" ]] && DOTGIT_PREVIEW='bat -p --color=always'
|
[[ -z "$DOTGIT_PREVIEW" ]] && DOTGIT_PREVIEW='bat -p --color=always'
|
||||||
|
[[ -z "$DOTGIT_OPEN_FMT" ]] && DOTGIT_OPEN_FMT='split' # or e.g. '+e {file}|{line}' for nvim
|
||||||
|
|
||||||
# the master alias
|
# the master alias
|
||||||
alias .git='git --git-dir=${DOT_REPO} --work-tree=${DOT_HOME}'
|
alias .git='git --git-dir=${DOT_REPO} --work-tree=${DOT_HOME}'
|
||||||
|
|
@ -19,6 +19,7 @@ alias .ga='.git add'
|
||||||
alias .gc='.git commit'
|
alias .gc='.git commit'
|
||||||
alias .gco='.git checkout'
|
alias .gco='.git checkout'
|
||||||
alias .gd='.git diff'
|
alias .gd='.git diff'
|
||||||
|
alias .gds='.git diff --stat'
|
||||||
alias .gss='.git status --short'
|
alias .gss='.git status --short'
|
||||||
alias .glo='.git log --oneline --decorate'
|
alias .glo='.git log --oneline --decorate'
|
||||||
alias .glg='.git log --stat'
|
alias .glg='.git log --stat'
|
||||||
|
|
@ -56,12 +57,11 @@ fi
|
||||||
|
|
||||||
# if fzf is installed we can have nice things
|
# if fzf is installed we can have nice things
|
||||||
# https://github.com/junegunn/fzf
|
# https://github.com/junegunn/fzf
|
||||||
read -r -d '' FZF_HEADER<<EOF
|
if [[ $(command -v fzf) ]]; then
|
||||||
|
read -r -d '' FZF_HEADER<<EOF
|
||||||
[enter] open/edit [ctrl-/] toggle preview [ctrl-w] toggle wrap
|
[enter] open/edit [ctrl-/] toggle preview [ctrl-w] toggle wrap
|
||||||
EOF
|
EOF
|
||||||
|
fzf_opts=(--multi="$DOTGIT_MULTI_LIMIT" --ansi -0
|
||||||
if [[ $(command -v fzf) ]]; then
|
|
||||||
fzf_opts=(--multi="$DOTGIT_MULTI_LIMIT" --ansi -0
|
|
||||||
--preview-window "right,60%,<60(down,75%),+{2}/2"
|
--preview-window "right,60%,<60(down,75%),+{2}/2"
|
||||||
--header "$FZF_HEADER"
|
--header "$FZF_HEADER"
|
||||||
--bind 'ctrl-z:ignore'
|
--bind 'ctrl-z:ignore'
|
||||||
|
|
@ -69,27 +69,41 @@ if [[ $(command -v fzf) ]]; then
|
||||||
--bind 'ctrl-w:toggle-preview-wrap'
|
--bind 'ctrl-w:toggle-preview-wrap'
|
||||||
)
|
)
|
||||||
_dotgit_ge() {
|
_dotgit_ge() {
|
||||||
local gitdir
|
local gitdir result
|
||||||
local files
|
local -a files
|
||||||
gitdir=$(.git rev-parse --show-toplevel)
|
gitdir=$(.git rev-parse --show-toplevel)
|
||||||
files=$(cd "$gitdir" && .git ls-files --full-name |
|
result=$(cd "$gitdir" && .git ls-files --full-name |
|
||||||
fzf "${fzf_opts[@]}" \
|
fzf "${fzf_opts[@]}" \
|
||||||
--preview "$DOTGIT_PREVIEW {1}" \
|
--preview "$DOTGIT_PREVIEW {1}" \
|
||||||
--bind "enter:accept-non-empty" \
|
--bind "enter:accept-non-empty" \
|
||||||
-q "${@:-}" | paste -sd' ')
|
-q "${@:-}")
|
||||||
[[ -n "$files" ]] && sh -c "cd \"$gitdir\" && \"$EDITOR\" $files"
|
[[ -z "$result" ]] && return
|
||||||
|
while IFS= read -r line; do files+=("$line"); done <<< "$result"
|
||||||
|
(cd "$gitdir" && "$EDITOR" "${files[@]}")
|
||||||
}
|
}
|
||||||
alias .ge='_dotgit_ge'
|
alias .ge='_dotgit_ge'
|
||||||
|
|
||||||
_dotgit_gg() {
|
_dotgit_gg() {
|
||||||
local gitdir
|
local gitdir result clean fname lnum
|
||||||
local files
|
local -a editor_args
|
||||||
gitdir=$(.git rev-parse --show-toplevel)
|
gitdir=$(.git rev-parse --show-toplevel)
|
||||||
files=$(cd "$gitdir" && .git grep --full-name --color=always -n "$@" |
|
result=$(cd "$gitdir" && .git grep --full-name --color=always -n "$@" |
|
||||||
fzf "${fzf_opts[@]}" -d ":" \
|
fzf "${fzf_opts[@]}" -d ":" \
|
||||||
--preview "$DOTGIT_PREVIEW -H{2} {1}" \
|
--preview "$DOTGIT_PREVIEW -H{2} {1}")
|
||||||
--accept-nth "$DOTGIT_MULTI_ACCEPT" | paste -sd' ')
|
[[ -z "$result" ]] && return
|
||||||
[[ -n "$files" ]] && sh -c "cd \"$gitdir\" && \"$EDITOR\" $files"
|
while IFS= read -r line; do
|
||||||
|
clean=$(printf '%s' "$line" | sed 's/\x1b\[[0-9;]*[A-Za-z]//g')
|
||||||
|
[[ -z "$clean" ]] && continue
|
||||||
|
fname="${clean%%:*}"
|
||||||
|
lnum="${clean#*:}"; lnum="${lnum%%:*}"
|
||||||
|
if [[ "$DOTGIT_OPEN_FMT" == 'split' ]]; then
|
||||||
|
editor_args+=("+$lnum" "$fname")
|
||||||
|
else
|
||||||
|
local arg="${DOTGIT_OPEN_FMT//\{file\}/$fname}"
|
||||||
|
editor_args+=("${arg//\{line\}/$lnum}")
|
||||||
|
fi
|
||||||
|
done <<< "$result"
|
||||||
|
[[ ${#editor_args[@]} -gt 0 ]] && (cd "$gitdir" && "$EDITOR" "${editor_args[@]}")
|
||||||
}
|
}
|
||||||
alias .gg='_dotgit_gg'
|
alias .gg='_dotgit_gg'
|
||||||
else
|
else
|
||||||
|
|
@ -105,4 +119,4 @@ fi
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
# the line above makes the source below not complain
|
# the line above makes the source below not complain
|
||||||
[[ "$DOTGIT_ANYGIT" == 'yes' ]] && \
|
[[ "$DOTGIT_ANYGIT" == 'yes' ]] && \
|
||||||
sed '/alias \.g.*DOT_REPO/d; s/\.g/g/g; s/dotgit/anygit/g' < "$0" | source /dev/stdin
|
sed '/alias \.g.*DOT_REPO/d; s/\.g/g/g; s/dotgit/anygit/g' < "${BASH_SOURCE[0]:-$0}" | source /dev/stdin
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue