Fish & Gits

I’ve been using the Fish shell for a while, and it’s really gotten to the point where I miss it when I can’t use it :)

To share with folks, here are some of my Fish configurations and Git configs that make my life as a Blender developer easier.

This post was made possible by the Blender Development Fund.

Fish Config

Update 2024-04-03: I’ve started to track the pull request related functions my projects.blender.org profile space. Go there to get the latest versions.

These I store in ~/.config/fish/conf.d/aliases.fish:

set BLENDER_BUILD_ROOT  /home/sybren/workspace/blender-git
set FLAMENCO_ROOT /home/sybren/workspace/blender/flamenco-3

function cdf -d "CD to Flamenco directory"
    cd $FLAMENCO_ROOT
end

function cdlibs -d "CD to Blender libs directory"
    cd $BLENDER_BUILD_ROOT/lib
end

function cddeps -d "CD to Blender deps directory"
    cd $BLENDER_BUILD_ROOT/build_deps/deps
end

function cdbuild -d "CD to Blender release build directory"
    cd $BLENDER_BUILD_ROOT/build_linux
end

function cddebug -d "CD to Blender debug build directory"
    cd $BLENDER_BUILD_ROOT/build_debug
end

function cdsrc -d "CD to Blender source directory"
    cd $BLENDER_BUILD_ROOT/blender
end

function cdtracker -d "CD to Blender bug tracker directory"
    cd $BLENDER_BUILD_ROOT/tracker
end

function cddocs -d "CD to Blender developer docs and activate the venv"
    cd $BLENDER_BUILD_ROOT/developer-docs
    . ./.venv/bin/activate.fish
end

function cdmanual -d "CD to Blender manual and activate the venv"
    cd $BLENDER_BUILD_ROOT/manual
    . ./.venv/bin/activate.fish
end

function _makebranch -a BRANCH
    cdsrc; or return 1
    printf "\033[95mChecking out branch \033[96m$BRANCH\033[0m\n"
    git co $BRANCH; or return 2
    printf "\033[95mPulling branch \033[96m$BRANCH\033[0m\n"
    git pull; or return 5
    printf "\033[95mmake update\033[0m\n"
    make update; or return 3
    printf "\033[95mBuilding Blender\033[0m\n"
    bb; or return 4
    printf "\033[95mBuilt $BRANCH\033[0m\n"
end

function mm -d "Make Main, update & build Blender main branch, release mode"
    _makebranch main
end

function mmb -d "Make Main, then run Blender"
    _makebranch main; and blender --open-last $argv
end

function mr -d "Make release branch"
    cdsrc
    set branch (git branch -r --list 'origin/blender-v*-release' | sort -n | tail -n 1 | sed 's+.*origin/++')
    printf "\033[95mSwitching to release branch\033[0m \033[96m$branch\033[0m\n"
    _makebranch $branch
end

function bb -d "Build Blender, release mode"
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_linux/ $argv; or return $status
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_linux/ install
end

function bbb -d "Build Blender and run with last file"
    bb && blender --open-last $argv
end

function bbd -d "Build Blender, debug mode"
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_debug/ $argv; or return $status
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_debug/ install
end

function bbbd -d "Build Blender in Debug mode and run with last file"
    bbd && blenderdebug --open-last $argv
end

function bbt -d "Build Blender, Clang-Tidy mode"
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_tidy/ $argv
end

function bbr -d "Build Blender, release branch"
    nice -n 1 ninja -C $BLENDER_BUILD_ROOT/build_release/ $argv
end

function cdb
    set BLENDVER (blender --version | grep '^Blender' | cut -d' ' -f2 | sed 's/\\([0-9]\\+\\.[0-9]\\+\\).*/\\1/')
    echo "Blender version: $BLENDVER"
    cd ~/.config/blender/$BLENDVER
end

function git_rebase_onto_main
    read -P "Rebase onto main? ENTER for yes, CTRL+C for no."; or begin
        printf "\033[94mNot rebasing, the work is done.\033[0m\n"
        return
    end
    git rebase main; and git submodule foreach git pull --rebase origin main
end

