diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8b203089976ea38290999c419533854253159a0a..3e01dbc17c9499b50d9c809ed5f24fdea94e2d06 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -19,6 +19,8 @@ default:
 stages:
   - analyze
   - deploy
+  - integrate
+  - test
 
 workflow:
   rules:
@@ -28,66 +30,120 @@ workflow:
 # ---------------------------------------------------------------------------------------
 # Stage: analyze
 # ---------------------------------------------------------------------------------------
-pylint:
-  stage: analyze
-  timeout: 2m
-  script:
-    - pylint --rcfile=pylintrc *.py
-
-black:
-  stage: analyze
-  timeout: 2m
-  script:
-    - black --diff --check *.py
-
-executable:
-  stage: analyze
-  timeout: 2m
-  script:
-    - (! find ! -executable -name "*.py" -exec echo "not executable:"" {}" \; | grep .)
-
-yamllint:
-  stage: analyze
-  timeout: 2m
-  script:
-    - yamllint -c .yamllint.yml *.yml .*.yml
+# pylint:
+#   stage: analyze
+#   timeout: 2m
+#   script:
+#     - pylint --rcfile=pylintrc *.py
+#
+# black:
+#   stage: analyze
+#   timeout: 2m
+#   script:
+#     - black --diff --check *.py
+#
+# executable:
+#   stage: analyze
+#   timeout: 2m
+#   script:
+#     - (! find ! -executable -name "*.py" -exec echo "not executable:"" {}" \; | grep .)
+#
+# yamllint:
+#   stage: analyze
+#   timeout: 2m
+#   script:
+#     - yamllint -c .yamllint.yml *.yml .*.yml
 
 
 # ---------------------------------------------------------------------------------------
-# Stage: deploy
+# Stage: deploy-test
 # ---------------------------------------------------------------------------------------
-.deploy: &deploy
+.deploy:
   stage: deploy
-  when: manual
-  allow_failure: true
   script:
     - cd ${CI_PROJECT_DIR}
-    - if [[ "$CI_COMMIT_BRANCH" == "master" ]]; then MERGE="--merge"; else MERGE=""; fi
+    - if [[ "$CI_COMMIT_BRANCH" == "master" ]]; then
+      MERGE="--merge"; else MERGE=""; fi
     - ./deploy_gitlab_ci.py
       --gitlab-url=${CI_SERVER_URL}
       --token=${GITBOT_TOKEN}
-      --project=${CI_PROJECT_ROOT_NAMESPACE}/${CI_JOB_NAME}
+      --manifest-project=${MANIFEST_PROJECT}
       --submodule=.gitlab-ci
       --revision=${CI_COMMIT_SHA}
       ${MERGE}
+      ${DEPLOY_TO}
+
+    - ./generate_job_from_template.py
+      --template=gitlab-ci-integration.jinja2
+      --image=${CI_IMAGE_PYTHON}
+      --branch="integrate/${CI_PROJECT_NAME}/${CI_COMMIT_REF_NAME}"
+      --manifest-project=${MANIFEST_PROJECT}
+      --verbose
+      ${DEPLOY_TO}
+      > integration.yml
+    - cat integration.yml
+  artifacts:
+    paths:
+      - integration.yml
+
+deploy-foobar:
+  extends: .deploy
+  variables:
+    PROJECT_ROOT:
+      ${CI_PROJECT_ROOT_NAMESPACE}/yocto/infrastructure/ci-test
+    MANIFEST_PROJECT:
+      ${PROJECT_ROOT}/minimal-manifest
+
+    DEPLOY_TO:
+      ${PROJECT_ROOT}/minimal-foo
+      ${PROJECT_ROOT}/minimal-bar
+
+trigger-foobar:
+  stage: integrate
+  trigger:
+    include:
+      - artifact: integration.yml
+        job: deploy-foobar
+    strategy: depend
+
+
+# ---------------------------------------------------------------------------------------
+# Stage: deploy
+# ---------------------------------------------------------------------------------------
+# .deploy: &deploy
+#   stage: deploy
+#   when: manual
+#   allow_failure: true
+#   script:
+#     - cd ${CI_PROJECT_DIR}
+#     - if [[ "$CI_COMMIT_BRANCH" == "master" ]]; then MERGE="--merge";
+#          else MERGE=""; fi
+#     - ./deploy_gitlab_ci.py
+#       --gitlab-url=${CI_SERVER_URL}
+#       --token=${GITBOT_TOKEN}
+#       --project=${CI_PROJECT_ROOT_NAMESPACE}/${CI_JOB_NAME}
+#       --submodule=.gitlab-ci
+#       --revision=${CI_COMMIT_SHA}
+#       ${MERGE}
+#
 
