[alias]
    exec = "!exec" ; make aliases usable in aliases
;####################################################
; basic shortcuts
;####################################################

    a = "add"
    b = "branch"
    br = "branch"
    c = "commit"
    cl = "clean"
    co = "checkout"
    cp = "cherry-pick"
    d = "diff"
    f = "fetch"
    l = "log"
    m = "merge"
    p = "pull"
    r = "reset"
    rb = "rebase"
    re = "remote"
    rv = "revert"
    s = "status"
    st = "status"
    sb = "show-branch"
    sub = "submodule"

;####################################################
; typos
;####################################################

    ad = add
    bisec = bisect
    bisetc = bisect
    branhc = branch
    breach = branch
    breanch = branch
    checkotu = checkout
    checkou = checkout
    checout = checkout
    cherrypick = cherry-pick
    cloen = clone
    comit = commit
    comitt = commit
    committ = commit
    dif = diff
    fetc = fetch
    fethc = fetch
    greo = grep
    grp = grep
    grpe = grep
    hceckout = checkout
    mereg = merge
    merg = merge
    puhs = push
    rbanch = branch
    stat = status
    statis = status
    stats = status
    statsu = status
    statsus = status
    statu = status
    statys = status
    stauts = status
    sttus = status
    submodules = submodule
    tags = tag


;####################################################
; config
;####################################################

    aliases = "config --get-regexp '^alias.*'" ; show all aliases
    whoami = "config --local --get-regexp '^user'" ; show local user settings (in current repo)
    user = "config --local --get-regexp '^user'"
    guser = "config --global --get-regexp '^user'" ; show global user settings
    gwhoami = "guser"

;####################################################
; branching
;####################################################

    bra = "branch -a"
    branches = "branch -a"
    bm = "branch --merged" ; branches whose tips are reachable from commit or HEAD
    merged = "bm"
    bnm = "branch --no-merged" ; branches whose tips are NOT reachable from commit or HEAD
    brd = "branch -D" ; force delete unmerged branch
    bv = "branch -v" ; show branch list with those last commits
    bvv = "branch -vv" ; bv + remote branches tracked by them

    cob = "checkout -b" ; create new branch with name given

    ma = "merge --abort" ; abort merging
    mc = "merge --continue" ; continue merging
    mn = "merge --no-commit" ; merge without commit

    current-branch = "branch --show-current"
    default-branch = "config init.defaultBranch" ; get default branch name
    upstream-branch = "!git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD)"

;####################################################
; staging
;####################################################

    aa = "add --all" ; add all unstaged into index

    dc = "diff --cached" ; show diff of staged files
    dw = "diff --word-diff" ; show word diff in unstaged files
    dwc = "diff --word-diff --cached" ; dc + dw

    clf = "clean -df" ; remove new files in current and nested dirs
    clff = "clean -dff" ; remove new files in current and nested dirs + repos
    clx = "clean -dffx" ; remove new + ignored files in current and nested dirs + repos
    cleanout = "!git clean -df && git checkout -- ."

    discard = "checkout --" ; удаляет изменения в файле
    unstage = "reset HEAD" ; staged file => unstaged

;####################################################
; committing
;####################################################

    ca = "commit --all" ; stage all changes and make a commit (interative)
    cm = "commit --message" ; make a commit with message given (non-interactive)
    cam = "commit --all --message" ; ca + cm (non-interactive)
    amendm = "commit --amend --all --message" ; amend + edit commit message (non-interactive)
    amend = "commit --amend --all --no-edit" ; add new changes into last commit (non-interactive)

    cpa = "cherry-pick --abort" ; abort cherry-picking
    cpc = "cherry-pick --continue" ; continue cherry-picking
    cpn = "cherry-pick --no-commit" ; cherry-pick without commit
    cpnx = "cherry-pick --no-commit -x" ; cherry-pick without commit and add commit name to COMMIT_MSG

    rh = "reset --hard" ; откат коммита с удалением всех изменений
    rhh = "reset --hard HEAD" ; откат коммита с удалением всех изменений на последний коммит
    rs = "reset --soft" ; откат коммита с сохранением всех изменений
    rsh = "reset --soft HEAD" ; откат коммита с сохранением всех изменений

    ; make a temporary commit with current worktree state as is
    wip = "!git add . && git commit --message 'WIP' --no-verify"
    wipa = "!git add . && git commit --message 'WIP' --no-verify --amend"

    ; undo last commit preserving all changes
    undo = "reset --soft HEAD~1"
    uncommit = "reset --soft HEAD~1"
    rvn = "revert --no-commit"