function svnadd -a SUBDIR -d "Add new files and remove deleted files"
  # This is the Fish way of doing `SVN_STATUS=$(<svn status $SUBDIR)`
  begin; set -l IFS; set SVN_STATUS (svn status $SUBDIR); end

  echo "$SVN_STATUS" | grep '^\? ' | sed 's/^.//' | xargs --no-run-if-empty -n 1 svn add
  echo "$SVN_STATUS" | grep '^\! ' | sed 's/^.//' | xargs --no-run-if-empty -n 1 svn rm
end

function pr -d "Pull in a Blender pull request"
    # Set defaults
    set _flag_owner blender
    set _flag_repo blender

    argparse 'o/owner=' 'r/repo=' -- $argv
    or return 48

    # Check for -r owner/repo notation:
    set _flag_combined (echo "$_flag_repo" | string split /)
    set _num_combined (count $_flag_combined)
    if [ $_num_combined -gt 1 ]
        set _flag_owner $_flag_combined[1]
        set _flag_repo $_flag_combined[2]
    end

    set PRNUM $argv[1]

    set JSON "pr-$PRNUM.json"
    set URL "https://projects.blender.org/api/v1/repos/$_flag_owner/$_flag_repo/pulls/$PRNUM"
    if ! curl --fail --no-progress-meter -o$JSON $URL
        printf "\033[91mError fetching $URL\033[0m\n"
        return 49
    end

    # Sanity check we can read the result
    if ! jq <$JSON >/dev/null
        printf "\033[91mCannot parse JSON at $JSON\033[0m\n" >&2
        return 50
    end

    set PR_STATUS (jq -r .state <$JSON)
    if [ (jq -r .merged <$JSON) = "true" ]
        printf "\033[92mPR is already merged, check $URL\033[0m\n"
        echo "Merged at:" (jq -r .merged_at <$JSON)
        echo "Merged by:" (jq -r .merged_by.full_name <$JSON)
        return 51
    end
    if [ (jq -r .state <$JSON) = "closed" ]
        printf "\033[91mPR is closed, check $URL\033[0m\n"
        return 50
    end

    set PR_NUM (jq -r .number <$JSON)
    set PR_TITLE (jq -r .title <$JSON)
    printf "\033[95mPulling #$PR_NUM: $PR_TITLE\033[0m\n"

    set PR_REPO (jq -r .head.repo.full_name <$JSON)   # "ChrisLend/blender"
    set PR_AUTHOR (jq -r .head.repo.owner.username <$JSON)   # "ChrisLend"
    set PR_BRANCH (jq -r .head.ref <$JSON) # "vertical_scrolling_offscreen"
    set PR_BASE_BRANCH (jq -r .base.ref <$JSON) # "main" or "blender-v3.5-release"
    set LOCAL_BRANCH "PR/$PRNUM/$PR_AUTHOR-$PR_BRANCH"

    printf "\033[90mIncoming branch: $PR_REPO\033[0m\n"
    printf "\033[90mBase  branch   : $PR_BASE_BRANCH\033[0m\n"
    printf "\033[90mLocal branch   : $LOCAL_BRANCH\033[0m\n"

    rm -f $JSON

    set CURBRANCH (git branch --show-current 2>/dev/null)
    if test "$CURBRANCH" != "$PR_BASE_BRANCH";
        git checkout $PR_BASE_BRANCH
    end
    if git branch | grep -q $LOCAL_BRANCH;
        printf "\033[95mBranch $LOCAL_BRANCH exists, going to refresh it\033[0m\n"
        git branch -D $LOCAL_BRANCH
    else
        printf "\033[96mBranch $LOCAL_BRANCH does not exist\033[0m\n"
    end

    git checkout -b $LOCAL_BRANCH $PR_BASE_BRANCH; or return 47
    git pull --no-rebase --ff --no-edit --commit https://projects.blender.org/$PR_REPO $PR_BRANCH; or return 48

    printf "\033[95mBranch $LOCAL_BRANCH is ready for use\033[0m\n"
    printf "\033[94mPulled #$PR_NUM: $PR_TITLE\033[0m\n"
end

