diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp
index 2dbaaae8568413de1f73e876e220b57a00d3a780..4f6c5b7eece7377454794fb5eabc931f5821d374 100644
--- a/src/plugins/projectexplorer/projectnodes.cpp
+++ b/src/plugins/projectexplorer/projectnodes.cpp
@@ -166,6 +166,11 @@ void Node::emitNodeUpdated()
         ProjectTree::instance()->emitNodeUpdated(this);
 }
 
+Node *Node::trim(const QSet<Node *> &keepers)
+{
+    return keepers.contains(this) ? nullptr : this;
+}
+
 FileNode *Node::asFileNode()
 {
     return nullptr;
@@ -330,6 +335,26 @@ QIcon FolderNode::icon() const
     return m_icon;
 }
 
+Node *FolderNode::trim(const QSet<Node *> &keepers)
+{
+    if (keepers.contains(this))
+        return nullptr;
+
+    bool keepThis = false;
+    QList<Node *> toTrim = Utils::transform(m_fileNodes, [&keepers](Node *n) { return n->trim(keepers); });
+    int count = toTrim.count();
+    toTrim = Utils::filtered(toTrim, [](const Node *n) { return n; });
+    keepThis = (count != toTrim.count());
+    removeFileNodes(Utils::transform(toTrim, [](Node *n) { return static_cast<FileNode *>(n); }));
+
+    toTrim = Utils::transform(m_folderNodes, [&keepers](Node *n) { return n->trim(keepers); });
+    count = toTrim.count();
+    toTrim = Utils::filtered(toTrim, [](const Node *n) { return n; });
+    keepThis = keepThis || (count != toTrim.count());
+    removeFolderNodes(Utils::transform(toTrim, [](Node *n) { return static_cast<FolderNode *>(n); }));
+    return keepThis ? nullptr : this;
+}
+
 QList<FileNode*> FolderNode::fileNodes() const
 {
     return m_fileNodes;
@@ -899,6 +924,22 @@ ProjectNode *ProjectNode::asProjectNode()
     return this;
 }
 
+Node *ProjectNode::trim(const QSet<Node *> &keepers)
+{
+    if (keepers.contains(this))
+        return nullptr;
+
+    QList<Node *> toTrim
+            = Utils::transform(m_projectNodes, [&keepers](Node *n) { return n->trim(keepers); });
+    int count = toTrim.count();
+    toTrim = Utils::filtered(toTrim, [](Node *n) { return n; });
+    removeProjectNodes(Utils::transform(toTrim, [](Node *n) { return static_cast<ProjectNode *>(n); }));
+
+    if (!FolderNode::trim(keepers))
+        return nullptr;
+
+    return (toTrim.count() != count) ? nullptr : this;
+}
 
 /*!
   \class ProjectExplorer::SessionNode
diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h
index c512b76a2780ec70bd73349f3f7a368a96c3a0ee..2e6a39e2ecbe122164f2aec002b951b4a726b924 100644
--- a/src/plugins/projectexplorer/projectnodes.h
+++ b/src/plugins/projectexplorer/projectnodes.h
@@ -124,6 +124,8 @@ public:
 
     void emitNodeUpdated();
 
+    virtual Node *trim(const QSet<Node *> &keepers);
+
     virtual FileNode *asFileNode();
     virtual FolderNode *asFolderNode();
     virtual ProjectNode *asProjectNode();
@@ -183,6 +185,8 @@ public:
     QString displayName() const override;
     QIcon icon() const;
 
+    Node *trim(const QSet<Node *> &keepers) override;
+
     QList<FileNode *> fileNodes() const;
     FileNode *fileNode(const Utils::FileName &file) const;
     FileNode *recursiveFileNode(const Utils::FileName &file) const;
@@ -282,6 +286,8 @@ public:
 
     ProjectNode *asProjectNode() override;
 
+    Node *trim(const QSet<Node *> &keepers) override;
+
 protected:
     // this is just the in-memory representation, a subclass
     // will add the persistent stuff