Boost Your Productivity: Essential Git Aliases to Save 20 Minutes Daily
Tags: automation, webdev, monorepo, opensource
Published: 2023-12-05 15:35:22


(note: surprisingly, this article was not written by Ai)


### Introduction:

  Git aliases are a powerful method of automating tasks - saving you time and making coding more enjoyable.

  This blog post will give you everything you need to know to get started with optimizing your workflow.

  Keep reading to get access to my custom code snippets that are will definitely save you many precious dev minutes and guarantee a job at google (100% guaranteed, no doubt)

### **Setting Up Prerequisites (2 mins)**

  Before diving into the aliases, here are a few prerequisites 


  1. Ensure you have Git Bash installed. for more info see [the official download page](https://git-scm.com/downloads)
  2. Ensure you have the `code` command configured (See below)
  3. (optional) I recommend to set up git bash as default vs code terminal, for more info see [setting up git bash with vs code](https://medium.com/danielpadua/git-bash-with-vscode-593d5998f6be)

### Setting up the `code` command

  The `code` command creates a new file AND opens it in your code editor

  ```bash
  ~/your-project-directory/src> code my-file-name.tsx
  ```
  NOTE: unlike `touch` , when the new file is open in your code editor you must hit `ctrl+s` to ensure is saved.

  The convenience this provides is why it is beloved by many developers and a consistent part of my daily development workflow.

  The code command is required for some of the advanced bash scripts later in this article to work.

  Here is how to set it up:

  1. Inside vs-code, press F1 to open the command pallete
  2. type `shell command` to find `Shell Command: Install 'code' command in PATH command` and hit enter
  3. restart your terminal

  For more info on this, see [this stack overflow post](https://stackoverflow.com/questions/46638944/code-is-not-recognized-as-an-internal-or-external-command)

## **Defining Git Bash Aliases**

### My approach

  These scripts have been written with typescript / python developers in mind.

  My aim is to create scripts that are easy to understand and change by developers most familiar with high-level programming languages.

  While some members of the Bash scripting community may find my snippets somewhat unconventional, I hope that the majority finds my methods to helpful.

### Defining aliases overview:

  - `~/.bashrc` is where you will be placing all of your alias definitions.
  - You can access this using `code ~/.bashrc`  (or the rc alias later on)
  - After making changes, ensure to save `.bashrc` restart your terminal

  A few tips:

  - use `ctrl+'` to open terminal in vs code
  - use `ctrl+shift+5` to add a new terminal
    - eg if you have your development sever running in one terminal, you can still use the second terminal to write commands
  - use `ctrl+d` to close the specific terminal instance that you are focused on
  - use `ctrl+c` to cancel operation
  - can “restart” the terminal by using `ctrl+shift+5` to create a new one and then `ctrl+d` to close the current one

## Basic use cases

  These basic use cases are mostly for convenience and DX

### The alias for aliases!

  ```bash
  # Overview: 
  #   Opens ~/.bashrc in vscode so that you can edit your aliases
  # Usage:
  #   ~/anywhere> rc
  alias rc="code ~/.bashrc"
  ```
### Relative navigation aliases

  ```bash
  # Overview:
  #   Aliases for easily navigating relative to the current directory
  # Usage:
  #   ~/dev/my-app/src/folder/nested-folder> ...
  #   ~/dev/my-app/src> 
  alias .='cd .'            # navigate to current directory
  alias ..='cd ..'          # navigate to parent directory
  alias ...='cd ../../'     # navigate to grandparent directory
  alias ....='cd ../../../' # navigate to great-grandparent directory
  ```

### Package manager

  ```bash
  # Overview: 
  #   Runs pnpm as normal but more concise
  #   Replace with yarn or npm if needed
  # Usage:
  #   ~/dev/my-app> x dev 
  alias x='pnpm "$@"'
  ```
## Advanced custom use cases

  These are custom use cases that save me a lot of time and effort everyday, and I highly recommend trying them out!

### Absolute Navigation (relative to the root of the repo)

  ```bash
  # This a helper function for the git aliases below

  # credit: https://stackoverflow.com/a/38852055
  # Print the name of the git working tree's root directory
  function git_root() {
    local root first_commit
    # git displays its own error if not in a repository
    root=$(git rev-parse --show-toplevel) || return
    if [[ -n $root ]]; then
      echo $root
      return
    elif [[ $(git rev-parse --is-inside-git-dir) = true ]]; then
      # We're inside the .git directory
      # Store the commit id of the first commit to compare later
      # It's possible that $GIT_DIR points somewhere not inside the repo
      first_commit=$(git rev-list --parents HEAD | tail -1) ||
        echo "$0: Can't get initial commit" 2>&1 && false && return
      root=$(git rev-parse --git-dir)/.. &&
        # subshell so we don't change the user's working directory
      ( cd "$root" &&
        if [[ $(git rev-list --parents HEAD | tail -1) = $first_commit ]]; then
          pwd
        else
          echo "$FUNCNAME: git directory is not inside its repository" 2>&1
          false
        fi
      )
    else
      echo "$FUNCNAME: Can't determine repository root" 2>&1
      false
    fi
  }

  # Overview:
  #   Custom implementation of cd command that uses absolute path from git root
  #   Supports custom aliases eg: r a = cd to apps
  #   The alises configured below are specialised for monorepo development with turbo.build 
  #   You can easily tailor these to your needs eg for a non-monorepo setup 
  # Usage examples:
  #   ~/dev/my-app> r a 
  #   => ~/dev/my-app/apps
  #------------------------
  #   ~/dev/my-app> r a/w
  #   => ~/dev/my-app/apps/webapp
  #------------------------
  #   ~/dev/my-app> r a/d
  #   => ~/dev/my-app/apps/docs
  #------------------------
  #   ~/dev/my-app> r p 
  #   => ~/dev/my-app/packages
  #------------------------
  #   ~/dev/my-app> r p/ui
  #   => ~/dev/my-app/packages/ui
  #------------------------
  #   ~/dev/my-app> r t
  #   => ~/dev/my-app/tooling
  function cd_from_git_root() {
    local root
    local input=${1:-}
    local base_key=""
    local subpath=""

    # if no argument provided, set default path
    if [[ -z $input ]]; then
      input="."
    fi

    # Extract base key and subpath
    base_key=${input:0:1}
    subpath=${input:2}

    # Define key => path mappings
    declare -A key_to_base_path
    key_to_base_path[a]="apps"
    key_to_base_path[p]="packages"
    key_to_base_path[t]="tooling"

    # Define specific shortcut => path mappings
    declare -A shortcuts
    shortcuts[a/w]="apps/webapp"
    shortcuts[a/m]="apps/marketing"
    shortcuts[a/d]="apps/docs"

    # Check for specific shortcuts first
    if [[ -n ${shortcuts[$input]} ]]; then
      path="${shortcuts[$input]}"
    elif [[ -n ${key_to_base_path[$base_key]} ]]; then
      path="${key_to_base_path[$base_key]}/$subpath"
    else
      path=$input
    fi

    # Remove leading slash if present
    path=$(echo $path | sed -r "s/^\///")

    root=$(git_root) || return 1  # Get git root using custom git_root function
    root="$root/$path"
    cd "$root" || return 1  # Navigate to the path or return an error
  }

  # add convenient names
  alias cdr='cd_from_git_root'
  alias r='cd_from_git_root'
  ```
### Scaffolding folders

  ```bash
  # Overview:
  #  A custom implementation of the mkdir command that scaffolds a folder and inner files
  #  first argument is the folder name
  #  second argument is a string of options
  #  options:
  #   - s: (Story)  => generate story file (folder_name.story.tsx)
  #   - d: (Docs)   => generate docs file (folder_name.mdx)
  #   - r: (React)  => make all generated files .tsx instead of .ts 
  #   - t: (Test)   => generate test file (folder_name.test.tsx)
  # Usage examples:
  #   ~/dev/my-app> mkdir+ my-component rst
  #   creates:
  #     my-component
  #       - index.ts
  #       - my-component.tsx
  #       - my-component.story.tsx
  #       - my-component.test.tsx
  #------------------------
  #   ~/dev/my-app> mkdir+ my-component s
  #   creates:
  #     my-component
  #       - index.ts
  #       - my-component.tsx
  #       - my-component.story.tsx
  #------------------------
  #   ~/dev/my-app> mkdir+ my-util t
  #   creates:
  #     my-util
  #       - index.ts
  #       - my-util.tsx
  #       - my-util.test.tsx
  #------------------------
  mkdir+() {
      # get values from arguments
      folder_name=$1
      options=$2

      # Default options
      declare -A opt
      opt[test]="false"  # Could set to true if you want to generate test files by default
      opt[story]="false"
      opt[docs]="false"
      opt[react]="false"

      # Update options based on the input string
      if [[ $options == *"s"* ]]; then
          opt[story]="true"
      fi
      if [[ $options == *"d"* ]]; then
          opt[docs]="true"
      fi
      if [[ $options == *"r"* ]]; then
          opt[react]="true"
      fi
      if [[ $options == *"t"* ]]; then
          opt[test]="true"
      fi

      # Set file extension based on React option
      file_extension="ts"
      if [[ ${opt[react]} == "true" ]]; then
          file_extension="tsx"
      fi

      # Create folder and base files
      mkdir "$folder_name" && cd "$folder_name" &&
      touch "index.${file_extension}" &&
      echo "export * from './$folder_name';" >> "index.${file_extension}" &&
      touch "$folder_name.${file_extension}" &&
      code "$folder_name.${file_extension}"

      # Generate test file by default
      touch "$folder_name.test.${file_extension}"

      # Generate story file if 's' is present
      if [[ ${opt[story]} == "true" ]]; then
          touch "$folder_name.story.${file_extension}"
      fi

      # Generate docs file if 'd' is present
      if [[ ${opt[docs]} == "true" ]]; then
          touch "$folder_name.mdx"
      fi

      # navigate back to where the command was run so that the user can create multiple folders
      cd ..
  }
  ```
### Evaluation of git alias vs node.js code gen tools

  Combining this approach of absolute navigation (`r` alias) with the folder scaffolding alias (`mkdir+`) can it super fast to build out a project. This has a significant speed advantage when compared to using node.js codegen tools like plop.js as it only uses bash and therefore can execute the commands without starting up a node.js server.

  Although using plop.js is more well for usecases where you have a predictable boilerplate pattern that you reuse frequently. This is because plop enables you to more easily define the contents of the file by using the handlebars templating langauge. I do not recommend trying to define similar templates using bash.

  I personally use plop for defining UI components as they all share a similar syntax for the stories / testing / definition file.  Let me know if you are interested in accessing my code generation files and I may write another post to share them with you.

### **Conclusion:**

  Incorporating these Git aliases into your daily routine can significantly enhance your productivity. For further resources on coding efficiency, check out my other posts on snippets and monorepo management.

  Thank you for your time and engagement. If you found this post helpful or have your own snippets to share, I’d love to hear from you in the comments.

### About the author:

  Thanks for reading! I’m Dawid, founder of Ream and a software engineer passionate about integrating technology with holistic personal growth. My experience in psychology, computer science, and business has fuelled my drive to create human-centric digital tools. This blog reflects my commitment to practical, efficient solutions in software engineering and beyond. If you found this post helpful or want to connect, feel free to reach out. Let’s continue to learn and grow together in our tech journeys.