-3rd-party/kuk/uboot-imx-kuk: *deploy
-kernel/linux-guf: *deploy
-kernel/linux-imx-kuk: *deploy
-kernel/modules/egalaxi2c: *deploy
-kernel/modules/gfplatdetect: *deploy
-tools/gf-emc-test-suite: *deploy
-tools/gf-productiontests: *deploy
-tools/gfeeprom: *deploy
-tools/gfxml2dto: *deploy
-tools/guf-show-demo: *deploy
-tools/libmdb: *deploy
-tools/touchcal-conv: *deploy
-tools/xconfig: *deploy
-yocto/config: *deploy
-yocto/infrastructure/ci-test/minimal-bar: *deploy
-yocto/infrastructure/ci-test/minimal-foo: *deploy
-yocto/infrastructure/ci-test/minimal-manifest: *deploy
-yocto/layers/meta-guf-distro: *deploy
-yocto/layers/meta-guf-machine: *deploy
-yocto/manifest: *deploy
+# 3rd-party/kuk/uboot-imx-kuk: *deploy
+# kernel/linux-guf: *deploy
+# kernel/linux-imx-kuk: *deploy
+# kernel/modules/egalaxi2c: *deploy
+# kernel/modules/gfplatdetect: *deploy
+# tools/gf-emc-test-suite: *deploy
+# tools/gf-productiontests: *deploy
+# tools/gfeeprom: *deploy
+# tools/gfxml2dto: *deploy
+# tools/guf-show-demo: *deploy
+# tools/libmdb: *deploy
+# tools/touchcal-conv: *deploy
+# tools/xconfig: *deploy
+# yocto/config: *deploy
+# yocto/infrastructure/ci-test/minimal-bar: *deploy
+# yocto/infrastructure/ci-test/minimal-foo: *deploy
+# yocto/infrastructure/ci-test/minimal-manifest: *deploy
+# yocto/layers/meta-guf-distro: *deploy
+# yocto/layers/meta-guf-machine: *deploy
+# yocto/manifest: *deploy
diff --git a/deploy_gitlab_ci.py b/deploy_gitlab_ci.py
index 106329aed650372e67e4c5af3887d43b50f588a0..d9eb03905d8dd498bff30a0f961f7b114fa047ba 100755
--- a/deploy_gitlab_ci.py
+++ b/deploy_gitlab_ci.py
@@ -25,6 +25,62 @@ def update_rev_in_gitlab_ci(repo, submodule_project, submodule_revision):
         repo.git.add(gitlab_ci_yml)
 
 
+def deploy_into(project, submodule, revision, branch, replace_exising_branch=False):
+    """Update the submodule and include refs to the submodule in the given project.
+        Create mergerequest if needed.
+
+    Parameters:
+        project ( gitlab project): The project which's submodule should be updated
+        submodule_name (string): The name of the submodule to pull
+        submodule_revision (hex string): The sha hash of the commit to update the submodule to
+        branch (string): branch to update, if None, the projects default branch is used
+        replace_exising_branch: When an existing integration branch is found it is always replaced.
+
+    Returns: tuple of:
+        branch (string): Name of the newly created integration branch
+        merge_request (gitlab mr): Mergerequest for the integration branch
+    """
+    # Update submodule
+    integration_branch, _, submodule_project = update_submodule(
+        project,
+        submodule,
+        revision,
+        branch,
+        pre_commit_hook=update_rev_in_gitlab_ci,
+        replace_exising_branch=replace_exising_branch,
+    )
+
+    logging.debug("Integration branch: %s", integration_branch)
+
+    # If submodule is already at specified revision, return directly
+    if not integration_branch:
+        return None, submodule_project
+
+    # Get source merge request
+    mrs = get_merge_requests(
+        submodule_project,
+        # TODO should this be submodule_project's default branch?
+        target_branch="master",
+        commit=revision,
+    )
+    if not mrs:
+        sys.exit(
+            "ERROR: could not determine source merge request for commit %s" % revision
+        )
+    source_mr = mrs[0]
+
+    # Create merge request
+    mr, created = create_merge_request(
+        project, integration_branch, project.default_branch
+    )
+    if created:
+        common.crosslink_merge_requests(source_mr, mr)
+        print("Created new merge request:\n%s" % mr.web_url)
+    else:
+        print("Existing integration merge request:\n%s" % mr.web_url)
+    return integration_branch, mr
+
+
 def main():
     parser = argparse.ArgumentParser()
     parser.add_argument(
@@ -41,9 +97,9 @@ def main():
     )
     parser.add_argument(
         "--project",
+        "--manifest-project",
         help="""name of the GitLab project""",
         dest="project",
-        required=True,
     )
     parser.add_argument(
         "--submodule",
@@ -72,6 +128,12 @@ def main():
         required=False,
         default=False,
     )
