diff --git a/rust/rhgitaly/src/gitlab/revision.rs b/rust/rhgitaly/src/gitlab/revision.rs
index 65ced17df56fd683d7929cd7330dc2260e9eacf6_cnVzdC9yaGdpdGFseS9zcmMvZ2l0bGFiL3JldmlzaW9uLnJz..6b1e19b408fe568b7c5d727cfc79d8a8d3f30828_cnVzdC9yaGdpdGFseS9zcmMvZ2l0bGFiL3JldmlzaW9uLnJz 100644
--- a/rust/rhgitaly/src/gitlab/revision.rs
+++ b/rust/rhgitaly/src/gitlab/revision.rs
@@ -17,6 +17,8 @@
 //! the hlpers to handle them are in particular provided by this module.
 use std::path::Path;
 
-use hg::revlog::node::Node;
+use tracing::{info, warn};
+
+use hg::revlog::node::{Node, NodePrefix};
 
 use super::state::{
@@ -21,7 +23,8 @@
 
 use super::state::{
-    has_keep_around, map_lookup_typed_ref, stream_gitlab_branches, stream_gitlab_special_refs,
-    stream_gitlab_tags, StateFileError, TypedRef,
+    get_gitlab_default_branch, has_keep_around, lookup_typed_ref_as_node, map_lookup_typed_ref,
+    stream_gitlab_branches, stream_gitlab_special_refs, stream_gitlab_tags, StateFileError,
+    TypedRef,
 };
 
 #[derive(Debug, derive_more::From)]
@@ -102,6 +105,65 @@
     .await??)
 }
 
+pub async fn gitlab_revision_node_prefix(
+    store_path: &Path,
+    revision: &[u8],
+) -> Result<Option<NodePrefix>, RefError> {
+    if revision == b"HEAD" {
+        match get_gitlab_default_branch(store_path).await? {
+            None => {
+                info!("No GitLab default branch");
+                return Ok(None);
+            }
+            Some(branch) => {
+                match lookup_typed_ref_as_node(stream_gitlab_branches(store_path).await?, &branch)
+                    .await?
+                {
+                    None => {
+                        warn!("GitLab default branch not found in state file");
+                        return Ok(None);
+                    }
+                    Some(node) => {
+                        return Ok(Some(node.into()));
+                    }
+                }
+            }
+        }
+    }
+
+    // Full nodes have the highest precedence in Gitaly.
+    // They also are frequently used and cheap to check (no I/O).
+    if let Ok(node) = Node::from_hex(revision) {
+        return Ok(Some(node.into()));
+    }
+
+    // Full refs are well qualified, hence have high precedence
+    if let Ok(node) = full_ref_node(store_path, revision).await {
+        return Ok(Some(node.into()));
+    }
+
+    // Tags have the highest precedence amongst potentially ambiguous revisions
+    if let Some(node) =
+        lookup_typed_ref_as_node(stream_gitlab_tags(store_path).await?, revision).await?
+    {
+        return Ok(Some(node.into()));
+    }
+
+    // Branches. TODO duplication, maybe chain the streams if not None
+    if let Some(node) =
+        lookup_typed_ref_as_node(stream_gitlab_branches(store_path).await?, revision).await?
+    {
+        return Ok(Some(node.into()));
+    }
+
+    // Last case: Node Prefix
+    if let Ok(prefix) = NodePrefix::from_hex(revision) {
+        return Ok(Some(prefix));
+    }
+
+    Ok(None)
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;