function prprune -d "Delete all PR/* branches"
    set BRANCHES (string trim (git branch | grep '^  PR/'))
    if test -z "$BRANCHES";
        echo "No PR branches to prune"
        return 0
    end
    git branch -D $BRANCHES
end

function ffmp4 -a FNAME -d "Use FFmpeg to convert MKV to MP4"
    set OUTNAME (string replace -i .mkv .mp4 "$FNAME")
    if test "$FNAME" = "$OUTNAME";
        set OUTNAME (string replace -i -- .mov .mp4 "$FNAME")
    end
    if test "$FNAME" = "$OUTNAME";
        set OUTNAME (string replace -i -- .webm .mp4 "$FNAME")
    end
    if test "$FNAME" = "$OUTNAME";
        set OUTNAME (string replace -i -- .mp4 -recoded.mp4 "$FNAME")
    end
    if test "$FNAME" = "$OUTNAME";
        echo "Input must end in .mkv, .mp4, .webm, or .mov"
        return 1
    end

    ffmpeg -i "$FNAME" -c:v h264 -crf 23 -c:a aac -b:a 192k "$OUTNAME"
    or return $status

    dolphin --select "$OUTNAME" & disown
end

alias l='ls -F --color=auto'
alias ll='l -lh'
alias df='df -h'
alias du='du -h'
alias grep='grep --color'
alias qtc='qtcreator -client'
alias sqlite='sqlite3'
alias docker-logfile='docker inspect --format="{{.LogPath}}"'
alias json_pp="python3 -c 'import json, sys; print(json.dumps(json.load(sys.stdin), sort_keys=True, indent=4))'"
alias trimlong="sed 's/\(.\{120\}\).*/\1…/'"
alias ffprobe-json="ffprobe -v error -hide_banner -print_format json -show_streams -show_format"
alias dot2png="dot -Tpng -O"
alias abccat="abcls -a -m -l -r -t"
alias cdp="cd (pwd -P)"
alias bcode="code $BLENDER_BUILD_ROOT/blender.code-workspace"
alias dcode="cddocs; code ."
alias wg='wget --content-disposition'

alias rbi="git rebase --interactive"
alias rbc="git rebase --continue"
alias rba="git rebase --abort"
alias gg="git gui"
alias gga="git gui citool --amend"

Git Config

My Git configuration (~/.gitconfig) also has some nice aliases & other options:

[color]
    ui = auto
[pull]
    rebase = true
[push]
    default = simple
[alias]
    co = "checkout"
    cp = "cherry-pick"
    ff = "merge --ff-only"
    mt = "mergetool"
    up = "checkout @~1"
    st = "status --ignore-submodules=none"
    car = "commit --amend --reset-author"
    rbi = "rebase -i"
    rbc = "rebase --continue"
    rba = "rebase --abort"
    tpush = "!git push && git push --tags"
    out = "log @{u}.. --pretty=oneline"
    head = "show HEAD"
    unstash = "stash pop"
    authors = "!f() { git log --since 'now - 1 year' \"$@\" | grep ^Author | sed 's/Author: //' | sed 's/<.*>//' | sort -f | uniq -ci | sort -nr | nl -s '' | sort -nr; } ; f"
    glog = "log --all --graph --abbrev-commit --decorate --date=short --format=format:'%C(bold blue)%h%C(reset) %C(green)(%ad)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(dim magenta)%d%C(reset)'"
    onelog = "log --abbrev-commit --decorate --date=short --format=format:'%C(bold blue)%h%C(reset) %C(green)(%ad)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(dim magenta)%d%C(reset)'"
    ver = "log --oneline -n 1 --no-abbrev"
[diff]
    tool = kdiff3
    guitool = kdiff3
[merge]
    tool = kdiff3
    guitool = kdiff3
  	renamelimit = 4096
[core]
    excludesfile = /home/sybren/.configfiles/gitignore_global
[gui]
    gcwarning = false
    encoding = utf-8
[rerere]
  	enabled = true
[gc]
  	rerereUnresolved = 365
  	rerereResolved = 365
dr. Sybren A. Stüvel
dr. Sybren A. Stüvel
Open Source software developer, photographer, drummer, and electronics tinkerer

Related