;####################################################
; rebasing
;####################################################

    rba = "rebase --abort"
    rbc = "rebase --continue"
    rbi = "rebase --interactive"
    rbs = "rebase --skip"

;####################################################
; manage remotes
;####################################################

    remotes = "remote --verbose" ; show remote repos list
    rev = "remote --verbose"
    rea = "remote add"
    rs = "remote show"
    rso = "remote show origin" ; show state of local branches against origin ones
    rp = "remote prune" ; remove stale local references to remote branches
    rpd = "remote prune --dry-run" ; show stale local references to remote branches
    rpo = "remote prune origin" ; remove stale local references to origin branches
    rpo = "remote prune origin --dry-run" ; show stale local references to origin branches

;####################################################
; garbage
;####################################################

    ; remove unreachable objects
    vacuum="!git reflog expire --expire-unreachable=now --all; git gc --prune=now"

    ; force remove current branch from local (brd) and remote repos
    brod = "!git branch -D "$1"; git push origin :"$1";"

    orphans = "fsck --full"
    repacker = "repack -Adf --depth=300 --window=300 --window-memory=1g"
    pruner = "!git prune --expire=now; git reflog expire --expire-unreachable=now --rewrite --all"
    optimizer = "!git pruner; git repacker; git prune-packed"
    ; trim = "!DEFAULT=$(git default-branch); git branch --merged ${1-$DEFAULT} | grep -v " ${1-$DEFAULT}$" | xargs git branch -d; git remote prune origin;"

;####################################################
; logs
;####################################################

    lo = "log --oneline"
    lgda = "log --graph --decorate --all"
    head = "log -1 HEAD" ; show the last commit in current branch
    heads = "log --graph --decorate --simplify-by-decoration --oneline" ; show last commit of each branch as tree graph
    log-small = "log --graph --decorate --all --pretty=format:'%C(bold red)%h%C(reset) %C(bold blue)%an%C(reset) %C(green)%cr%C(reset) [%aD]%d%n%B'"
    log-my = "!git log --author $(git config user.email)" ; show only my own commits
    ; outbound = "log @{upstream}.."
    inbound = "!git remote update --prune; git log ..@{upstream}"

;####################################################
; updating local repo
;####################################################

    pf = "pull --force"
    pullf = "pull --force"
    pullt = "pull --tags"
    pt = "pull --tags"
    pullft = "pull --force --tags"
    pft = "pull --force --tags"
    prs = "pull --recurse-submodules" ; pull with submodules

    fa = "fetch --all" ; fetch branches from all remotes

;####################################################
; updating remote repo
;####################################################

    pushf = "push --force"
    pusht = "push --tags"
    pushft = "push --tags --force"

    repush = "!git push origin :$1 && git push origin $1'" ; when 'push --force' is prohibited

;####################################################
; statistics
;####################################################

    contributors = "shortlog --summary --numbered --no-merges" ; users participating in development

;####################################################
; complex tasks
;####################################################

    archive = "!f() { top=$(rev-parse --show-toplevel); cd $top; tar cvzf $top.tar.gz $top ; }; f" ; make repo .tar.gz
    gzip = "archive"
    targz = "archive"

    dev = "!git checkout dev && git pull" ; quick switch on 'dev' branch and update it
    develop = "!git checkout develop && git pull" ; quick switch on 'develop' branch and update it
    main = "!git checkout main && git pull" ; quick switch on main branch and update it
    master = "!git checkout master && git pull" ; quick switch on master branch and update it

;####################################################
; other tasks
;####################################################

    tags = "tag -n1 --list" ; shot tag names and commit message
    stashes = "stash list" ; show stashed changes
    init = "init -q" ; blm is racism, 'master' branch must be 'master' branch
    start = "!git init --quiet --initial-branch master; git commit --no-verify --allow-empty --message 'Initial commit'" ; quick start empty repo
    cloner = "clone --recursive" ; clone with submodules
    fuck = "!git checkout $(git config init.defaultBranch); git fetch origin --prune; git reset --hard origin/$(git config init.defaultBranch); git clean -dff"

    ; https://words.filippo.io/git-fixup-amending-an-older-commit/
    cf = "!f() { TARGET=$(git rev-parse \"$1\"); git commit --fixup=$TARGET && GIT_EDITOR=true git rebase --interactive --autosquash $TARGET~; }; f"

    ; dehead = "!BR=$(git branch --show-current); if [ -n "$BR" ]; then echo $BR; else git describe --contains --all HEAD; fi;"
