Repository: VirtusLab/git-machete
Pull request #668 (2022-09-29 15:30:04)

Release 3.12.1


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 106f239..375bb71 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -23,37 +23,17 @@ jobs:
           command: |
             sudo apt-get update
 
-            # For ensure-completion-scripts-correct.sh
+            # For enforce-completion-scripts-correct.sh
             sudo apt-get install zsh fish
 
-            # For ensure-shell-scripts-pass-shellcheck.sh
+            # For enforce-shell-scripts-pass-shellcheck.sh
             sudo apt-get install shellcheck
 
-            # For ensure-links-correct.sh
+            # For enforce-links-correct.sh
             npm install --global remark-cli remark-lint-no-dead-urls remark-validate-links
       - run:
           name: Perform general checks
-          # language=sh
-          command: |
-            # We don't want `less` to open for `git grep` results.
-            export GIT_PAGER=cat
-
-            PATH=$(pwd)/ci/checks:$PATH
-            set -x
-            enforce-correct-shebangs.sh
-            enforce-indent-two-spaces-outside-python.sh
-            enforce-issue-number-for-todos.sh
-            ensure-completion-scripts-correct.sh
-            ensure-links-correct.sh
-            ensure-release-notes-up-to-date.sh
-            ensure-shell-scripts-pass-shellcheck.sh
-            ensure-version-bumped.sh
-            prohibit-deploy-step-in-circleci.sh
-            prohibit-double-backticks-in-py.sh
-            prohibit-single-backtick-in-rst.sh
-            prohibit-strings-split-without-delimiter.sh
-            prohibit-tab-character.sh
-            prohibit-trailing-whitespace.sh
+          command: ci/checks/run-all-checks.sh
 
   # Earliest versions of python/git supported by git-machete
   "python 3_6 git 1_8_10":
@@ -105,13 +85,13 @@ jobs:
       - codecov/upload:
           file: coverage.xml
 
-  "sphinx docs and python 3_10 git 2_33_1":
+  "docs and python 3_10 git 2_33_1":
     executor: ubuntu_executor
     steps:
       - checkout
       - run:
           name: Run tests against Python 3.10 and git 2.33.1 (with building docs)
-          command: PYTHON_VERSION=3.10 GIT_VERSION=2.33.1 BUILD_DOCS=true  bash ci/tox/ci-run.sh
+          command: PYTHON_VERSION=3.10 GIT_VERSION=2.33.1 BUILD_SPHINX_DOCS=true CHECK_PY_DOCS_UP_TO_DATE=true bash ci/tox/ci-run.sh
       - store_test_results:
           path: test-results/
       - store_artifacts:
@@ -128,11 +108,6 @@ jobs:
           # Side effects: does an actual release, but to the test PyPI
           command: bash ci/pypi/ci-deploy.sh --dry-run
 
-      - run:
-          name: '[Dry run] Update Homebrew tap with local installation test'
-          # Prerequisites: artifacts must be released to test PyPI first
-          command: bash ci/homebrew-tap/ci-deploy.sh --dry-run
-
       - run:
           name: '[Dry run] Publish image to Docker Hub'
           command: bash ci/docker/ci-deploy.sh --dry-run
@@ -167,11 +142,6 @@ jobs:
           name: 'Deploy to PyPI'
           command: bash ci/pypi/ci-deploy.sh
 
-      - run:
-          name: 'Update Homebrew tap'
-          # Prerequisites: artifacts must be released to PyPI first
-          command: bash ci/homebrew-tap/ci-deploy.sh
-
       - run:
           name: 'Publish image to Docker Hub'
           command: bash ci/docker/ci-deploy.sh
@@ -211,7 +181,7 @@ mandatory_jobs: &mandatory_jobs
   - python 3_7 git 2_7_6
   - pep8 and python 3_8 git 2_25_0
   - coverage and python 3_9 git 2_30_1
-  - sphinx docs and python 3_10 git 2_33_1
+  - docs and python 3_10 git 2_33_1
 
 workflows:
   version: 2
@@ -222,7 +192,7 @@ workflows:
       - python 3_7 git 2_7_6
       - pep8 and python 3_8 git 2_25_0
       - coverage and python 3_9 git 2_30_1
-      - sphinx docs and python 3_10 git 2_33_1
+      - docs and python 3_10 git 2_33_1
       - dry run deploy:
           filters:
             branches:
diff --git a/.dockerignore b/.dockerignore
index 06f2ba2..3eea7d5 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -7,6 +7,5 @@
 !requirements.txt
 !setup.py
 
-git_machete/tests/
 **/*.pyc
 **/__pycache__/
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b7df6ae..fd19a0c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,11 +4,12 @@
 
 Make sure the following bundled plugins are enabled:
 * Docker
+* Git
 * Markdown
 * Ini
 * IntelliLang (for language injections, e.g. Markdown/shell scripts in YAML)
 * ReStructuredText
-* Shell script
+* Shell Script (also: agree to enable Shellcheck when asked)
 * YAML
 
 Optionally, you can also install the following non-bundled plugins from Marketplace:
@@ -18,6 +19,17 @@ Optionally, you can also install the following non-bundled plugins from Marketpl
 * [Requirements](https://plugins.jetbrains.com/plugin/10837-requirements/)
 
 
+## Git setup
+
+From the main project folder, run the following commands:
+
+```shell
+ln -s ../../hook_samples/machete-status-branch .git/hooks/machete-status-branch
+ln -s ../../hook_samples/post-commit .git/hooks/post-commit
+ln -s ../../ci/checks/run-all-checks.sh .git/hooks/pre-commit
+```
+
+
 ## Run tests locally
 
 To develop that project and run tests locally, it is needed to have Python installed with `tox`.
@@ -27,16 +39,14 @@ Use `.tox/venv/bin/python` as a reference `python` interpreter in your IDE.
 
 To run tests, execute `tox`.
 
-It's also possible to execute tests graphically in pycharm (right-clicking on the test file
+It's also possible to execute tests graphically in PyCharm (right-clicking on the test file
 or clicking the green triangle on the left of the test case name), which can be very useful when debugging a single test case.
-To do so, make sure that following libraries are installed (preferably via pip):
-* pytest
-* pytest-mock
-* pytest-xdist
+To do so, make sure that the libraries from [requirements.testenv.txt](requirements.testenv.txt) are installed in the current venv.
+
 
 ## Generate sandbox repositories
 
-Run `docs/setup-sandbox` script to set up a test repo under `~/machete-sandbox` with a remote in `~/machete-sandbox-remote`.
+Run [`graphics/setup-sandbox`](graphics/setup-sandbox) script to set up a test repo under `~/machete-sandbox` with a remote in `~/machete-sandbox-remote`.
 
 
 ## Command properties/classification
@@ -75,7 +85,7 @@ This tool is [semantically versioned](https://semver.org) with respect to all of
 * output format of plumbing commands (see above for the list)
 * accepted environment variables
 
-Output format of any non-plumbing command can change in non-backward-compatible manner even between patch-level updates.
+Output format of any [non-plumbing command](#command-propertiesclassification) can change in a non-backward-compatible manner even between patch-level updates.
 
 
 ## CI Docker setup reference
@@ -84,32 +94,38 @@ Output format of any non-plumbing command can change in non-backward-compatible
 * [Nifty Docker tricks for your CI (vol. 2)](https://medium.com/virtuslab/nifty-docker-tricks-for-your-ci-vol-2-c5191a67f1a4)
 
 
-## FAQ's about Pull Requests
-**What is the proper base for pull request?**
+## FAQ about Pull Requests
+
+#### What is the proper base for pull request?
 
-Please set the base of pull request to `develop` branch. Current branch protection rules on GitHub only allow to merge `develop` or `hotfix` branches into `master`.
+Please set the base of pull request to `develop` branch.
+Current branch protection rules on GitHub only allow to merge `develop` or `hotfix/*` branches into `master`.
 
-**Who closes GitHub comments? Author of changes, reviewer or initiator of the conversation?**
+#### Who closes GitHub comments? Author of changes, reviewer or initiator of the conversation?
 
 It makes sense to close comment:
 
-1) If the comment was trivial and was addressed as suggested by the reviewer, then it is enough for the PR author to simply `Resolve` the thread and that's it
-2) If the comment was not trivial and/or for some reason the PR author believes that the comment should not be addressed as suggested by the reviewer, then it is best to leave the thread open after replying; then the reviewer can press `Resolve` once they have decided that the matter is cleared.
+1) If the comment was trivial and was addressed as suggested by the reviewer,
+   then it is enough for the PR author to simply `Resolve` the thread and that's it.
+2) If the comment was not trivial and/or for some reason the PR author believes that the comment should not be addressed as suggested by the reviewer,
+   then it is best to leave the thread open after replying; then the reviewer can press `Resolve` once they have decided that the matter is cleared.
 