+    parser.add_argument(
+        "projects",
+        help="""List of projects the change should be deployed to additionally
+                to the manifest project given as named parameter.""",
+        nargs="*",
+    )
     parser.add_argument(
         "-v",
         "--verbose",
@@ -86,42 +148,37 @@ def main():
     gitlab = Gitlab(args.gitlab_url, private_token=args.token)
     project = common.get_project(gitlab, args.project)
 
-    # Update submodule
-    integration_branch, _, submodule_project = update_submodule(
+    logging.debug("Integrate into: %s", args.project)
+
+    # Update submodule in this project, create MR
+    integration_branch, mr = deploy_into(
         project,
         args.submodule,
         args.revision,
         args.branch,
-        pre_commit_hook=update_rev_in_gitlab_ci,
+        replace_exising_branch=len(args.projects) > 0,
     )
+    merge_request_manifest = mr
+    merge_requests = []
 
-    logging.debug("Integration branch: %s", integration_branch)
     # If submodule is already at specified revision, exit successfully
+    # TODO: is this correct for multi deploy also?
     if not integration_branch:
         sys.exit(0)
 
-    # Get source merge request
-    mrs = get_merge_requests(
-        submodule_project,
-        target_branch="master",
-        commit=args.revision,
-    )
-    if not mrs:
-        sys.exit(
-            "ERROR: could not determine source merge request for commit %s"
-            % args.revision
+    for p in args.projects:
+        gitlab_p = common.get_project(gitlab, p)
+        logging.debug("Integrate into: %s", p)
+
+        integration_branch, mr = deploy_into(
+            gitlab_p,
+            args.submodule,
+            args.revision,
+            args.branch,
         )
-    source_mr = mrs[0]
+        merge_requests.append(mr)
 
-    # Create merge request
-    mr, created = create_merge_request(
-        project, integration_branch, project.default_branch
-    )
-    if created:
-        common.crosslink_merge_requests(source_mr, mr)
-        print("Created new merge request:\n%s" % mr.web_url)
-    else:
-        print("Existing integration merge request:\n%s" % mr.web_url)
+        logging.debug("Integration branch: %s", integration_branch)
 
     if not args.merge:
         print(
@@ -132,20 +189,24 @@ def main():
         )
         sys.exit(0)
 
-    # Wait until GitLab has checked merge status
-    common.wait_until_merge_status_is_set(project, mr)
-
-    # Attempt to merge
-    merged = accept_merge_request(project, mr, rebase=True)
-
-    if not merged:
-        sys.exit(
-            "Integration MR could not be merged. You have two possibilities to fix "
-            "this:\n"
-            "  1. Checkout the MR and rebase it on the current master manually, or\n"
-            "  2. Delete the MR (Edit -> Delete in the MR UI)\n"
-            "In either case restart this job afterwards in order to get it merged."
-        )
+    # The manifest needs to be merged at last
+    merge_requests.append(merge_request_manifest) 
+    for mr in merge_requests:
+        logging.debug("Merge %s", mr)
+        # Wait until GitLab has checked merge status
+        common.wait_until_merge_status_is_set(project, mr)
+
+        # Attempt to merge
+        merged = accept_merge_request(project, mr, rebase=True)
+
+        if not merged:
+            sys.exit(
+                "Integration MR could not be merged. You have two possibilities to fix "
+                "this:\n"
+                "  1. Checkout the MR and rebase it on the current master manually, or\n"
+                "  2. Delete the MR (Edit -> Delete in the MR UI)\n"
+                "In either case restart this job afterwards in order to get it merged."
+            )
 
     print("Successfully merged")
 
diff --git a/foobar-manifest-integration.yml b/foobar-manifest-integration.yml
index 6ebf3279707beeeed8d2de678ddb8f8d87d41ed6..6074b3ec11ac9d60e3a6dbbb345fea04c6a39b6f 100644
--- a/foobar-manifest-integration.yml
+++ b/foobar-manifest-integration.yml
@@ -29,7 +29,23 @@ stages:
 
 workflow:
   rules:
-    # Do not run pipelines on forked projects
+    # Explicitly allow externally triggered pipelines in every case
+    - if: $CI_PIPELINE_SOURCE == "pipeline" || $CI_PIPELINE_SOURCE == "api"
+    # Do not run pipelines for merge requests for integrate/gitlab-ci/ branches
+    # These are trigger explicitly from the integration pipeline in gitlab-ci repo
+    - if: $CI_COMMIT_REF_NAME =~ /^integrate\/gitlab-ci\/.*/
+      when: never
+    # Do not run pipelines on forked projects.
+    # The pipelines would not work anyway because of the users permissions.
+    # There are two cases catched here:
+    # 1. The project is forked into someones gitlab namespace and a MR to
+    #    include a change into this forked project is created. In this case
+    #    is the CI_PROJECT_ROOT_NAMESPACE not SECO-Northern-Europe but the
+    #    namespace the fork lives in.
+    # 2. The MR from the forked project is created to merge the change into this
+    #    the project in the SECO-Northern-Europe namespace (customer sending
+    #    change to us). Here the the IDs used below differ.
+    #
     - if: $CI_PROJECT_ROOT_NAMESPACE == "SECO-Northern-Europe"
         && $CI_MERGE_REQUEST_SOURCE_PROJECT_ID == $CI_MERGE_REQUEST_PROJECT_ID
 
@@ -44,6 +60,7 @@ yamllint:
     - infrastructure
   timeout: 2m
   script:
+    - printenv
     - yamllint -c .gitlab-ci/.yamllint.yml .*.yml
 
 # ---------------------------------------------------------------------------------------
@@ -56,21 +73,30 @@ integrate:
     # the time a merge request is created. Otherwise we cannot guarantee a green
     # master after merging.
     - if: $CI_MERGE_REQUEST_IID
+    # Explicitly allow externally triggered pipelines in every case
+    - if: $CI_PIPELINE_SOURCE == "pipeline" || $CI_PIPELINE_SOURCE == "api"
   tags:
     - infrastructure
   timeout: 2m
   cache:
     policy: push
   script:
+    - printenv
     - cd ${CI_PROJECT_DIR}
+    - if [ -n "${CI_MERGE_REQUEST_IID}" ];then
+      MERGE_REQUEST="${CI_MERGE_REQUEST_IID}";
+      else
+      MERGE_REQUEST="${CI_OPEN_MERGE_REQUESTS%%,*}";
+      fi
     - .gitlab-ci/integrate_into_manifest.py
         --gitlab-url=${CI_SERVER_URL}
         --token=${GITBOT_TOKEN}
         --manifest-project=${MANIFEST_PROJECT}
         --integration-base=${MASTER_BRANCH}
         --project=${CI_PROJECT_PATH}
-        --merge-request=${CI_MERGE_REQUEST_IID}
+        --merge-request=${MERGE_REQUEST}
         --save-revision-to=manifest_revision
+        --verbose
   artifacts:
     paths:
       - manifest_revision
@@ -105,7 +131,10 @@ merge:
 build:
   stage: build
   rules:
-    - if: $CI_MERGE_REQUEST_IID
+    # execute this in MR only and not for integrate/gitlab-ci/ integrations
+    # branches. These are build after the integration has been done in all
+    # projects
+    - if: $CI_MERGE_REQUEST_IID && $CI_COMMIT_REF_NAME !~ /^integrate\/gitlab-ci\/.*/
   trigger:
     project: SECO-Northern-Europe/yocto/infrastructure/ci-test/minimal-manifest
     branch: "integrate/${CI_PROJECT_NAME}/${CI_COMMIT_REF_NAME}"
@@ -118,16 +147,23 @@ check:
   stage: check
   rules:
     - if: $CI_MERGE_REQUEST_IID
+    # Explicitly allow externally triggered pipelines in every case
+    - if: $CI_PIPELINE_SOURCE == "pipeline" || $CI_PIPELINE_SOURCE == "api"
   needs: ["integrate"]
   tags:
     - infrastructure
   timeout: 2m
   script:
     - cd ${CI_PROJECT_DIR}
+    - if [ -n "${CI_MERGE_REQUEST_IID}" ];then
+      MERGE_REQUEST="${CI_MERGE_REQUEST_IID}";
+      else
+      MERGE_REQUEST="${CI_OPEN_MERGE_REQUESTS%%,*}";
+      fi
     - .gitlab-ci/check_if_integration_branch_is_up_to_date.py
         --gitlab-url=${CI_SERVER_URL}
         --token=${GITBOT_TOKEN}
         --manifest-project=${MANIFEST_PROJECT}
         --integration-base=${MASTER_BRANCH}
         --project=${CI_PROJECT_PATH}
-        --merge-request=${CI_MERGE_REQUEST_IID}
+        --merge-request=${MERGE_REQUEST}
diff --git a/generate_job_from_template.py b/generate_job_from_template.py
new file mode 100755
index 0000000000000000000000000000000000000000..2fb3c89cd93f61d813bdf28e2193d5ad74c46168
--- /dev/null
+++ b/generate_job_from_template.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import argparse
+import io
+import logging
+import os
+import re
+import sys
+from copy import deepcopy
+from jinja2 import Environment, FileSystemLoader, StrictUndefined
+from jinja2.exceptions import TemplateNotFound
+from ruamel.yaml import YAML
+
+
+def parse_template(yaml_string):
+    """
+    Round trip lava_job through ruamel to test parsing and improve formatting.
+    Comments are preserved.
+
+    In: yaml-formatted string
+    Out: validated yaml-formatted string
+    """
+    yaml = YAML()
+    yaml.indent(sequence=4, offset=2)
+    # ruamel does not provide a mechanism to dump to string, so use StringIO to catch it
+    output = io.StringIO()
+    yaml.dump(yaml.load(yaml_string), output)
+    return output.getvalue()
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        "--template",
+        help="""A Jinja2 template for the yml file to be genarated.
+                All variables in the templates will be substituted using the
+                Jinja2 engine. Variables can be passed either as environment 
+                variables or as command line arguments
+                (e.g. --my-variable=myvalue). In the latter, hyphens ("-") are 
+                replaced with underscores ("_"), i.e. "--my-variable" 
+                becomes "my_variable".""",
+        required=True,
+    )
+    parser.add_argument(
+        "-v",
+        "--verbose",
+        action="store_true",
+        help="""Increase verbosity.""",
+    )
+    parser.add_argument(
+        "arguments",
+        nargs="*",
+        help="""Arguments passed as list to the template.""",
+    )
+
+    # parse known args
+    args, unknown = parser.parse_known_args()
+    if args.verbose:
+        logging.basicConfig(level=logging.DEBUG)
+    logging.debug("Using template: %s", args.template)
+
+    # parse optional arguments
+    parser = argparse.ArgumentParser()
+    for arg in unknown:
+        if arg.startswith(("-", "--")):
+            parser.add_argument(arg.split("=")[0])
+    optional_args, _ = parser.parse_known_args()
+    logging.debug("Optional args: %s", optional_args)
+
+    # update context with given optional arguments
+    j2_env = Environment(undefined=StrictUndefined, extensions=["jinja2.ext.do"])
+    context = dict(deepcopy(os.environ))
+    for arg in vars(optional_args):
+        context[arg] = vars(optional_args)[arg]
+    if args.arguments:
+        context["optional_arguments"] = args.arguments
+
+    for k, v in context.items():
+        logging.debug("Optional args: %s -- %s", k, v)
+
+    # render the template
+    j2_env.loader = FileSystemLoader(os.path.dirname(args.template))
+
+    try:
+        lava_job = j2_env.get_template(os.path.basename(args.template)).render(context)
+        lava_job = parse_template(lava_job)
+        # Remove duplicate newlines
+        lava_job = re.sub(r"\n+", r"\n", lava_job)
+
+        print(lava_job)
+
+    except TemplateNotFound:
+        print("ERROR: Template %s not found" % args.template, file=sys.stderr)
+        exit(1)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/gitlab-ci-integration.jinja2 b/gitlab-ci-integration.jinja2
new file mode 100644
index 0000000000000000000000000000000000000000..14ab4729599e393955b56b41b119a54907434417
--- /dev/null
+++ b/gitlab-ci-integration.jinja2
@@ -0,0 +1,52 @@
+---
+#======================================================
+# Trigger the integration pipeline for all repos using 
+# the gitlab-ci repository.
+#======================================================
+
+{% if image is defined %}
+image: {{ image }}
+{% endif %}
+
+workflow:
+  rules:
+    # This rule is needed, as otherwise the workflow:rules from
+    # the parent job seem to be used and prevent the pipeline generation
+    - if: $CI_PIPELINE_SOURCE == "parent_pipeline"
+
+stages:
+  - integrate
+  - build
+
+default:
+  tags:
+    # All jobs should use the infrastructure runner
+    - infrastructure
+
+{% set projectneeds = { 'project': "" } %}
+{% if optional_arguments is defined %}
+{% set prev_project = "" %}
+{% for project in optional_arguments %}
+{% set projectshort = project.split('/')[-1] %}
+{{ projectshort }}:
+  stage: integrate
+  needs: [ {{ projectneeds.project }} ]
+  trigger:
+    project: {{ project }}
+    branch: {{ branch }}
+    strategy: depend
+
+{% if projectneeds.update({ 'project': projectshort }) %}{% endif %}
+{% endfor %}
+{% endif %}
+
+{% if manifest_project is defined %}
+{% set manifest_project_short = manifest_project.split('/')[-1] %}
+{{ manifest_project_short }}:
+  stage: build
+  trigger:
+    project: {{ manifest_project }}
+    branch: {{ branch }}
+    strategy: depend
+
+{% endif %}
diff --git a/integrate_into_manifest.py b/integrate_into_manifest.py
index dec97e8334b80f319ef72cd6b25ef67655957dde..0f705faee74886812d563a710d648b490892d95a 100755
--- a/integrate_into_manifest.py
+++ b/integrate_into_manifest.py
@@ -2,6 +2,7 @@
 import common
 
 import argparse
+import logging
 import sys
 import tempfile
 import re
@@ -42,14 +43,36 @@ def integrate_into_manifest(
         except IndexError:
             sys.exit("ERROR: branch '%s' not found" % integration_base)
 
-        # Create integration branch (delete former one if already exists)
-        integration_branch = common.integration_branch_name(
-            project.name, merge_request.source_branch
-        )
-        for ref in manifest_repo.references:
-            if integration_branch == ref.name:
-                manifest_repo.delete_head(ref)
-        manifest_repo.head.set_reference(manifest_repo.create_head(integration_branch))
+        # Special handling for the gitlab-ci integration
+        # When the branch 'merge_request.source_branch' already starts with
+        # integrate/gitlab-ci we add our new commit to this branch
+        # Otherwise (normal behaviour) a new integration branch is created
+        integration_branch = None
+        if merge_request.source_branch.startswith("integrate/gitlab-ci"):
+            logging.debug("Integration of gitlab-ci: %s", merge_request.source_branch)
+            for ref in manifest_repo.references:
+                # remove 'origin/' from the ref before compare
+                refname = ref.name.split("/", 1)[1]
+                logging.debug("Found ref: %s", refname)
+                if merge_request.source_branch == ref.name:
+                    logging.debug("Found integration for gitlab-ci")
+                    manifest_repo.head.set_reference(ref)
+                    integration_branch = merge_request.source_branch
+                    break
+
+        if integration_branch is None:
+            # Create integration branch (delete former one if already exists)
+            integration_branch = common.integration_branch_name(
+                project.name, merge_request.source_branch
+            )
+            for ref in manifest_repo.references:
+                if integration_branch == ref.name:
+                    manifest_repo.delete_head(ref)
+            manifest_repo.head.set_reference(
+                manifest_repo.create_head(integration_branch)
+            )
+
+        logging.debug("Integration branch: %s", integration_branch)
 
         # Parse manifest file
         try:
@@ -189,7 +212,8 @@ def main():
     )
     parser.add_argument(
         "--merge-request",
-        help="""project merge request IID containing the changes to be integrated""",
+        help="""project merge request IID or link containing the
+                changes to be integrated""",
         dest="merge_request",
         required=True,
     )
@@ -199,17 +223,49 @@ def main():
         dest="revision_file",
         required=False,
     )
+    parser.add_argument(
+        "-v",
+        "--verbose",
+        action="store_true",
+        help="""Increase verbosity.""",
+    )
 
     args, _ = parser.parse_known_args()
+    if args.verbose:
+        logging.basicConfig(level=logging.DEBUG)
 
+    logging.debug(args)
     gitlab = Gitlab(args.gitlab_url, private_token=args.token)
 
     manifest_project = common.get_project(gitlab, args.manifest_project)
     project = common.get_project(gitlab, args.project)
+    logging.debug(project)
+    mr_iid = args.merge_request
+    logging.debug(mr_iid)
+    # MR may also be specified as
+    # SECO-Northern-Europe/yocto/infrastructure/ci-test/minimal-bar!115
+    if mr_iid.startswith(args.project):
+        mr_number = int(mr_iid.split("!")[-1])
+        logging.debug("Number of MR: %d", mr_number)
+        logging.debug(project.mergerequests.list())
+        mr_iid = None
+        for mr in project.mergerequests.list():
+            logging.debug(mr)
+            logging.debug(int(mr.iid))
+            logging.debug(mr.id)
+            if int(mr.iid) == mr_number:
+                mr_iid = mr.id
+                break
+
+        logging.debug(mr_iid)
+        if mr_iid is None:
+            sys.exit(
+                "ERROR: could not get %s"
+                % (args.merge_request)
+            )
+
     try:
-        merge_request = project.mergerequests.get(
-            args.merge_request, retry_transient_errors=True
-        )
+        merge_request = project.mergerequests.get(mr_iid, retry_transient_errors=True)
     except GitlabGetError as e:
         sys.exit(
             "ERROR: could not get %s!%s: %s"
diff --git a/update_submodule.py b/update_submodule.py
index 64d19e16f3ca74e08f383722f7146a4ee232547f..b0d5930ef9d92f587a8ea21f4c71deb735b21e41 100755
--- a/update_submodule.py
+++ b/update_submodule.py
@@ -12,7 +12,12 @@ from gitlab import Gitlab
 
 
 def update_submodule(
-    project, submodule_name, submodule_revision, branch=None, pre_commit_hook=None
+    project,
+    submodule_name,
+    submodule_revision,
+    branch=None,
+    pre_commit_hook=None,
+    replace_exising_branch=False,
 ):
     """Update submodule of gitlab project to given revision
 
@@ -23,6 +28,7 @@ def update_submodule(
         branch (string): branch to update, if None, the projects default branch is used
         pre_commit_hook: Function to be called before the actual commit is done, to add additional changes.
                          Arguments passed: ( repo, submodule_project, submodule_revision)
+        replace_exising_branch: When an existing integration branch is found it is always replaced.
     Returns: tuple of:
         branch (string): Name of the newly created integration branch
         revision (string): hexsha of the new commit
@@ -116,16 +122,16 @@ def update_submodule(
         if existing_branch:
             repo.head.set_reference(existing_branch)
             submodule = common.get_submodule(repo, submodule_name)
-            if submodule.hexsha == submodule_revision:
+            if replace_exising_branch or submodule.hexsha != submodule_revision:
+                print("Replacing outdated integration branch %s" % integration_branch)
+                repo.head.set_reference(branch)
+                submodule = common.get_submodule(repo, submodule_name)
+            else:
                 print(
                     "Submodule is already at %s on branch %s"
                     % (submodule_revision, integration_branch)
                 )
                 return (integration_branch, existing_branch.commit, submodule_project)
-            else:
-                print("Replacing outdated integration branch %s" % integration_branch)
-                repo.head.set_reference(branch)
-                submodule = common.get_submodule(repo, submodule_name)
         else:
             print("Creating integration branch %s" % integration_branch)