Repository: VirtusLab/git-machete (python)

Issue:
`whileDescendantOf` config for fork point override isn't just redundant, it's probably erroneous
Repro:
1. 2 unique commits on a branch Y
2. delete its base branch X
3. override fork-point for Y to Y~2
4. `git machete squash` while on Y
5. fork point override to Y~2 no longer applies, due to `whileDescendantOf` config, even though that's still logically the fork point (and is pointed by `to`)

Time to deprecate the setting: newer version of git-machete doesn't need to take this config into account at all. To retain backward compatibility (esp. with IntelliJ plugin, rather than earlier versions of the CLI), let's still set the `whileDescendantOf` to the same commit as `to`.


Pull request:
Deprecate `machete.overrideForkPoint.<branch>.whileDescendantOf` key
Closes #611
See https://github.com/VirtusLab/git-machete-intellij-plugin/pull/1581

Patch:
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 2b57b92..95879e8 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,8 +1,8 @@
 # Release notes
 
-## New in git-machete 3.15.3
+## New in git-machete 3.16.0
 
-- improved: stability of releases to Homebrew
+- deprecated: `machete.overrideForkPoint.<branch>.whileDescendantOf` is no longer taken into account; it's still written, however, for compatibility reasons
 
 ## New in git-machete 3.15.2
 