-**Do you make squash before develop?**
+#### Do you make squash before develop?
 
 Any technique is okay as long as there are [NO unnecessary merge commits](https://slides.com/plipski/git-machete#/8).
-`Squash and merge` from GitHub is okay, fast-forward made from console or via `git machete advance` & `git push` is ok too.
+`Squash and merge` from GitHub is okay, fast-forward made from console or via `git machete advance` is okay too.
 
-**Is there any commit message convention?**
+#### Is there any commit message convention?
 
-Nothing special, as long as they look neat in the sense that they are written in imperative form and describe what actually happened on a given commit.
+Nothing special, as long as they look neat in the sense that they are written in the [imperative form](https://cbea.ms/git-commit/#imperative)
+and describe what actually happened on a given commit.
 
-**How do you know that the comment has been approved?**
+#### How do you know that the comment has been approved?
 
-As in the first point, if the PR author accepts the suggested comment without any additional comments, simply `Resolve` on GitHub will suffice. There is no need to reply things like "Accepted", "Done", etc as it just spams the reviewer's email.
+As in the first point, if the PR author accepts the suggested comment without any additional comments, simply `Resolve` on GitHub will suffice.
+There is no need to reply things like "Accepted", "Done", etc. as it just spams the reviewer's mailbox.
 
-**Can I resolve all comments in a single commit or each comment in an individual commit?**
+#### Can I resolve all comments in a single commit or each comment in an individual commit?
 
 Review fixes should be pushed on separate commits for easier viewing on GitHub (unlike in e.g. Gerrit's amend-based flow).
 
@@ -120,7 +136,7 @@ Review fixes should be pushed on separate commits for easier viewing on GitHub (
 
 1. Verify that all checks have passed.
 
-1. Merge develop into master and push to remote repository using console:
+1. Merge develop into master and push to remote repository using console (**not** using GitHub Merge Button):
 
          git checkout develop
          git pull origin develop
@@ -135,13 +151,12 @@ Review fixes should be pushed on separate commits for easier viewing on GitHub (
 1. Verify that the latest version is uploaded to [PyPI](https://pypi.org/project/git-machete).
 
 1. Verify that the latest version is uploaded to [Anaconda](https://anaconda.org/conda-forge/git-machete).
-   There also exists [conda-forge/git-machete-feedstock](https://github.com/conda-forge/git-machete-feedstock) repository which is
-   responsible for keeping the package up-to-date based on PyPI's release, which is done automatically by a bot.
-   Instruction on how to be a maintainer and other helpful tips are in:
+   Thanks to the courtesy of [@asford (Alex Ford)](https://github.com/asford),
+   there exists [conda-forge/git-machete-feedstock](https://github.com/conda-forge/git-machete-feedstock) repository.
+   A bot is responsible for keeping the package up-to-date based on PyPI's release.
+   Instruction on how to be a maintainer and other helpful tips can be found in
    [conda-forge recipe maintainer docs](https://conda-forge.org/docs/maintainer/adding_pkgs.html#recipe-maintainer).
 
-1. Verify that the latest commit in [VirtusLab/homebrew-git-machete](https://github.com/VirtusLab/homebrew-git-machete) tap repo refers to the latest version.
-
 1. Verify that a Docker image for the new version has been pushed to Docker Hub: [gitmachete/git-machete](https://hub.docker.com/r/gitmachete/git-machete/tags).
 
 1. Verify that a newly released version is present in `latest/stable` channel in [Snap](https://snapcraft.io/git-machete/releases).
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 310e5f3..04d1d05 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,11 @@
 # Release notes
 
+## New in git-machete 3.12.1
+
+- fixed: removed redundant files from Ubuntu package
+- fixed: fork-point overridden with invalid commit hash is ignored (doesn't crash git-machete anymore)
+- fixed: `git machete diff` now works as intended (runs `git diff` against the current working directory, not the current branch)
+
 ## New in git-machete 3.12.0
 
 - added: subcommand `git machete list childless`
@@ -587,4 +593,3 @@
 ## New in git-machete 1.0.1
 
 - fixed: some `git machete` subcommands crashing when run during an ongoing merge or rebase
-
diff --git a/blogs/docker-ci-tricks-2/blog.md b/blogs/docker-ci-tricks-2/blog.md
index 67545b5..11291fa 100644
--- a/blogs/docker-ci-tricks-2/blog.md
+++ b/blogs/docker-ci-tricks-2/blog.md
@@ -67,7 +67,7 @@ source ci/docker-pull-or-build-and-push.sh tox
 
 # ... skipped ...
 ```
-There is no definition of a `DIRECTORY_HASH` in here, but there is an execution of a [ci/docker-pull-or-build-and-push.sh](https://github.com/VirtusLab/git-machete/blob/develop/ci/docker-pull-or-build-and-push.sh) with `tox` argument in which we can see the definition:
+There is no definition of a `DIRECTORY_HASH` in here, but there is an execution of a `ci/docker-pull-or-build-and-push.sh` with `tox` argument in which we can see the definition:
 
 ```shell script
 # ... skipped ...
diff --git a/blogs/git-machete-1/blog.md b/blogs/git-machete-1/blog.md
index 167e4a8..802a5e2 100644
--- a/blogs/git-machete-1/blog.md
+++ b/blogs/git-machete-1/blog.md
@@ -249,4 +249,3 @@ More git-savvy users may argue that it should be enough to simply use the `--for
 `git merge-base --fork-point` (and thus `git rebase` with the said option) only takes the reflog of the one provided upstream branch into account.
 This works fine as long as nobody disturbs the structure of the tree in the definition file (i.e. the upstream branch of any branch doesn't change).
 Unfortunately, as mentioned before in this post, such tree structure modifications happen pretty often in real-life development, therefore a custom, more powerful way to find the fork point was necessary.
-
diff --git a/blogs/git-machete-1/sandbox-setup-reduced.sh b/blogs/git-machete-1/sandbox-setup-reduced.sh
index e552609..d8d787e 100755
--- a/blogs/git-machete-1/sandbox-setup-reduced.sh
+++ b/blogs/git-machete-1/sandbox-setup-reduced.sh
@@ -34,4 +34,3 @@ git checkout adjust-reads-prec
   cmt 1st round of fixes
 
 git branch -d root
-
diff --git a/blogs/git-machete-1/sandbox-setup.sh b/blogs/git-machete-1/sandbox-setup.sh
index b1a294d..8552e02 100755
--- a/blogs/git-machete-1/sandbox-setup.sh
+++ b/blogs/git-machete-1/sandbox-setup.sh
@@ -12,7 +12,6 @@ cmt() {
   touch $f
   git add $f
   git commit -m "$*"
-
 }
 
 
@@ -82,4 +81,3 @@ echo
 git machete status $1
 echo
 echo
-
diff --git a/blogs/git-machete-2/blog.md b/blogs/git-machete-2/blog.md
index 945ce87..9c927a0 100644
--- a/blogs/git-machete-2/blog.md
+++ b/blogs/git-machete-2/blog.md
@@ -190,4 +190,3 @@ $ git machete traverse
 
 Assuming you're sticking to rebase flow (in particular, you never merge upstream branch like `master` into your topic branches but instead rebase topic branches onto `master`),
 those few git-machete cuts should magically sort out your repository... whatever kind of jungle you might have had before.
-
diff --git a/blogs/git-machete-2/sandbox-setup-2.sh b/blogs/git-machete-2/sandbox-setup-2.sh
index aa12000..6eb2936 100755
--- a/blogs/git-machete-2/sandbox-setup-2.sh
+++ b/blogs/git-machete-2/sandbox-setup-2.sh
@@ -81,4 +81,3 @@ echo
 git machete status $1
 echo
 echo
-
diff --git a/ci/checks/ensure-completion-scripts-correct.sh b/ci/checks/enforce-completion-scripts-correct.sh
similarity index 100%
rename from ci/checks/ensure-completion-scripts-correct.sh
rename to ci/checks/enforce-completion-scripts-correct.sh
diff --git a/ci/checks/ensure-consistent-style-for-fork-point.sh b/ci/checks/enforce-consistent-style-for-fork-point.sh
similarity index 72%
rename from ci/checks/ensure-consistent-style-for-fork-point.sh
rename to ci/checks/enforce-consistent-style-for-fork-point.sh
index 473ff78..280d354 100755
--- a/ci/checks/ensure-consistent-style-for-fork-point.sh
+++ b/ci/checks/enforce-consistent-style-for-fork-point.sh
@@ -3,8 +3,9 @@
 set -e -o pipefail -u
 
 self_dir=$(cd "$(dirname "$0")" &>/dev/null; pwd -P)
+self_name=$(basename "$0")
 source "$self_dir"/utils.sh
 
-if git grep '[fF]orkpoint' -- :^ci/checks/ensure-consistent-style-for-fork-point.sh; then
+if git grep '[fF]orkpoint' -- :!**/$self_name; then
   die "Please use 'fork point' or 'Fork point' or 'fork_point' instead of 'forkpoint' or 'Forkpoint'."
 fi
diff --git a/ci/checks/ensure-consistent-style-for-github.sh b/ci/checks/enforce-consistent-style-for-github.sh
similarity index 68%
rename from ci/checks/ensure-consistent-style-for-github.sh
rename to ci/checks/enforce-consistent-style-for-github.sh
index 260dde8..62fb8dc 100755
--- a/ci/checks/ensure-consistent-style-for-github.sh
+++ b/ci/checks/enforce-consistent-style-for-github.sh
@@ -4,7 +4,8 @@ set -e -o pipefail -u
 
 self_dir=$(cd "$(dirname "$0")" &>/dev/null; pwd -P)
 source "$self_dir"/utils.sh
+self_name=$(basename "$0")
 
-if git grep -we Github -- :^ci/checks/ensure-consistent-style-for-github.sh; then
+if git grep -w Github -- :!**/$self_name; then
   die "Please use 'GitHub' instead of 'Github'."
 fi
diff --git a/ci/checks/enforce-correct-shebangs.sh b/ci/checks/enforce-correct-shebangs.sh
index bccff56..521e06d 100755
--- a/ci/checks/enforce-correct-shebangs.sh
+++ b/ci/checks/enforce-correct-shebangs.sh
@@ -2,7 +2,7 @@
 
 set -e -o pipefail -u
 
-if grep -r '^#!/usr/bin/env python2\?$' .; then
+if git grep -E '^#!/usr/bin/env python(2)?$' .; then
   echo "Ambiguous python shebang, please declare shebangs that point to python3:  #!/usr/bin/env python3"
   exit 1
 fi
diff --git a/ci/checks/ensure-links-correct.sh b/ci/checks/enforce-links-correct.sh
similarity index 100%
rename from ci/checks/ensure-links-correct.sh
rename to ci/checks/enforce-links-correct.sh
diff --git a/ci/checks/enforce-newline-at-eof.sh b/ci/checks/enforce-newline-at-eof.sh
new file mode 100755
index 0000000..ca743d6
--- /dev/null
+++ b/ci/checks/enforce-newline-at-eof.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+set -e -o pipefail -u
+
+self_dir=$(cd "$(dirname "$0")" &>/dev/null; pwd -P)
+source "$self_dir"/utils.sh
+
+found=0
+for file in $(git grep -I --files-with-matches ''); do
+  last_two_characters=$(tail -c2 "$file" | xxd -p)
+  if [[ $last_two_characters == 0a0a ]]; then
+    echo "$file (more than one newline character at EOF)"
+    found=1
+  elif [[ $last_two_characters != *0a ]]; then
+    echo "$file (no newline character at EOF)"
+    found=1
+  fi
+done
+
+if [[ $found -ne 0 ]]; then
+  die 'The above non-binary file(s) do not end with a single newline character, please tidy up'
+fi
diff --git a/ci/checks/ensure-release-notes-up-to-date.sh b/ci/checks/enforce-release-notes-up-to-date.sh
similarity index 100%
rename from ci/checks/ensure-release-notes-up-to-date.sh
rename to ci/checks/enforce-release-notes-up-to-date.sh
diff --git a/ci/checks/ensure-shell-scripts-pass-shellcheck.sh b/ci/checks/enforce-shell-scripts-pass-shellcheck.sh
similarity index 100%
rename from ci/checks/ensure-shell-scripts-pass-shellcheck.sh
rename to ci/checks/enforce-shell-scripts-pass-shellcheck.sh
diff --git a/ci/checks/ensure-version-bumped.sh b/ci/checks/enforce-version-bumped.sh
similarity index 100%
rename from ci/checks/ensure-version-bumped.sh
rename to ci/checks/enforce-version-bumped.sh
diff --git a/ci/checks/prohibit-trailing-whitespace.sh b/ci/checks/prohibit-trailing-whitespace.sh
index e67e9ae..2135518 100755
--- a/ci/checks/prohibit-trailing-whitespace.sh
+++ b/ci/checks/prohibit-trailing-whitespace.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-if git grep -EIn '\s+$' -- :^'*.py'; then
+if git grep -EIn '\s+$' -- :!'*.py'; then
   echo 'The above lines contain trailing whitespace, please tidy up'
   exit 1
 fi
diff --git a/ci/checks/run-all-checks.sh b/ci/checks/run-all-checks.sh
new file mode 100755
index 0000000..6be5f3f
--- /dev/null
+++ b/ci/checks/run-all-checks.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+# We don't want `less` to open for `git grep` results.
+export GIT_PAGER=cat
+
+PATH=./ci/checks:$PATH
+
+# `-x`, so that we have more clarity which check actually failed
+# (rather than searching the right script by error message).
+set -e -x
+
+enforce-completion-scripts-correct.sh
+enforce-consistent-style-for-fork-point.sh
+enforce-consistent-style-for-github.sh
+enforce-correct-shebangs.sh
+enforce-indent-two-spaces-outside-python.sh
+enforce-issue-number-for-todos.sh
+if [[ $0 != *.git/hooks/pre-commit ]]; then
+  # This one needs to connect to the linked websites and can potentially run long,
+  # let's skip it when this script is executed as git pre-commit hook.
+  enforce-links-correct.sh
+fi
+enforce-newline-at-eof.sh
+enforce-release-notes-up-to-date.sh
+enforce-shell-scripts-pass-shellcheck.sh
+enforce-version-bumped.sh
+prohibit-deploy-step-in-circleci.sh
+prohibit-double-backticks-in-py.sh
+prohibit-single-backtick-in-rst.sh
+prohibit-strings-split-without-delimiter.sh
+prohibit-tab-character.sh
+prohibit-trailing-whitespace.sh
diff --git a/ci/ci-run-commons.sh b/ci/ci-run-commons.sh
new file mode 100644
index 0000000..1c0914e
--- /dev/null
+++ b/ci/ci-run-commons.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+set -e -o pipefail -u
+
+function retry() {
+  attempts=$1
+  interval=10
+  for i in $(seq 1 $attempts); do
+    if "${@:2}"; then break; fi
+
+    echo "Attempt #$i out of $attempts at command '$*' failed"
+    if [[ $i -lt $attempts ]]; then
+      echo "Sleeping $interval seconds..."
+      sleep $interval
+    fi
+  done
+}
+
+# If image is not found by pull, build the image and push it to the Docker Hub.
+function docker_compose_pull_or_build_and_push() {
+  image_name=$1
+  DIRECTORY_HASH=$(git rev-parse HEAD:ci/$image_name)
+  export DIRECTORY_HASH
+  cd "$(git rev-parse --show-toplevel)/ci/$image_name/"
+
+  # Let's retry pulling the image in case of a spurious failure
+  # (`error pulling image configuration: Get "https://docker-images-prod.s3.dualstack.us-east-1.amazonaws.com/...": dial tcp ...:443: i/o timeout`)
+  retry 3 docker-compose --ansi=never pull $image_name
+
+  # A very unpleasant workaround for https://github.com/docker/compose/issues/7258
+  # (since v1.25.1, `docker-compose pull` is NOT failing when it can't fetch the image).
+  image_tag=$(docker-compose --ansi=never config | yq eval ".services.$image_name.image" -)
+  if ! docker image inspect "$image_tag" &>/dev/null; then
+    docker-compose --ansi=never build $image_name
+    # In builds coming from forks, secret vars are unavailable for security reasons; hence, we have to skip pushing the newly built image.
+    if [[ ${DOCKER_PASSWORD-} && ${DOCKER_USERNAME-} ]]; then
+      echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
+      # In case the push fails due to e.g. timeouts (which unfortunately sometimes happen on CI), we don't want to fail the entire deployment.
+      docker-compose --ansi=never push $image_name || true
+    fi
+  fi
+}
diff --git a/ci/deb-ppa-upload/.gitignore b/ci/deb-ppa-upload/.gitignore
deleted file mode 100644
index 4c49bd7..0000000
--- a/ci/deb-ppa-upload/.gitignore
+++ /dev/null
@@ -1,1 +0,0 @@
-.env
diff --git a/ci/deb-ppa-upload/Dockerfile b/ci/deb-ppa-upload/Dockerfile
index b24d90e..6dd0e06 100644
--- a/ci/deb-ppa-upload/Dockerfile
+++ b/ci/deb-ppa-upload/Dockerfile
@@ -1,47 +1,20 @@
-FROM ubuntu:20.04 as base
+FROM ubuntu:20.04
 SHELL ["/bin/bash", "-e", "-o", "pipefail", "-u", "-x", "-c"]
 
 # See https://github.com/phusion/baseimage-docker/issues/58 for why DEBIAN_FRONTEND=noninteractive is needed.
-RUN apt-get update \
-    && DEBIAN_FRONTEND=noninteractive apt-get install -y debhelper devscripts fakeroot dh-python gawk python3-all python3-paramiko python3-setuptools \
-    && rm -rfv /var/lib/apt/lists/*
-
-FROM base AS circle_ci
-RUN install -d -m 0700 ~/.gnupg/ ~/.gnupg/private-keys-v1.d/ ~/.ssh/
-
-COPY dput.cf /etc/
-
-COPY gpg-sign.sh /root/
-RUN chmod +x ~/gpg-sign.sh
-
-COPY release-notes-to-changelog.awk /root/
-COPY entrypoint.sh /root/
-RUN chmod +x /root/entrypoint.sh
-CMD ["/root/entrypoint.sh"]
-WORKDIR /root/git-machete
-
-FROM base AS local
-ARG user_id
-ARG group_id
-RUN set -x \
-    && [ ${user_id:-0} -ne 0 ] \
-    && [ ${group_id:-0} -ne 0 ] \
-    # sometimes the given `group_id` is already taken and `addgroup` raises an error, so let's check its existence first
-    && (getent group $group_id || addgroup --gid=${group_id} ci-user) \
-    && useradd -l -u ${user_id} -g $group_id ci-user \
-    && install -d -m 0755 -o ci-user -g $group_id /home/ci-user
-
-USER ci-user
-
-RUN install -d -m 0700 ~/.gnupg/ ~/.gnupg/private-keys-v1.d/ ~/.ssh/
+RUN \
+    apt-get update; \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y \
+      debhelper devscripts fakeroot dh-python gawk python3-all python3-paramiko python3-setuptools sudo; \
+    rm -rfv /var/lib/apt/lists/*
 
 COPY dput.cf /etc/
-
-COPY --chown=ci-user:ci-user gpg-sign.sh /home/ci-user/
-RUN chmod +x ~/gpg-sign.sh
-
-COPY --chown=ci-user:ci-user release-notes-to-changelog.awk /home/ci-user/
-COPY --chown=ci-user:ci-user entrypoint.sh /home/ci-user/
-RUN chmod +x ~/entrypoint.sh
-CMD ["/home/ci-user/entrypoint.sh"]
-WORKDIR /home/ci-user/git-machete
+COPY entrypoint.sh gpg-sign.sh release-notes-to-changelog.awk run.sh /
+RUN chmod a+r /etc/dput.cf /release-notes-to-changelog.awk
+RUN chmod a+rx /entrypoint.sh /gpg-sign.sh /run.sh
+ENTRYPOINT ["/entrypoint.sh"]
+CMD ["/run.sh"]
+# One extra level under / is needed, since Debian packaging tools will write files
+# in the parent directory of current working directory.
+WORKDIR /git-machete/mount/
+RUN chmod -R a+rwx /git-machete
diff --git a/ci/deb-ppa-upload/build-context/entrypoint.sh b/ci/deb-ppa-upload/build-context/entrypoint.sh
index 14a0962..1f15099 100644
--- a/ci/deb-ppa-upload/build-context/entrypoint.sh
+++ b/ci/deb-ppa-upload/build-context/entrypoint.sh
@@ -1,55 +1,14 @@
 #!/usr/bin/env bash
 
-{ [[ -f setup.py ]] && grep -q "name='git-machete'" setup.py; } || {
-  echo "Error: the repository should be mounted as a volume under $(pwd)"
-  exit 1
-}
-
 set -e -o pipefail -u
-echo "$GPG_PRIVATE_KEY_PASSPHRASE" > ~/.gnupg/passphrase.txt
-echo "$GPG_PRIVATE_KEY_CONTENTS_BASE64" | base64 -d > ~/.gnupg/private-keys-v1.d/"$GPG_PRIVATE_KEY_ID".key
-echo "$GPG_PUBRING_KEYBOX_CONTENTS_BASE64" | base64 -d > ~/.gnupg/pubring.kbx
-echo "$GPG_TRUSTDB_GPG_CONTENTS_BASE64" | base64 -d > ~/.gnupg/trustdb.gpg
-echo "$SSH_PRIVATE_KEY_CONTENTS_BASE64" | base64 -d > ~/.ssh/id_rsa
-chmod 400 ~/.ssh/id_rsa
-
-set -x
-VERSION=$(python3 setup.py --version)
-export VERSION
-envsubst '$VERSION' < debian/files.envsubst > debian/files
-cp LICENSE debian/copyright
-# The first version ever released to PPA is 2.12.8, so we skip everything older than that from the changelog.
-sed '/## New in git-machete 2\.12\.7/,$d' RELEASE_NOTES.md | awk \
-  -v distro_name="$TARGET_DISTRO_NAME" \
-  -v distro_number="$TARGET_DISTRO_NUMBER" \
-  -f ~/release-notes-to-changelog.awk > debian/changelog
 
-# Since we upload over SFTP, we need to whitelist the host first to avoid the prompt.
-# Let's retry ssh-keyscan to protect again rare spurious failures.
-attempts=3
-i=1
-while true; do
-  if ssh-keyscan ppa.launchpad.net > ~/.ssh/known_hosts; then
-    break
-  elif (( i < attempts )); then
-    echo "Retrying ssh-keyscan..."
-    i=$((i + 1))
-    sleep 5
-  else
-    echo "ssh-keyscan did not succeed despite $attempts attempts"
-    exit 1
+if [[ ${GID-} && ${UID-} ]]; then
+  if ! getent group "$GID" &>/dev/null; then
+    groupadd --gid="$GID" docker
   fi
-done
-
-# `-p` flag points to a script that wraps gpg so that we don't get asked for password to the private key on TTY.
-debuild -S -p"$HOME/gpg-sign.sh"
-cat ../python3-git-machete_*.dsc
-cat ../python3-git-machete_*_source.buildinfo
-cat ../python3-git-machete_*_source.changes
-tar tvf ../python3-git-machete_*.tar.gz
+  useradd --create-home --gid="$GID" --no-log-init --uid="$UID" docker
 
-if [[ $DO_DPUT == true ]]; then
-  dput ppa:virtuslab/git-machete ../python3-git-machete_*_source.changes
+  sudo --preserve-env --set-home --user=docker bash -c "$*"
 else
-  echo "Refraining from running 'dput' since it's a dry run"
+  bash -c "$@"
 fi
diff --git a/ci/deb-ppa-upload/build-context/run.sh b/ci/deb-ppa-upload/build-context/run.sh
new file mode 100644
index 0000000..130bb87
--- /dev/null
+++ b/ci/deb-ppa-upload/build-context/run.sh
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+
+set -e -o pipefail -u
+
+if ! ( [ -f setup.py ] && grep -q "name='git-machete'" setup.py ); then
+  echo "Error: the repository should be mounted as a volume under $(pwd)"
+  exit 1
+fi
+
+install -d -m 0700 ~/.gnupg/ ~/.gnupg/private-keys-v1.d/ ~/.ssh/
+echo "$GPG_PRIVATE_KEY_PASSPHRASE" > ~/.gnupg/passphrase.txt
+echo "$GPG_PRIVATE_KEY_CONTENTS_BASE64" | base64 -d > ~/.gnupg/private-keys-v1.d/"$GPG_PRIVATE_KEY_ID".key
+echo "$GPG_PUBRING_KEYBOX_CONTENTS_BASE64" | base64 -d > ~/.gnupg/pubring.kbx
+echo "$GPG_TRUSTDB_GPG_CONTENTS_BASE64" | base64 -d > ~/.gnupg/trustdb.gpg
+echo "$SSH_PRIVATE_KEY_CONTENTS_BASE64" | base64 -d > ~/.ssh/id_rsa
+chmod 400 ~/.ssh/id_rsa
+
+set -x
+VERSION=$(python3 setup.py --version)
+export VERSION
+envsubst '$VERSION' < debian/files.envsubst > debian/files
+cp LICENSE debian/copyright
+# The first version ever released to PPA is 2.12.8, so we skip everything older than that from the changelog.
+sed '/## New in git-machete 2\.12\.7/,$d' RELEASE_NOTES.md | awk \
+  -v distro_name="$TARGET_DISTRO_NAME" \
+  -v distro_number="$TARGET_DISTRO_NUMBER" \
+  -f /release-notes-to-changelog.awk > debian/changelog
+
+# Since we upload over SFTP, we need to whitelist the host first to avoid the prompt.
+# Let's retry ssh-keyscan to protect again rare spurious failures.
+attempts=3
+i=1
+while true; do
+  if ssh-keyscan ppa.launchpad.net > ~/.ssh/known_hosts; then
+    break
+  elif (( i < attempts )); then
+    echo "Retrying ssh-keyscan..."
+    i=$((i + 1))
+    sleep 5
+  else
+    echo "ssh-keyscan did not succeed despite $attempts attempts"
+    exit 1
+  fi
+done
+
+# `-p` flag points to a script that wraps gpg so that we don't get asked for password to the private key on TTY.
+debuild -S -p"/gpg-sign.sh"
+cat ../python3-git-machete_*.dsc
+cat ../python3-git-machete_*_source.buildinfo
+cat ../python3-git-machete_*_source.changes
+tar tvf ../python3-git-machete_*.tar.gz
+
+if [[ $DO_DPUT == true ]]; then
+  dput ppa:virtuslab/git-machete ../python3-git-machete_*_source.changes
+else
+  echo "Refraining from running 'dput' since it's a dry run"
+fi
diff --git a/ci/deb-ppa-upload/ci-deploy.sh b/ci/deb-ppa-upload/ci-deploy.sh
index 33d1035..eec26be 100644
--- a/ci/deb-ppa-upload/ci-deploy.sh
+++ b/ci/deb-ppa-upload/ci-deploy.sh
@@ -8,8 +8,9 @@ else
   do_dput=true
 fi
 
-source ci/docker-pull-or-build-and-push.sh deb-ppa-upload
+source "$(git rev-parse --show-toplevel)"/ci/ci-run-commons.sh
 
-docker-compose --ansi never run -e TARGET_DISTRO_NAME=bionic -e TARGET_DISTRO_NUMBER=18.04 -e DO_DPUT=$do_dput deb-ppa-upload
-docker-compose --ansi never run -e TARGET_DISTRO_NAME=focal  -e TARGET_DISTRO_NUMBER=20.04 -e DO_DPUT=$do_dput deb-ppa-upload
-docker-compose --ansi never run -e TARGET_DISTRO_NAME=jammy  -e TARGET_DISTRO_NUMBER=22.04 -e DO_DPUT=$do_dput deb-ppa-upload
+docker_compose_pull_or_build_and_push deb-ppa-upload
+docker-compose --ansi=never run -e TARGET_DISTRO_NAME=bionic -e TARGET_DISTRO_NUMBER=18.04 -e DO_DPUT=$do_dput deb-ppa-upload
+docker-compose --ansi=never run -e TARGET_DISTRO_NAME=focal  -e TARGET_DISTRO_NUMBER=20.04 -e DO_DPUT=$do_dput deb-ppa-upload
+docker-compose --ansi=never run -e TARGET_DISTRO_NAME=jammy  -e TARGET_DISTRO_NUMBER=22.04 -e DO_DPUT=$do_dput deb-ppa-upload
diff --git a/ci/deb-ppa-upload/docker-compose.yml b/ci/deb-ppa-upload/docker-compose.yml
index ee23caf..d4eca24 100644
--- a/ci/deb-ppa-upload/docker-compose.yml
+++ b/ci/deb-ppa-upload/docker-compose.yml
@@ -5,13 +5,9 @@ services:
     build:
       context: build-context
       dockerfile: ../Dockerfile # relative to build-context
-      target: ${TARGET:-circle_ci}
-      args:
-        - user_id=${USER_ID:-0}
-        - group_id=${GROUP_ID:-0}
     volumes:
       # Host path is relative to current directory, not build-context
-      - ./../..:${MOUNT_POINT:-/root}/git-machete
+      - ./../..:/git-machete/mount/
     environment:
       - DO_DPUT
       - TARGET_DISTRO_NAME
diff --git a/ci/deb-ppa-upload/local-run.sh b/ci/deb-ppa-upload/local-run.sh
index 8fa29f5..44d8ce7 100755
--- a/ci/deb-ppa-upload/local-run.sh
+++ b/ci/deb-ppa-upload/local-run.sh
@@ -3,14 +3,14 @@
 set -e -o pipefail -u
 
 source "$(git rev-parse --show-toplevel)"/ci/local-run-commons.sh deb-ppa-upload
+
 export_directory_hash deb-ppa-upload
 cd "$(git rev-parse --show-toplevel)"/ci/deb-ppa-upload/
 check_env gpg-ssh.env
 
 set -x
-export TARGET=local
-export MOUNT_POINT=/home/ci-user
-docker-compose build --build-arg user_id="$(id -u)" --build-arg group_id="$(id -g)" deb-ppa-upload
-docker-compose run -e TARGET_DISTRO_NAME=bionic -e TARGET_DISTRO_NUMBER=18.04 -e DO_DPUT=false deb-ppa-upload
-docker-compose run -e TARGET_DISTRO_NAME=focal  -e TARGET_DISTRO_NUMBER=20.04 -e DO_DPUT=false deb-ppa-upload
-docker-compose run -e TARGET_DISTRO_NAME=jammy  -e TARGET_DISTRO_NUMBER=22.04 -e DO_DPUT=false deb-ppa-upload
+docker-compose build deb-ppa-upload
+common_flags="-e GID=$(id -g) -e UID=$(id -u) -e DO_DPUT=false"
+docker-compose run $common_flags -e TARGET_DISTRO_NAME=bionic -e TARGET_DISTRO_NUMBER=18.04 deb-ppa-upload
+docker-compose run $common_flags -e TARGET_DISTRO_NAME=focal  -e TARGET_DISTRO_NUMBER=20.04 deb-ppa-upload
+docker-compose run $common_flags -e TARGET_DISTRO_NAME=jammy  -e TARGET_DISTRO_NUMBER=22.04 deb-ppa-upload
diff --git a/ci/docker-pull-or-build-and-push.sh b/ci/docker-pull-or-build-and-push.sh
deleted file mode 100644
index d9a7893..0000000
--- a/ci/docker-pull-or-build-and-push.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-
-set -e -o pipefail -u
-image_name=$1
-
-DIRECTORY_HASH=$(git rev-parse HEAD:ci/$image_name)
-export DIRECTORY_HASH
-cd ci/$image_name/
-
-function retry() {
-  attempts=$1
-  interval=10
-  for i in $(seq 1 $attempts); do
-    if "${@:2}"; then break; fi
-
-    echo "Attempt #$i out of $attempts at command '$*' failed"
-    if [[ $i -lt $attempts ]]; then
-      echo "Sleeping $interval seconds..."
-      sleep $interval
-    fi
-  done
-}
-
-# If image is not found by pull, build the image and push it to the Docker Hub.
-
-# Let's retry pulling the image in case of a spurious failure
-# (`error pulling image configuration: Get "https://docker-images-prod.s3.dualstack.us-east-1.amazonaws.com/...": dial tcp ...:443: i/o timeout`)
-retry 3 docker-compose --ansi never pull $image_name
-
-# A very unpleasant workaround for https://github.com/docker/compose/issues/7258
-# (since v1.25.1, `docker-compose pull` is NOT failing when it can't fetch the image).
-image_tag=$(docker-compose --ansi never config | yq eval ".services.$image_name.image" -)
-docker image inspect "$image_tag" &>/dev/null || {
-  docker-compose --ansi never build $image_name
-  # In builds coming from forks, secret vars are unavailable for security reasons; hence, we have to skip pushing the newly built image.
-  if [[ ${DOCKER_PASSWORD-} && ${DOCKER_USERNAME-} ]]; then
-    echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
-    # In case the push fails due to e.g. timeouts (which unfortunately sometimes happen on CI), we don't want to fail the entire deployment.
-    docker-compose --ansi never push $image_name || true
-  fi
-}
diff --git a/ci/docker/Dockerfile b/ci/docker/Dockerfile
index 12113e9..da5e304 100644
--- a/ci/docker/Dockerfile
+++ b/ci/docker/Dockerfile
@@ -6,10 +6,10 @@ COPY . /tmp/input/
 WORKDIR /tmp/input/
 RUN find . | sort
 RUN \
-  export PYTHONDONTWRITEBYTECODE=1; \
-  python setup.py install; \
-  git machete --version; \
-  rm -rf /tmp/input/
+    export PYTHONDONTWRITEBYTECODE=1; \
+    python setup.py install; \
+    git machete --version; \
+    rm -rf /tmp/input/
 
 WORKDIR /repo
 VOLUME /repo
diff --git a/ci/homebrew-tap/ci-deploy.sh b/ci/homebrew-tap/ci-deploy.sh
deleted file mode 100644
index e95a98d..0000000
--- a/ci/homebrew-tap/ci-deploy.sh
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env bash
-
-set -e -o pipefail -u
-
-if [[ ${1-} == "--dry-run" || ${CIRCLE_BRANCH-} != "master" ]]; then
-  do_push=false
-  pypi_host=test.pypi.org
-else
-  do_push=true
-  pypi_host=pypi.org
-fi
-
-version=$(python3 setup.py --version)
-
-git clone https://${GITHUB_TOKEN}@github.com/VirtusLab/homebrew-git-machete.git ../homebrew-git-machete
-cd ../homebrew-git-machete/
-
-set -x
-git config user.email "gitmachete@virtuslab.com"
-git config user.name "Git Machete Release Bot"
-sha256=$(
-  curl -s https://$pypi_host/pypi/git-machete/$version/json \
-  | jq --raw-output '.urls | map(select(.packagetype == "sdist")) | .[0].digests.sha256')
-sed -i "s/git-machete-.*\.tar\.gz/git-machete-$version.tar.gz/" git-machete.rb
-sed -i "s/pypi\.org/$pypi_host/" git-machete.rb
-sed -i "s/^  sha256 .*/  sha256 \"$sha256\"/" git-machete.rb
-cat git-machete.rb
-git add git-machete.rb
-git commit --message "Release $version, CircleCI build: $CIRCLE_BUILD_NUM"
-
-if [[ $do_push == true ]]; then
-  git push origin master
-else
-  echo "Refraining from push since it's a dry run"
-  # install git-machete from local formula with homebrew
-  /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" < /dev/null
-  eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
-  brew install --build-from-source --formula ./git-machete.rb
-  if [[ "$version" != "$(git machete --version | cut -d' ' -f4)" ]]; then
-    echo "Something went wrong during brew installation: installed version does not match version from formula."
-    echo "Formula version: $version, installed version: $(git machete --version | cut -d' ' -f4)"
-    exit 1
-  fi
-  brew remove git-machete
-fi
diff --git a/ci/nixpkgs-build/ci-run.sh b/ci/nixpkgs-build/ci-run.sh
index be08af9..51e693c 100644
--- a/ci/nixpkgs-build/ci-run.sh
+++ b/ci/nixpkgs-build/ci-run.sh
@@ -2,7 +2,8 @@
 
 set -e -o pipefail -u -x
 
-source ci/docker-pull-or-build-and-push.sh nixpkgs-build
+source "$(git rev-parse --show-toplevel)"/ci/ci-run-commons.sh
 
 git_revision=$(git rev-parse HEAD)
-docker-compose --ansi never run -e GIT_REVISION=$git_revision nixpkgs-build
+docker_compose_pull_or_build_and_push nixpkgs-build
+docker-compose --ansi=never run -e GIT_REVISION="$git_revision" nixpkgs-build
diff --git a/ci/nixpkgs-build/local-run.sh b/ci/nixpkgs-build/local-run.sh
index aeeac05..01aa449 100755
--- a/ci/nixpkgs-build/local-run.sh
+++ b/ci/nixpkgs-build/local-run.sh
@@ -1,13 +1,12 @@
 #!/usr/bin/env bash
 
-set -e -o pipefail -u
-
-cd "$(git rev-parse --show-toplevel)"/ci/nixpkgs-build/
+set -e -o pipefail -u -x
 
 source "$(git rev-parse --show-toplevel)"/ci/local-run-commons.sh nixpkgs-build
+
 export_directory_hash nixpkgs-build
+cd "$(git rev-parse --show-toplevel)"/ci/nixpkgs-build/
 
 git_revision=$(git rev-parse "@{upstream}")
-
 docker-compose build nixpkgs-build
-docker-compose run -e GIT_REVISION=$git_revision nixpkgs-build
+docker-compose run -e GIT_REVISION="$git_revision" nixpkgs-build
diff --git a/ci/rpm/.gitignore b/ci/rpm/.gitignore
deleted file mode 100644
index 4c49bd7..0000000
--- a/ci/rpm/.gitignore
+++ /dev/null
@@ -1,1 +0,0 @@
-.env
diff --git a/ci/rpm/Dockerfile b/ci/rpm/Dockerfile
index 94e8e0e..accde12 100644
--- a/ci/rpm/Dockerfile
+++ b/ci/rpm/Dockerfile
@@ -1,27 +1,10 @@
-FROM fedora:35 as base
+FROM fedora:35
 SHELL ["/bin/bash", "-e", "-o", "pipefail", "-u", "-x", "-c"]
 
 RUN dnf install -y python3-pip rpm-build
-RUN ln -s /usr/bin/python3 /usr/local/bin/python
 
-FROM base AS circle_ci
-COPY entrypoint.sh /root/
-RUN chmod +x /root/entrypoint.sh
-CMD ["/root/entrypoint.sh"]
-WORKDIR /root/git-machete
-
-FROM base AS local
-ARG user_id
-ARG group_id
-RUN set -x \
-    && [ ${user_id:-0} -ne 0 ] \
-    && [ ${group_id:-0} -ne 0 ] \
-    # sometimes the given `group_id` is already taken and `addgroup` raises an error, so let's check its existence first
-    && (getent group $group_id || groupadd --gid=${group_id} ci-user) \
-    && useradd -l -u ${user_id} -g $group_id ci-user \
-    && install -d -m 0755 -o ci-user -g $group_id /home/ci-user
-USER ci-user
-COPY --chown=ci-user:ci-user entrypoint.sh /home/ci-user/
-RUN chmod +x ~/entrypoint.sh
-CMD ["/home/ci-user/entrypoint.sh"]
-WORKDIR /home/ci-user/git-machete
+COPY entrypoint.sh run.sh /
+RUN chmod +x /entrypoint.sh /run.sh
+ENTRYPOINT ["/entrypoint.sh"]
+CMD ["/run.sh"]
+WORKDIR /git-machete
diff --git a/ci/rpm/build-context/entrypoint.sh b/ci/rpm/build-context/entrypoint.sh
index 0c2f6c0..1f15099 100644
--- a/ci/rpm/build-context/entrypoint.sh
+++ b/ci/rpm/build-context/entrypoint.sh
@@ -1,10 +1,14 @@
 #!/usr/bin/env bash
 
-{ [[ -f setup.py ]] && grep -q "name='git-machete'" setup.py; } || {
-  echo "Error: the repository should be mounted as a volume under $(pwd)"
-  exit 1
-}
+set -e -o pipefail -u
 
-set -x
+if [[ ${GID-} && ${UID-} ]]; then
+  if ! getent group "$GID" &>/dev/null; then
+    groupadd --gid="$GID" docker
+  fi
+  useradd --create-home --gid="$GID" --no-log-init --uid="$UID" docker
 
-python setup.py bdist_rpm
+  sudo --preserve-env --set-home --user=docker bash -c "$*"
+else
+  bash -c "$@"
+fi
diff --git a/ci/rpm/build-context/run.sh b/ci/rpm/build-context/run.sh
new file mode 100644
index 0000000..0cb754b
--- /dev/null
+++ b/ci/rpm/build-context/run.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+set -e -o pipefail -u
+
+if ! ( [ -f setup.py ] && grep -q "name='git-machete'" setup.py ); then
+  echo "Error: the repository should be mounted as a volume under $(pwd)"
+  exit 1
+fi
+
+python3 setup.py bdist_rpm
diff --git a/ci/rpm/ci-run.sh b/ci/rpm/ci-run.sh
index 308b8c8..b346608 100644
--- a/ci/rpm/ci-run.sh
+++ b/ci/rpm/ci-run.sh
@@ -2,6 +2,7 @@
 
 set -e -o pipefail -u -x
 
-source ci/docker-pull-or-build-and-push.sh rpm
+source "$(git rev-parse --show-toplevel)"/ci/ci-run-commons.sh
 
-docker-compose --ansi never run rpm
+docker_compose_pull_or_build_and_push rpm
+docker-compose --ansi=never run rpm
diff --git a/ci/rpm/docker-compose.yml b/ci/rpm/docker-compose.yml
index cd39001..363bfc9 100644
--- a/ci/rpm/docker-compose.yml
+++ b/ci/rpm/docker-compose.yml
@@ -5,10 +5,6 @@ services:
     build:
       context: build-context
       dockerfile: ../Dockerfile # relative to build-context
-      target: ${TARGET:-circle_ci}
-      args:
-        - user_id=${USER_ID:-0}
-        - group_id=${GROUP_ID:-0}
     volumes:
       # Host path is relative to current directory, not build-context
-      - ./../..:${MOUNT_POINT:-/root}/git-machete
+      - ./../..:/git-machete
diff --git a/ci/rpm/local-run.sh b/ci/rpm/local-run.sh
index 81e664e..f3abd4f 100755
--- a/ci/rpm/local-run.sh
+++ b/ci/rpm/local-run.sh
@@ -2,12 +2,11 @@
 
 set -e -o pipefail -u
 
-source ../local-run-commons.sh rpm
+source "$(git rev-parse --show-toplevel)"/ci/local-run-commons.sh rpm
+
 export_directory_hash rpm
 cd "$(git rev-parse --show-toplevel)"/ci/rpm/
 
 set -x
-export TARGET=local
-export MOUNT_POINT=/home/ci-user
-docker-compose build --build-arg user_id="$(id -u)" --build-arg group_id="$(id -g)" rpm
-docker-compose run rpm
+docker-compose build rpm
+docker-compose run -e GID="$(id -g)" -e UID="$(id -u)" rpm
diff --git a/ci/tox/.env-sample b/ci/tox/.env-sample
index 75c7d2d..ddbf2a2 100644
--- a/ci/tox/.env-sample
+++ b/ci/tox/.env-sample
@@ -1,7 +1,9 @@
-# Can be used by docker-compose for building the `gitmachete/ci-tox` image locally
-GIT_VERSION=2.25.0
+# Vars for `docker-compose build`
+GIT_VERSION=2.25.0  # note that generally the older the git version, the faster the build
 PYTHON_VERSION=3.8
 
+# Vars for `docker-compose run`
+BUILD_SPHINX_DOCS=false
+CHECK_PY_DOCS_UP_TO_DATE=false
 CHECK_COVERAGE=false
-BUILD_DOCS=false
 CHECK_PEP8=false
diff --git a/ci/tox/Dockerfile b/ci/tox/Dockerfile
index 7efd684..687e1f0 100644
--- a/ci/tox/Dockerfile
+++ b/ci/tox/Dockerfile
@@ -1,55 +1,39 @@
 ARG python_version
-FROM python:${python_version}-alpine as base
+FROM python:${python_version}-alpine
 SHELL ["/bin/sh", "-e", "-o", "pipefail", "-u", "-x", "-c"]
 # Required since the earlier versions of git assume the location of python to be /usr/bin/python during the build.
 RUN ln -s /usr/local/bin/python /usr/bin/python
 
 ARG git_version
-RUN set -x \
-    && apk add --no-cache --virtual=git-build-deps alpine-sdk autoconf gettext wget zlib-dev \
-    && wget -q https://github.com/git/git/archive/v$git_version.tar.gz \
-    && tar xzf v$git_version.tar.gz \
-    && rm v$git_version.tar.gz \
-    && cd git-$git_version/ \
-    && make configure \
-    && ./configure \
-    && sed -i 's/#warning .*//' /usr/include/sys/poll.h  `# to reduce amount of spam warnings in logs` \
-    && make \
-    && make install \
-    && cd .. \
-    && rm -r git-$git_version/ \
-    && git --version \
-    && apk del git-build-deps \
-    && rm -rfv /usr/local/bin/git-shell /usr/local/share/git-gui/ \
-    && cd /usr/local/libexec/git-core/ \
-    && rm -fv git-credential-* git-daemon git-fast-import git-http-backend git-imap-send git-remote-testsvn git-shell
+RUN \
+    apk add --no-cache --virtual=git-build-deps alpine-sdk autoconf gettext wget zlib-dev; \
+    wget -q https://github.com/git/git/archive/v$git_version.tar.gz; \
+    tar xzf v$git_version.tar.gz; \
+    rm v$git_version.tar.gz; \
+    cd git-$git_version/; \
+    make configure; \
+    ./configure; \
+    sed -i 's/#warning .*//' /usr/include/sys/poll.h  `# to reduce amount of spam warnings in logs`; \
+    make; \
+    make install; \
+    cd ..; \
+    rm -r git-$git_version/; \
+    git --version; \
+    apk del git-build-deps; \
+    rm -rfv /usr/local/bin/git-shell /usr/local/share/git-gui/; \
+    cd /usr/local/libexec/git-core/; \
+    rm -fv git-credential-* git-daemon git-fast-import git-http-backend git-imap-send git-remote-testsvn git-shell
 
 ARG python_version
 ENV PYTHON_VERSION=${python_version}
 ENV PYTHON=python${python_version}
-RUN apk add --no-cache gcc musl-dev # both packages are required to install mypy
-
-FROM base AS circle_ci
+RUN apk add --no-cache gcc musl-dev  # packages required to install mypy
 RUN $PYTHON -m pip install tox
-ENV PATH=$PATH:/root/.local/bin/
-COPY entrypoint.sh /root/
-RUN chmod +x /root/entrypoint.sh
-CMD ["/root/entrypoint.sh"]
-WORKDIR /root/git-machete
 
-FROM base AS local
-ARG user_id
-ARG group_id
-RUN set -x \
-    && [ ${user_id:-0} -ne 0 ] \
-    && [ ${group_id:-0} -ne 0 ] \
-    # sometimes the given `group_id` is already taken and `addgroup` raises an error, so let's check its existence first
-    && (getent group $group_id || addgroup --gid=${group_id} ci-user) \
-    && adduser --uid=${user_id} --ingroup=$(getent group $group_id | cut -d: -f1) --disabled-password ci-user
-USER ci-user
-RUN $PYTHON -m pip install --user tox
-ENV PATH=$PATH:/home/ci-user/.local/bin/
-COPY --chown=ci-user:ci-user entrypoint.sh /home/ci-user/
-RUN chmod +x ~/entrypoint.sh
-CMD ["/home/ci-user/entrypoint.sh"]
-WORKDIR /home/ci-user/git-machete
+RUN apk add --no-cache bash sudo  # packages required to run the entrypoint script
+ENV PATH=$PATH:/root/.local/bin/
+COPY entrypoint.sh run.sh /
+RUN chmod a+rx /entrypoint.sh /run.sh
+ENTRYPOINT ["/entrypoint.sh"]
+CMD ["/run.sh"]
+WORKDIR /git-machete
diff --git a/ci/tox/build-context/entrypoint.sh b/ci/tox/build-context/entrypoint.sh
index eff06c2..b5859a5 100644
--- a/ci/tox/build-context/entrypoint.sh
+++ b/ci/tox/build-context/entrypoint.sh
@@ -1,29 +1,17 @@
-#!/bin/sh
+#!/usr/bin/env bash
 
-{ [ -f setup.py ] && grep -q "name='git-machete'" setup.py; } || {
-  echo "Error: the repository should be mounted as a volume under $(pwd)"
-  exit 1
-}
+set -e -o pipefail -u
 
-set -e -u -x
+if [[ ${GID-} && ${UID-} ]]; then
+  if ! getent group "$GID" &>/dev/null; then
+    addgroup --gid="$GID" docker
+  fi
+  # `adduser` doesn't accept a numeric GID, we need to extract & provide group name
+  # (might not be `docker` if the group existed already in the image).
+  group_name=$(getent group "$GID" | cut -d: -f1)
+  adduser --disabled-password --ingroup="$group_name" --uid="$UID" docker
 
-env | sort | head -3
-
-if [[ $CHECK_COVERAGE = true ]]; then
-  TOX_ENV_LIST="mypy-py${PYTHON_VERSION/./},coverage"
+  sudo --preserve-env --set-home --user=docker bash -c "$*"
 else
-  TOX_ENV_LIST="mypy-py${PYTHON_VERSION/./},py${PYTHON_VERSION/./}"
-fi
-
-if [[ $BUILD_DOCS = true ]]; then
-  TOX_ENV_LIST="$TOX_ENV_LIST,docs"
+  bash -c "$@"
 fi
-
-if [[ $CHECK_PEP8 = true ]]; then
-  TOX_ENV_LIST="$TOX_ENV_LIST,pep8"
-fi
-
-tox -e $TOX_ENV_LIST
-
-$PYTHON setup.py install --user
-git machete --version
diff --git a/ci/tox/build-context/run.sh b/ci/tox/build-context/run.sh
new file mode 100644
index 0000000..0bcc609
--- /dev/null
+++ b/ci/tox/build-context/run.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+set -e -o pipefail -u
+
+if ! ( [ -f setup.py ] && grep -q "name='git-machete'" setup.py ); then
+  echo "Error: the repository should be mounted as a volume under $(pwd)"
+  exit 1
+fi
+
+env | sort | head -3
+
+set -x
+
+if [[ $CHECK_COVERAGE = true ]]; then
+  TOX_ENV_LIST="mypy-py${PYTHON_VERSION/./},coverage"
+else
+  TOX_ENV_LIST="mypy-py${PYTHON_VERSION/./},py${PYTHON_VERSION/./}"
+fi
+
+if [[ $BUILD_SPHINX_DOCS = true ]]; then
+  TOX_ENV_LIST="$TOX_ENV_LIST,sphinx-docs"
+fi
+
+if [[ $CHECK_PY_DOCS_UP_TO_DATE = true ]]; then
+  TOX_ENV_LIST="$TOX_ENV_LIST,check-py-docs"
+fi
+
+if [[ $CHECK_PEP8 = true ]]; then
+  TOX_ENV_LIST="$TOX_ENV_LIST,pep8"
+fi
+
+tox -e $TOX_ENV_LIST
+
+$PYTHON setup.py install --user
+PATH=$PATH:$HOME/.local/bin/
+git machete --version
diff --git a/ci/tox/ci-run.sh b/ci/tox/ci-run.sh
index cadd444..10cd5de 100644
--- a/ci/tox/ci-run.sh
+++ b/ci/tox/ci-run.sh
@@ -2,6 +2,7 @@
 
 set -e -o pipefail -u -x
 
-source ci/docker-pull-or-build-and-push.sh tox
+source "$(git rev-parse --show-toplevel)"/ci/ci-run-commons.sh
 
-docker-compose --ansi never run tox
+docker_compose_pull_or_build_and_push tox
+docker-compose --ansi=never run tox
diff --git a/ci/tox/docker-compose.yml b/ci/tox/docker-compose.yml
index c11b3e6..4def728 100644
--- a/ci/tox/docker-compose.yml
+++ b/ci/tox/docker-compose.yml
@@ -5,16 +5,14 @@ services:
     build:
       context: build-context
       dockerfile: ../Dockerfile # relative to build-context
-      target: ${TARGET:-circle_ci}
       args:
-        - user_id=${USER_ID:-0}
-        - group_id=${GROUP_ID:-0}
         - git_version=${GIT_VERSION:-0.0.0}
         - python_version=${PYTHON_VERSION:-0.0.0}
     environment:
-      - BUILD_DOCS=${BUILD_DOCS:-false}
+      - BUILD_SPHINX_DOCS=${BUILD_SPHINX_DOCS:-false}
+      - CHECK_PY_DOCS_UP_TO_DATE=${CHECK_PY_DOCS_UP_TO_DATE:-false}
       - CHECK_COVERAGE=${CHECK_COVERAGE:-false}
       - CHECK_PEP8=${CHECK_PEP8:-false}
     volumes:
       # Host path is relative to current directory, not build-context
-      - ../..:${MOUNT_POINT:-/root}/git-machete
+      - ../..:/git-machete
diff --git a/ci/tox/local-run.sh b/ci/tox/local-run.sh
index 656ab94..e0702f8 100755
--- a/ci/tox/local-run.sh
+++ b/ci/tox/local-run.sh
@@ -10,7 +10,5 @@ check_var GIT_VERSION
 check_var PYTHON_VERSION
 
 set -x
-export TARGET=local
-export MOUNT_POINT=/home/ci-user
-docker-compose build --build-arg user_id="$(id -u)" --build-arg group_id="$(id -g)" tox
-docker-compose run tox
\ No newline at end of file
+docker-compose build tox
+docker-compose run -e GID="$(id -g)" -e UID="$(id -u)" tox
diff --git a/debian/.gitignore b/debian/.gitignore
index f3bf582..77af607 100644
--- a/debian/.gitignore
+++ b/debian/.gitignore
@@ -1,4 +1,4 @@
-# These files are automatically generated by ci/deb-ppa-upload/build-context/entrypoint.sh:
+# These files are automatically generated by ci/deb-ppa-upload/build-context/run.sh:
 # * debian/changelog from RELEASE_NOTES.md
 # * debian/copyright from LICENSE
 # * debian/files from debian/files.envsubst
diff --git a/debian/source/options b/debian/source/options
index c3d517b..79a4cd7 100644
--- a/debian/source/options
+++ b/debian/source/options
@@ -15,6 +15,7 @@ tar-ignore = .eggs
 tar-ignore = *.envsubst
 tar-ignore = graphics
 tar-ignore = .git
+tar-ignore = .github
 tar-ignore = .gitignore
 tar-ignore = hook_samples
 tar-ignore = htmlcov
@@ -27,12 +28,12 @@ tar-ignore = .mypy_cache
 tar-ignore = __pycache__
 tar-ignore = *.pyc
 tar-ignore = .python-version
-tar-ignore = .remarkrc.yml
-tar-ignore = .remarkrc_master.yml
+tar-ignore = requirements*.*txt
+tar-ignore = .remarkrc*.yml
 tar-ignore = RELEASE_NOTES.md
 tar-ignore = snap
 tar-ignore = *.swp
 tar-ignore = test-results
 tar-ignore = tests
 tar-ignore = .tox
-tar-ignore = tox.ini
\ No newline at end of file
+tar-ignore = tox.ini
diff --git a/docs/enforce-docs-up-to-date.sh b/docs/enforce-docs-up-to-date.sh
new file mode 100755
index 0000000..4869016
--- /dev/null
+++ b/docs/enforce-docs-up-to-date.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+set -e -o pipefail -u
+
+current_docs=$(<git_machete/generated_long_docs.py)
+generated_docs=$(python docs/generate_py_docs.py)
+
+if [[ "$current_docs" != "$generated_docs" ]]; then
+  echo "Command line docs are not up-to-date. Please regenerate docs via tox -e py-docs"
+  exit 1
+fi
diff --git a/docs/generate_py_docs.py b/docs/generate_py_docs.py
new file mode 100644
index 0000000..884cec8
--- /dev/null
+++ b/docs/generate_py_docs.py
@@ -0,0 +1,184 @@
+from bs4 import BeautifulSoup
+from docutils import core
+import os
+from os.path import isfile, join
+import re
+from textwrap import dedent, indent
+
+
+def rst2html(input_string: str, source_path: str = None, destination_path: str = None,
+             input_encoding: str = 'unicode', doctitle: bool = True,
+             initial_header_level: int = 1):
+    overrides = {'input_encoding': input_encoding,
+                 'doctitle_xform': doctitle,
+                 'initial_header_level': initial_header_level}
+    parts = core.publish_parts(
+        source=input_string, source_path=source_path,
+        destination_path=destination_path,
+        writer_name='html', settings_overrides=overrides)
+    return parts['body']
+
+
+def html2txt(html: str):
+    html_elements = BeautifulSoup(html, features="html.parser")
+    INDENT = 3 * ' '
+
+    # remove style tags
+    for tag in html_elements.select('style'):
+        tag.decompose()
+
+    # remove non-breaking spaces
+    for tag in html_elements.select('td'):
+        if tag.text == u'\xa0':
+            tag.decompose()
+
+    # substitute double backticks with a single backtick
+    for tag in html_elements.select('tt'):
+        tag.insert_before('`')
+        tag.insert_after('`')
+
+    # format cite's tag text with single backticks
+    for tag in html_elements.select('cite'):
+        tag.insert_before('`')
+        tag.insert_after('`')
+
+    # format colors
+    for tag in html_elements.select('span'):
+        if 'class' in tag.attrs:
+            color = ' '.join(tag.attrs['class']).replace('gray', 'dim')
+            if color in ['green', 'yellow', 'red', 'dim']:
+                tag.insert_before(f'<{color}>')
+                tag.insert_after(f'</{color}>')
+
+    # make the option's text inside the option list bold
+    for tag in html_elements.select('span'):
+        if 'class' in tag.attrs:
+            if ' '.join(tag.attrs['class']) == 'option':
+                tag.insert_before('<b>')
+                tag.insert_after('</b>')
+
+    # keep bold text bold
+    for tag in html_elements.select('strong'):
+        tag.insert_before('<b>')
+        tag.insert_after('</b>')
+
+    # add new lines after the paragraph tag
+    for tag in html_elements.select('p'):
+        if 'class' in tag.attrs:
+            if ' '.join(tag.attrs['class']) == 'first':
+                tag.insert_before(' ')
+            if 'admonition-title' in ' '.join(tag.attrs['class']):
+                tag.decompose()
+            else:
+                tag.insert_before('\n')
+        else:
+            tag.insert_before('\n\n')
+
+    # add indent and bullet points to the nested bulleted list
+    for tag in html_elements.select('li'):
+        if tag.parent.parent is not None:
+            if tag.parent.parent.name == 'li':
+                lines = tag.text.splitlines()
+                tag.string = f' - {lines[0]}'
+                if len(lines) > 1:
+                    tag.string += indent('\n' + '\n'.join(lines[1:]), INDENT)
+
+    # add indent and bullet points to the bulleted list
+    for tag in html_elements.select('li'):
+        if tag.parent.parent is not None:
+            if tag.parent.parent.name != 'li':
+                lines = tag.text.splitlines()
+                tag.string = f'\n{INDENT}* {lines[0]}'
+                if len(lines) > 1:
+                    tag.string += indent('\n' + '\n'.join(lines[1:]), INDENT + '  ')
+
+    # format elements in the `Option:` section by adding new line and indent
+    for tag in html_elements.select('kbd'):
+        tag.insert_before(f'\n{INDENT}')
+
+    # add indent to the description list
+    for tag in html_elements.select('dt'):
+        tag.string = '\n' + indent(tag.text.strip(), INDENT)
+
+    # add indent to the nested description list
+    for tag in html_elements.select('dd'):
+        tag.string = '\n' + indent(tag.text, 2 * INDENT) + '\n'
+
+    # add new line and indent for the cells inside a table (e.g. options inside **Options:** section)
+    for tag in html_elements.select('td'):
+        if 'class' not in tag.attrs:
+            tag.string = indent(f'\n{tag.text}', 2 * INDENT)
+
+    # format code examples
+    for tag in html_elements.select('pre'):
+        if 'class' in tag.attrs:
+            if ' '.join(tag.attrs['class']).replace('first', '').replace('last', '').replace('  ', ' ') == 'code literal-block':
+                tag.string = '\n<dim>' + indent(tag.text, '  ') + '</dim>'
+            elif 'literal-block' in ' '.join(tag.attrs['class']):
+                tag.string = '<b>' + indent(tag.text.rstrip('\n'), INDENT) + '</b>'
+
+    # build python docs string out of the previously formatted html tags
+    text: str = ''
+    for html_element in html_elements.descendants:
+        if isinstance(html_element, str):
+            if html_element != '\n':
+                new_text = html_element
+            else:
+                new_text = ''
+            text += new_text
+    return text
+
+
+def skip_or_replace_unparseable_directives(rst: str) -> str:
+    rst = rst.replace(':ref:', '')
+    return rst
+
+
+def resolve_includes(rst: str, docs_source_path: str) -> str:
+    matches = re.findall(r'(.*)\.\. include:: (.*)', rst)
+    for indent_, match in matches:
+        with open(f'{docs_source_path}/{match}', 'r') as handle:
+            include_text = handle.read()
+        rst = rst.replace(f'{indent_}.. include:: {match}', indent(dedent(include_text), indent_))
+    return rst
+
+
+def skip_prefix_new_lines(txt: str) -> str:
+    txt = re.sub(r'\A[\n]+', '', txt)
+    return txt
+
+
+def replace_3_newlines_and_more_with_2_newlines(txt: str) -> str:
+    for i in range(10, 2, -1):
+        txt = txt.replace(i * '\n', '\n\n')
+    return txt
+
+
+if __name__ == '__main__':
+    docs_source_path = 'docs/source'
+    warning_text = '# ---------------------------------------------------------------------------------------------------------\n' \
+                   '# Warning: This file is NOT supposed to be edited directly, ' \
+                   'but instead regenerated via tox -e docs\n' \
+                   '# ---------------------------------------------------------------------------------------------------------\n'
+    output_text = 'from typing import Dict\n\n' + warning_text + '\nlong_docs: Dict[str, str] = {\n'
+    path = docs_source_path + '/cli_help'
+    commands_and_file_paths = {f.split('.')[0]: join(path, f) for f in sorted(os.listdir(path)) if isfile(join(path, f))}
+
+    for command, file in commands_and_file_paths.items():
+        with open(file, 'r') as f:
+            rst = f.read()
+
+        rst = skip_or_replace_unparseable_directives(rst)
+        rst = resolve_includes(rst=rst, docs_source_path=docs_source_path)
+
+        html = rst2html(rst)
+
+        plain_text = html2txt(html)
+        plain_text = skip_prefix_new_lines(plain_text)
+        plain_text = plain_text.replace('---', '—')
+
+        output_text += f'    "{command}": """\n' + indent(plain_text, '        ') + '\n   """,\n'
+        output_text = replace_3_newlines_and_more_with_2_newlines(output_text)
+
+    output_text += '}'
+    print(output_text)
diff --git a/docs/source/cli_help/add.rst b/docs/source/cli_help/add.rst
index dba00c3..f644435 100644
--- a/docs/source/cli_help/add.rst
+++ b/docs/source/cli_help/add.rst
@@ -11,7 +11,8 @@ add
 Adds the provided <branch> (or the current branch, if none specified) to the definition file.
 If <branch> is provided but no local branch with the given name exists:
 
-    * if a remote branch of the same name exists in exactly one remote, then user is asked whether to check out this branch locally (as in ``git checkout``),
+    * if a remote branch of the same name exists in exactly one remote,
+      then user is asked whether to check out this branch locally (as in ``git checkout``),
     * otherwise, user is asked whether it should be created as a new local branch.
 
 If the definition file is empty or ``-R/--as-root`` is provided, the branch will be added as a root of the tree of branch dependencies.
@@ -23,8 +24,10 @@ Note: all the effects of ``add`` (except git branch creation) can as well be ach
 
 **Options:**
 
--o, --onto=<target-upstream-branch>    Specifies the target parent branch to add the given branch onto. Cannot be specified together with ``-R/--as-root``.
+-o, --onto=<target-upstream-branch>    Specifies the target parent branch to add the given branch onto.
+                                       Cannot be specified together with ``-R/--as-root``.
 
--R, --as-root                          Add the given branch as a new root (and not onto any other branch). Cannot be specified together with ``-o/--onto``.
+-R, --as-root                          Add the given branch as a new root (and not onto any other branch).
+                                       Cannot be specified together with ``-o/--onto``.
 
 -y, --yes                              Don't ask for confirmation whether to create the branch or whether to add onto the inferred upstream.
diff --git a/docs/source/cli_help/advance.rst b/docs/source/cli_help/advance.rst
index ce519be..ad0ec36 100644
--- a/docs/source/cli_help/advance.rst
+++ b/docs/source/cli_help/advance.rst
@@ -19,10 +19,12 @@ and subsequently slides out ``D``. All three steps require manual confirmation u
 
 The downstream ``D`` is selected according to the following criteria:
 
-    * if ``C`` has exactly one downstream (child) branch ``d`` connected with a :green:`green edge` (see :ref:`status` for definition) to ``C`` or is overridden, then ``d`` is selected as ``D``,
+    * if ``C`` has exactly one downstream (child) branch ``d`` connected with a :green:`green edge` (see help for :ref:`status`) to ``C``
+      or is overridden, then ``d`` is selected as ``D``,
     * if ``C`` has no downstream branches connected with a :green:`green edge` to ``C``, then ``advance`` fails,
     * if ``C`` has more than one downstream branch connected with a :green:`green edge` to ``C``,
-      then user is asked to pick the branch to fast-forward merge into (similarly to what happens in ``git machete go down``). If ``--yes`` is specified, then ``advance`` fails.
+      then user is asked to pick the branch to fast-forward merge into (similarly to what happens in ``git machete go down``).
+      If ``--yes`` is specified, then ``advance`` fails.
 
 As an example, if ``git machete status --color=never --list-commits`` is as follows:
 
@@ -34,18 +36,12 @@ As an example, if ``git machete status --color=never --list-commits`` is as foll
       |
       | Enable adding remote branch in the manner similar to git checkout
       o-feature/add-from-remote
-      | |
-      | | Add support and sample for machete-post-slide-out hook
-      | o-feature/post-slide-out-hook
-      |
-      | Remove support for Python 2
-      | Remove support for Python 2 --- 1st round of fixes
-      ?-chore/v3
-      |
-      | Apply Python2-compatible static typing
-      x-feature/types
+        |
+        | Add support and sample for machete-post-slide-out hook
+        o-feature/post-slide-out-hook
 
-then running ``git machete advance`` will fast-forward the current branch ``develop`` to match ``feature/add-from-remote``, and subsequently slide out the latter.
+then running ``git machete advance`` will fast-forward the current branch ``develop`` to match ``feature/add-from-remote``,
+and subsequently slide out the latter.
 After ``advance`` completes, ``status`` will show:
 
 .. code-block::
@@ -57,16 +53,10 @@ After ``advance`` completes, ``status`` will show:
       |
       | Add support and sample for machete-post-slide-out hook
       o-feature/post-slide-out-hook
-      |
-      | Remove support for Python 2
-      | Remove support for Python 2 --- 1st round of fixes
-      ?-chore/v3
-      |
-      | Apply Python2-compatible static typing
-      x-feature/types
 
 Note that the current branch after the operation is still ``develop``, just pointing to ``feature/add-from-remote``'s tip now.
 
 **Options:**
 
--y, --yes         Don't ask for confirmation whether to fast-forward the current branch or whether to slide-out the downstream. Fails if the current branch has more than one :green:`green-edge` downstream branch.
+-y, --yes         Don't ask for confirmation whether to fast-forward the current branch or whether to slide-out the downstream.
+                  Fails if the current branch has more than one :green:`green-edge` downstream branch.
diff --git a/docs/source/cli_help/anno.rst b/docs/source/cli_help/anno.rst
index 57f775a..b0875bf 100644
--- a/docs/source/cli_help/anno.rst
+++ b/docs/source/cli_help/anno.rst
@@ -9,7 +9,8 @@ anno
     git machete anno [-b|--branch=<branch>] [<annotation text>]
     git machete anno -H|--sync-github-prs
 
-If invoked without any <annotation text>, prints out the custom annotation for the given branch (or current branch, if none specified with ``-b/--branch``).
+If invoked without any <annotation text>, prints out the custom annotation for the given branch
+(or current branch, if none specified with ``-b/--branch``).
 
 If invoked with a single empty string <annotation text>, like:
 
diff --git a/docs/source/cli_help/clean.rst b/docs/source/cli_help/clean.rst
index 063df51..6772f7e 100644
--- a/docs/source/cli_help/clean.rst
+++ b/docs/source/cli_help/clean.rst
@@ -9,7 +9,9 @@ clean
     git machete clean [-c|--checkout-my-github-prs] [-y|--yes]
 
 Synchronizes with the remote repository:
-    1. if invoked with ``-H`` or ``--checkout-my-github-prs``, checks out open PRs for the current user associated with the GitHub token and also traverses the chain of pull requests upwards, adding branches one by one to git-machete and checks them out locally as well,
+
+    1. if invoked with ``-H`` or ``--checkout-my-github-prs``, checks out open PRs for the current user associated with the GitHub token
+       and also traverses the chain of pull requests upwards, adding branches one by one to git-machete and checks them out locally as well,
     2. deletes unmanaged branches,
     3. deletes untracked managed branches that have no downstream branch.
 
diff --git a/docs/source/cli_help/config.rst b/docs/source/cli_help/config.rst
index 4e99d05..df8bb6d 100644
--- a/docs/source/cli_help/config.rst
+++ b/docs/source/cli_help/config.rst
@@ -8,78 +8,34 @@ Note: ``config`` is not a command as such, just a help topic (there is no ``git
 
 **Config keys:**
 
-    * ``machete.github.{remote,organization,repository}``:
+``machete.github.{remote,organization,repository}``:
+    When executing ``git machete github <subcommand>`` command, the following will happen:
 
-        When executing ``git machete github <subcommand>`` command, GitHub API server URL will be inferred from ``git remote``.
-        You can override this by setting the following local git config keys:
+    .. include:: github_config_keys.rst
 
-            Remote name
-                E.g. ``machete.github.remote`` = ``origin``
+``machete.overrideForkPoint.<branch>.{to,whileDescendantOf}``:
+    Executing ``git machete fork-point --override-to=<revision> [<branch>]`` sets up a fork point override for <branch>.
+    The override data is stored under ``machete.overrideForkPoint.<branch>.to`` and
+    ``machete.overrideForkPoint.<branch>.whileDescendantOf`` git config keys.
 
-            Organization name
-                E.g. ``machete.github.organization`` = ``VirtusLab``
+``machete.status.extraSpaceBeforeBranchName``:
+    .. include:: status_config_key.rst
 
-            Repository name
-                E.g. ``machete.github.repository`` = ``git-machete``
-
-        To do this, run ``git config --local --edit`` and add the following section:
-
-        .. code-block:: ini
-
-            [machete "github"]
-                organization = <organization_name>
-                repository = <repo_name>
-                remote = <remote_name>
-
-    * ``machete.overrideForkPoint.<branch>.{to,whileDescendantOf}``
-
-        Executing ``git machete fork-point --override-to=<revision> [<branch>]`` sets up a fork point override for <branch>.
-        The override data is stored under ``machete.overrideForkPoint.<branch>.to`` and ``machete.overrideForkPoint.<branch>.whileDescendantOf`` git config keys.
-
-    * ``machete.status.extraSpaceBeforeBranchName``
-
-        To make it easier to select branch name from the ``status`` output on certain terminals
-        (e.g. `Alacritty <https://github.com/alacritty/alacritty>`_), you can add an extra
-        space between ``└─`` and ``branch name`` by setting ``git config machete.status.extraSpaceBeforeBranchName true``.
-
-        For example, by default it's:
-
-        .. code-block::
-
-          develop
-          │
-          ├─feature_branch1
-          │
-          └─feature_branch2
-
-        With ``machete.status.extraSpaceBeforeBranchName`` config set to ``true``:
-
-        .. code-block::
-
-           develop
-           │
-           ├─ feature_branch1
-           │
-           └─ feature_branch2
-
-    * ``machete.worktree.useTopLevelMacheteFile``
-
-        The default value of this key is ``true``, which means that the path to machete definition file will be ``.git/machete``
-        for both regular directory and worktree. If you want the worktree to have its own machete definition file (located under
-        ``.git/worktrees/.../machete``), set ``git config machete.worktree.useTopLevelMacheteFile false``.
+``machete.worktree.useTopLevelMacheteFile``:
+    The default value of this key is ``true``, which means that the path to machete definition file will be ``.git/machete``
+    for both regular directory and worktree. If you want the worktree to have its own machete definition file (located under
+    ``.git/worktrees/.../machete``), set ``git config machete.worktree.useTopLevelMacheteFile false``.
 
 
 **Environment variables:**
 
-    * ``GIT_MACHETE_EDITOR``
-
-        Name of the editor used by ``git machete e[dit]``, example: ``vim`` or ``nano``.
-
-    * ``GIT_MACHETE_REBASE_OPTS``
-
-        Used to pass extra options to the underlying ``git rebase`` invocation (called by the executed command, such as: ``reapply``, ``slide-out``, ``traverse``, ``update``)
-        Example: ``GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete update``.
+``GIT_MACHETE_EDITOR``
+    Name of the editor used by ``git machete e[dit]``, example: ``vim`` or ``nano``.
 
-    * ``GITHUB_TOKEN``
+``GIT_MACHETE_REBASE_OPTS``
+    Used to pass extra options to the underlying ``git rebase`` invocation (called by the executed command,
+    such as: ``reapply``, ``slide-out``, ``traverse``, ``update``)
+    Example: ``GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete update``.
 
-        Used to store GitHub API token. Used by commands such as: ``anno``, ``clean``, ``github``.
+``GITHUB_TOKEN``
+    Used to store GitHub API token. Used by commands such as: ``anno``, ``clean``, ``github``.
diff --git a/docs/source/cli_help/delete-unmanaged.rst b/docs/source/cli_help/delete-unmanaged.rst
index 802b411..bd5a5b6 100644
--- a/docs/source/cli_help/delete-unmanaged.rst
+++ b/docs/source/cli_help/delete-unmanaged.rst
@@ -12,8 +12,9 @@ Goes one-by-one through all the local git branches that don't exist in the defin
 and ask to delete each of them (with ``git branch -d`` or ``git branch -D``) if confirmed by user.
 No branch will be deleted unless explicitly confirmed by the user (or unless ``-y/--yes`` option is passed).
 
-Note: this should be used with care since deleting local branches can sometimes make it impossible for ``git machete`` to properly figure out fork points.
-See :ref:`fork-point` for more details.
+Note: this should be used with care since deleting local branches can sometimes make it impossible
+for ``git machete`` to properly figure out fork points.
+See help for :ref:`fork-point` for more details.
 
 **Options:**
 
diff --git a/docs/source/cli_help/diff.rst b/docs/source/cli_help/diff.rst
index c225bfc..5c32540 100644
--- a/docs/source/cli_help/diff.rst
+++ b/docs/source/cli_help/diff.rst
@@ -8,8 +8,9 @@ diff
 
     git machete d[iff] [-s|--stat] [<branch>]
 
-Runs ``git diff`` of the given branch tip against its fork point or, if none specified, of the current working tree against the fork point of the currently checked out branch.
-See :ref:`fork-point` for more details on meaning of the *fork point*.
+Runs ``git diff`` of the given branch tip against its fork point or, if none specified,
+of the current working tree against the fork point of the currently checked out branch.
+See help for :ref:`fork-point` for more details on the meaning of *fork point*.
 
 Note: the branch in question does not need to occur in the definition file.
 
diff --git a/docs/source/cli_help/discover.rst b/docs/source/cli_help/discover.rst
index 79cec4f..23a4b56 100644
--- a/docs/source/cli_help/discover.rst
+++ b/docs/source/cli_help/discover.rst
@@ -8,16 +8,24 @@ discover
 
     git machete discover [-C|--checked-out-since=<date>] [-l|--list-commits] [-r|--roots=<branch1>,<branch2>,...] [-y|--yes]
 
-Discovers and displays tree of branch dependencies using a heuristic based on reflogs and asks whether to overwrite the existing definition :ref:`file` with the new discovered tree.
-If confirmed with a ``y[es]`` or ``e[dit]`` reply, backs up the current definition file (if it exists) as ``$GIT_DIR/machete~`` and saves the new tree under the usual ``$GIT_DIR/machete`` path.
-If the reply was ``e[dit]``, additionally an editor is opened (as in :ref:`git machete edit<edit>`) after saving the new definition file.
+Discovers and displays tree of branch dependencies using a heuristic based on reflogs and asks whether to overwrite the existing definition
+:ref:`file` with the new discovered tree.
+If confirmed with a ``y[es]`` or ``e[dit]`` reply, backs up the current definition file (if it exists) as ``$GIT_DIR/machete~``
+and saves the new tree under the usual ``$GIT_DIR/machete`` path.
+If the reply was ``e[dit]``, additionally an editor is opened (as in: ``git machete`` :ref:`edit`) after saving the new definition file.
 
 **Options:**
 
--C, --checked-out-since=<date>   Only consider branches checked out at least once since the given date. <date> can be e.g. ``2 weeks ago`` or ``2020-06-01``, as in ``git log --since=<date>``. If not present, the date is selected automatically so that around 10 branches are included.
+-C, --checked-out-since=<date>   Only consider branches checked out at least once since the given date.
+                                 <date> can be e.g. ``2 weeks ago`` or ``2020-06-01``, as in ``git log --since=<date>``.
+                                 If not present, the date is selected automatically so that around 10 branches are included.
 
--l, --list-commits               When printing the discovered tree, additionally lists the messages of commits introduced on each branch (as for ``git machete status``).
+-l, --list-commits               When printing the discovered tree, additionally lists the messages of commits introduced on each branch
+                                 (as for ``git machete status``).
 
--r, --roots=<branch1,...>        Comma-separated list of branches that should be considered roots of trees of branch dependencies. If not present, ``master`` is assumed to be a root. Note that in the process of discovery, certain other branches can also be additionally deemed to be roots as well.
+-r, --roots=<branch1,...>        Comma-separated list of branches that should be considered roots of trees of branch dependencies.
+                                 If not present, ``master`` is assumed to be a root. Note that in the process of discovery,
+                                 certain other branches can also be additionally deemed to be roots as well.
 
--y, --yes                        Don't ask for confirmation before saving the newly-discovered tree. Mostly useful in scripts; not recommended for manual use.
+-y, --yes                        Don't ask for confirmation before saving the newly-discovered tree.
+                                 Mostly useful in scripts; not recommended for manual use.
diff --git a/docs/source/cli_help/file.rst b/docs/source/cli_help/file.rst
index 76b369d..59e536b 100644
--- a/docs/source/cli_help/file.rst
+++ b/docs/source/cli_help/file.rst
@@ -12,9 +12,13 @@ Outputs the absolute path of machete definition file.
 The file is always called ``machete`` and is located in the git directory of the project.
 
 Three cases are possible:
-    * if ``git machete`` is executed from a regular working directory (not a worktree or submodule), the file is located under ``.git/machete``,
-    * if ``git machete`` is executed from a **worktree**, the file path depends on the ``machete.worktree.useTopLevelMacheteFile`` config key value:
 
-        * if ``machete.worktree.useTopLevelMacheteFile`` is true (default), the file is located under ``.git/machete``
-        * if ``machete.worktree.useTopLevelMacheteFile`` is false, the file is located under ``.git/worktrees/.../machete``,
+    * if ``git machete`` is executed from a regular working directory (not a worktree or submodule),
+      the file is located under ``.git/machete``,
+    * if ``git machete`` is executed from a **worktree**,
+      the file path depends on the ``machete.worktree.useTopLevelMacheteFile`` config key value:
+
+      - if ``machete.worktree.useTopLevelMacheteFile`` is true (default), the file is located under ``.git/machete``
+      - if ``machete.worktree.useTopLevelMacheteFile`` is false, the file is located under ``.git/worktrees/.../machete``,
+
     * if ``git machete`` is executed from a **submodule**, this file is located in the git folder of the submodule itself under ``.git/modules/.../machete``.
diff --git a/docs/source/cli_help/format.rst b/docs/source/cli_help/format.rst
index 8139bd4..72e718b 100644
--- a/docs/source/cli_help/format.rst
+++ b/docs/source/cli_help/format.rst
@@ -25,7 +25,7 @@ Branches ``adjust-reads-prec``, ``edit-margin-not-allowed`` and ``grep-errors-sc
 
 Every branch name can be followed (after a single space as a delimiter) by a custom annotation --- a PR number in the above example.
 The annotations don't influence the way ``git machete`` operates other than that they are displayed in the output of the ``status`` command.
-Also see :ref:`anno` command.
+Also see help for :ref:`anno` command.
 
 Tabs or any number of spaces can be used as indentation.
 It's only important to be consistent wrt. the sequence of characters used for indentation between all lines.
diff --git a/docs/source/cli_help/github.rst b/docs/source/cli_help/github.rst
index 31fafa3..b6f4a86 100644
--- a/docs/source/cli_help/github.rst
+++ b/docs/source/cli_help/github.rst
@@ -15,62 +15,56 @@ Creates, checks out and manages GitHub PRs while keeping them reflected in branc
 .. include:: github_api_access.rst
 .. include:: github_config_keys.rst
 
-``anno-prs``:
+**Subcommands:**
 
-  Annotates the branches based on their corresponding GitHub PR numbers and authors.
-  Any existing annotations are overwritten for the branches that have an opened PR; annotations for the other branches remain untouched.
-  Equivalent to ``git machete anno --sync-github-prs``.
+``anno-prs``:
+    Annotates the branches based on their corresponding GitHub PR numbers and authors.
+    Any existing annotations are overwritten for the branches that have an opened PR; annotations for the other branches remain untouched.
+    Equivalent to ``git machete anno --sync-github-prs``.
 
 
 ``checkout-prs [--all | --by=<github-login> | --mine | <PR-number-1> ... <PR-number-N>]``:
+    Check out the head branch of the given pull requests (specified by numbers or by a flag),
+    also traverse chain of pull requests upwards, adding branches one by one to git-machete and check them out locally.
+    Once the specified pull requests are checked out locally, annotate local branches with corresponding pull request numbers.
+    If only one PR has been checked out, then switch the local repository's HEAD to its head branch.
 
-  Check out the head branch of the given pull requests (specified by numbers or by a flag),
-  also traverse chain of pull requests upwards, adding branches one by one to git-machete and check them out locally.
-  Once the specified pull requests are checked out locally, annotate local branches with corresponding pull request numbers.
-  If only one PR has been checked out, then switch the local repository's HEAD to its head branch.
-
-  **Options:**
+    **Options:**
 
-    ``--all``    Checkout all open PRs.
+    --all                   Checkout all open PRs.
 
-    ``--by``    Checkout open PRs authored by the given GitHub user.
+    --by=<github-login>     Checkout open PRs authored by the given GitHub user, where ``<github-login>`` is the GitHub account name.
 
-      **Parameters:**
-        ``<github-login>`` GitHub account name.
+    --mine                  Checkout open PRs for the current user associated with the GitHub token.
 
-    ``--mine``    Checkout open PRs for the current user associated with the GitHub token.
+    **Parameters:**
 
-  **Parameters:**
-    ``<PR-number-1> ... <PR-number-N>``
-      Pull request numbers to checkout.
+    ``<PR-number-1> ... <PR-number-N>``    Pull request numbers to checkout.
 
 ``create-pr [--draft]``:
+    Creates a PR for the current branch, using the upstream (parent) branch as the PR base.
+    Once the PR is successfully created, annotates the current branch with the new PR's number.
 
-  Creates a PR for the current branch, using the upstream (parent) branch as the PR base.
-  Once the PR is successfully created, annotates the current branch with the new PR's number.
+    If ``.git/info/description`` file is present, its contents are used as PR description.
+    If ``.git/info/milestone`` file is present, its contents (a single number --- milestone id) are used as milestone.
+    If ``.git/info/reviewers`` file is present, its contents (one GitHub login per line) are used to set reviewers.
 
-  If ``.git/info/description`` file is present, its contents are used as PR description.
-  If ``.git/info/milestone`` file is present, its contents (a single number --- milestone id) are used as milestone.
-  If ``.git/info/reviewers`` file is present, its contents (one GitHub login per line) are used to set reviewers.
+    **Options:**
 
-  **Options:**
-
-    ``--draft``
-      Creates the new PR as a draft.
+    --draft    Creates the new PR as a draft.
 
 ``retarget-pr``:
-
-  Sets the base of the current branch's PR to upstream (parent) branch, as seen by git machete (see ``git machete show up``).
+    Sets the base of the current branch's PR to upstream (parent) branch, as seen by git machete (see ``git machete show up``).
 
 ``sync``:
+    Synchronizes with the remote repository:
 
-  Synchronizes with the remote repository:
-
-    1. checks out open PRs for the current user associated with the GitHub token and also traverses the chain of pull requests upwards, adding branches one by one to git-machete and checks them out locally as well,
-    2. deletes unmanaged branches,
-    3. deletes untracked managed branches that have no downstream branch.
+      1. checks out open PRs for the current user associated with the GitHub token and also traverses the chain of pull requests upwards,
+         adding branches one by one to git-machete and checks them out locally as well,
+      2. deletes unmanaged branches,
+      3. deletes untracked managed branches that have no downstream branch.
 
-  Equivalent of ``git machete clean --checkout-my-github-prs``.
+    Equivalent of ``git machete clean --checkout-my-github-prs``.
 
 **Environment variables (all subcommands):**
 
diff --git a/docs/source/cli_help/go.rst b/docs/source/cli_help/go.rst
index 22a1f2f..bebff0b 100644
--- a/docs/source/cli_help/go.rst
+++ b/docs/source/cli_help/go.rst
@@ -13,11 +13,15 @@ where <direction> is one of: ``d[own]``, ``f[irst]``, ``l[ast]``, ``n[ext]``, ``
 Checks out the branch specified by the given direction relative to the current branch:
 
     * ``down``:    the direct children/downstream branch of the current branch.
-    * ``first``:   the first downstream of the root branch of the current branch (like ``root`` followed by ``next``), or the root branch itself if the root has no downstream branches.
-    * ``last``:    the last branch in the definition file that has the same root as the current branch; can be the root branch itself if the root has no downstream branches.
+    * ``first``:   the first downstream of the root branch of the current branch (like ``root`` followed by ``next``),
+      or the root branch itself if the root has no downstream branches.
+    * ``last``:    the last branch in the definition file that has the same root as the current branch;
+      can be the root branch itself if the root has no downstream branches.
     * ``next``:    the direct successor of the current branch in the definition file.
     * ``prev``:    the direct predecessor of the current branch in the definition file.
-    * ``root``:    the root of the tree where the current branch is located. Note: this will typically be something like ``develop`` or ``master``, since all branches are usually meant to be ultimately merged to one of those.
+    * ``root``:    the root of the tree where the current branch is located.
+      Note: this will typically be something like ``develop`` or ``master``,
+      since all branches are usually meant to be ultimately merged to one of those.
     * ``up``:      the direct parent/upstream branch of the current branch.
 
 Roughly equivalent to ``git checkout $(git machete show <direction>)``.
diff --git a/docs/source/cli_help/hooks.rst b/docs/source/cli_help/hooks.rst
index ed99c23..cafc921 100644
--- a/docs/source/cli_help/hooks.rst
+++ b/docs/source/cli_help/hooks.rst
@@ -7,16 +7,19 @@ All hooks are executed from the top-level folder of the repository (or top-level
 
 Note: ``hooks`` is not a command as such, just a help topic (there is no ``git machete hooks`` command).
 
-* ``machete-post-slide-out <new-upstream> <lowest-slid-out-branch> [<new-downstreams>...]``
+**Hooks:**
 
+``machete-post-slide-out <new-upstream> <lowest-slid-out-branch> [<new-downstreams>...]``
     The hook that is executed after a branch (or possibly multiple branches, in case of ``slide-out``)
     is slid out by ``advance``, ``slide-out`` or ``traverse``.
 
     At least two parameters (branch names) are passed to the hook:
 
-        * <new-upstream> is the upstream of the branch that has been slid out, or in case of multiple branches being slid out --- the upstream of the highest slid out branch;
+        * <new-upstream> is the upstream of the branch that has been slid out, or in case of multiple branches being slid out
+          --- the upstream of the highest slid out branch;
         * <lowest-slid-out-branch> is the branch that has been slid out, or in case of multiple branches being slid out --- the lowest slid out branch;
-        * <new-downstreams> are all the following (possibly zero) parameters, which correspond to all original downstreams of <lowest-slid-out-branch>, now reattached as the downstreams of <new-upstream>.
+        * <new-downstreams> are all the following (possibly zero) parameters, which correspond to all original downstreams
+          of <lowest-slid-out-branch>, now reattached as the downstreams of <new-upstream>.
 
     Note that this may be zero, one, or multiple branches.
 
@@ -34,8 +37,7 @@ Note: ``hooks`` is not a command as such, just a help topic (there is no ``git m
     Note that non-zero exit code of the hook doesn't cancel the effects of slide-out itself, only the subsequent operations.
     The hook is executed only once the slide-out is complete and can in fact rely on .git/machete file being updated to the new branch layout.
 
-* ``machete-pre-rebase <new-base> <fork-point-hash> <branch-being-rebased>``
-
+``machete-pre-rebase <new-base> <fork-point-hash> <branch-being-rebased>``
     The hook that is executed before rebase is run during ``reapply``, ``slide-out``, ``traverse`` and ``update``.
     Note that it is NOT executed by ``squash`` (despite its similarity to ``reapply``), since no rebase is involved in ``squash``.
 
@@ -51,15 +53,16 @@ Note: ``hooks`` is not a command as such, just a help topic (there is no ``git m
     If machete-pre-rebase returns zero, the execution flow continues to ``git rebase``, which may also run ``pre-rebase hook`` if present.
     ``machete-pre-rebase`` is thus always launched before ``pre-rebase``.
 
-* ``machete-status-branch <branch-name>``
-
+``machete-status-branch <branch-name>``
     The hook that is executed for each branch displayed during ``discover``, ``status`` and ``traverse``.
 
-    The standard output of this hook is displayed at the end of the line, after branch name, (optionally) custom annotation and (optionally) remote sync-ness status.
-    Standard error is ignored. If the hook returns a non-zero exit code, both stdout and stderr are ignored, and printing the status continues as usual.
+    The standard output of this hook is displayed at the end of the line, after branch name, (optionally) custom annotation and
+    (optionally) remote sync-ness status. Standard error is ignored. If the hook returns a non-zero exit code, both stdout and stderr
+    are ignored, and printing the status continues as usual.
 
     Note: the hook is always invoked with ``ASCII_ONLY`` variable passed into the environment.
-    If ``status`` runs in ASCII-only mode (i.e. if ``--color=auto`` and stdout is not a terminal, or if ``--color=never``), then ``ASCII_ONLY=true``, otherwise ``ASCII_ONLY=false``.
+    If ``status`` runs in ASCII-only mode (i.e. if ``--color=auto`` and stdout is not a terminal, or if ``--color=never``),
+    then ``ASCII_ONLY=true``, otherwise ``ASCII_ONLY=false``.
 
-Please see `hook_samples <https://github.com/VirtusLab/git-machete/tree/master/hook_samples>`_ for examples.
+Please see `hook_samples <https://github.com/VirtusLab/git-machete/tree/master/hook_samples>`_ directory in git-machete project for examples.
 An example of using the standard git ``post-commit hook`` to ``git machete add`` branches automatically is also included.
diff --git a/docs/source/cli_help/list.rst b/docs/source/cli_help/list.rst
index 6402287..d21fd8e 100644
--- a/docs/source/cli_help/list.rst
+++ b/docs/source/cli_help/list.rst
@@ -16,8 +16,10 @@ Lists all branches that fall into one of the specified categories:
     * ``childless``: all branches that do not possess child branches,
     * ``managed``: all branches that appear in the definition file,
     * ``slidable``: all managed branches that have an upstream and can be slid out with :ref:`slide-out` command
-    * ``slidable-after <branch>``: the downstream branch of the <branch>, if it exists and is the only downstream of <branch> (i.e. the one that can be slid out immediately following <branch>),
+    * ``slidable-after <branch>``: the downstream branch of the <branch>, if it exists and is the only downstream of <branch>
+      (i.e. the one that can be slid out immediately following <branch>),
     * ``unmanaged``: all local branches that don't appear in the definition file,
-    * ``with-overridden-fork-point``: all local branches that have a :ref:`fork point<fork-point>` override set up (even if this override does not affect the location of their fork point anymore).
+    * ``with-overridden-fork-point``: all local branches that have a :ref:`fork point<fork-point>` override set up
+      (even if this override does not affect the location of their fork point anymore).
 
 This command is generally not meant for a day-to-day use, it's mostly needed for the sake of branch name completion in shell.
diff --git a/docs/source/cli_help/log.rst b/docs/source/cli_help/log.rst
index 489e4ea..cdcc0b3 100644
--- a/docs/source/cli_help/log.rst
+++ b/docs/source/cli_help/log.rst
@@ -9,6 +9,6 @@ log
     git machete l[og] [<branch>]
 
 Runs ``git log`` for the range of commits from tip of the given branch (or current branch, if none specified) back to its fork point.
-See :ref:`fork-point` for more details on meaning of the *fork point*.
+See help for :ref:`fork-point` for more details on meaning of the *fork point*.
 
 Note: the branch in question does not need to occur in the definition file.
diff --git a/docs/source/cli_help/reapply.rst b/docs/source/cli_help/reapply.rst
index ff42262..a315c65 100644
--- a/docs/source/cli_help/reapply.rst
+++ b/docs/source/cli_help/reapply.rst
@@ -9,8 +9,9 @@ reapply
     git machete reapply [-f|--fork-point=<fork-point-commit>]
 
 Interactively rebase the current branch on the top of its computed fork point.
-The chunk of the history to be rebased starts at the automatically computed fork point of the current branch by default, but can also be set explicitly by ``--fork-point``.
-See :ref:`fork-point` for more details on meaning of the *fork point*.
+The chunk of the history to be rebased starts at the automatically computed fork point of the current branch by default,
+but can also be set explicitly by ``--fork-point``.
+See help for :ref:`fork-point` for more details on meaning of the *fork point*.
 
 Note: the current reapplied branch does not need to occur in the definition file.
 
@@ -25,5 +26,4 @@ but there is also dedicated ``squash`` command that achieves the same goal witho
 
 ``GIT_MACHETE_REBASE_OPTS``
     Extra options to pass to the underlying ``git rebase`` invocation, space-separated.
-
     Example: ``GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete reapply``.
diff --git a/docs/source/cli_help/show.rst b/docs/source/cli_help/show.rst
index 646648e..645a6c2 100644
--- a/docs/source/cli_help/show.rst
+++ b/docs/source/cli_help/show.rst
@@ -15,9 +15,13 @@ Outputs name of the branch (or possibly multiple branches, in case of ``down``)
 
     * ``current``: the current branch; exits with a non-zero status if none (detached HEAD)
     * ``down``:    the direct children/downstream branch of the given branch.
-    * ``first``:   the first downstream of the root branch of the given branch (like ``root`` followed by ``next``), or the root branch itself if the root has no downstream branches.
-    * ``last``:    the last branch in the definition file that has the same root as the given branch; can be the root branch itself if the root has no downstream branches.
+    * ``first``:   the first downstream of the root branch of the given branch (like ``root`` followed by ``next``),
+      or the root branch itself if the root has no downstream branches.
+    * ``last``:    the last branch in the definition file that has the same root as the given branch; can be the root branch itself
+      if the root has no downstream branches.
     * ``next``:    the direct successor of the given branch in the definition file.
     * ``prev``:    the direct predecessor of the given branch in the definition file.
-    * ``root``:    the root of the tree where the given branch is located. Note: this will typically be something like ``develop`` or ``master``, since all branches are usually meant to be ultimately merged to one of those.
+    * ``root``:    the root of the tree where the given branch is located.
+      Note: this will typically be something like ``develop`` or ``master``,
+      since all branches are usually meant to be ultimately merged to one of those.
     * ``up``:      the direct parent/upstream branch of the given branch.
diff --git a/docs/source/cli_help/slide-out.rst b/docs/source/cli_help/slide-out.rst
index 6931df6..8be3905 100644
--- a/docs/source/cli_help/slide-out.rst
+++ b/docs/source/cli_help/slide-out.rst
@@ -46,21 +46,27 @@ Note: This command doesn't delete any branches from git, just removes them from
 
 **Options:**
 
--d, --down-fork-point=<down-fork-point-commit>    If updating by rebase, specifies the alternative fork point for downstream branches for the operation. ``git machete fork-point`` overrides for downstream branches are recommended over use of this option. See also doc for ``--fork-point`` option in ``git machete help reapply`` and ``git machete help update``. Not allowed if updating by merge.
+-d, --down-fork-point=<down-fork-point-commit>    If updating by rebase, specifies the alternative fork point for downstream branches for the operation.
+                                                  ``git machete fork-point`` overrides for downstream branches are recommended over use of this option.
+                                                  See also doc for ``--fork-point`` option in ``git machete help reapply`` and ``git machete help update``.
+                                                  Not allowed if updating by merge.
 
 --delete                                          Delete the slid-out branches.
 
 -M, --merge                                       Update the downstream branch by merge rather than by rebase.
 
--n                                                If updating by rebase, equivalent to ``--no-interactive-rebase``. If updating by merge, equivalent to ``--no-edit-merge``.
+-n                                                If updating by rebase, equivalent to ``--no-interactive-rebase``.
+                                                  If updating by merge, equivalent to ``--no-edit-merge``.
 
---no-edit-merge                                   If updating by merge, skip opening the editor for merge commit message while doing ``git merge`` (i.e. pass ``--no-edit`` flag to underlying ``git merge``). Not allowed if updating by rebase.
+--no-edit-merge                                   If updating by merge, skip opening the editor for merge commit message while doing
+                                                  ``git merge`` (i.e. pass ``--no-edit`` flag to underlying ``git merge``).
+                                                  Not allowed if updating by rebase.
 
---no-interactive-rebase                           If updating by rebase, run ``git rebase`` in non-interactive mode (without ``-i/--interactive`` flag). Not allowed if updating by merge.
+--no-interactive-rebase                           If updating by rebase, run ``git rebase`` in non-interactive mode (without ``-i/--interactive`` flag).
+                                                  Not allowed if updating by merge.
 
 **Environment variables:**
 
 ``GIT_MACHETE_REBASE_OPTS``
     Extra options to pass to the underlying ``git rebase`` invocations, space-separated.
-
     Example: ``GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete slide-out``.
diff --git a/docs/source/cli_help/squash.rst b/docs/source/cli_help/squash.rst
index 597e939..36c951c 100644
--- a/docs/source/cli_help/squash.rst
+++ b/docs/source/cli_help/squash.rst
@@ -9,8 +9,9 @@ squash
     git machete squash [-f|--fork-point=<fork-point-commit>]
 
 Squashes the commits belonging uniquely to the current branch into a single commit.
-The chunk of the history to be squashed starts at the automatically computed fork point of the current branch by default, but can also be set explicitly by ``--fork-point``.
-See :ref:`fork-point` for more details on meaning of the *fork point*.
+The chunk of the history to be squashed starts at the automatically computed fork point of the current branch by default,
+but can also be set explicitly by ``--fork-point``.
+See help for :ref:`fork-point` for more details on meaning of the *fork point*.
 The message for the squashed is taken from the earliest squashed commit, i.e. the commit directly following the fork point.
 
 Note: the current squashed branch does not need to occur in the definition file.
diff --git a/docs/source/cli_help/status.rst b/docs/source/cli_help/status.rst
index f8286f0..e83cf23 100644
--- a/docs/source/cli_help/status.rst
+++ b/docs/source/cli_help/status.rst
@@ -38,11 +38,12 @@ Apart from simply ASCII-formatting the definition file, this also:
         detected by commit equivalency (default), or by strict detection of merge commits (if ``--no-detect-squash-merges`` passed).
 
 
-    * prints (``untracked``/``ahead of <remote>``/``behind <remote>``/``diverged from [& older than] <remote>``) message if the branch is not in sync with its remote counterpart;
+    * prints (``untracked``/``ahead of <remote>``/``behind <remote>``/``diverged from [& older than] <remote>``) message if the branch
+      is not in sync with its remote counterpart;
 
-    * displays the custom annotations (see :ref:`format` and :ref:`anno`) next to each branch, if present;
+    * displays the custom annotations (see help for :ref:`format` and :ref:`anno`) next to each branch, if present;
 
-    * displays the output of ``machete-status-branch hook`` (see :ref:`hooks`), if present;
+    * displays the output of ``machete-status-branch hook`` (see help for :ref:`hooks`), if present;
 
     * optionally lists commits introduced on each branch if ``-l/--list-commits`` or ``-L/--list-commits-with-hashes`` is supplied.
 
@@ -50,9 +51,9 @@ Name of the currently checked-out branch is underlined (or shown in blue on term
 
 In case of :yellow:`yellow edge`, use ``-l`` or ``-L`` flag to show the exact location of the inferred fork point
 (which indicates e.g. what range of commits is going to be rebased when the branch is updated).
-The inferred fork point can be always overridden manually, see :ref:`fork-point`.
+The inferred fork point can be always overridden manually, see help for :ref:`fork-point`.
 
-:grey:`Grey/dimmed edge` suggests that the downstream branch can be slid out (see :ref:`slide-out` and :ref:`traverse`).
+:grey:`Grey/dimmed edge` suggests that the downstream branch can be slid out (see help for :ref:`slide-out` and :ref:`traverse`).
 
 Using colors can be disabled with a ``--color`` flag set to ``never``.
 With ``--color=always``, git machete always emits colors and with ``--color=auto``, it emits colors only when standard output is connected to a terminal.
@@ -70,6 +71,7 @@ With ``--color=always``, git machete always emits colors and with ``--color=auto
     |
     m-<branch4>     # grey (merged to parent)
 
+
 **Options:**
 
 --color=WHEN                      Colorize the output; WHEN can be ``always``, ``auto`` (default; i.e. only if stdout is a terminal), or ``never``.
@@ -78,30 +80,10 @@ With ``--color=always``, git machete always emits colors and with ``--color=auto
 
 -L, --list-commits-with-hashes    Additionally list the short hashes and messages of commits introduced on each branch.
 
---no-detect-squash-merges         Only consider *strict* (fast-forward or 2-parent) merges, rather than rebase/squash merges, when detecting if a branch is merged into its upstream (parent).
-
- .. note::
-
-    To make it easier to select branch name from the ``status`` output on certain terminals
-    (e.g. `Alacritty <https://github.com/alacritty/alacritty>`_), you can add an extra
-    space between ``└─`` and ``branch name`` by setting ``git config machete.status.extraSpaceBeforeBranchName true``.
-
-    For example, by default the status is displayed as:
-
-    .. code-block::
-
-      develop
-      │
-      ├─feature_branch1
-      │
-      └─feature_branch2
-
-    With ``machete.status.extraSpaceBeforeBranchName`` config set to ``true``:
+--no-detect-squash-merges         Only consider *strict* (fast-forward or 2-parent) merges, rather than rebase/squash merges,
+                                  when detecting if a branch is merged into its upstream (parent).
 
-    .. code-block::
+**Config keys:**
 
-       develop
-       │
-       ├─ feature_branch1
-       │
-       └─ feature_branch2
+``machete.status.extraSpaceBeforeBranchName``
+    .. include:: status_config_key.rst
diff --git a/docs/source/cli_help/traverse.rst b/docs/source/cli_help/traverse.rst
index f87355c..f3d3b0a 100644
--- a/docs/source/cli_help/traverse.rst
+++ b/docs/source/cli_help/traverse.rst
@@ -34,12 +34,13 @@ For each branch, the command:
       - by commit equivalency (default), or by strict detection of merge commits (if ``--no-detect-squash-merges`` passed),
       - if so, asks the user whether to slide out the branch from the dependency tree (typically branches are no longer needed after they're merged);
 
-    * otherwise, if the branch has a :red:`red` or :yellow:`yellow` edge to its parent/upstream (see :ref:`status`):
+    * otherwise, if the branch has a :red:`red` or :yellow:`yellow` edge to its parent/upstream (see help for :ref:`status`):
 
       - asks the user whether to rebase (default) or merge (if ``--merge`` passed) the branch onto into its upstream branch
         --- equivalent to ``git machete update`` with no ``--fork-point`` option passed;
 
-    * if the branch is not tracked on a remote, is ahead of its remote counterpart, or diverged from the counterpart & has newer head commit than the counterpart:
+    * if the branch is not tracked on a remote, is ahead of its remote counterpart, or diverged from the counterpart &
+      has newer head commit than the counterpart:
 
       - asks the user whether to push the branch (possibly with ``--force-with-lease`` if the branches diverged);
 
@@ -70,11 +71,14 @@ Unlike with e.g. ``git rebase``, there is no special ``--continue`` flag, as ``t
 
 -n                           If updating by rebase, equivalent to ``--no-interactive-rebase``. If updating by merge, equivalent to ``--no-edit-merge``.
 
---no-detect-squash-merges    Only consider *strict* (fast-forward or 2-parent) merges, rather than rebase/squash merges, when detecting if a branch is merged into its upstream (parent).
+--no-detect-squash-merges    Only consider *strict* (fast-forward or 2-parent) merges, rather than rebase/squash merges,
+                             when detecting if a branch is merged into its upstream (parent).
 
---no-edit-merge              If updating by merge, skip opening the editor for merge commit message while doing ``git merge`` (i.e. pass ``--no-edit`` flag to the underlying ``git merge``). Not allowed if updating by rebase.
+--no-edit-merge              If updating by merge, skip opening the editor for merge commit message while doing ``git merge``
+                             (i.e. pass ``--no-edit`` flag to the underlying ``git merge``). Not allowed if updating by rebase.
 
---no-interactive-rebase      If updating by rebase, run ``git rebase`` in non-interactive mode (without ``-i/--interactive`` flag). Not allowed if updating by merge.
+--no-interactive-rebase      If updating by rebase, run ``git rebase`` in non-interactive mode (without ``-i/--interactive`` flag).
+                             Not allowed if updating by merge.
 
 --no-push                    Do not push any (neither tracked nor untracked) branches to remote, re-enable via ``--push``.
 
@@ -84,11 +88,19 @@ Unlike with e.g. ``git rebase``, there is no special ``--continue`` flag, as ``t
 
 --push-untracked             Push untracked branches to remote --- default behavior.
 
---return-to=WHERE            Specifies the branch to return after traversal is successfully completed; WHERE can be ``here`` (the current branch at the moment when traversal starts), ``nearest-remaining`` (nearest remaining branch in case the ``here`` branch has been slid out by the traversal) or ``stay`` (the default --- just stay wherever the traversal stops). Note: when user quits by ``q``/``yq`` or when traversal is stopped because one of git actions fails, the behavior is always ``stay``.
+--return-to=WHERE            Specifies the branch to return after traversal is successfully completed;
+                             WHERE can be ``here`` (the current branch at the moment when traversal starts), ``nearest-remaining``
+                             (nearest remaining branch in case the ``here`` branch has been slid out by the traversal) or
+                             ``stay`` (the default --- just stay wherever the traversal stops). Note: when user quits by ``q``/``yq``
+                             or when traversal is stopped because one of git actions fails, the behavior is always ``stay``.
 
---start-from=WHERE           Specifies the branch to start the traversal from; WHERE can be ``here`` (the default --- current branch, must be managed by git machete), ``root`` (root branch of the current branch, as in ``git machete show root``) or ``first-root`` (first listed managed branch).
+--start-from=WHERE           Specifies the branch to start the traversal from; WHERE can be ``here``
+                             (the default --- current branch, must be managed by git machete), ``root`` (root branch of the current branch,
+                             as in ``git machete show root``) or ``first-root`` (first listed managed branch).
 
--w, --whole                  Equivalent to ``-n --start-from=first-root --return-to=nearest-remaining``; useful for quickly traversing & syncing all branches (rather than doing more fine-grained operations on the local section of the branch tree).
+-w, --whole                  Equivalent to ``-n --start-from=first-root --return-to=nearest-remaining``;
+                             useful for quickly traversing & syncing all branches (rather than doing more fine-grained operations on the
+                             local section of the branch tree).
 
 -W                           Equivalent to ``--fetch --whole``; useful for even more automated traversal of all branches.
 
@@ -98,5 +110,4 @@ Unlike with e.g. ``git rebase``, there is no special ``--continue`` flag, as ``t
 
 ``GIT_MACHETE_REBASE_OPTS``
     Extra options to pass to the underlying ``git rebase`` invocations, space-separated.
-
     Example: ``GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete traverse``.
diff --git a/docs/source/cli_help/update.rst b/docs/source/cli_help/update.rst
index 8260a7e..aa8e2cb 100644
--- a/docs/source/cli_help/update.rst
+++ b/docs/source/cli_help/update.rst
@@ -11,26 +11,30 @@ update
 Synchronizes the current branch with its upstream (parent) branch either by rebase (default) or by merge (if ``--merge`` option passed).
 
 If updating by rebase, interactively rebases the current branch on the top of its upstream (parent) branch.
-The chunk of the history to be rebased starts at the fork point of the current branch, which by default is inferred automatically, but can also be set explicitly by ``--fork-point``.
-See :ref:`fork-point` for more details on meaning of the *fork point*.
+The chunk of the history to be rebased starts at the fork point of the current branch, which by default is inferred automatically,
+but can also be set explicitly by ``--fork-point``.
+See help for :ref:`fork-point` for more details on the meaning of *fork point*.
 
 If updating by merge, merges the upstream (parent) branch into the current branch.
 
 **Options:**
 
--f, --fork-point=<fork-point-commit>    If updating by rebase, specifies the alternative fork point commit after which the rebased part of history is meant to start. Not allowed if updating by merge.
+-f, --fork-point=<fork-point-commit>    If updating by rebase, specifies the alternative fork point commit after which the rebased
+                                        part of history is meant to start. Not allowed if updating by merge.
 
 -M, --merge                             Update by merge rather than by rebase.
 
--n                                      If updating by rebase, equivalent to ``--no-interactive-rebase``. If updating by merge, equivalent to ``--no-edit-merge``.
+-n                                      If updating by rebase, equivalent to ``--no-interactive-rebase``.
+                                        If updating by merge, equivalent to ``--no-edit-merge``.
 
---no-edit-merge                         If updating by merge, skip opening the editor for merge commit message while doing ``git merge`` (i.e. pass ``--no-edit`` flag to underlying ``git merge``). Not allowed if updating by rebase.
+--no-edit-merge                         If updating by merge, skip opening the editor for merge commit message while doing ``git merge``
+                                        (i.e. pass ``--no-edit`` flag to underlying ``git merge``). Not allowed if updating by rebase.
 
---no-interactive-rebase                 If updating by rebase, run ``git rebase`` in non-interactive mode (without ``-i/--interactive`` flag). Not allowed if updating by merge.
+--no-interactive-rebase                 If updating by rebase, run ``git rebase`` in non-interactive mode (without ``-i/--interactive`` flag).
+                                        Not allowed if updating by merge.
 
 **Environment variables:**
 
 ``GIT_MACHETE_REBASE_OPTS``
     Extra options to pass to the underlying ``git rebase`` invocation, space-separated.
-
     Example: ``GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete update``.
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 340151c..5fc2014 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -48,7 +48,8 @@ exclude_patterns = [
     'description.rst',
     'learning_materials.rst',
     'github_api_access.rst',
-    'github_config_keys.rst'
+    'github_config_keys.rst',
+    'status_config_key.rst'
 ]
 
 
diff --git a/docs/source/github_api_access.rst b/docs/source/github_api_access.rst
index 45fdf71..e0b9b0b 100644
--- a/docs/source/github_api_access.rst
+++ b/docs/source/github_api_access.rst
@@ -1,7 +1,8 @@
  .. note::
 
-    To allow GitHub API access for private repositories (and also to perform side-effecting actions like opening a PR, even in case of public repositories),
-    a GitHub API token with ``repo`` scope is required, see https://github.com/settings/tokens. This will be resolved from the first of:
+    To allow GitHub API access for private repositories (and also to perform side-effecting actions like opening a PR,
+    even in case of public repositories), a GitHub API token with ``repo`` scope is required, see https://github.com/settings/tokens.
+    This will be resolved from the first of:
 
         1. ``GITHUB_TOKEN`` env var,
         2. content of the ``.github-token`` file in the home directory (``~``),
diff --git a/docs/source/github_config_keys.rst b/docs/source/github_config_keys.rst
index cd9771c..da228e1 100644
--- a/docs/source/github_config_keys.rst
+++ b/docs/source/github_config_keys.rst
@@ -14,7 +14,7 @@
 
     To do this, run ``git config --local --edit`` and add the following section:
 
-    .. code-block:: ini
+    .. code-block::
 
         [machete "github"]
             organization = <organization_name>
diff --git a/docs/source/status_config_key.rst b/docs/source/status_config_key.rst
new file mode 100644
index 0000000..c5459f9
--- /dev/null
+++ b/docs/source/status_config_key.rst
@@ -0,0 +1,25 @@
+ .. note::
+
+    To make it easier to select branch name from the ``status`` output on certain terminals
+    (e.g. `Alacritty <https://github.com/alacritty/alacritty>`_), you can add an extra
+    space between └─ and ``branch name`` by setting ``git config machete.status.extraSpaceBeforeBranchName true``.
+
+    For example, by default the status is displayed as:
+
+    .. code-block::
+
+      develop
+      │
+      ├─feature_branch1
+      │
+      └─feature_branch2
+
+    With ``machete.status.extraSpaceBeforeBranchName`` config set to ``true``:
+
+    .. code-block::
+
+       develop
+       │
+       ├─ feature_branch1
+       │
+       └─ feature_branch2
diff --git a/git_machete/__init__.py b/git_machete/__init__.py
index 447562b..22b49ef 100644
--- a/git_machete/__init__.py
+++ b/git_machete/__init__.py
@@ -1,1 +1,1 @@
-__version__ = '3.12.0'
+__version__ = '3.12.1'
diff --git a/git_machete/cli.py b/git_machete/cli.py
index d037907..4b3d64b 100644
--- a/git_machete/cli.py
+++ b/git_machete/cli.py
@@ -11,7 +11,8 @@ import git_machete.options
 from git_machete import __version__
 from git_machete import utils
 from git_machete.client import MacheteClient
-from git_machete.docs import short_docs, long_docs
+from git_machete.generated_long_docs import long_docs
+from git_machete.handmade_short_docs import short_docs
 from git_machete.exceptions import MacheteException, StopInteraction
 from git_machete.git_operations import AnyBranchName, AnyRevision, GitContext, LocalBranchShortName, RemoteBranchShortName
 from git_machete.utils import bold, fmt, underline, excluding, warn
@@ -462,7 +463,12 @@ def set_utils_global_variables(
 
 def get_local_branch_short_name_from_arg_or_current_branch(
         branch_from_arg: Optional[AnyBranchName], git_context: GitContext) -> LocalBranchShortName:
-    return LocalBranchShortName.of(branch_from_arg.replace('refs/heads/', '')) if branch_from_arg else git_context.get_current_branch()
+    return get_local_branch_short_name_from_arg(branch_from_arg) if branch_from_arg else git_context.get_current_branch()
+
+
+def get_local_branch_short_name_from_arg(
+        branch_from_arg: Optional[AnyBranchName]) -> Optional[LocalBranchShortName]:
+    return LocalBranchShortName.of(branch_from_arg.replace('refs/heads/', '')) if branch_from_arg else None
 
 
 def exit_script(status_code: Optional[int] = None, error: Optional[BaseException] = None) -> None:
@@ -563,7 +569,7 @@ def launch(orig_args: List[str]) -> None:
             machete_client.delete_unmanaged(opt_yes=cli_opts.opt_yes)
         elif cmd in {"diff", alias_by_command["diff"]}:
             machete_client.read_definition_file(perform_interactive_slide_out=should_perform_interactive_slide_out)
-            machete_client.diff(branch=get_local_branch_short_name_from_arg_or_current_branch(cli_opts.opt_branch, git),
+            machete_client.diff(branch=get_local_branch_short_name_from_arg(cli_opts.opt_branch),
                                 opt_stat=cli_opts.opt_stat)  # passing None if not specified
         elif cmd == "discover":
             # No need to read definition file.
diff --git a/git_machete/client.py b/git_machete/client.py
index 64845aa..66c43d3 100644
--- a/git_machete/client.py
+++ b/git_machete/client.py
@@ -1583,17 +1583,20 @@ class MacheteClient:
                 self.__git.get_config_attr_or_none(self.config_key_for_override_fork_point_while_descendant_of(branch))) is not None
 
     def __get_fork_point_override_data(self, branch: LocalBranchShortName) -> Optional[ForkPointOverrideData]:
+        to, while_descendant_of = None, None
         to_key = self.config_key_for_override_fork_point_to(branch)
-        to = FullCommitHash.of(self.__git.get_config_attr_or_none(to_key) or "")
+        if FullCommitHash.is_valid(self.__git.get_config_attr_or_none(to_key)):
+            to = FullCommitHash.of(self.__git.get_config_attr_or_none(to_key))
         while_descendant_of_key = self.config_key_for_override_fork_point_while_descendant_of(branch)
-        while_descendant_of = FullCommitHash.of(self.__git.get_config_attr_or_none(while_descendant_of_key) or "")
+        if FullCommitHash.is_valid(self.__git.get_config_attr_or_none(to_key)):
+            while_descendant_of = FullCommitHash.of(self.__git.get_config_attr_or_none(while_descendant_of_key))
         if not to and not while_descendant_of:
             return None
         if to and not while_descendant_of:
-            warn(f"{to_key} config is set but {while_descendant_of_key} config is missing")
+            warn(f"{to_key} config is set but {while_descendant_of_key} config is missing or invalid")
             return None
         if not to and while_descendant_of:
-            warn(f"{while_descendant_of_key} config is set but {to_key} config is missing")
+            warn(f"{while_descendant_of_key} config is set but {to_key} config is missing or invalid")
             return None
 
         to_hash: Optional[FullCommitHash] = self.__git.get_commit_hash_by_revision(to)
diff --git a/git_machete/docs.py b/git_machete/docs.py
deleted file mode 100644
index fa30f7e..0000000
--- a/git_machete/docs.py
+++ /dev/null
@@ -1,855 +0,0 @@
-import textwrap
-from typing import Dict
-from git_machete.constants import DISCOVER_DEFAULT_FRESH_BRANCH_COUNT
-
-short_docs: Dict[str, str] = {
-    "add": "Add a branch to the tree of branch dependencies",
-    "advance": "Fast-forward merge one of children to the current branch, push it and then slide out the child",
-    "anno": "Manage custom annotations",
-    "clean": "Delete untracked and unmanaged branches and also optionally check out user's open GitHub PRs",
-    "config": "Display docs for the git machete configuration keys and environment variables",
-    "delete-unmanaged": "Delete local branches that are not present in the definition file",
-    "diff": "Diff current working directory or a given branch against its computed fork point",
-    "discover": "Automatically discover tree of branch dependencies",
-    "edit": "Edit the definition file",
-    "file": "Display the location of the definition file",
-    "fork-point": "Display or override fork point for a branch",
-    "format": "Display docs for the format of the definition file",
-    "github": "Create, check out and manage GitHub PRs while keeping them reflected in git machete",
-    "go": "Check out the branch relative to the position of the current branch, accepts down/first/last/next/root/prev/up argument",
-    "help": "Display this overview, or detailed help for a specified command",
-    "hooks": "Display docs for the extra hooks added by git machete",
-    "is-managed": "Check if the current branch is managed by git machete (mostly for scripts)",
-    "list": "List all branches that fall into one of pre-defined categories (mostly for internal use)",
-    "log": "Log the part of history specific to the given branch",
-    "reapply": "Rebase the current branch onto its computed fork point",
-    "show": "Show name(s) of the branch(es) relative to the position of a branch, accepts down/first/last/next/root/prev/up argument",
-    "slide-out": "Slide out the current branch and sync its downstream (child) branches with its upstream (parent) branch via rebase or merge",
-    "squash": "Squash the unique history of the current branch into a single commit",
-    "status": "Display formatted tree of branch dependencies, including info on their sync with upstream branch and with remote",
-    "traverse": "Walk through the tree of branch dependencies and rebase, merge, slide out, push and/or pull each branch one by one. By default starts from current branch",
-    "update": "Sync the current branch with its upstream (parent) branch via rebase or merge",
-    "version": "Display the version and exit"
-}
-
-github_api_access = '''To allow GitHub API access for private repositories (and also to perform side-effecting actions like opening a PR,
-even in case of public repositories), a GitHub API token with `repo` scope is required, see https://github.com/settings/tokens.
-This will be resolved from the first of:
-    1. `GITHUB_TOKEN` env var,
-    2. content of the `.github-token` file in the home directory (`~`),
-    3. current auth token from the `gh` GitHub CLI,
-    4. current auth token from the `hub` GitHub CLI.'''
-
-github_config_keys = '''GitHub API server URL will be inferred from `git remote`.
-You can override this by setting the following local git config keys:
-    Remote name
-        E.g. `machete.github.remote` = `origin`
-    Organization name
-        E.g. `machete.github.organization` = `VirtusLab`
-    Repository name
-        E.g. `machete.github.repository` = `git-machete`
-
-To do this, run `git config --local --edit` and add the following section:
-    [machete "github"]
-        organization = <organization_name>
-        repository = <repo_name>
-        remote = <remote_name>'''
-
-status_extraSpaceBeforeBranchName_config_key = '''The default value of this key is `false` but in order to make it easier to select branch
-name from the `git machete status` output on certain terminals (e.g. Alacritty), you can add an extra
-space between └─ and branch name by setting `git config machete.status.extraSpaceBeforeBranchName true`.
-
-For example, by default the status is displayed as:
-    develop
-    │
-    ├─feature_branch1
-    │
-    └─feature_branch2
-
-With `machete.status.extraSpaceBeforeBranchName` config set to `true`:
-    develop
-    │
-    ├─ feature_branch1
-    │
-    └─ feature_branch2'''
-
-long_docs: Dict[str, str] = {
-    "add": """
-        <b>Usage: git machete add [-o|--onto=<target-upstream-branch>] [-R|--as-root] [-y|--yes] [<branch>]</b>
-
-        Adds the provided <branch> (or the current branch, if none specified) to the definition file.
-        If <branch> is provided but no local branch with the given name exists:
-        * if a remote branch of the same name exists in exactly one remote, then user is asked whether to check out this branch locally (as in `git checkout`),
-        * otherwise, user is asked whether it should be created as a new local branch.
-
-        If the definition file is empty or `-R`/`--as-root` is provided, the branch will be added as a root of the tree of branch dependencies.
-        Otherwise, the desired upstream (parent) branch can be specified with `-o`/`--onto`.
-        Neither of these options is mandatory, however; if both are skipped, git machete will try to automatically infer the target upstream.
-        If the upstream branch can be inferred, the user will be presented with inferred branch and asked to confirm.
-
-        Note: all the effects of `add` (except git branch creation) can as well be achieved by manually editing the definition file.
-
-        <b>Options:</b>
-          <b>-o, --onto=<target-upstream-branch></b>    Specifies the target parent branch to add the given branch onto.
-                                                 Cannot be specified together with `-R`/`--as-root`.
-
-          <b>-R, --as-root</b>                          Add the given branch as a new root (and not onto any other branch).
-                                                 Cannot be specified together with `-o`/`--onto`.
-
-          <b>-y, --yes</b>                              Don't ask for confirmation whether to create the branch or whether to add onto the inferred upstream.
-    """,
-    "advance": """
-        <b>Usage: git machete advance [-y|--yes]</b>
-
-        Fast forwards (as in `git merge --ff-only`) the current branch `C` to match its downstream `D`, pushes `C`
-        and subsequently slides out `D`. All three steps require manual confirmation unless `-y`/`--yes` is provided.
-
-        The downstream `D` is selected according to the following criteria:
-        * if `C` has exactly one downstream branch `d` whose tip is a descendant of `C`, and whose fork point is equal to `C` or is overridden
-          (basically: there's a <b><green>green edge</green></b> between `C` and `d`), then `d` is selected as `D`,
-        * if `C` has no downstream branches connected with a <b><green>green edge</green></b> to `C`, then `advance` fails,
-        * if `C` has more than one downstream branch connected with a <b><green>green edge</green></b> to `C`,
-          then user is asked to pick the branch to fast-forward merge into (similarly to what happens in `git machete go down`).
-          If `--yes` is specified, then `advance` fails.
-
-        As an example, if `git machete status --color=never --list-commits` is as follows:
-        <dim>
-          master
-          |
-          m-develop *
-            |
-            | Enable adding remote branch in the manner similar to git checkout
-            o-feature/add-from-remote
-            | |
-            | | Add support and sample for machete-post-slide-out hook
-            | o-feature/post-slide-out-hook
-            |
-            | Remove support for Python 2
-            | Remove support for Python 2 - 1st round of fixes
-            ?-chore/v3
-            |
-            | Apply Python2-compatible static typing
-            x-feature/types
-        </dim>
-        then running `git machete advance` will fast-forward the current branch `develop` to match `feature/add-from-remote`, and subsequently slide out the latter.
-        After `advance` completes, `status` will show:
-        <dim>
-          master
-          |
-          | Enable adding remote branch in the manner similar to git checkout
-          o-develop *
-            |
-            | Add support and sample for machete-post-slide-out hook
-            o-feature/post-slide-out-hook
-            |
-            | Remove support for Python 2
-            | Remove support for Python 2 - 1st round of fixes
-            ?-chore/v3
-            |
-            | Apply Python2-compatible static typing
-            x-feature/types
-        </dim>
-        Note that the current branch after the operation is still `develop`, just pointing to `feature/add-from-remote`'s tip now.
-
-        <b>Options:</b>
-          <b>-y, --yes</b>         Don't ask for confirmation whether to fast-forward the current branch or whether to slide-out the downstream.
-                            Fails if the current branch has more than one green-edge downstream branch.
-    """,
-    "anno": f"""
-        <b>Usage:
-          git machete anno [-b|--branch=<branch>] [<annotation text>]
-          git machete anno -H|--sync-github-prs</b>
-
-        If invoked without any argument, prints out the custom annotation for the given branch (or current branch, if none specified with `-b/--branch`).
-
-        If invoked with a single empty string argument, like:
-        <dim>$ git machete anno ''</dim>
-        then clears the annotation for the current branch (or a branch specified with `-b/--branch`).
-
-        If invoked with `-H` or `--sync-github-prs`, annotates the branches based on their corresponding GitHub PR numbers and authors.
-        Any existing annotations are overwritten for the branches that have an opened PR; annotations for the other branches remain untouched.
-
-{textwrap.indent(github_api_access, "          ")}
-
-{textwrap.indent(github_config_keys, "          ")}
-
-        In any other case, sets the annotation for the given/current branch to the given argument.
-        If multiple arguments are passed to the command, they are concatenated with a single space.
-
-        Note: all the effects of `anno` can be always achieved by manually editing the definition file.
-
-        <b>Options:</b>
-          <b>-b, --branch=<branch></b>      Branch to set the annotation for.
-          <b>-H, --sync-github-prs</b>      Annotate with GitHub PR numbers and authors where applicable.
-    """,
-    "clean": f"""
-        <b>Usage: git machete clean [-c|--checkout-my-github-prs] [-y|--yes]</b>
-
-        Synchronizes with the remote repository:
-            1. if invoked with `-H` or `--checkout-my-github-prs`, checks out open PRs for the current user associated with the GitHub token and also traverses the chain of pull requests upwards, adding branches one by one to git-machete and checks them out locally as well,
-            2. deletes unmanaged branches,
-            3. deletes untracked managed branches that have no downstream branch.
-
-        No branch will be deleted unless explicitly confirmed by the user (or unless `-y/--yes` option is passed).
-        Equivalent of `git machete github sync` if invoked with `-H` or `--checkout-my-github-prs`.
-
-{textwrap.indent(github_api_access, "          ")}
-
-{textwrap.indent(github_config_keys, "          ")}
-
-        **Options:**
-          <b>--c, --checkout-my-github-prs</b>     Checkout your open PRs into local branches.
-          <b>-y, --yes</b>                         Don't ask for confirmation when deleting branches from git.
-    """,
-    "config": f"""
-        <b>Config keys: </b>
-
-        - `machete.github.{{remote,organization,repository}}`:
-
-          When executing `git machete github <subcommand>` command, {textwrap.indent(github_config_keys, "          ").strip()}
-
-        - `machete.overrideForkPoint.<branch>.{{to,whileDescendantOf}}`
-
-          Executing `git machete fork-point --override-to=<revision> [<branch>]` sets up a fork point override for <branch>.
-          The override data is stored under `machete.overrideForkPoint.<branch>.to` and `machete.overrideForkPoint.<branch>.whileDescendantOf` git config keys.
-
-        - `machete.status.extraSpaceBeforeBranchName`
-
-          {textwrap.indent(status_extraSpaceBeforeBranchName_config_key, "          ").strip()}
-
-        - `machete.worktree.useTopLevelMacheteFile`
-
-          The default value of this key is `true`, which means that the path to machete definition file will be `.git/machete`
-          for both regular directory and worktree. If you want the worktree to have its own machete definition file (located under
-          `.git/worktrees/.../machete`), set `git config machete.worktree.useTopLevelMacheteFile false`.
-
-
-        <b>Environment variables: </b>
-
-        - `GIT_MACHETE_EDITOR`
-
-          Name of the editor used by `git machete e[dit]`, example: `vim` or `nano`.
-
-        - `GIT_MACHETE_REBASE_OPTS`
-
-          Used to pass extra options to the underlying `git rebase` invocation (called by the executed command, such as: `reapply`, `slide-out`, `traverse`, `update`)
-          Example: `GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete update`.
-
-        - `GITHUB_TOKEN`
-
-          Used to store GitHub API token. Used by commands such as: `anno`, `clean`, `github`.
-    """,
-    "delete-unmanaged": """
-        <b>Usage: git machete delete-unmanaged [-y|--yes]</b>
-
-        Goes one-by-one through all the local git branches that don't exist in the definition file,
-        and ask to delete each of them (with `git branch -d` or `git branch -D`) if confirmed by user.
-        No branch will be deleted unless explicitly confirmed by the user (or unless `-y/--yes` option is passed).
-
-        Note: this should be used with care since deleting local branches can sometimes make it impossible for `git machete` to properly figure out fork points.
-        See `git machete help fork-point` for more details.
-
-        <b>Options:</b>
-          <b>-y, --yes</b>          Don't ask for confirmation.
-    """,
-    "diff": """
-        <b>Usage: git machete d[iff] [-s|--stat] [<branch>]</b>
-
-        Runs `git diff` of the given branch tip against its fork point or, if none specified, of the current working tree against the fork point of the currently checked out branch.
-        See `git machete help fork-point` for more details on meaning of the "fork point".
-
-        Note: the branch in question does not need to occur in the definition file.
-
-        Options:
-          <b>-s, --stat</b>    Makes `git machete diff` pass `--stat` option to `git diff`, so that only summary (diffstat) is printed.
-    """,
-    "discover": f"""
-        <b>Usage: git machete discover [-C|--checked-out-since=<date>] [-l|--list-commits] [-r|--roots=<branch1>,<branch2>,...] [-y|--yes]</b>
-
-        Discovers and displays tree of branch dependencies using a heuristic based on reflogs and asks whether to overwrite the existing definition file with the new discovered tree.
-        If confirmed with a `y[es]` or `e[dit]` reply, backs up the current definition file (if it exists) as `$GIT_DIR/machete~` and saves the new tree under the usual `$GIT_DIR/machete` path.
-        If the reply was `e[dit]`, additionally an editor is opened (as in `git machete edit`) after saving the new definition file.
-
-        Options:
-          <b>-C, --checked-out-since=<date></b>   Only consider branches checked out at least once since the given date. <date> can be e.g. `2 weeks ago` or `2020-06-01`, as in `git log --since=<date>`.
-                                           If not present, the date is selected automatically so that around {str(DISCOVER_DEFAULT_FRESH_BRANCH_COUNT)} branches are included.
-
-          <b>-l, --list-commits</b>               When printing the discovered tree, additionally lists the messages of commits introduced on each branch (as for `git machete status`).
-
-          <b>-r, --roots=<branch1,...></b>        Comma-separated list of branches that should be considered roots of trees of branch dependencies.
-                                           If not present, `master` is assumed to be a root.
-                                           Note that in the process of discovery, certain other branches can also be additionally deemed to be roots as well.
-
-          <b>-y, --yes</b>                        Don't ask for confirmation before saving the newly-discovered tree.
-                                           Mostly useful in scripts; not recommended for manual use.
-    """,
-    "edit": """
-        <b>Usage: git machete e[dit]</b>
-
-        Opens an editor and lets you edit the definition file manually.
-
-        The editor is determined by checking up the following locations:
-        * `$GIT_MACHETE_EDITOR`
-        * `$GIT_EDITOR`
-        * `$(git config core.editor)`
-        * `$VISUAL`
-        * `$EDITOR`
-        * `editor`
-        * `nano`
-        * `vi`
-        and selecting the first one that is defined and points to an executable file accessible on `PATH`.
-
-        Note that the above editor selection only applies for editing the definition file,
-        but not for any other actions that may be indirectly triggered by git-machete, including editing of rebase TODO list, commit messages etc.
-
-        The definition file can be always accessed and edited directly under the path returned by `git machete file`
-        (usually `.git/machete`, unless worktrees or submodules are involved).
-    """,
-    "file": """
-        <b>Usage: git machete file</b>
-
-        Outputs the absolute path of machete definition file.
-        The file is always called `machete` and is located in the git directory of the project.
-
-        Three cases are possible:
-        * if `git machete` is executed from a regular working directory (not a worktree or submodule), the file is located under `.git/machete`,
-        * if `git machete` is executed from a <b>worktree</b>, the file path depends on the `machete.worktree.useTopLevelMacheteFile` config key value:
-          * if `machete.worktree.useTopLevelMacheteFile` is true (default), the file is located under `.git/machete`
-          * if `machete.worktree.useTopLevelMacheteFile` is false, the file is located under `.git/worktrees/.../machete`,
-        * if `git machete` is executed from a <b>submodule</b>, this file is located in the git folder of the submodule itself under `.git/modules/.../machete`.
-    """,
-    "fork-point": """
-        <b>Usage:
-          git machete fork-point [--inferred] [<branch>]
-          git machete fork-point --override-to=<revision>|--override-to-inferred|--override-to-parent [<branch>]
-          git machete fork-point --unset-override [<branch>]</b>
-
-        Note: in all three forms, if no <branch> is specified, the currently checked out branch is assumed.
-        The branch in question does not need to occur in the definition file.
-
-
-        Without any option, displays full hash of the fork point commit for the <branch>.
-        Fork point of the given <branch> is the commit at which the history of the <branch> diverges from history of any other branch.
-
-        Fork point is assumed by many `git machete` commands as the place where the unique history of the <branch> starts.
-        The range of commits between the fork point and the tip of the given branch is, for instance:
-        * listed for each branch by `git machete status --list-commits`
-        * passed to `git rebase` by `git machete reapply`/`slide-out`/`traverse`/`update`
-        * provided to `git diff`/`log` by `git machete diff`/`log`.
-
-        `git machete` assumes fork point of <branch> is the most recent commit in the log of <branch> that has NOT been introduced on that very branch,
-        but instead occurs on a reflog (see help for `git reflog`) of some other, usually chronologically earlier, branch.
-        This yields a correct result in typical cases, but there are some situations
-        (esp. when some local branches have been deleted) where the fork point might not be determined correctly.
-        Thus, all rebase-involving operations (`reapply`, `slide-out`, `traverse` and `update`) run `git rebase` in the interactive mode by default,
-        unless told explicitly not to do so by `--no-interactive-rebase` flag, so that the suggested commit range can be inspected before the rebase commences.
-        Also, `reapply`, `slide-out`, `squash`, and `update` allow to specify the fork point explicitly by a command-line option.
-
-        `git machete fork-point` is different (and more powerful) than `git merge-base --fork-point`,
-        since the latter takes into account only the reflog of the one provided upstream branch,
-        while the former scans reflogs of all local branches and their remote tracking branches.
-        This makes git-machete's `fork-point` more resilient to modifications of .git/machete file where certain branches are re-attached under new parents (upstreams).
-
-
-        With `--override-to=<revision>`, sets up a fork point override for <branch>.
-        Fork point for <branch> will be overridden to the provided <revision> (commit) as long as the <branch> still points to (or is descendant of) the commit X
-        that <branch> pointed to at the moment the override is set up.
-        Even if revision is a symbolic name (e.g. other branch name or `HEAD~3`) and not explicit commit hash (like `a1b2c3ff`),
-        it's still resolved to a specific commit hash at the moment the override is set up (and not later when the override is actually used).
-        The override data is stored under `machete.overrideForkPoint.<branch>.to` and `machete.overrideForkPoint.<branch>.whileDescendantOf` git config keys.
-        Note: the provided fork point <revision> must be an ancestor of the current <branch> commit X.
-
-        With `--override-to-parent`, overrides fork point of the <branch> to the commit currently pointed by <branch>'s parent in the branch dependency tree.
-        Note: this will only work if <branch> has a parent at all (i.e. is not a root) and parent of <branch> is an ancestor of current <branch> commit X.
-
-        With `--inferred`, displays the commit that `git machete fork-point` infers to be the fork point of <branch>.
-        If there is NO fork point override for <branch>, this is identical to the output of `git machete fork-point`.
-        If there is a fork point override for <branch>, this is identical to the what the output of `git machete fork-point` would be if the override was NOT present.
-
-        With `--override-to-inferred` option, overrides fork point of the <branch> to the commit that `git machete fork-point` infers to be the fork point of <branch>.
-        Note: this piece of information is also displayed by `git machete status --list-commits` in case a <b><yellow>yellow edge</yellow></b> occurs.
-
-        With `--unset-override`, the fork point override for <branch> is unset.
-        This is simply done by removing the corresponding `machete.overrideForkPoint.<branch>.*` config entries.
-
-
-        <b>Note:</b> if an overridden fork point applies to a branch `B`, then it's considered to be connected with a <b><green>green edge</green></b> to its upstream (parent) `U`,
-        even if the overridden fork point of `B` is NOT equal to the commit pointed by `U`.
-    """,
-    "format": """
-        Note: there is no 'git machete format' command as such; 'format' is just a topic of 'git machete help'.
-
-        The format of the definition file should be as follows:
-        <dim>
-          develop
-              adjust-reads-prec PR #234
-                  block-cancel-order PR #235
-                      change-table
-                          drop-location-type
-              edit-margin-not-allowed
-                  full-load-gatling
-              grep-errors-script
-          master
-              hotfix/receipt-trigger PR #236
-        </dim>
-        In the above example `develop` and `master` are roots of the tree of branch dependencies.
-        Branches `adjust-reads-prec`, `edit-margin-not-allowed` and `grep-errors-script` are direct downstream branches for `develop`.
-        `block-cancel-order` is a downstream branch of `adjust-reads-prec`, `change-table` is a downstream branch of `block-cancel-order` and so on.
-
-        Every branch name can be followed (after a single space as a delimiter) by a custom annotation - a PR number in the above example.
-        The annotations don't influence the way `git machete` operates other than that they are displayed in the output of the `status` command.
-        Also see help for the `anno` command.
-
-        Tabs or any number of spaces can be used as indentation.
-        It's only important to be consistent wrt. the sequence of characters used for indentation between all lines.
-    """,
-    "github": f"""
-        <b>Usage: git machete github <subcommand></b>
-        where <subcommand> is one of: `anno-prs`, `checkout-prs`, `create-pr`, `retarget-pr`, `sync`.
-
-        Creates, checks out and manages GitHub PRs while keeping them reflected in branch definition file.
-
-{textwrap.indent(github_api_access, "          ")}
-
-{textwrap.indent(github_config_keys, "          ")}
-
-
-        <b>`anno-prs`:</b>
-
-          Annotates the branches based on their corresponding GitHub PR numbers and authors.
-          Any existing annotations are overwritten for the branches that have an opened PR; annotations for the other branches remain untouched.
-          Equivalent to `git machete anno --sync-github-prs`.
-
-        <b>`checkout-prs [--all | --by=<github-login> | --mine | <PR-number-1> ... <PR-number-N>]`:</b>
-
-          Check out the head branch of the given pull requests (specified by numbers or by a flag),
-          also traverse chain of pull requests upwards, adding branches one by one to git-machete and check them out locally.
-          Once the specified pull requests are checked out locally, annotate local branches with corresponding pull request numbers.
-          If only one PR has been checked out, then switch the local repository's HEAD to its head branch.
-
-          <b>Options:</b>
-            <b>--all</b>     Checkout all open PRs.
-            <b>--by</b>      Checkout open PRs authored by the given GitHub user.
-              <b>Parameters:</b>
-                <b><github-login></b> GitHub account name.
-            <b>--mine</b>    Checkout open PRs for the current user associated with the GitHub token.
-
-          <b>Parameters:</b>
-            <b><PR-number-1> ... <PR-number-N></b>    Pull request numbers to checkout.
-
-        <b>`create-pr [--draft]`:</b>
-
-          Creates a PR for the current branch, using the upstream (parent) branch as the PR base.
-          Once the PR is successfully created, annotates the current branch with the new PR's number.
-
-          If `.git/info/description` file is present, its contents is used as PR description.
-          If `.git/info/milestone` file is present, its contents (a single number - milestone id) is used as milestone.
-          If `.git/info/reviewers` file is present, its contents (one GitHub login per line) are used to set reviewers.
-
-          <b>Options:</b>
-            <b>--draft</b>    Creates the new PR as a draft.
-
-        <b>`retarget-pr`:</b>
-
-          Sets the base of the current branch's PR to upstream (parent) branch, as seen by git machete (see `git machete show up`).
-
-        <b>`sync`:</b>
-
-            Synchronizes with the remote repository:
-                1. checks out open PRs for the current user associated with the GitHub token and also traverses the chain of pull requests upwards, adding branches one by one to git-machete and checks them out locally as well,
-                2. deletes unmanaged branches,
-                3. deletes untracked managed branches that have no downstream branch.
-          Equivalent of `git machete clean --checkout-my-github-prs`.
-    """,
-    "go": """
-        <b>Usage: git machete g[o] <direction></b>
-        where <direction> is one of: `d[own]`, `f[irst]`, `l[ast]`, `n[ext]`, `p[rev]`, `r[oot]`, `u[p]`
-
-        Checks out the branch specified by the given direction relative to the current branch:
-        * `down`:    the direct children/downstream branch of the current branch.
-        * `first`:   the first downstream of the root branch of the current branch (like `root` followed by `next`), or the root branch itself if the root has no downstream branches.
-        * `last`:    the last branch in the definition file that has the same root as the current branch; can be the root branch itself if the root has no downstream branches.
-        * `next`:    the direct successor of the current branch in the definition file.
-        * `prev`:    the direct predecessor of the current branch in the definition file.
-        * `root`:    the root of the tree where the current branch is located. Note: this will typically be something like `develop` or `master`, since all branches are usually meant to be ultimately merged to one of those.
-        * `up`:      the direct parent/upstream branch of the current branch.
-
-        Roughly equivalent to `git checkout $(git machete show <direction>)`.
-    """,
-    "help": """
-        <b>Usage: git machete help [<command>]</b>
-
-        Prints a summary of this tool, or a detailed info on a command if provided.
-    """,
-    "hooks": """
-        As with the standard git hooks, git-machete looks for its own specific hooks in `$GIT_DIR/hooks/*` (or `$(git config core.hooksPath)/*`, if set).
-        All hooks are executed from the top-level folder of the repository (or top-level folder of worktree/submodule, if applicable).
-
-        Note: `hooks` is not a command as such, just a help topic (there is no `git machete hooks` command).
-
-        * <b>machete-post-slide-out <new-upstream> <lowest-slid-out-branch> [<new-downstreams>...]</b>
-            The hook that is executed after a branch (or possibly multiple branches, in case of `slide-out`)
-            is slid out by `advance`, `slide-out` or `traverse`.
-
-            At least two parameters (branch names) are passed to the hook:
-            * <b><new-upstream></b> is the upstream of the branch that has been slid out,
-              or in case of multiple branches being slid out - the upstream of the highest slid out branch;
-            * <b><lowest-slid-out-branch></b> is the branch that has been slid out,
-              or in case of multiple branches being slid out - the lowest slid out branch;
-            * <b><new-downstreams></b> are all the following (possibly zero) parameters,
-              which correspond to all original downstreams of <lowest-slid-out-branch>, now reattached as the downstreams of <new-upstream>.
-              Note that this may be zero, one, or multiple branches.
-
-            Note: the hook, if present, is executed:
-            * zero or once during a `advance` execution (depending on whether the slide-out has been confirmed or not),
-            * exactly once during a `slide-out` execution (even if multiple branches are slid out),
-            * zero or more times during `traverse` (every time a slide-out operation is confirmed).
-
-            If the hook returns a non-zero exit code, then an error is raised and the execution of the command is aborted,
-            i.e. `slide-out` won't attempt rebase of the new downstream branches and `traverse` won't continue the traversal.
-            In case of `advance` there is no difference (other than exit code of the entire `advance` command being non-zero),
-            since slide-out is the last operation that happens within `advance`.
-            Note that non-zero exit code of the hook doesn't cancel the effects of slide-out itself, only the subsequent operations.
-            The hook is executed only once the slide-out is complete and can in fact rely on .git/machete file being updated to the new branch layout.
-
-        * <b>machete-pre-rebase <new-base> <fork-point-hash> <branch-being-rebased></b>
-            The hook that is executed before rebase is run during `reapply`, `slide-out`, `traverse` and `update`.
-            Note that it is NOT executed by `squash` (despite its similarity to `reapply`), since no rebase is involved in `squash`.
-
-            The parameters are exactly the three revisions that are passed to `git rebase --onto`:
-            1. what is going to be the new base for the rebased commits,
-            2. what is the fork point - the place where the rebased history diverges from the upstream history,
-            3. what branch is rebased.
-            If the hook returns a non-zero exit code, an error is raised and the entire rebase is aborted.
-
-            Note: this hook is independent from git's standard `pre-rebase` hook.
-            If machete-pre-rebase returns zero, the execution flow continues to `git rebase`, which may also run `pre-rebase` hook if present.
-            `machete-pre-rebase` is thus always launched before `pre-rebase`.
-
-        * <b>machete-status-branch <branch-name></b>
-            The hook that is executed for each branch displayed during `discover`, `status` and `traverse`.
-
-            The standard output of this hook is displayed at the end of the line, after branch name, (optionally) custom annotation and (optionally) remote sync-ness status.
-            Standard error is ignored. If the hook returns a non-zero exit code, both stdout and stderr are ignored, and printing the status continues as usual.
-
-            Note: the hook is always invoked with `ASCII_ONLY` variable passed into the environment.
-            If `status` runs in ASCII-only mode (i.e. if `--color=auto` and stdout is not a terminal, or if `--color=never`), then `ASCII_ONLY=true`, otherwise `ASCII_ONLY=false`.
-
-        Please see hook_samples/ directory of git-machete project for examples.
-        An example of using the standard git `post-commit` hook to `git machete add` branches automatically is also included.
-    """,
-    "is-managed": """
-        <b>Usage: git machete is-managed [<branch>]</b>
-
-        Returns with zero exit code if the given branch (or current branch, if none specified) is managed by git-machete (i.e. listed in .git/machete).
-
-        Returns with a non-zero exit code in case:
-        * the <branch> is provided but isn't managed (or doesn't exist), or
-        * the <branch> isn't provided and the current branch isn't managed, or
-        * the <branch> isn't provided and there's no current branch (detached HEAD).
-    """,
-    "list": """
-        <b>Usage: git machete list <category></b>
-        where <category> is one of: `addable`, `managed`, `slidable`, `slidable-after <branch>`, `unmanaged`, `with-overridden-fork-point`.
-
-        Lists all branches that fall into one of the specified categories:
-        * `addable`: all branches (local or remote) than can be added to the definition file,
-        * `childless`: all branches that do not possess child branches,
-        * `managed`: all branches that appear in the definition file,
-        * `slidable`: all managed branches that have an upstream and can be slid out with `slide-out` command
-        * `slidable-after <branch>`: the downstream branch of the <branch>, if it exists and is the only downstream of <branch> (i.e. the one that can be slid out immediately following <branch>),
-        * `unmanaged`: all local branches that don't appear in the definition file,
-        * `with-overridden-fork-point`: all local branches that have a fork point override set up (even if this override does not affect the location of their fork point anymore).
-
-        This command is generally not meant for a day-to-day use, it's mostly needed for the sake of branch name completion in shell.
-    """,
-    "log": """
-        <b>Usage: git machete l[og] [<branch>]</b>
-
-        Runs `git log` for the range of commits from tip of the given branch (or current branch, if none specified) back to its fork point.
-        See `git machete help fork-point` for more details on meaning of the "fork point".
-
-        Note: the branch in question does not need to occur in the definition file.
-    """,
-    "reapply": """
-        <b>Usage: git machete reapply [-f|--fork-point=<fork-point-commit>]</b>
-
-        Interactively rebase the current branch on the top of its computed fork point.
-        The chunk of the history to be rebased starts at the automatically computed fork point of the current branch by default, but can also be set explicitly by `--fork-point`.
-        See `git machete help fork-point` for more details on meaning of the "fork point".
-
-        Note: the current reapplied branch does not need to occur in the definition file.
-
-        Tip: `reapply` can be used for squashing the commits on the current branch to make history more condensed before push to the remote,
-        but there is also dedicated `squash` command that achieves the same goal without running `git rebase`.
-
-        <b>Options:</b>
-          <b>-f, --fork-point=<fork-point-commit></b>    Specifies the alternative fork point commit after which the rebased part of history is meant to start.
-
-        <b>Environment variables:</b>
-          <b>GIT_MACHETE_REBASE_OPTS</b>                 Extra options to pass to the underlying `git rebase` invocation, space-separated.
-                                                  Example: `GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete reapply`.
-    """,
-    "show": """
-        <b>Usage: git machete show <direction> [<branch>]</b>
-        where <direction> is one of: `c[urrent]`, `d[own]`, `f[irst]`, `l[ast]`, `n[ext]`, `p[rev]`, `r[oot]`, `u[p]`
-        displayed relative to given <branch>, or the current checked out branch if <branch> is unspecified.
-
-        Outputs name of the branch (or possibly multiple branches, in case of `down`) that is:
-
-        * `current`: the current branch; exits with a non-zero status if none (detached HEAD)
-        * `down`:    the direct children/downstream branch of the given branch.
-        * `first`:   the first downstream of the root branch of the given branch (like `root` followed by `next`), or the root branch itself if the root has no downstream branches.
-        * `last`:    the last branch in the definition file that has the same root as the given branch; can be the root branch itself if the root has no downstream branches.
-        * `next`:    the direct successor of the given branch in the definition file.
-        * `prev`:    the direct predecessor of the given branch in the definition file.
-        * `root`:    the root of the tree where the given branch is located. Note: this will typically be something like `develop` or `master`, since all branches are usually meant to be ultimately merged to one of those.
-        * `up`:      the direct parent/upstream branch of the given branch.
-    """,
-    "slide-out": """
-        <b>Usage: git machete slide-out [-d|--down-fork-point=<down-fork-point-commit>] [--delete] [-M|--merge] [-n|--no-edit-merge|--no-interactive-rebase] [<branch> [<branch> [<branch> ...]]]</b>
-
-        Removes the given branch (or multiple branches) from the branch tree definition. If no branch has been specified current branch is assumed as the only branch.
-        Then synchronizes the downstream (child) branches of the last specified branch on the top of the upstream (parent) branch of the first specified branch.
-        Sync is performed either by rebase (default) or by merge (if `--merge` option passed).
-
-        The most common use is to slide out a single branch whose upstream was a `develop`/`master` branch and that has been recently merged.
-
-        Since this tool is designed to perform only one single rebase/merge at the end, provided branches must form a chain, i.e. all of the following conditions must be met:
-        * for i=1..N-1, (i+1)-th branch must be the only downstream (child) branch of the i-th branch,
-        * all provided branches must have an upstream branch (so, in other words, roots of branch dependency tree cannot be slid out).
-
-        For example, let's assume the following dependency tree:
-        <dim>
-          develop
-              adjust-reads-prec
-                  block-cancel-order
-                      change-table
-                          drop-location-type
-                      add-notification
-        </dim>
-        And now let's assume that `adjust-reads-prec` and later `block-cancel-order` were merged to develop.
-        After running `git machete slide-out adjust-reads-prec block-cancel-order` the tree will be reduced to:
-        <dim>
-          develop
-              change-table
-                  drop-location-type
-              add-notification
-        </dim>
-        and `change-table` and `add-notification` will be rebased onto develop (fork point for this rebase is configurable, see `-d` option below).
-
-        Note: This command doesn't delete any branches from git, just removes them from the tree of branch dependencies.
-
-        <b>Options:</b>
-          <b>-d, --down-fork-point=<down-fork-point-commit></b>    If updating by rebase, specifies the alternative fork point for downstream branches for the operation.
-                                                            `git machete fork-point` overrides for downstream branches are recommended over use of this option.
-                                                            See also doc for `--fork-point` option in `git machete help reapply` and `git machete help update`.
-                                                            Not allowed if updating by merge.
-
-          <b>--delete</b>                                          Delete slid-out branches from git.
-
-          <b>-M, --merge</b>                                       Update the downstream branch by merge rather than by rebase.
-
-          <b>-n</b>                                                If updating by rebase, equivalent to `--no-interactive-rebase`. If updating by merge, equivalent to `--no-edit-merge`.
-
-          <b>--no-edit-merge</b>                                   If updating by merge, skip opening the editor for merge commit message while doing `git merge` (i.e. pass `--no-edit` flag to underlying `git merge`).
-                                                            Not allowed if updating by rebase.
-
-          <b>--no-interactive-rebase</b>                           If updating by rebase, run `git rebase` in non-interactive mode (without `-i/--interactive` flag).
-                                                            Not allowed if updating by merge.
-
-        <b>Environment variables:</b>
-          <b>GIT_MACHETE_REBASE_OPTS</b>                           Extra options to pass to the underlying `git rebase` invocations, space-separated.
-                                                            Example: `GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete slide-out`.
-    """,
-    "squash": """
-        <b>Usage: git machete squash [-f|--fork-point=<fork-point-commit>]</b>
-
-        Squashes the commits belonging uniquely to the current branch into a single commit.
-        The chunk of the history to be squashed starts at the automatically computed fork point of the current branch by default, but can also be set explicitly by `--fork-point`.
-        See `git machete help fork-point` for more details on meaning of the "fork point".
-        The message for the squashed is taken from the earliest squashed commit, i.e. the commit directly following the fork point.
-
-        Note: the current squashed branch does not need to occur in the definition file.
-
-        Tip: `squash` does NOT run `git rebase` under the hood. For more complex scenarios that require rewriting the history of current branch, see `reapply` and `update`.
-
-        <b>Options:</b>
-          <b>-f, --fork-point=<fork-point-commit></b>    Specifies the alternative fork point commit after which the squashed part of history is meant to start.
-    """,
-    "status": f"""
-        <b>Usage: git machete s[tatus] [--color=WHEN] [-l|--list-commits] [-L|--list-commits-with-hashes] [--no-detect-squash-merges]</b>
-
-        Displays a tree-shaped status of the branches listed in the definition file.
-
-        Apart from simply ASCII-formatting the definition file, this also:
-
-        * colors the edges between upstream (parent) and downstream (children) branches:
-
-          - <b><red>red edge</red></b> means that the downstream branch tip is <b>not a direct descendant</b> of the upstream branch tip,
-
-          - <b><yellow>yellow edge</yellow></b> means that the downstream branch tip is a <b>direct descendant</b> of the upstream branch tip,
-            but the fork point (see help on `fork-point`) of the downstream branch is <b>not equal</b> to the upstream branch tip,
-
-          - <b><green>green edge</green></b> means that the downstream branch tip is a <b>direct descendant</b> of the upstream branch tip
-            and the fork point of the downstream branch is <b>equal</b> to the upstream branch tip,
-
-          - <b><dim>grey/dimmed edge</dim></b> means that the downstream branch has been <b>merged</b> to the upstream branch,
-            detected by commit equivalency (default), or by strict detection of merge commits (if `--no-detect-squash-merges` passed).
-
-
-        * prints `(untracked/ahead of <remote>/behind <remote>/diverged from [& older than] <remote>)` message if the branch is not in sync with its remote counterpart;
-
-        * displays the custom annotations (see help on `format` and `anno`) next to each branch, if present;
-
-        * displays the output of `machete-status-branch` hook (see help on `hooks`), if present;
-
-        * optionally lists commits introduced on each branch if `-l`/`--list-commits` or `-L`/`--list-commits-with-hashes` is supplied.
-
-        Name of the currently checked-out branch is underlined (or shown in blue on terminals that don't support underline).
-
-        In case of yellow edge, use `-l` flag to show the exact location of the inferred fork point
-        (which indicates e.g. what range of commits is going to be rebased when the branch is updated).
-        The inferred fork point can be always overridden manually, see help on `fork-point`.
-
-        Grey/dimmed edge suggests that the downstream branch can be slid out (see help on `slide-out` and `traverse`).
-
-        Using colors can be disabled with a `--color` flag set to `never`.
-        With `--color=always`, git machete always emits colors and with `--color=auto`, it emits colors only when standard output is connected to a terminal.
-        `--color=auto` is the default. When colors are disabled, relation between branches is represented in the following way (not including the hash-comments):
-        <dim>
-          <branch0>
-          |
-          o-<branch1> *   # green (in sync with parent; asterisk for the current branch)
-          | |
-          | x-<branch2>   # red (not in sync with parent)
-          |   |
-          |   ?-<branch3> # yellow (in sync with parent, but parent is not the fork point)
-          |
-          m-<branch4>     # grey (merged to parent)
-        </dim>
-        <b>Options:</b>
-          <b>--color=WHEN</b>                      Colorize the output; WHEN can be `always`, `auto` (default; i.e. only if stdout is a terminal), or `never`.
-
-          <b>-l, --list-commits</b>                Additionally list the commits introduced on each branch.
-
-          <b>-L, --list-commits-with-hashes</b>    Additionally list the short hashes and messages of commits introduced on each branch.
-
-          <b>--no-detect-squash-merges</b>         Only consider "strict" (fast-forward or 2-parent) merges, rather than rebase/squash merges,
-                                            when detecting if a branch is merged into its upstream (parent).
-
-        <b>Config keys:</b>
-{textwrap.indent(status_extraSpaceBeforeBranchName_config_key, "          ")}
-    """,
-    "traverse": """
-        <b>Usage: git machete t[raverse] [-F|--fetch] [-l|--list-commits] [-M|--merge]
-                                         [-n|--no-edit-merge|--no-interactive-rebase] [--no-detect-squash-merges]
-                                         [--[no-]push] [--[no-]push-untracked]
-                                         [--return-to=WHERE] [--start-from=WHERE] [-w|--whole] [-W] [-y|--yes]</b>
-
-        Traverses the branch tree in pre-order (i.e. simply in the order as they occur in the definition file).
-        By default `traverse` starts from the current branch.
-        This behaviour can, however, be customized using options: `--start-from=`, `--whole` or `-w`, `-W`.
-
-        For each branch, the command:
-        * detects if the branch is merged (<b><dim>grey</dim></b> edge) to its parent (aka upstream)
-          - by commit equivalency (default), or by strict detection of merge commits (if `--no-detect-squash-merges` passed),
-          - if so, asks the user whether to slide out the branch from the dependency tree (typically branches are no longer needed after they're merged);
-        * otherwise, if the branch has a <b><red>red</red></b> or <b><yellow>yellow</yellow></b> edge to its parent/upstream (see `status`):
-          - asks the user whether to rebase (default) or merge (if `--merge` passed) the branch onto into its upstream branch - equivalent to `git machete update` with no `--fork-point` option passed;
-
-        * if the branch is not tracked on a remote, is ahead of its remote counterpart, or diverged from the counterpart & has newer head commit than the counterpart:
-          - asks the user whether to push the branch (possibly with `--force-with-lease` if the branches diverged);
-        * otherwise, if the branch diverged from the remote counterpart & has older head commit than the counterpart:
-          - asks the user whether to `git reset --keep` the branch to its remote counterpart
-        * otherwise, if the branch is behind its remote counterpart:
-          - asks the user whether to pull the branch;
-
-        * and finally, if any of the above operations has been successfully completed:
-          - prints the updated `status`.
-
-        If the traverse flow is stopped (typically due to merge/rebase conflicts), just run `git machete traverse` after the merge/rebase is finished.
-        It will pick up the walk from the current branch (unless `--start-from=` or `-w` etc. is passed).
-        Unlike with e.g. `git rebase`, there is no special `--continue` flag, as `traverse` is stateless
-        (doesn't keep a state of its own like `git rebase` does in `.git/rebase-apply/`).
-
-        <b>Options:</b>
-          <b>-F, --fetch</b>                  Fetch the remotes of all managed branches at the beginning of traversal (no `git pull` involved, only `git fetch`).
-
-          <b>-l, --list-commits</b>           When printing the status, additionally list the messages of commits introduced on each branch.
-
-          <b>-M, --merge</b>                  Update by merge rather than by rebase.
-
-          <b>-n</b>                           If updating by rebase, equivalent to `--no-interactive-rebase`. If updating by merge, equivalent to `--no-edit-merge`.
-
-          <b>--no-detect-squash-merges</b>    Only consider "strict" (fast-forward or 2-parent) merges, rather than rebase/squash merges,
-                                       when detecting if a branch is merged into its upstream (parent).
-
-          <b>--no-edit-merge</b>              If updating by merge, skip opening the editor for merge commit message while doing `git merge` (i.e. pass `--no-edit` flag to underlying `git merge`).
-                                       Not allowed if updating by rebase.
-
-          <b>--no-interactive-rebase</b>      If updating by rebase, run `git rebase` in non-interactive mode (without `-i/--interactive` flag).
-                                       Not allowed if updating by merge.
-
-          <b>--no-push</b>                    Do not push any (neither tracked nor untracked) branches to remote, re-enable via `--push`.
-
-          <b>--no-push-untracked</b>          Do not push untracked branches to remote, re-enable via `--push-untracked`.
-
-          <b>--push</b>                       Push all (both tracked and untracked) branches to remote - default behavior.
-
-          <b>--push-untracked</b>             Push untracked branches to remote - default behavior.
-
-          <b>--return-to=WHERE</b>            Specifies the branch to return after traversal is successfully completed; WHERE can be `here` (the current branch at the moment when traversal starts),
-                                       `nearest-remaining` (nearest remaining branch in case the `here` branch has been slid out by the traversal)
-                                       or `stay` (the default - just stay wherever the traversal stops).
-                                       Note: when user quits by `q/yq` or when traversal is stopped because one of git actions fails, the behavior is always `stay`.
-
-          <b>--start-from=WHERE</b>           Specifies the branch to start the traversal from; WHERE can be `here` (the default - current branch, must be managed by git-machete),
-                                       `root` (root branch of the current branch, as in `git machete show root`) or `first-root` (first listed managed branch).
-
-          <b>-w, --whole</b>                  Equivalent to `-n --start-from=first-root --return-to=nearest-remaining`;
-                                       useful for quickly traversing & syncing all branches (rather than doing more fine-grained operations on the local section of the branch tree).
-
-          <b>-W</b>                           Equivalent to `--fetch --whole`; useful for even more automated traversal of all branches.
-
-          <b>-y, --yes</b>                    Don't ask for any interactive input, including confirmation of rebase/push/pull. Implies `-n`.
-
-        <b>Environment variables:</b>
-          <b>GIT_MACHETE_REBASE_OPTS</b>      Extra options to pass to the underlying `git rebase` invocations, space-separated.
-                                       Example: `GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete traverse`.
-    """,
-    "update": """
-        <b>Usage: git machete update [-f|--fork-point=<fork-point-commit>] [-M|--merge] [-n|--no-edit-merge|--no-interactive-rebase]</b>
-
-        Synchronizes the current branch with its upstream (parent) branch either by rebase (default) or by merge (if `--merge` option passed).
-
-        If updating by rebase, interactively rebases the current branch on the top of its upstream (parent) branch.
-        The chunk of the history to be rebased starts at the fork point of the current branch, which by default is inferred automatically, but can also be set explicitly by `--fork-point`.
-        See `git machete help fork-point` for more details on meaning of the "fork point".
-
-        If updating by merge, merges the upstream (parent) branch into the current branch.
-
-        <b>Options:</b>
-          <b>-f, --fork-point=<fork-point-commit></b>    If updating by rebase, specifies the alternative fork point commit after which the rebased part of history is meant to start.
-                                                  Not allowed if updating by merge.
-
-          <b>-M, --merge</b>                             Update by merge rather than by rebase.
-
-          <b>-n</b>                                      If updating by rebase, equivalent to `--no-interactive-rebase`. If updating by merge, equivalent to `--no-edit-merge`.
-
-          <b>--no-edit-merge</b>                         If updating by merge, skip opening the editor for merge commit message while doing `git merge` (i.e. pass `--no-edit` flag to underlying `git merge`).
-                                                  Not allowed if updating by rebase.
-
-          <b>--no-interactive-rebase</b>                 If updating by rebase, run `git rebase` in non-interactive mode (without `-i/--interactive` flag).
-                                                  Not allowed if updating by merge.
-
-        <b>Environment variables:</b>
-          <b>GIT_MACHETE_REBASE_OPTS</b>                 Extra options to pass to the underlying `git rebase` invocation, space-separated.
-                                                  Example: `GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete update`.
-    """,
-    "version": """
-        <b>Usage: git machete version</b>
-
-        Prints the version and exits.
-    """
-}
diff --git a/git_machete/generated_long_docs.py b/git_machete/generated_long_docs.py
new file mode 100644
index 0000000..14b6159
--- /dev/null
+++ b/git_machete/generated_long_docs.py
@@ -0,0 +1,1028 @@
+from typing import Dict
+
+# ---------------------------------------------------------------------------------------------------------
+# Warning: This file is NOT supposed to be edited directly, but instead regenerated via tox -e docs
+# ---------------------------------------------------------------------------------------------------------
+
+long_docs: Dict[str, str] = {
+    "add": """
+        <b>Usage:</b><b>
+           git machete add [-o|--onto=<target-upstream-branch>] [-R|--as-root] [-y|--yes] [<branch>]</b>
+
+        Adds the provided <branch> (or the current branch, if none specified) to the definition file.
+        If <branch> is provided but no local branch with the given name exists:
+           * if a remote branch of the same name exists in exactly one remote,
+             then user is asked whether to check out this branch locally (as in `git checkout`),
+           * otherwise, user is asked whether it should be created as a new local branch.
+
+        If the definition file is empty or `-R/--as-root` is provided, the branch will be added as a root of the tree of branch dependencies.
+        Otherwise, the desired upstream (parent) branch can be specified with `-o/--onto`.
+        Neither of these options is mandatory, however; if both are skipped, git machete will try to automatically infer the target upstream.
+        If the upstream branch can be inferred, the user will be presented with inferred branch and asked to confirm.
+
+        Note: all the effects of `add` (except git branch creation) can as well be achieved by manually editing the definition file.
+
+        <b>Options:</b>
+           <b>-o</b>, <b>--onto=<target-upstream-branch></b>
+              Specifies the target parent branch to add the given branch onto.
+              Cannot be specified together with `-R/--as-root`.
+           <b>-R</b>, <b>--as-root</b>
+              Add the given branch as a new root (and not onto any other branch).
+              Cannot be specified together with `-o/--onto`.
+           <b>-y</b>, <b>--yes</b>
+              Don't ask for confirmation whether to create the branch or whether to add onto the inferred upstream.
+   """,
+    "advance": """
+        <b>Usage:</b><b>
+           git machete advance [-y|--yes]</b>
+
+        Fast forwards (as in `git merge --ff-only`) the current branch `C` to match its downstream `D`, pushes `C`
+        and subsequently slides out `D`. All three steps require manual confirmation unless `-y/--yes` is provided.
+
+        The downstream `D` is selected according to the following criteria:
+           * if `C` has exactly one downstream (child) branch `d` connected with a <green>green edge</green> (see help for `status`) to `C`
+             or is overridden, then `d` is selected as `D`,
+           * if `C` has no downstream branches connected with a <green>green edge</green> to `C`, then `advance` fails,
+           * if `C` has more than one downstream branch connected with a <green>green edge</green> to `C`,
+             then user is asked to pick the branch to fast-forward merge into (similarly to what happens in `git machete go down`).
+             If `--yes` is specified, then `advance` fails.
+
+        As an example, if `git machete status --color=never --list-commits` is as follows:
+        <dim>
+          master
+          |
+          m-develop *
+            |
+            | Enable adding remote branch in the manner similar to git checkout
+            o-feature/add-from-remote
+              |
+              | Add support and sample for machete-post-slide-out hook
+              o-feature/post-slide-out-hook
+        </dim>
+
+        then running `git machete advance` will fast-forward the current branch `develop` to match `feature/add-from-remote`,
+        and subsequently slide out the latter.
+        After `advance` completes, `status` will show:
+        <dim>
+          master
+          |
+          | Enable adding remote branch in the manner similar to git checkout
+          o-develop *
+            |
+            | Add support and sample for machete-post-slide-out hook
+            o-feature/post-slide-out-hook
+        </dim>
+
+        Note that the current branch after the operation is still `develop`, just pointing to `feature/add-from-remote`'s tip now.
+
+        <b>Options:</b>
+           <b>-y</b>, <b>--yes</b>
+              Don't ask for confirmation whether to fast-forward the current branch or whether to slide-out the downstream.
+              Fails if the current branch has more than one <green>green-edge</green> downstream branch.
+   """,
+    "anno": """
+        <b>Usage:</b><b>
+           git machete anno [-b|--branch=<branch>] [<annotation text>]
+           git machete anno -H|--sync-github-prs</b>
+
+        If invoked without any <annotation text>, prints out the custom annotation for the given branch
+        (or current branch, if none specified with `-b/--branch`).
+
+        If invoked with a single empty string <annotation text>, like:<b>
+           $ git machete anno ''</b>
+
+        then clears the annotation for the current branch (or a branch specified with `-b/--branch`).
+
+        If invoked with `-H` or `--sync-github-prs`, annotates the branches based on their corresponding GitHub PR numbers and authors.
+        Any existing annotations are overwritten for the branches that have an opened PR; annotations for the other branches remain untouched.
+
+        To allow GitHub API access for private repositories (and also to perform side-effecting actions like opening a PR,
+        even in case of public repositories), a GitHub API token with `repo` scope is required, see https://github.com/settings/tokens.
+        This will be resolved from the first of:
+           * `GITHUB_TOKEN` env var,
+           * content of the `.github-token` file in the home directory (`~`),
+           * current auth token from the `gh` GitHub CLI,
+           * current auth token from the `hub` GitHub CLI.
+
+        GitHub API server URL will be inferred from `git remote`.
+        You can override this by setting the following git config keys:
+           Remote name
+              E.g. `machete.github.remote` = `origin`
+
+           Organization name
+              E.g. `machete.github.organization` = `VirtusLab`
+
+           Repository name
+              E.g. `machete.github.repository` = `git-machete`
+
+        To do this, run `git config --local --edit` and add the following section:
+        <dim>
+          [machete "github"]
+              organization = <organization_name>
+              repository = <repo_name>
+              remote = <remote_name>
+        </dim>
+
+        In any other case, sets the annotation for the given/current branch to the given <annotation text>.
+        If multiple <annotation text>'s are passed to the command, they are concatenated with a single space.
+
+        Note: all the effects of `anno` can be always achieved by manually editing the definition file.
+
+        <b>Options:</b>
+           <b>-b</b>, <b>--branch=<branch></b>
+              Branch to set the annotation for.
+           <b>-H</b>, <b>--sync-github-prs</b>
+              Annotate with GitHub PR numbers and authors where applicable.
+
+        <b>Environment variables:</b>
+           `GITHUB_TOKEN`
+              GitHub API token.
+
+   """,
+    "clean": """
+        <b>Usage:</b><b>
+           git machete clean [-c|--checkout-my-github-prs] [-y|--yes]</b>
+
+        Synchronizes with the remote repository:
+           * if invoked with `-H` or `--checkout-my-github-prs`, checks out open PRs for the current user associated with the GitHub token
+             and also traverses the chain of pull requests upwards, adding branches one by one to git-machete and checks them out locally as well,
+           * deletes unmanaged branches,
+           * deletes untracked managed branches that have no downstream branch.
+
+        No branch will be deleted unless explicitly confirmed by the user (or unless `-y/--yes` option is passed).
+        Equivalent of `git machete github sync` if invoked with `-H` or `--checkout-my-github-prs`.
+
+        To allow GitHub API access for private repositories (and also to perform side-effecting actions like opening a PR,
+        even in case of public repositories), a GitHub API token with `repo` scope is required, see https://github.com/settings/tokens.
+        This will be resolved from the first of:
+           * `GITHUB_TOKEN` env var,
+           * content of the `.github-token` file in the home directory (`~`),
+           * current auth token from the `gh` GitHub CLI,
+           * current auth token from the `hub` GitHub CLI.
+
+        GitHub API server URL will be inferred from `git remote`.
+        You can override this by setting the following git config keys:
+           Remote name
+              E.g. `machete.github.remote` = `origin`
+
+           Organization name
+              E.g. `machete.github.organization` = `VirtusLab`
+
+           Repository name
+              E.g. `machete.github.repository` = `git-machete`
+
+        To do this, run `git config --local --edit` and add the following section:
+        <dim>
+          [machete "github"]
+              organization = <organization_name>
+              repository = <repo_name>
+              remote = <remote_name>
+        </dim>
+
+        <b>Options:</b>
+           <b>-c</b>, <b>--checkout-my-github-prs</b>
+              Checkout your open PRs into local branches.
+           <b>-y</b>, <b>--yes</b>
+              Don't ask for confirmation when deleting branches from git.
+
+        <b>Environment variables:</b>
+           `GITHUB_TOKEN`
+              GitHub API token.
+
+   """,
+    "config": """
+        Documentation about available `git machete` config keys and environment variables that change the command's default behavior.
+
+        Note: `config` is not a command as such, just a help topic (there is no `git machete config` command).
+
+        <b>Config keys:</b>
+           `machete.github.{remote,organization,repository}`:
+ 
+              When executing `git machete github <subcommand>` command, the following will happen:
+
+              GitHub API server URL will be inferred from `git remote`.
+              You can override this by setting the following git config keys:
+
+                 Remote name
+              E.g. `machete.github.remote` = `origin`
+
+                 Organization name
+              E.g. `machete.github.organization` = `VirtusLab`
+
+                 Repository name
+              E.g. `machete.github.repository` = `git-machete`
+
+              To do this, run `git config --local --edit` and add the following section:
+
+              [machete "github"]
+                  organization = <organization_name>
+                  repository = <repo_name>
+                  remote = <remote_name>
+
+           `machete.overrideForkPoint.<branch>.{to,whileDescendantOf}`:
+              Executing `git machete fork-point --override-to=<revision> [<branch>]` sets up a fork point override for <branch>.
+              The override data is stored under `machete.overrideForkPoint.<branch>.to` and
+              `machete.overrideForkPoint.<branch>.whileDescendantOf` git config keys.
+
+           `machete.status.extraSpaceBeforeBranchName`:
+
+              To make it easier to select branch name from the `status` output on certain terminals
+              (e.g. Alacritty), you can add an extra
+              space between └─ and `branch name` by setting `git config machete.status.extraSpaceBeforeBranchName true`.
+
+              For example, by default the status is displayed as:
+
+              develop
+              │
+              ├─feature_branch1
+              │
+              └─feature_branch2
+
+              With `machete.status.extraSpaceBeforeBranchName` config set to `true`:
+
+              develop
+              │
+              ├─ feature_branch1
+              │
+              └─ feature_branch2
+
+           `machete.worktree.useTopLevelMacheteFile`:
+              The default value of this key is `true`, which means that the path to machete definition file will be `.git/machete`
+              for both regular directory and worktree. If you want the worktree to have its own machete definition file (located under
+              `.git/worktrees/.../machete`), set `git config machete.worktree.useTopLevelMacheteFile false`.
+
+        <b>Environment variables:</b>
+           `GIT_MACHETE_EDITOR`
+              Name of the editor used by `git machete e[dit]`, example: `vim` or `nano`.
+
+           `GIT_MACHETE_REBASE_OPTS`
+              Used to pass extra options to the underlying `git rebase` invocation (called by the executed command,
+              such as: `reapply`, `slide-out`, `traverse`, `update`)
+              Example: `GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete update`.
+
+           `GITHUB_TOKEN`
+              Used to store GitHub API token. Used by commands such as: `anno`, `clean`, `github`.
+
+   """,
+    "delete-unmanaged": """
+        <b>Usage:</b><b>
+           git machete delete-unmanaged [-y|--yes]</b>
+
+        Goes one-by-one through all the local git branches that don't exist in the definition file,
+        and ask to delete each of them (with `git branch -d` or `git branch -D`) if confirmed by user.
+        No branch will be deleted unless explicitly confirmed by the user (or unless `-y/--yes` option is passed).
+
+        Note: this should be used with care since deleting local branches can sometimes make it impossible
+        for `git machete` to properly figure out fork points.
+        See help for `fork-point` for more details.
+
+        <b>Options:</b>
+           <b>-y</b>, <b>--yes</b>
+              Don't ask for confirmation.
+   """,
+    "diff": """
+        <b>Usage:</b><b>
+           git machete d[iff] [-s|--stat] [<branch>]</b>
+
+        Runs `git diff` of the given branch tip against its fork point or, if none specified,
+        of the current working tree against the fork point of the currently checked out branch.
+        See help for `fork-point` for more details on the meaning of fork point.
+
+        Note: the branch in question does not need to occur in the definition file.
+
+        <b>Options:</b>
+           <b>-s</b>, <b>--stat</b>
+              Makes `git machete diff` pass `--stat` option to `git diff`, so that only summary (diffstat) is printed.
+   """,
+    "discover": """
+        <b>Usage:</b><b>
+           git machete discover [-C|--checked-out-since=<date>] [-l|--list-commits] [-r|--roots=<branch1>,<branch2>,...] [-y|--yes]</b>
+
+        Discovers and displays tree of branch dependencies using a heuristic based on reflogs and asks whether to overwrite the existing definition
+        `file` with the new discovered tree.
+        If confirmed with a `y[es]` or `e[dit]` reply, backs up the current definition file (if it exists) as `$GIT_DIR/machete~`
+        and saves the new tree under the usual `$GIT_DIR/machete` path.
+        If the reply was `e[dit]`, additionally an editor is opened (as in: `git machete` `edit`) after saving the new definition file.
+
+        <b>Options:</b>
+           <b>-C</b>, <b>--checked-out-since=<date></b>
+              Only consider branches checked out at least once since the given date.
+              <date> can be e.g. `2 weeks ago` or `2020-06-01`, as in `git log --since=<date>`.
+              If not present, the date is selected automatically so that around 10 branches are included.
+           <b>-l</b>, <b>--list-commits</b>
+              When printing the discovered tree, additionally lists the messages of commits introduced on each branch
+              (as for `git machete status`).
+           <b>-r</b>, <b>--roots=<branch1,...></b>
+              Comma-separated list of branches that should be considered roots of trees of branch dependencies.
+              If not present, `master` is assumed to be a root. Note that in the process of discovery,
+              certain other branches can also be additionally deemed to be roots as well.
+           <b>-y</b>, <b>--yes</b>
+              Don't ask for confirmation before saving the newly-discovered tree.
+              Mostly useful in scripts; not recommended for manual use.
+   """,
+    "edit": """
+        <b>Usage:</b><b>
+           git machete e[dit]</b>
+
+        Opens an editor and lets you edit the definition file manually.
+
+        The editor is determined by checking up the following locations:
+           * `$GIT_MACHETE_EDITOR`
+           * `$GIT_EDITOR`
+           * `$(git config core.editor)`
+           * `$VISUAL`
+           * `$EDITOR`
+           * `editor`
+           * `nano`
+           * `vi`
+
+        and selecting the first one that is defined and points to an executable file accessible on `PATH`.
+
+        Note that the above editor selection only applies for editing the definition file,
+        but not for any other actions that may be indirectly triggered by git machete, including editing of rebase TODO list, commit messages etc.
+
+        The definition file can be always accessed and edited directly under the path returned by `git machete file`
+        (usually `.git/machete`, unless worktrees or submodules are involved).
+
+        <b>Environment variables:</b>
+           `GIT_MACHETE_EDITOR`
+              Name of the editor executable.
+
+   """,
+    "file": """
+        <b>Usage:</b><b>
+           git machete file</b>
+
+        Outputs the absolute path of machete definition file.
+        The file is always called `machete` and is located in the git directory of the project.
+
+        Three cases are possible:
+           * if `git machete` is executed from a regular working directory (not a worktree or submodule),
+             the file is located under `.git/machete`,
+           * if `git machete` is executed from a <b>worktree</b>,
+             the file path depends on the `machete.worktree.useTopLevelMacheteFile` config key value:
+              - if `machete.worktree.useTopLevelMacheteFile` is true (default), the file is located under `.git/machete`
+              - if `machete.worktree.useTopLevelMacheteFile` is false, the file is located under `.git/worktrees/.../machete`,
+
+           * if `git machete` is executed from a <b>submodule</b>, this file is located in the git folder of the submodule itself under `.git/modules/.../machete`.
+   """,
+    "fork-point": """
+        <b>Usage:</b><b>
+           git machete fork-point [--inferred] [<branch>]
+           git machete fork-point --override-to=<revision>|--override-to-inferred|--override-to-parent [<branch>]
+           git machete fork-point --unset-override [<branch>]</b>
+
+        Note: in all three forms, if no <branch> is specified, the currently checked out branch is assumed.
+        The branch in question does not need to occur in the definition file.
+
+        Without any option, displays full hash of the fork point commit for the <branch>.
+        Fork point of the given <branch> is the commit at which the history of the <branch> diverges from history of any other branch.
+
+        Fork point is assumed by many `git machete` commands as the place where the unique history of the <branch> starts.
+        The range of commits between the fork point and the tip of the given branch is, for instance:
+           * listed for each branch by `git machete status --list-commits`
+           * passed to `git rebase` by `git machete` `reapply`/`slide-out`/`traverse`/`update`
+           * provided to `git diff`/`log` by `git machete` `diff`/`log`.
+
+        `git machete` assumes fork point of <branch> is the most recent commit in the log of <branch> that has NOT been introduced on that very branch,
+        but instead occurs on a reflog (see help for `git reflog`) of some other, usually chronologically earlier, branch.
+        This yields a correct result in typical cases, but there are some situations
+        (esp. when some local branches have been deleted) where the fork point might not be determined correctly.
+        Thus, all rebase-involving operations (`reapply`, `slide-out`, `traverse` and `update`) run `git rebase` in the interactive mode by default,
+        unless told explicitly not to do so by `--no-interactive-rebase` flag, so that the suggested commit range can be inspected before the rebase commences.
+        Also, `reapply`, `slide-out`, `squash`, and `update` allow to specify the fork point explicitly by a command-line option.
+
+        `git machete fork-point` is different (and more powerful) than `git merge-base --fork-point`,
+        since the latter takes into account only the reflog of the one provided upstream branch,
+        while the former scans reflogs of all local branches and their remote tracking branches.
+        This makes git machete's `fork-point` more resilient to modifications of `.git/machete` `file` where certain branches are re-attached under new parents (upstreams).
+
+        With `--override-to=<revision>`, sets up a fork point override for <branch>.
+        Fork point for <branch> will be overridden to the provided <revision> (commit) as long as the <branch> still points to (or is descendant of) the commit X
+        that <branch> pointed to at the moment the override is set up.
+        Even if revision is a symbolic name (e.g. other branch name or `HEAD~3)` and not explicit commit hash (like `a1b2c3ff`),
+        it's still resolved to a specific commit hash at the moment the override is set up (and not later when the override is actually used).
+        The override data is stored under `machete.overrideForkPoint.<branch>.to` and `machete.overrideForkPoint.<branch>.whileDescendantOf` git config keys.
+        Note: the provided fork point <revision> must be an ancestor of the current <branch> commit X.
+
+        With `--override-to-parent`, overrides fork point of the <branch> to the commit currently pointed by <branch>'s parent in the branch dependency tree.
+        Note: this will only work if <branch> has a parent at all (i.e. is not a root) and parent of <branch> is an ancestor of current <branch> commit X.
+
+        With `--inferred`, displays the commit that `git machete fork-point` infers to be the fork point of <branch>.
+        If there is NO fork point override for <branch>, this is identical to the output of `git machete fork-point`.
+        If there is a fork point override for <branch>, this is identical to the what the output of `git machete fork-point` would be if the override was NOT present.
+
+        With `--override-to-inferred` option, overrides fork point of the <branch> to the commit that `git machete fork-point` infers to be the fork point of <branch>.
+        Note: this piece of information is also displayed by `git machete status --list-commits` in case a <yellow>yellow</yellow> edge occurs.
+
+        With `--unset-override`, the fork point override for <branch> is unset.
+        This is simply done by removing the corresponding `machete.overrideForkPoint.<branch>.*` config entries.
+
+        Note: if an overridden fork point applies to a branch `B`, then it's considered to be connected with a <green>green</green> edge to its upstream (parent) `U`,
+        even if the overridden fork point of `B` is NOT equal to the commit pointed by `U`.
+   """,
+    "format": """
+        Note: there is no `git machete format` command as such; `format` is just a topic of `git machete help`.
+
+        The format of the definition file should be as follows:
+        <dim>
+          develop
+              adjust-reads-prec PR #234
+                  block-cancel-order PR #235
+                      change-table
+                          drop-location-type
+              edit-margin-not-allowed
+                  full-load-gatling
+              grep-errors-script
+          master
+              hotfix/receipt-trigger PR #236
+        </dim>
+
+        In the above example `develop` and `master` are roots of the tree of branch dependencies.
+        Branches `adjust-reads-prec`, `edit-margin-not-allowed` and `grep-errors-script` are direct downstream branches for `develop`.
+        `block-cancel-order` is a downstream branch of `adjust-reads-prec`, `change-table` is a downstream branch of `block-cancel-order` and so on.
+
+        Every branch name can be followed (after a single space as a delimiter) by a custom annotation — a PR number in the above example.
+        The annotations don't influence the way `git machete` operates other than that they are displayed in the output of the `status` command.
+        Also see help for `anno` command.
+
+        Tabs or any number of spaces can be used as indentation.
+        It's only important to be consistent wrt. the sequence of characters used for indentation between all lines.
+   """,
+    "github": """
+        <b>Usage:</b><b>
+           git machete github <subcommand></b>
+
+        where `<subcommand>` is one of: `anno-prs`, `checkout-prs`, `create-pr`, `retarget-pr`.
+
+        Creates, checks out and manages GitHub PRs while keeping them reflected in branch definition file.
+
+        To allow GitHub API access for private repositories (and also to perform side-effecting actions like opening a PR,
+        even in case of public repositories), a GitHub API token with `repo` scope is required, see https://github.com/settings/tokens.
+        This will be resolved from the first of:
+           * `GITHUB_TOKEN` env var,
+           * content of the `.github-token` file in the home directory (`~`),
+           * current auth token from the `gh` GitHub CLI,
+           * current auth token from the `hub` GitHub CLI.
+
+        GitHub API server URL will be inferred from `git remote`.
+        You can override this by setting the following git config keys:
+           Remote name
+              E.g. `machete.github.remote` = `origin`
+
+           Organization name
+              E.g. `machete.github.organization` = `VirtusLab`
+
+           Repository name
+              E.g. `machete.github.repository` = `git-machete`
+
+        To do this, run `git config --local --edit` and add the following section:
+        <dim>
+          [machete "github"]
+              organization = <organization_name>
+              repository = <repo_name>
+              remote = <remote_name>
+        </dim>
+
+        <b>Subcommands:</b>
+           `anno-prs`:
+              Annotates the branches based on their corresponding GitHub PR numbers and authors.
+              Any existing annotations are overwritten for the branches that have an opened PR; annotations for the other branches remain untouched.
+              Equivalent to `git machete anno --sync-github-prs`.
+
+           `checkout-prs [--all | --by=<github-login> | --mine | <PR-number-1> ... <PR-number-N>]`:
+ 
+              Check out the head branch of the given pull requests (specified by numbers or by a flag),
+              also traverse chain of pull requests upwards, adding branches one by one to git-machete and check them out locally.
+              Once the specified pull requests are checked out locally, annotate local branches with corresponding pull request numbers.
+              If only one PR has been checked out, then switch the local repository's HEAD to its head branch.
+
+              <b>Options:</b>
+
+                 <b>--all</b>
+              Checkout all open PRs.
+
+                 <b>--by=<github-login></b>
+
+              Checkout open PRs authored by the given GitHub user, where `<github-login>` is the GitHub account name.
+
+                 <b>--mine</b>
+              Checkout open PRs for the current user associated with the GitHub token.
+
+              <b>Parameters:</b>
+
+              `<PR-number-1> ... <PR-number-N>`    Pull request numbers to checkout.
+
+           `create-pr [--draft]`:
+ 
+              Creates a PR for the current branch, using the upstream (parent) branch as the PR base.
+              Once the PR is successfully created, annotates the current branch with the new PR's number.
+
+              If `.git/info/description` file is present, its contents are used as PR description.
+              If `.git/info/milestone` file is present, its contents (a single number — milestone id) are used as milestone.
+              If `.git/info/reviewers` file is present, its contents (one GitHub login per line) are used to set reviewers.
+
+              <b>Options:</b>
+
+                 <b>--draft</b>
+              Creates the new PR as a draft.
+
+           `retarget-pr`:
+              Sets the base of the current branch's PR to upstream (parent) branch, as seen by git machete (see `git machete show up`).
+
+           `sync`:
+ 
+              Synchronizes with the remote repository:
+
+                 * checks out open PRs for the current user associated with the GitHub token and also traverses the chain of pull requests upwards,
+                   adding branches one by one to git-machete and checks them out locally as well,
+
+                 * deletes unmanaged branches,
+
+                 * deletes untracked managed branches that have no downstream branch.
+
+              Equivalent of `git machete clean --checkout-my-github-prs`.
+
+        <b>Environment variables (all subcommands):</b>
+           `GITHUB_TOKEN`
+              GitHub API token.
+
+   """,
+    "go": """
+        <b>Usage:</b><b>
+           git machete g[o] <direction></b>
+
+        where <direction> is one of: `d[own]`, `f[irst]`, `l[ast]`, `n[ext]`, `p[rev]`, `r[oot]`, `u[p]`
+
+        Checks out the branch specified by the given direction relative to the current branch:
+           * `down`:    the direct children/downstream branch of the current branch.
+           * `first`:   the first downstream of the root branch of the current branch (like `root` followed by `next`),
+             or the root branch itself if the root has no downstream branches.
+           * `last`:    the last branch in the definition file that has the same root as the current branch;
+             can be the root branch itself if the root has no downstream branches.
+           * `next`:    the direct successor of the current branch in the definition file.
+           * `prev`:    the direct predecessor of the current branch in the definition file.
+           * `root`:    the root of the tree where the current branch is located.
+             Note: this will typically be something like `develop` or `master`,
+             since all branches are usually meant to be ultimately merged to one of those.
+           * `up`:      the direct parent/upstream branch of the current branch.
+
+        Roughly equivalent to `git checkout $(git machete show <direction>)`.
+   """,
+    "help": """
+        <b>Usage:</b><b>
+           git machete help [<command>]</b>
+
+        Prints a summary of this tool, or a detailed info on a command if provided.
+   """,
+    "hooks": """
+        As with the standard git hooks, git machete looks for its own specific hooks in `$GIT_DIR/hooks/*` (or `$(git config core.hooksPath)/*`, if set).
+        All hooks are executed from the top-level folder of the repository (or top-level folder of worktree/submodule, if applicable).
+
+        Note: `hooks` is not a command as such, just a help topic (there is no `git machete hooks` command).
+
+        <b>Hooks:</b>
+           `machete-post-slide-out <new-upstream> <lowest-slid-out-branch> [<new-downstreams>...]`
+ 
+              The hook that is executed after a branch (or possibly multiple branches, in case of `slide-out`)
+              is slid out by `advance`, `slide-out` or `traverse`.
+
+              At least two parameters (branch names) are passed to the hook:
+
+                 * <new-upstream> is the upstream of the branch that has been slid out, or in case of multiple branches being slid out
+                   — the upstream of the highest slid out branch;
+
+                 * <lowest-slid-out-branch> is the branch that has been slid out, or in case of multiple branches being slid out — the lowest slid out branch;
+
+                 * <new-downstreams> are all the following (possibly zero) parameters, which correspond to all original downstreams
+                   of <lowest-slid-out-branch>, now reattached as the downstreams of <new-upstream>.
+
+              Note that this may be zero, one, or multiple branches.
+
+              Note: the hook, if present, is executed:
+
+                 * zero or once during a `advance` execution (depending on whether the slide-out has been confirmed or not),
+
+                 * exactly once during a `slide-out` execution (even if multiple branches are slid out),
+
+                 * zero or more times during `traverse` (every time a slide-out operation is confirmed).
+
+              If the hook returns a non-zero exit code, then an error is raised and the execution of the command is aborted,
+              i.e. `slide-out` won't attempt rebase of the new downstream branches and `traverse` won't continue the traversal.
+              In case of `advance` there is no difference (other than exit code of the entire `advance` command being non-zero),
+              since slide-out is the last operation that happens within `advance`.
+
+              Note that non-zero exit code of the hook doesn't cancel the effects of slide-out itself, only the subsequent operations.
+              The hook is executed only once the slide-out is complete and can in fact rely on .git/machete file being updated to the new branch layout.
+
+           `machete-pre-rebase <new-base> <fork-point-hash> <branch-being-rebased>`
+ 
+              The hook that is executed before rebase is run during `reapply`, `slide-out`, `traverse` and `update`.
+              Note that it is NOT executed by `squash` (despite its similarity to `reapply`), since no rebase is involved in `squash`.
+
+              The parameters are exactly the three revisions that are passed to `git rebase --onto`:
+
+                 * what is going to be the new base for the rebased commits,
+
+                 * what is the fork point — the place where the rebased history diverges from the upstream history,
+
+                 * what branch is rebased.
+
+              If the hook returns a non-zero exit code, an error is raised and the entire rebase is aborted.
+
+              Note: this hook is independent from git's standard `pre-rebase hook`.
+              If machete-pre-rebase returns zero, the execution flow continues to `git rebase`, which may also run `pre-rebase hook` if present.
+              `machete-pre-rebase` is thus always launched before `pre-rebase`.
+
+           `machete-status-branch <branch-name>`
+ 
+              The hook that is executed for each branch displayed during `discover`, `status` and `traverse`.
+
+              The standard output of this hook is displayed at the end of the line, after branch name, (optionally) custom annotation and
+              (optionally) remote sync-ness status. Standard error is ignored. If the hook returns a non-zero exit code, both stdout and stderr
+              are ignored, and printing the status continues as usual.
+
+              Note: the hook is always invoked with `ASCII_ONLY` variable passed into the environment.
+              If `status` runs in ASCII-only mode (i.e. if `--color=auto` and stdout is not a terminal, or if `--color=never`),
+              then `ASCII_ONLY=true`, otherwise `ASCII_ONLY=false`.
+
+        Please see hook_samples directory in git-machete project for examples.
+        An example of using the standard git `post-commit hook` to `git machete add` branches automatically is also included.
+   """,
+    "is-managed": """
+        <b>Usage:</b><b>
+           git machete is-managed [<branch>]</b>
+
+        Returns with zero exit code if the given branch (or current branch, if none specified) is managed by git machete (i.e. listed in .git/machete).
+
+        Returns with a non-zero exit code in case:
+           * the <branch> is provided but isn't managed (or doesn't exist), or
+           * the <branch> isn't provided and the current branch isn't managed, or
+           * the <branch> isn't provided and there's no current branch (detached HEAD).
+   """,
+    "list": """
+        <b>Usage:</b><b>
+           git machete list <category></b>
+
+        where <category> is one of: `addable`, `childless`, `managed`, `slidable`, `slidable-after <branch>`, `unmanaged`, `with-overridden-fork-point`.
+
+        Lists all branches that fall into one of the specified categories:
+           * `addable`: all branches (local or remote) than can be added to the definition file,
+           * `childless`: all branches that do not possess child branches,
+           * `managed`: all branches that appear in the definition file,
+           * `slidable`: all managed branches that have an upstream and can be slid out with `slide-out` command
+           * `slidable-after <branch>`: the downstream branch of the <branch>, if it exists and is the only downstream of <branch>
+             (i.e. the one that can be slid out immediately following <branch>),
+           * `unmanaged`: all local branches that don't appear in the definition file,
+           * `with-overridden-fork-point`: all local branches that have a `fork point<fork-point>` override set up
+             (even if this override does not affect the location of their fork point anymore).
+
+        This command is generally not meant for a day-to-day use, it's mostly needed for the sake of branch name completion in shell.
+   """,
+    "log": """
+        <b>Usage:</b><b>
+           git machete l[og] [<branch>]</b>
+
+        Runs `git log` for the range of commits from tip of the given branch (or current branch, if none specified) back to its fork point.
+        See help for `fork-point` for more details on meaning of the fork point.
+
+        Note: the branch in question does not need to occur in the definition file.
+   """,
+    "reapply": """
+        <b>Usage:</b><b>
+           git machete reapply [-f|--fork-point=<fork-point-commit>]</b>
+
+        Interactively rebase the current branch on the top of its computed fork point.
+        The chunk of the history to be rebased starts at the automatically computed fork point of the current branch by default,
+        but can also be set explicitly by `--fork-point`.
+        See help for `fork-point` for more details on meaning of the fork point.
+
+        Note: the current reapplied branch does not need to occur in the definition file.
+
+        Tip: `reapply` can be used for squashing the commits on the current branch to make history more condensed before push to the remote,
+        but there is also dedicated `squash` command that achieves the same goal without running `git rebase`.
+
+        <b>Options:</b>
+           <b>-f</b>, <b>--fork-point=<fork-point-commit></b>
+              Specifies the alternative fork point commit after which the rebased part of history is meant to start.
+
+        <b>Environment variables:</b>
+           `GIT_MACHETE_REBASE_OPTS`
+              Extra options to pass to the underlying `git rebase` invocation, space-separated.
+              Example: `GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete reapply`.
+
+   """,
+    "show": """
+        <b>Usage:</b><b>
+           git machete show <direction> [<branch>]</b>
+
+        where <direction> is one of: `c[urrent]`, `d[own]`, `f[irst]`, `l[ast]`, `n[ext]`, `p[rev]`, `r[oot]`, `u[p]`
+        displayed relative to given <branch>, or the current checked out branch if <branch> is unspecified.
+
+        Outputs name of the branch (or possibly multiple branches, in case of `down`) that is:
+           * `current`: the current branch; exits with a non-zero status if none (detached HEAD)
+           * `down`:    the direct children/downstream branch of the given branch.
+           * `first`:   the first downstream of the root branch of the given branch (like `root` followed by `next`),
+             or the root branch itself if the root has no downstream branches.
+           * `last`:    the last branch in the definition file that has the same root as the given branch; can be the root branch itself
+             if the root has no downstream branches.
+           * `next`:    the direct successor of the given branch in the definition file.
+           * `prev`:    the direct predecessor of the given branch in the definition file.
+           * `root`:    the root of the tree where the given branch is located.
+             Note: this will typically be something like `develop` or `master`,
+             since all branches are usually meant to be ultimately merged to one of those.
+           * `up`:      the direct parent/upstream branch of the given branch.
+   """,
+    "slide-out": """
+        <b>Usage:</b><b>
+           git machete slide-out [-d|--down-fork-point=<down-fork-point-commit>] [--delete] [-M|--merge] [-n|--no-edit-merge|--no-interactive-rebase] [<branch> [<branch> [<branch> ...]]]</b>
+
+        Removes the given branch (or multiple branches) from the branch tree definition.  If no branch has been specified current branch is assumed as the only branch.
+        Then synchronizes the downstream (child) branches of the last specified branch on the top of the upstream (parent) branch of the first specified branch.
+        Sync is performed either by rebase (default) or by merge (if `--merge` option passed).
+
+        The most common use is to slide out a single branch whose upstream was a `develop`/`master` branch and that has been recently merged.
+
+        Since this tool is designed to perform only one single rebase/merge at the end, provided branches must form a chain, i.e. all of the following conditions must be met:
+           * for i=1..N-1, (i+1)-th branch must be the only downstream (child) branch of the i-th branch,
+           * all provided branches must have an upstream branch (so, in other words, roots of branch dependency tree cannot be slid out).
+
+        For example, let's assume the following dependency tree:
+        <dim>
+          develop
+              adjust-reads-prec
+                  block-cancel-order
+                      change-table
+                          drop-location-type
+                      add-notification
+        </dim>
+
+        And now let's assume that `adjust-reads-prec` and later `block-cancel-order` were merged to develop.
+        After running `git machete slide-out adjust-reads-prec block-cancel-order` the tree will be reduced to:
+        <dim>
+          develop
+              change-table
+                  drop-location-type
+              add-notification
+        </dim>
+
+        and `change-table` and `add-notification` will be rebased onto develop (fork point for this rebase is configurable, see `-d` option below).
+
+        Note: This command doesn't delete any branches from git, just removes them from the tree of branch dependencies.
+
+        <b>Options:</b>
+           <b>-d</b>, <b>--down-fork-point=<down-fork-point-commit></b>
+              If updating by rebase, specifies the alternative fork point for downstream branches for the operation.
+              `git machete fork-point` overrides for downstream branches are recommended over use of this option.
+              See also doc for `--fork-point` option in `git machete help reapply` and `git machete help update`.
+              Not allowed if updating by merge.
+           <b>--delete</b>
+              Delete the slid-out branches.
+           <b>-M</b>, <b>--merge</b>
+              Update the downstream branch by merge rather than by rebase.
+           <b>-n</b>
+              If updating by rebase, equivalent to `--no-interactive-rebase`.
+              If updating by merge, equivalent to `--no-edit-merge`.
+           <b>--no-edit-merge</b>
+              If updating by merge, skip opening the editor for merge commit message while doing
+              `git merge` (i.e. pass `--no-edit` flag to underlying `git merge`).
+              Not allowed if updating by rebase.
+           <b>--no-interactive-rebase</b>
+              If updating by rebase, run `git rebase` in non-interactive mode (without `-i/--interactive` flag).
+              Not allowed if updating by merge.
+
+        <b>Environment variables:</b>
+           `GIT_MACHETE_REBASE_OPTS`
+              Extra options to pass to the underlying `git rebase` invocations, space-separated.
+              Example: `GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete slide-out`.
+
+   """,
+    "squash": """
+        <b>Usage:</b><b>
+           git machete squash [-f|--fork-point=<fork-point-commit>]</b>
+
+        Squashes the commits belonging uniquely to the current branch into a single commit.
+        The chunk of the history to be squashed starts at the automatically computed fork point of the current branch by default,
+        but can also be set explicitly by `--fork-point`.
+        See help for `fork-point` for more details on meaning of the fork point.
+        The message for the squashed is taken from the earliest squashed commit, i.e. the commit directly following the fork point.
+
+        Note: the current squashed branch does not need to occur in the definition file.
+
+        Tip: `squash` does NOT run `git rebase` under the hood. For more complex scenarios that require rewriting the history of current branch, see `reapply` and `update`.
+
+        <b>Options:</b>
+           <b>-f</b>, <b>--fork-point=<fork-point-commit></b>
+              Specifies the alternative fork point commit after which the squashed part of history is meant to start.
+   """,
+    "status": """
+        <b>Usage:</b><b>
+           git machete s[tatus] [--color=WHEN] [-l|--list-commits] [-L|--list-commits-with-hashes] [--no-detect-squash-merges]</b>
+
+        Displays a tree-shaped status of the branches listed in the definition file.
+
+        Apart from simply ASCII-formatting the definition file, this also:
+           * colors the edges between upstream (parent) and downstream (children) branches:
+              - <red>red edge</red> means that the downstream branch tip is not a direct descendant of the upstream branch tip,
+              - <yellow>yellow edge</yellow> means that the downstream branch tip is a direct descendant of the upstream branch tip,
+                but the `fork point<fork-point>` of the downstream branch is not equal to the upstream branch tip,
+              - <green>green edge</green> means that the downstream branch tip is a direct descendant of the upstream branch tip
+                and the fork point of the downstream branch is equal to the upstream branch tip,
+              - grey/dimmed edge means that the downstream branch has been merged to the upstream branch,
+                detected by commit equivalency (default), or by strict detection of merge commits (if `--no-detect-squash-merges` passed).
+
+           * prints (`untracked`/`ahead of <remote>`/`behind <remote>`/`diverged from [& older than] <remote>`) message if the branch
+             is not in sync with its remote counterpart;
+           * displays the custom annotations (see help for `format` and `anno`) next to each branch, if present;
+           * displays the output of `machete-status-branch hook` (see help for `hooks`), if present;
+           * optionally lists commits introduced on each branch if `-l/--list-commits` or `-L/--list-commits-with-hashes` is supplied.
+
+        Name of the currently checked-out branch is underlined (or shown in blue on terminals that don't support underline).
+
+        In case of <yellow>yellow edge</yellow>, use `-l` or `-L` flag to show the exact location of the inferred fork point
+        (which indicates e.g. what range of commits is going to be rebased when the branch is updated).
+        The inferred fork point can be always overridden manually, see help for `fork-point`.
+
+        Grey/dimmed edge suggests that the downstream branch can be slid out (see help for `slide-out` and `traverse`).
+
+        Using colors can be disabled with a `--color` flag set to `never`.
+        With `--color=always`, git machete always emits colors and with `--color=auto`, it emits colors only when standard output is connected to a terminal.
+        `--color=auto` is the default. When colors are disabled, relation between branches is represented in the following way (not including the hash-comments):
+        <dim>
+          <branch0>
+          |
+          o-<branch1> *   # green (in sync with parent; asterisk for the current branch)
+          | |
+          | x-<branch2>   # red (not in sync with parent)
+          |   |
+          |   ?-<branch3> # yellow (in sync with parent, but parent is not the fork point)
+          |
+          m-<branch4>     # grey (merged to parent)
+        </dim>
+
+        <b>Options:</b>
+           <b>--color=WHEN</b>
+              Colorize the output; WHEN can be `always`, `auto` (default; i.e. only if stdout is a terminal), or `never`.
+           <b>-l</b>, <b>--list-commits</b>
+              Additionally list the commits introduced on each branch.
+           <b>-L</b>, <b>--list-commits-with-hashes</b>
+              Additionally list the short hashes and messages of commits introduced on each branch.
+           <b>--no-detect-squash-merges</b>
+              Only consider strict (fast-forward or 2-parent) merges, rather than rebase/squash merges,
+              when detecting if a branch is merged into its upstream (parent).
+
+        <b>Config keys:</b>
+           `machete.status.extraSpaceBeforeBranchName`
+
+              To make it easier to select branch name from the `status` output on certain terminals
+              (e.g. Alacritty), you can add an extra
+              space between └─ and `branch name` by setting `git config machete.status.extraSpaceBeforeBranchName true`.
+
+              For example, by default the status is displayed as:
+
+              develop
+              │
+              ├─feature_branch1
+              │
+              └─feature_branch2
+
+              With `machete.status.extraSpaceBeforeBranchName` config set to `true`:
+
+              develop
+              │
+              ├─ feature_branch1
+              │
+              └─ feature_branch2
+
+   """,
+    "traverse": """
+        <b>Usage:</b><b>
+           git machete t[raverse] [-F|--fetch] [-l|--list-commits] [-M|--merge]
+                                  [-n|--no-edit-merge|--no-interactive-rebase] [--no-detect-squash-merges]
+                                  [--[no-]push] [--[no-]push-untracked]
+                                  [--return-to=WHERE] [--start-from=WHERE] [-w|--whole] [-W] [-y|--yes]</b>
+
+        Traverses the branch tree in pre-order (i.e. simply in the order as they occur in the definition file).
+        By default `traverse` starts from the current branch.
+        This behaviour can, however, be customized using options: `--start-from=`, `--whole` or `-w`, `-W`.
+
+        For each branch, the command:
+           * detects if the branch is merged (grey edge) to its parent (aka upstream):
+              - by commit equivalency (default), or by strict detection of merge commits (if `--no-detect-squash-merges` passed),
+              - if so, asks the user whether to slide out the branch from the dependency tree (typically branches are no longer needed after they're merged);
+
+           * otherwise, if the branch has a <red>red</red> or <yellow>yellow</yellow> edge to its parent/upstream (see help for `status`):
+              - asks the user whether to rebase (default) or merge (if `--merge` passed) the branch onto into its upstream branch
+                — equivalent to `git machete update` with no `--fork-point` option passed;
+
+           * if the branch is not tracked on a remote, is ahead of its remote counterpart, or diverged from the counterpart &
+             has newer head commit than the counterpart:
+              - asks the user whether to push the branch (possibly with `--force-with-lease` if the branches diverged);
+
+           * otherwise, if the branch diverged from the remote counterpart & has older head commit than the counterpart:
+              - asks the user whether to `git reset --keep` the branch to its remote counterpart
+
+           * otherwise, if the branch is behind its remote counterpart:
+              - asks the user whether to pull the branch;
+
+           * and finally, if any of the above operations has been successfully completed:
+              - prints the updated `status`.
+
+        If the traverse flow is stopped (typically due to merge/rebase conflicts), just run `git machete traverse` after the merge/rebase is finished.
+        It will pick up the walk from the current branch (unless `--start-from=` or `-w` etc. is passed).
+        Unlike with e.g. `git rebase`, there is no special `--continue` flag, as `traverse` is stateless
+        (doesn't keep a state of its own like `git rebase` does in `.git/rebase-apply/`).
+
+        <b>Options:</b>
+           <b>-F</b>, <b>--fetch</b>
+              Fetch the remotes of all managed branches at the beginning of traversal (no `git pull` involved, only `git fetch`).
+           <b>-l</b>, <b>--list-commits</b>
+              When printing the status, additionally list the messages of commits introduced on each branch.
+           <b>-M</b>, <b>--merge</b>
+              Update by merge rather than by rebase.
+           <b>-n</b>
+              If updating by rebase, equivalent to `--no-interactive-rebase`. If updating by merge, equivalent to `--no-edit-merge`.
+           <b>--no-detect-squash-merges</b>
+              Only consider strict (fast-forward or 2-parent) merges, rather than rebase/squash merges,
+              when detecting if a branch is merged into its upstream (parent).
+           <b>--no-edit-merge</b>
+              If updating by merge, skip opening the editor for merge commit message while doing `git merge`
+              (i.e. pass `--no-edit` flag to the underlying `git merge`). Not allowed if updating by rebase.
+           <b>--no-interactive-rebase</b>
+              If updating by rebase, run `git rebase` in non-interactive mode (without `-i/--interactive` flag).
+              Not allowed if updating by merge.
+           <b>--no-push</b>
+              Do not push any (neither tracked nor untracked) branches to remote, re-enable via `--push`.
+           <b>--no-push-untracked</b>
+              Do not push untracked branches to remote, re-enable via `--push-untracked`.
+           <b>--push</b>
+              Push all (both tracked and untracked) branches to remote — default behavior.
+           <b>--push-untracked</b>
+              Push untracked branches to remote — default behavior.
+           <b>--return-to=WHERE</b>
+              Specifies the branch to return after traversal is successfully completed;
+              WHERE can be `here` (the current branch at the moment when traversal starts), `nearest-remaining`
+              (nearest remaining branch in case the `here` branch has been slid out by the traversal) or
+              `stay` (the default — just stay wherever the traversal stops). Note: when user quits by `q`/`yq`
+              or when traversal is stopped because one of git actions fails, the behavior is always `stay`.
+           <b>--start-from=WHERE</b>
+              Specifies the branch to start the traversal from; WHERE can be `here`
+              (the default — current branch, must be managed by git machete), `root` (root branch of the current branch,
+              as in `git machete show root`) or `first-root` (first listed managed branch).
+           <b>-w</b>, <b>--whole</b>
+              Equivalent to `-n --start-from=first-root --return-to=nearest-remaining`;
+              useful for quickly traversing & syncing all branches (rather than doing more fine-grained operations on the
+              local section of the branch tree).
+           <b>-W</b>
+              Equivalent to `--fetch --whole`; useful for even more automated traversal of all branches.
+           <b>-y</b>, <b>--yes</b>
+              Don't ask for any interactive input, including confirmation of rebase/push/pull. Implies `-n`.
+
+        <b>Environment variables:</b>
+           `GIT_MACHETE_REBASE_OPTS`
+              Extra options to pass to the underlying `git rebase` invocations, space-separated.
+              Example: `GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete traverse`.
+
+   """,
+    "update": """
+        <b>Usage:</b><b>
+           git machete update [-f|--fork-point=] [-M|--merge] [-n|--no-edit-merge|--no-interactive-rebase]</b>
+
+        Synchronizes the current branch with its upstream (parent) branch either by rebase (default) or by merge (if `--merge` option passed).
+
+        If updating by rebase, interactively rebases the current branch on the top of its upstream (parent) branch.
+        The chunk of the history to be rebased starts at the fork point of the current branch, which by default is inferred automatically,
+        but can also be set explicitly by `--fork-point`.
+        See help for `fork-point` for more details on the meaning of fork point.
+
+        If updating by merge, merges the upstream (parent) branch into the current branch.
+
+        <b>Options:</b>
+           <b>-f</b>, <b>--fork-point=<fork-point-commit></b>
+              If updating by rebase, specifies the alternative fork point commit after which the rebased
+              part of history is meant to start. Not allowed if updating by merge.
+           <b>-M</b>, <b>--merge</b>
+              Update by merge rather than by rebase.
+           <b>-n</b>
+              If updating by rebase, equivalent to `--no-interactive-rebase`.
+              If updating by merge, equivalent to `--no-edit-merge`.
+           <b>--no-edit-merge</b>
+              If updating by merge, skip opening the editor for merge commit message while doing `git merge`
+              (i.e. pass `--no-edit` flag to underlying `git merge`). Not allowed if updating by rebase.
+           <b>--no-interactive-rebase</b>
+              If updating by rebase, run `git rebase` in non-interactive mode (without `-i/--interactive` flag).
+              Not allowed if updating by merge.
+
+        <b>Environment variables:</b>
+           `GIT_MACHETE_REBASE_OPTS`
+              Extra options to pass to the underlying `git rebase` invocation, space-separated.
+              Example: `GIT_MACHETE_REBASE_OPTS="--keep-empty --rebase-merges" git machete update`.
+
+   """,
+    "version": """
+        <b>Usage:</b><b>
+           git machete version</b>
+
+        Prints the version and exits.
+   """,
+}
diff --git a/git_machete/git_operations.py b/git_machete/git_operations.py
index 0b55972..d9fd2b5 100644
--- a/git_machete/git_operations.py
+++ b/git_machete/git_operations.py
@@ -1,3 +1,4 @@
+import string
 from pathlib import Path
 from typing import Any, Callable, Dict, Generator, Iterator, List, Match, NamedTuple, Optional, Set, Tuple
 
@@ -123,6 +124,10 @@ class FullCommitHash(AnyRevision):
                                 'Consider posting an issue on https://github.com/VirtusLab/git-machete/issues/new')
         return None
 
+    @staticmethod
+    def is_valid(value: str) -> bool:
+        return value is not None and len(value) == 40 and all(c in string.hexdigits for c in value)
+
     def full_name(self) -> "FullCommitHash":
         return self
 
diff --git a/git_machete/handmade_short_docs.py b/git_machete/handmade_short_docs.py
new file mode 100644
index 0000000..828cfa7
--- /dev/null
+++ b/git_machete/handmade_short_docs.py
@@ -0,0 +1,35 @@
+from typing import Dict
+
+# ---------------------------------------------------------------------------------------------------------
+# This file is supposed to be modified manually
+# ---------------------------------------------------------------------------------------------------------
+
+short_docs: Dict[str, str] = {
+    "add": "Add a branch to the tree of branch dependencies",
+    "advance": "Fast-forward merge one of children to the current branch, push it and then slide out the child",
+    "anno": "Manage custom annotations",
+    "clean": "Delete untracked and unmanaged branches and also optionally check out user's open GitHub PRs",
+    "config": "Display docs for the git machete configuration keys and environment variables",
+    "delete-unmanaged": "Delete local branches that are not present in the definition file",
+    "diff": "Diff current working directory or a given branch against its computed fork point",
+    "discover": "Automatically discover tree of branch dependencies",
+    "edit": "Edit the definition file",
+    "file": "Display the location of the definition file",
+    "fork-point": "Display or override fork point for a branch",
+    "format": "Display docs for the format of the definition file",
+    "github": "Create, check out and manage GitHub PRs while keeping them reflected in git machete",
+    "go": "Check out the branch relative to the position of the current branch, accepts down/first/last/next/root/prev/up argument",
+    "help": "Display this overview, or detailed help for a specified command",
+    "hooks": "Display docs for the extra hooks added by git machete",
+    "is-managed": "Check if the current branch is managed by git machete (mostly for scripts)",
+    "list": "List all branches that fall into one of pre-defined categories (mostly for internal use)",
+    "log": "Log the part of history specific to the given branch",
+    "reapply": "Rebase the current branch onto its computed fork point",
+    "show": "Show name(s) of the branch(es) relative to the position of a branch, accepts down/first/last/next/root/prev/up argument",
+    "slide-out": "Slide out the current branch and sync its downstream (child) branches with its upstream (parent) branch via rebase or merge",
+    "squash": "Squash the unique history of the current branch into a single commit",
+    "status": "Display formatted tree of branch dependencies, including info on their sync with upstream branch and with remote",
+    "traverse": "Walk through the tree of branch dependencies and rebase, merge, slide out, push and/or pull each branch one by one. By default starts from current branch",
+    "update": "Sync the current branch with its upstream (parent) branch via rebase or merge",
+    "version": "Display the version and exit"
+}
diff --git a/graphics/setup-sandbox b/graphics/setup-sandbox
index 06fc9d3..4f40beb 100755
--- a/graphics/setup-sandbox
+++ b/graphics/setup-sandbox
@@ -1,12 +1,14 @@
 #!/usr/bin/env bash
 
+set -e -o pipefail -u
+
 newb() {
   git checkout -b $1
 }
 
 cmt() {
   b=$(git symbolic-ref --short HEAD)
-  f=${b/\//-}-${1}-${2}.txt
+  f=${b/\//-}-${1}-${2-}.txt
   touch $f
   git add $f
   git commit -m "$*"
@@ -15,10 +17,10 @@ cmt() {
 newrepo() {
   dir=$1
   rm -fr /tmp/_$dir
-  mv ~/$dir /tmp/_$dir
+  mv ~/$dir /tmp/_$dir || true
   mkdir ~/$dir
   cd ~/$dir
-  opt=$2
+  opt=${2-}
   git init $opt
 }
 
@@ -76,7 +78,6 @@ git branch -d root
 
 echo
 echo
-git machete status $1
+git machete status ${1-}
 echo
 echo
-
diff --git a/requirements.coverage.txt b/requirements.coverage.txt
index f2c5b45..4d34ea2 100644
--- a/requirements.coverage.txt
+++ b/requirements.coverage.txt
@@ -1,3 +1,3 @@
-coverage==6.4.3
-pytest==7.1.2
-pytest-mock==3.8.2
+coverage==6.5.0
+pytest==7.1.3
+pytest-mock==3.9.0
diff --git a/requirements.mypy.txt b/requirements.mypy.txt
index 738e055..fa04886 100644
--- a/requirements.mypy.txt
+++ b/requirements.mypy.txt
@@ -1,2 +1,2 @@
-mypy==0.971
-pytest==7.1.2
+mypy==0.981
+pytest==7.1.3
diff --git a/requirements.py-docs.txt b/requirements.py-docs.txt
new file mode 100644
index 0000000..1d8c767
--- /dev/null
+++ b/requirements.py-docs.txt
@@ -0,0 +1,3 @@
+docutils==0.19
+pygments==2.13
+beautifulsoup4==4.11.1
diff --git a/requirements.docs.txt b/requirements.sphinx-docs.txt
similarity index 63%
rename from requirements.docs.txt
rename to requirements.sphinx-docs.txt
index dc8f4c6..113d073 100644
--- a/requirements.docs.txt
+++ b/requirements.sphinx-docs.txt
@@ -1,2 +1,2 @@
-sphinx==5.1.1
+sphinx==5.2.3
 sphinx-rtd-theme==1.0.0
diff --git a/tox.ini b/tox.ini
index f222d67..1ca63d9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = pep8,mypy-py{36,37,38,39,310},py{36,37,38,39,310},coverage,docs
+envlist = pep8,mypy-py{36,37,38,39,310},py{36,37,38,39,310},coverage,sphinx-docs,py-docs
 minversion = 2.3.2
 skipsdist = True
 
@@ -32,7 +32,7 @@ commands = flake8
 ignore = W504
 show-source = True
 max-line-length = 140
-exclude = ./.*,build,dist,*egg,venv, git_machete/docs.py
+exclude = ./.*,build,dist,*egg,venv, git_machete/handmade_short_docs.py, git_machete/generated_long_docs.py
 import-order-style = pep8
 
 [testenv:venv]
@@ -53,14 +53,34 @@ commands =
   # Saves a report to coverage.xml (uploaded to Codecov from CI, as Codecov apparently does not accept .coverage binary files)
   coverage xml
 
-[testenv:docs]
-description = "Build documentation"
+[testenv:sphinx-docs]
+description = "Build Sphinx documentation"
 usedevelop=true
 deps =
-  -r{toxinidir}/requirements.docs.txt
+  -r{toxinidir}/requirements.sphinx-docs.txt
 commands =
   sphinx-build -W --keep-going -b html docs/source docs/html
 
+[testenv:py-docs]
+description = "Build Python documentation"
+# The generation of the python docs uses git_machete package
+usedevelop=true
+allowlist_externals = bash
+deps =
+  -r{toxinidir}/requirements.py-docs.txt
+commands =
+  bash -c "python docs/generate_py_docs.py > git_machete/generated_long_docs.py"
+
+[testenv:check-py-docs]
+description = "Check if Python documentation is up to date with Sphinx documentation"
+# The generation of the python docs uses git_machete package
+usedevelop=true
+allowlist_externals = bash
+deps =
+  -r{toxinidir}/requirements.py-docs.txt
+commands =
+  bash docs/enforce-docs-up-to-date.sh
+
 [testenv:mypy]
 allowlist_externals = tox
 commands = tox -e "mypy-py{36,37,38,39,310}"


Test patch:
diff --git a/ci/deb-ppa-test-install/Dockerfile b/ci/deb-ppa-test-install/Dockerfile
index 24b0023..d1be3ec 100644
--- a/ci/deb-ppa-test-install/Dockerfile
+++ b/ci/deb-ppa-test-install/Dockerfile
@@ -1,13 +1,13 @@
 ARG ubuntu_version
 FROM ubuntu:${ubuntu_version}
+SHELL ["/bin/bash", "-e", "-o", "pipefail", "-u", "-x", "-c"]
 
 # See https://github.com/phusion/baseimage-docker/issues/58 for why DEBIAN_FRONTEND=noninteractive is needed (20.04-only issue)
-RUN set -x \
-    && apt-get update \
-    && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y git software-properties-common \
-    && add-apt-repository ppa:virtuslab/git-machete \
-    && apt-get autoremove --purge -y software-properties-common \
-    && rm -rfv /var/lib/apt/lists/*
+RUN \
+    apt-get update; \
+    DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y git gpg-agent software-properties-common; \
+    add-apt-repository ppa:virtuslab/git-machete; \
+    apt-get autoremove --purge -y gpg-agent software-properties-common
 
 COPY entrypoint.sh /
 RUN chmod +x /entrypoint.sh
diff --git a/ci/deb-ppa-test-install/README.md b/ci/deb-ppa-test-install/README.md
index 2f29095..428ca52 100644
--- a/ci/deb-ppa-test-install/README.md
+++ b/ci/deb-ppa-test-install/README.md
@@ -2,7 +2,7 @@
 
 ```shell script
 cd ci/deb-ppa-test-install/
-export UBUNTU_VERSION=18.04  # or 20.04
+export UBUNTU_VERSION=18.04  # or 20.04 or 22.04
 docker-compose build deb-ppa-test-install
 docker-compose run deb-ppa-test-install
 ```
diff --git a/ci/deb-ppa-test-install/build-context/entrypoint.sh b/ci/deb-ppa-test-install/build-context/entrypoint.sh
index 801b9cf..2db3ea6 100644
--- a/ci/deb-ppa-test-install/build-context/entrypoint.sh
+++ b/ci/deb-ppa-test-install/build-context/entrypoint.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-set -e -x
+set -e -o pipefail -u -x
 
 apt-get update
 apt-get install --no-install-recommends -y python3-git-machete
diff --git a/requirements.testenv.txt b/requirements.testenv.txt
index e6ac79c..750d48d 100644
--- a/requirements.testenv.txt
+++ b/requirements.testenv.txt
@@ -1,3 +1,3 @@
-pytest==7.1.2
-pytest-mock==3.8.2
+pytest==7.1.3
+pytest-mock==3.9.0
 pytest-xdist==2.5.0
diff --git a/tests/mockers.py b/tests/mockers.py
index e4c843d..55bf541 100644
--- a/tests/mockers.py
+++ b/tests/mockers.py
@@ -410,3 +410,7 @@ def mock_exit_script(status_code: Optional[int] = None, error: Optional[BaseExce
         raise error
     else:
         sys.exit(status_code)
+
+
+def mock_exit_script_no_exit(status_code: Optional[int] = None, error: Optional[BaseException] = None) -> None:
+    return
diff --git a/tests/test_diff.py b/tests/test_diff.py
index c155039..440261d 100644
--- a/tests/test_diff.py
+++ b/tests/test_diff.py
@@ -32,6 +32,8 @@ class TestDiff:
                                                   file_content='Develop content\n',
                                                   message='develop commit')
                 .push()
+                .write_to_file(file_name='file_name.txt',
+                               file_content='Content not committed\n')
         )
 
         expected_status_output = """
@@ -42,12 +44,30 @@ class TestDiff:
         +++ b/develop_file_name.txt
         @@ -0,0 +1 @@
         +Develop content
+        diff --git a/file_name.txt b/file_name.txt
+        index ff98b6d..5c3aa83 100644
+        --- a/file_name.txt
+        +++ b/file_name.txt
+        @@ -1 +1 @@
+        -Some file content
+        +Content not committed
 
         """
 
-        # Test `git machete diff` without providing the branch name
+        # Test `git machete diff` without providing the branch name, git diff against the current working tree
         assert_command(["diff"], expected_status_output, indent='')
 
+        expected_status_output = """
+        diff --git a/develop_file_name.txt b/develop_file_name.txt
+        new file mode 100644
+        index 0000000..a3bd4e5
+        --- /dev/null
+        +++ b/develop_file_name.txt
+        @@ -0,0 +1 @@
+        +Develop content
+
+        """
+
         assert_command(["diff", "develop"], expected_status_output, indent='')
 
         assert_command(["diff", "refs/heads/develop"], expected_status_output, indent='')
diff --git a/tests/test_fork_point.py b/tests/test_fork_point.py
index 404bb40..facee4e 100644
--- a/tests/test_fork_point.py
+++ b/tests/test_fork_point.py
@@ -50,3 +50,30 @@ class TestForkPoint:
         assert_command(["fork-point", 'develop'], "515319fa0ab47f372f6159bcc8ac27b43ee8a0ed\n", strip_indentation=False)
 
         assert_command(["fork-point", 'refs/heads/develop'], "515319fa0ab47f372f6159bcc8ac27b43ee8a0ed\n", strip_indentation=False)
+
+    def test_fork_point_override(self) -> None:
+        """
+        Verify behaviour of a 'git machete fork-point' command with fork-point being overridden by config key.
+        """
+        (
+            self.repo_sandbox.new_branch("master")
+                .commit("master commit")
+                .new_branch("develop")
+                .commit("develop commit")
+        )
+        launch_command('discover', '-y')
+
+        # invalid fork point with length not equal to 40
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.to', 39 * 'a')
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.whileDescendantOf', 39 * 'b')
+        launch_command('fork-point')
+
+        # invalid, non-hexadecimal alphanumeric characters present in the fork point
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.to', 20 * 'g1')
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.whileDescendantOf', 20 * 'g1')
+        launch_command('fork-point')
+
+        # invalid, non-hexadecimal special characters present in the fork point
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.to', 40 * '#')
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.whileDescendantOf', 40 * '!')
+        launch_command('fork-point')
diff --git a/tests/test_help.py b/tests/test_help.py
index 79be711..acce166 100644
--- a/tests/test_help.py
+++ b/tests/test_help.py
@@ -2,9 +2,11 @@ from typing import Any, List
 
 import pytest
 
-from git_machete.docs import long_docs
+from git_machete.generated_long_docs import long_docs
 
-from .mockers import GitRepositorySandbox, launch_command, mock_run_cmd
+from unittest import mock
+
+from .mockers import GitRepositorySandbox, launch_command, mock_exit_script_no_exit, mock_run_cmd
 
 
 class TestHelp:
@@ -56,3 +58,9 @@ class TestHelp:
                 assert expected_exit_code_when_failed == e.value.code, \
                     f"Verify that `git machete {command} --help` causes " \
                     f"SystemExit with {expected_exit_code} exit code."
+
+    @mock.patch('git_machete.cli.exit_script', mock_exit_script_no_exit)
+    def test_help_output_has_no_ansi_codes(self) -> None:
+        for command in long_docs.keys():
+            help_output = launch_command('help', command)
+            assert '\033' not in help_output