diff --git a/docs/contributing/gitlab.rst b/docs/contributing/gitlab.rst
new file mode 100644
--- /dev/null
+++ b/docs/contributing/gitlab.rst
@@ -0,0 +1,291 @@
+.. highlight:: bash
+
+.. admonition:: Intended audience
+ :class: important
+
+ Contributors
+
+.. _gitlab-code-submission:
+
+Submitting code to SWH
+======================
+
+We use `gitlab `__ (`Community
+Edition `__) as the
+coding/collaboration forge.
+
+For a new contributor
+---------------------
+
+* `Signup `__ to
+ create a new gitlab user and wait for approval
+* Once approved, you will get notified
+* If you are not already, familiarize with git and gitlab `gitlab
+ basics `__
+* Create a
+ `fork `__
+ of the project you wish to work on
+* Setup `ssh keys `__ to
+ communicate with Gitlab
+* Sign the Software Heritage Contributor License Agreement
+* [Optional] Install gitlab cli tools
+* Create a local `feature
+ branch `__
+ for the feature you are trying to add
+* Commit code following the commit guidelines
+* Push your branch to your fork
+* Create a `merge
+ request `__
+ against the SWH project master branch for your branch
+* Make sure the merge request passes all the steps in the build
+* Address the review comments, if any
+* Once ready, wait for a team member to merge your code
+
+SSH key for pushes
+~~~~~~~~~~~~~~~~~~
+
+In your forge User Settings page (on the top right, click on your
+avatar, then click *Preferences*), you have access to a *SSH Keys*
+section (Direct link:
+``https://gitlab.softwareheritage.org/-/profile/keys``). You then have
+the option to upload a SSH public key, which will authenticate your
+pushes from git.
+
+Note: if you use a dedicated SSH key for this (which is recommended),
+create key pair using recommended algorithm; ED25519 as of today; see
+`this gitlab help
+page `__ for more
+details).
+
+You also need to configure ssh/git to use that key pair, for instance by
+editing the ``~/.ssh/config`` file:
+
+.. code-block::
+
+ # .ssh/config entry for gitlab.softwareheritage.org
+ Host gitlab.softwareheritage.org
+ User git
+ IdentityFile ~/.ssh/swh_gitlab_key
+ IdentitiesOnly yes
+ PreferredAuthentications publickey
+
+
+Finally, you should configure git to push over ssh when pushing to
+https://gitlab.softwareheritage.org, by running the following command:
+
+.. code-block::
+
+ git config --global url.git@gitlab.softwareheritage.org:.pushInsteadOf https://gitlab.softwareheritage.org
+
+This lets git know that it should use
+``git@gitlab.softwareheritage.org:`` as a base url when pushing
+repositories cloned from gitlab.softwareheritage.org over https.
+
+If you plan to `sign git revisions or
+tags `__,
+you may also want to `upload your GPG
+key `__ as well.
+
+Code Review in Gitlab
+---------------------
+
+As mentioned above, you can use the standard gitlab contribution
+workflow. This is based on having your own copy (fork) of the project
+you wan to hack on in your projects. The way you manage this fork of
+yours is up to you, but we strongly recommend the process described
+below.
+
+Workflow
+~~~~~~~~
+
+* fork the project on https://gitlab.softwareheritage.org (clicking the
+ “Fork” button)
+
+* clone the forked repository on your machine:
+
+.. code-block::
+
+ git clone https://gitlab.softwareheritage.org//swh-xxx.git
+ cd swh-xxx
+
+* add the upstream repository:
+
+.. code-block::
+
+ git remote add upstream https://gitlab.softwareheritage.org/modules/swh-xxx.git
+
+this allows you to easily fetch new upstream revisions in your local
+repository
+
+* work in a feature branch: ``git checkout -b my-feature``
+
+* hack; add tests; commit; hack; rework git history;
+
+* initial review request:
+
+ * push your branch in your forked repository:
+ ``git push origin my-feature [...] remote: To gitlab.softwareheritage.org:/swh-xxx.git * [new branch] my-feature -> my-feature``
+
+ * create a Merge Request from this branch in the gitlab web UI
+
+* react to change requests: hack/commit/hack/commit;
+
+* update your merge request:
+
+.. code-block::
+
+ git push origin my-feature
+
+ or, if you have reworked or rebased the git history of the
+ ``my-feature`` branch:
+
+.. code-block::
+
+ git push --force-with-lease origin my-feature
+
+* landing change: once the merge request has been approved, it will be
+ merged in the upstream main branch ([name=david]: *by who?*); it will
+ be merge if and only if the git branch behind the merge request can
+ be pushed directly on the upstream main branch (without an actual
+ merge) and the resulting revisions all pass CI, to keep the upstream
+ git history as clean and linear as possible.
+
+Starting a new feature and submit it for review
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+As mentioned above, you should work on your fork of the upstream
+project, in dedicated feature branches. In the following document, we
+assume you have forked the upstream project in your namespace on
+gitlab.softwareheritage.org, and you have cloned the repository with 2
+remote tracked repositories:
+
+.. code-block::
+
+ git remove -v
+ origin git@gitlab.softwareheritage.org:/swh-xxx.git (fetch)
+ origin git@gitlab.softwareheritage.org:/swh-xxx.git (push)
+ upstream git@gitlab.softwareheritage.org:swh/modules/swh-xxx.git (fetch)
+ upstream git@gitlab.softwareheritage.org:swh/modules/swh-xxx.git (push)
+
+Use a **one branch per feature** workflow, with well-separated **logical
+commits** (:ref:``following those conventions ``).
+Please create one merge request per logical feature/fix to keep the
+merge request size to a minimum.
+
+.. code-block::
+
+ git checkout -b my-shiny-feature
+ ... hack hack hack ...
+ git commit -m 'architecture skeleton for my-shiny-feature'
+ ... hack hack hack ...
+ git commit -m 'my-shiny-feature: implement module foo'
+ ... etc ...
+
+To **submit your code for review** the first time, you need to create a
+merge request. This is a 2 steps process:
+
+* first you need to push your branch in your forked project,
+* then you need to create the merge request from that branch against
+ the main branch upstream.
+
+This is typically a matter of:
+
+.. code-block::
+
+ git push origin my-shiny-feature
+ [...]
+ remote:
+ remote: To create a merge request for my-shiny-feature, visit:
+ remote: https://gitlab.softwareheritage.org//swh-xxx/-/merge_requests/new?merge_request%5Bsource_branch%5D=my-shiny-feature
+ remote:
+ To gitlab.softwareheritage.org:douardda/swh-xxx.git
+ * [new branch] my-shiny-feature -> my-shiny-feature
+
+and follow the URL provided to create the merge request from the gitlab
+web UI.
+
+Check the CI is green
+^^^^^^^^^^^^^^^^^^^^^
+
+When you create (or update) a merge request, the CI should be triggered
+automatically and test your proposed changes.
+
+If the result is not OK, it is your responsibility to update and fix
+your code to make the merge request ready for review.
+
+Ask for review
+^^^^^^^^^^^^^^
+
+Normally, any green merge request is automatically ready for review. By
+default, no specific reviewer is assigned to a merge request, meaning
+that it can be reviewed by any team member.
+
+You may want to ask specifically for a person to review your merge
+request. In this case, you can choose in the merge request web page to
+define one (or more) reviewers for your merge request.
+
+Updating your branch to reflect requested changes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Your feature might get accepted as is, YAY! Or, reviewers might request
+changes; no big deal!
+
+To implement requested changes in the code, hack on your branch as usual
+by:
+
+* adding new commits, and/or
+* rewriting old commits with git rebase (to preserve a nice, easy to
+ bisect history)
+* pulling on master and rebasing your branch against it if meanwhile
+ someone landed commits on master:
+
+.. code-block::
+
+ git checkout master
+ git pull
+ git checkout my-shiny-feature
+ git rebase master
+
+When you’re ready to **update your review request**, you just have to
+push your modifications in your local branch on gitlab:
+
+.. code-block::
+
+ git push origin my-shiny-feature
+
+or, it you made some git history rework (rebase etc), you need to use:
+
+.. code-block::
+
+ git push --force-with-lease origin my-shiny-feature
+
+The merge request should be updated automatically with your updated
+changes.
+
+Draft merge requests
+^^^^^^^^^^^^^^^^^^^^
+
+It is possible to prepare a merge request but keep it in a “draft”
+state, to make it clear to reviewers it is not ready for review yet.
+
+This can be done either by prefixing the merge request title with
+“Draft:”.
+
+You may also use the web UI feature “Mark as draft” (in the “Merge
+request actions” menu).
+
+Landing your change onto master
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+xxx
+
+Reviewing locally / landing someone else’s changes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+xxx
+
+See also
+--------
+
+* :ref:`code-review` for guidelines on how code is reviewed when
+ developing for Software Heritage