diff --git a/docs/source/cli_help/config.rst b/docs/source/cli_help/config.rst
index 6c37eca..d6ea155 100644
--- a/docs/source/cli_help/config.rst
+++ b/docs/source/cli_help/config.rst
@@ -14,13 +14,13 @@ Note: ``config`` is not a command as such, just a help topic (there is no ``git
     .. include:: github_config_keys.rst
         :start-line: 2
 
-``machete.overrideForkPoint.<branch>.{to,whileDescendantOf}``:
-    Executing ``git machete fork-point --override-to=<revision> [<branch>]`` sets up a fork point override for <branch>.
+``machete.overrideForkPoint.<branch>.to``:
+    Executing ``git machete fork-point --override-to[-parent|-inferred|=<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.
+    The override data is stored under ``machete.overrideForkPoint.<branch>.to`` git config key.
 
-    There should be **no** need for the user to interact with these keys directly.
+    There should be **no** need for the user to interact with this key directly,
+    ``git machete fork-point`` with flags should be used instead.
 
 ``machete.status.extraSpaceBeforeBranchName``:
     .. include:: status_config_key.rst
diff --git a/docs/source/cli_help/fork-point.rst b/docs/source/cli_help/fork-point.rst
index e4fcf7b..208965b 100644
--- a/docs/source/cli_help/fork-point.rst
+++ b/docs/source/cli_help/fork-point.rst
@@ -19,21 +19,21 @@ fork-point
   git machete fork-point --override-to=<revision>|--override-to-inferred|--override-to-parent [<branch>]
   git machete fork-point --unset-override [<branch>]
 
-Note: in all three forms, if no <branch> is specified, the currently checked out branch is assumed.
+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.
+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.
+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,
+``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.
@@ -47,26 +47,25 @@ while the former scans reflogs of all local branches and their remote tracking b
 This makes git machete's ``fork-point`` more resilient to modifications of ``.git/machete`` :ref:`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.
+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) that commit.
 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.
+The override data is stored under ``machete.overrideForkPoint.<branch>.to`` git config key.
+Note: the provided fork point <revision> must be an ancestor of the current ``<branch>`` commit.
 
-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 ``--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.
 
-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 ``--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>.
+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` 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.
+With ``--unset-override``, the fork point override for ``<branch>`` is unset.
+This is simply done by removing the corresponding ``machete.overrideForkPoint.<branch>.to`` config entry.
 
 
 Note: if an overridden fork point applies to a branch ``B``, then it's considered to be connected with a :green:`green` edge to its upstream (parent) ``U``,
diff --git a/git_machete/__init__.py b/git_machete/__init__.py
index 1394f3d..0c9d57a 100644
--- a/git_machete/__init__.py
+++ b/git_machete/__init__.py
@@ -1,1 +1,1 @@
-__version__ = '3.15.3'
+__version__ = '3.16.0'
diff --git a/git_machete/client.py b/git_machete/client.py
index 7bcaf09..c270dbc 100644
--- a/git_machete/client.py
+++ b/git_machete/client.py
@@ -1631,71 +1631,46 @@ class MacheteClient:
                     debug(f"upstream candidate {candidate} rejected ({reject_reason_message})")
         return None
 
-    # Also includes config that is incomplete (only one entry out of two) or otherwise invalid.
+    # Also includes config that is invalid (corresponding to a non-existent/GCed commit etc.).
     def has_any_fork_point_override_config(self, branch: LocalBranchShortName) -> bool:
         return (self.__git.get_config_attr_or_none(git_config_keys.override_fork_point_to(branch)) or
+                # Note that we still include the now-deprecated `whileDescendantOf` key for this purpose.
                 self.__git.get_config_attr_or_none(git_config_keys.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
+        # Note that here we ignore the now-deprecated `whileDescendantOf`.
         to_key = git_config_keys.override_fork_point_to(branch)
         if FullCommitHash.is_valid(value=self.__git.get_config_attr_or_none(to_key), git_context=self.__git):
             to = FullCommitHash.of(self.__git.get_config_attr_or_none(to_key))
-        while_descendant_of_key = git_config_keys.override_fork_point_while_descendant_of(branch)
-        if FullCommitHash.is_valid(value=self.__git.get_config_attr_or_none(while_descendant_of_key), git_context=self.__git):
-            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 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 or invalid")
+        else:
             return None
 
         to_hash: Optional[FullCommitHash] = self.__git.get_commit_hash_by_revision(to)
-        while_descendant_of_hash: Optional[FullCommitHash] = self.__git.get_commit_hash_by_revision(while_descendant_of)
-        if not to_hash or not while_descendant_of_hash:
-            if not to_hash:
-                warn(f"`{to_key}` config value {bold(to)} does not point to a valid commit")
-            if not while_descendant_of_hash:
-                warn(f"`{while_descendant_of_key}` config value {bold(while_descendant_of)} does not point to a valid commit")
-            return None
-        # This check needs to be performed every time the config is retrieved.
-        # We can't rely on the values being validated in set_fork_point_override(),
-        # since the config could have been modified outside of git-machete.
-        if not self.__git.is_ancestor_or_equal(to_hash.full_name(), while_descendant_of_hash.full_name()):
-            warn(
-                f"commit {bold(self.__git.get_short_commit_hash_by_revision(to))} pointed by `{to_key}` config "
-                f"is not an ancestor of commit {bold(self.__git.get_short_commit_hash_by_revision(while_descendant_of))} "
-                f"pointed by `{while_descendant_of_key}` config")
+        if not to_hash:
+            warn(f"`{to_key}` config value {bold(to)} does not point to a valid commit")
             return None
-        return ForkPointOverrideData(to_hash, while_descendant_of_hash)
+
+        return ForkPointOverrideData(to_hash)
 
     def __get_overridden_fork_point(self, branch: LocalBranchShortName) -> Optional[FullCommitHash]:
         override_data: ForkPointOverrideData = self.__get_fork_point_override_data(branch)
         if not override_data:
             return None
 
-        to, while_descendant_of = override_data.to_hash, override_data.while_descendant_of_hash
-        # Note that this check is distinct from the is_ancestor check performed in
-        # get_fork_point_override_data.
-        # While the latter checks the sanity of fork point override configuration,
-        # the former checks if the override still applies to wherever the given
-        # branch currently points.
-        if not self.__git.is_ancestor_or_equal(while_descendant_of.full_name(), branch.full_name()):
+        to = override_data.to_hash
+        # Checks if the override still applies to wherever the given branch currently points.
+        if not self.__git.is_ancestor_or_equal(to.full_name(), branch.full_name()):
             warn(fmt(
-                f"since branch {bold(branch)} is no longer a descendant of commit "
-                f"{bold(while_descendant_of)}, ",
-                f"the fork point override to commit {bold(to)} no longer applies.\n",
+                f"since branch {bold(branch)} is no longer a descendant of commit {bold(to)}, ",
+                "the fork point override to this commit no longer applies.\n",
                 f"Consider running:\n  `git machete fork-point --unset-override {branch}`\n"))
             return None
-        debug(f"since branch {branch} is descendant of while_descendant_of={while_descendant_of}, "
-              f"fork point of {branch} is overridden to {to}")
+        debug(f"since branch {branch} is descendant of {to}, fork point of {branch} is overridden to {to}")
         return to
 
     def unset_fork_point_override(self, branch: LocalBranchShortName) -> None:
         self.__git.unset_config_attr(git_config_keys.override_fork_point_to(branch))
+        # Note that we still unset the now-deprecated `whileDescendantOf` key.
         self.__git.unset_config_attr(git_config_keys.override_fork_point_while_descendant_of(branch))
 
     def set_fork_point_override(self, branch: LocalBranchShortName, to_revision: AnyRevision) -> None:
@@ -1711,20 +1686,15 @@ class MacheteClient:
         to_key = git_config_keys.override_fork_point_to(branch)
         self.__git.set_config_attr(to_key, to_hash)
 
+        # Let's still set the now-deprecated `whileDescendantOf` key to maintain compatibility with older git-machete clients
+        # (esp. IntelliJ plugin) that still require that key for an override to apply.
         while_descendant_of_key = git_config_keys.override_fork_point_while_descendant_of(branch)
-        branch_hash = self.__git.get_commit_hash_by_revision(branch)
-        self.__git.set_config_attr(while_descendant_of_key, branch_hash)
-
-        print(fmt(f"Fork point for <b>{branch}</b> is overridden to "
-                  f"<b>{self.__git.get_revision_repr(to_revision)}</b>.\n",
-                  f"This applies as long as <b>{branch}</b> points to (or is descendant of)"
-                  " its current head (commit "
-                  f"<b>{self.__git.get_short_commit_hash_by_revision(branch_hash)}</b>).\n\n",
-                  f"This information is stored under git config keys:\n"
-                  f"  * `{to_key}`\n"
-                  f"  * `{while_descendant_of_key}`\n\n",
-                  "To unset this override, use:\n  `git machete fork-point "
-                  f"--unset-override {branch}`"))
+        self.__git.set_config_attr(while_descendant_of_key, to_hash)
+
+        print(fmt(f"Fork point for <b>{branch}</b> is overridden to {self.__git.get_revision_repr(to_revision)}.\n",
+                  f"This applies as long as <b>{branch}</b> is a descendant of commit <b>{to_hash}</b>.\n\n"
+                  f"This information is stored under `{to_key}` git config key.\n\n"
+                  f"To unset this override, use:\n  `git machete fork-point --unset-override {branch}`"))
 
     def __pick_remote(
             self,
diff --git a/git_machete/generated_docs.py b/git_machete/generated_docs.py
index 17f432c..20466d5 100644
--- a/git_machete/generated_docs.py
+++ b/git_machete/generated_docs.py
@@ -272,14 +272,14 @@ long_docs: Dict[str, str] = {
               Note that you do <b>not</b> need to set all four keys at once.
               For example, in a typical usage of GitHub Enterprise, it should be enough to just set `machete.github.domain`.
 
-           `machete.overrideForkPoint.<branch>.{to,whileDescendantOf}`:
+           `machete.overrideForkPoint.<branch>.to`:
  
-              Executing `git machete fork-point --override-to=<revision> [<branch>]` sets up a fork point override for <branch>.
+              Executing `git machete fork-point --override-to[-parent|-inferred|=<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.
+              The override data is stored under `machete.overrideForkPoint.<branch>.to` git config key.
 
-              There should be <b>no</b> need for the user to interact with these keys directly.
+              There should be <b>no</b> need for the user to interact with this key directly,
+              `git machete fork-point` with flags should be used instead.
 
            `machete.status.extraSpaceBeforeBranchName`:
 
@@ -438,19 +438,19 @@ long_docs: Dict[str, str] = {
            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.
+        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.
+        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.
+        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,
+        `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.
@@ -463,26 +463,25 @@ long_docs: Dict[str, str] = {
         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.
+        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) that commit.
         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.
+        The override data is stored under `machete.overrideForkPoint.<branch>.to` git config key.
+        Note: the provided fork point <revision> must be an ancestor of the current `<branch>` commit.
 
-        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 `--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.
 
-        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 `--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>.
+        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.
+        With `--unset-override`, the fork point override for `<branch>` is unset.
+        This is simply done by removing the corresponding `machete.overrideForkPoint.<branch>.to` config entry.
 
         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`.
diff --git a/git_machete/git_operations.py b/git_machete/git_operations.py
index 078a719..ace674d 100644
--- a/git_machete/git_operations.py
+++ b/git_machete/git_operations.py
@@ -127,9 +127,7 @@ class FullCommitHash(AnyRevision):
 
     @staticmethod
     def is_valid(value: str, git_context: "GitContext") -> bool:
-        revision = AnyRevision(value)
-        return value is not None and len(value) == 40 and all(c in string.hexdigits for c in value) \
-            and git_context.is_commit_present_in_repository(revision)
+        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
@@ -157,9 +155,8 @@ class FullTreeHash(str):
 
 
 class ForkPointOverrideData:
-    def __init__(self, to_hash: FullCommitHash, while_descendant_of_hash: FullCommitHash):
+    def __init__(self, to_hash: FullCommitHash):
         self.to_hash: FullCommitHash = to_hash
-        self.while_descendant_of_hash: FullCommitHash = while_descendant_of_hash
 
 
 class GitLogEntry(NamedTuple):
@@ -193,7 +190,7 @@ class GitContext:
         self.__remotes_cached: Optional[List[str]] = None
         self.__counterparts_for_fetching_cached: Optional[
             Dict[LocalBranchShortName, Optional[RemoteBranchShortName]]] = None  # TODO (#110): default dict with None
-        self.__short_commit_hash_by_revision_cached: Dict[AnyRevision, ShortCommitHash] = {}
+        self.__short_commit_hash_by_revision_cached: Dict[AnyRevision, Optional[ShortCommitHash]] = {}
         self.__tree_hash_by_commit_hash_cached: Optional[
             Dict[FullCommitHash, Optional[FullTreeHash]]] = None  # TODO (#110): default dict with None
         self.__commit_hash_by_revision_cached: Optional[
@@ -424,9 +421,12 @@ class GitContext:
     def __find_short_commit_hash_by_revision(self, revision: AnyRevision) -> ShortCommitHash:
         return ShortCommitHash.of(self._popen_git("rev-parse", "--short", revision + "^{commit}").stdout.rstrip())  # noqa: FS003
 
-    def get_short_commit_hash_by_revision(self, revision: AnyRevision) -> ShortCommitHash:
+    def get_short_commit_hash_by_revision_or_none(self, revision: AnyRevision) -> Optional[ShortCommitHash]:
         if revision not in self.__short_commit_hash_by_revision_cached:
-            self.__short_commit_hash_by_revision_cached[revision] = self.__find_short_commit_hash_by_revision(revision)
+            try:
+                self.__short_commit_hash_by_revision_cached[revision] = self.__find_short_commit_hash_by_revision(revision)
+            except MacheteException:
+                self.__short_commit_hash_by_revision_cached[revision] = None
         return self.__short_commit_hash_by_revision_cached[revision]
 
     def __find_commit_hash_by_revision(self, revision: AnyRevision) -> Optional[FullCommitHash]:
@@ -682,11 +682,11 @@ class GitContext:
         self.__reflogs_cached = None
 
     def get_revision_repr(self, revision: AnyRevision) -> str:
-        short_hash = self.get_short_commit_hash_by_revision(revision)
-        if self.is_full_hash(revision.full_name()) or revision == short_hash:
-            return f"commit {revision}"
+        short_hash = self.get_short_commit_hash_by_revision_or_none(revision)
+        if not short_hash or self.is_full_hash(revision.full_name()) or revision == short_hash:
+            return f"commit <b>{revision}</b>"
         else:
-            return f"{revision} (commit {self.get_short_commit_hash_by_revision(revision)})"
+            return f"<b>{revision}</b> (commit <b>{short_hash}</b>)"
 
     # Note: while rebase is ongoing, the repository is always in a detached HEAD state,
     # so we need to extract the name of the currently rebased branch from the rebase-specific internals


Test patch:
diff --git a/tests/test_fork_point.py b/tests/test_fork_point.py
index 788be80..dfde52b 100644
--- a/tests/test_fork_point.py
+++ b/tests/test_fork_point.py
@@ -71,23 +71,23 @@ class TestForkPoint:
 
         # 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')
         assert launch_command('fork-point').strip() == develop_branch_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')
         assert launch_command('fork-point').strip() == develop_branch_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 * '!')
         assert launch_command('fork-point').strip() == develop_branch_fork_point
 
         # valid commit hash but not present in the repository
         self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.to', 40 * 'a')
-        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.whileDescendantOf', 40 * 'a')
-        assert launch_command('fork-point').strip() == develop_branch_fork_point
+        assert launch_command('fork-point').strip() == (
+               "Warn: since branch develop is no longer a descendant of commit aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, the fork point override to this commit no longer applies.\n"  # noqa: E501
+               "Consider running:\n"
+               "  git machete fork-point --unset-override develop\n\n" +
+               develop_branch_fork_point)
 
         # valid fork-point override commit hash
         launch_command('fork-point', f'--override-to={master_branch_first_commit_hash}')