{"id":307,"date":"2026-10-13T12:01:08","date_gmt":"2026-10-13T12:01:08","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2011\/12\/23\/depot-migration-between-perforce-servers-with-history-and-change-list\/"},"modified":"2026-10-13T12:01:08","modified_gmt":"2026-10-13T12:01:08","slug":"depot-migration-between-perforce-servers-with-history-and-change-list","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/depot-migration-between-perforce-servers-with-history-and-change-list\/","title":{"rendered":"Perforce Depot Migration Between Servers Without Losing History or Changelists"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Moving a Perforce depot to another server is not just a file copy task. If you need <strong>history, metadata, and changelist continuity<\/strong>, you must migrate server data carefully. This guide is for Perforce administrators and DevOps engineers who need a safer, structured migration approach based on the original post and its references.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Originally published on 2011-12-23; fully revised and updated.<\/em><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2011\/12\/migration-between-perforce-.png\" alt=\"Depot migration between Perforce servers\"\/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">What this migration must preserve<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When teams ask for depot migration, they usually mean all of the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Depot file content<\/li><li>File history<\/li><li>Changelist records<\/li><li>Usable server metadata after cutover<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The original article emphasizes avoiding history loss and mentions cleaning unnecessary data before merge, then using Perfmerge++ for combining repositories.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Migration options and trade-offs<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Approach<\/th><th>Best for<\/th><th>History and changelists<\/th><th>Main risk<\/th><\/tr><\/thead><tbody><tr><td>Full backup or checkpoint, then selective cleanup<\/td><td>Preparing a source server snapshot before moving data<\/td><td>Can preserve metadata when done correctly<\/td><td>Destructive cleanup steps if run on production by mistake<\/td><\/tr><tr><td>Perfmerge++ repository merge<\/td><td>Merging two Perforce repositories into a third combined repository<\/td><td>Designed to carry merged repository metadata<\/td><td>Operational complexity; requires careful staging and validation<\/td><\/tr><tr><td>File-level copy or workspace-only transfer<\/td><td>Quick content-only moves<\/td><td>Typically does not preserve full server metadata history<\/td><td>Incomplete migration for audit or traceability needs<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Recommended high-level workflow<\/h2>\n\n\n\n<pre class=\"mermaid\">\nflowchart TD\n    A[Take full backup and checkpoint] --> B[Create isolated staging copy]\n    B --> C[Remove unwanted depot data]\n    C --> D[Delete redundant changelists]\n    D --> E[Run repository merge step]\n    E --> F[Validate history and changelists]\n    F --> G[Cut over to destination server]\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Example command sequence for staging and cleanup<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use destructive commands only on a validated backup or staging clone first. The original post explicitly mentions checkpoint backup, changelist cleanup with <code>p4 change -f -d<\/code>, and obliteration of unwanted data.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\"># 1) Take a checkpoint or full backup from the source server<\/span>\np4 admin checkpoint\n\n<span class=\"hljs-comment\"># Alternative style often used in server administration contexts<\/span>\np4d -r \/p4\/root -jc<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\"># 2) Remove redundant changelists (example from original guidance)<\/span>\np4 change -f -d <span class=\"hljs-number\">12345<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\"># 3) Remove unwanted depot data before migration (destructive)<\/span>\np4 obliterate -y <span class=\"hljs-comment\">\/\/depot\/legacy-product\/...<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">After merge or restore, validate that expected paths, history, and changelist visibility are present.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\"># Basic post-migration checks<\/span>\np4 files <span class=\"hljs-comment\">\/\/depot\/target-product\/...<\/span>\np4 changes -m <span class=\"hljs-number\">20<\/span> <span class=\"hljs-comment\">\/\/depot\/target-product\/...<\/span>\np4 filelog <span class=\"hljs-comment\">\/\/depot\/target-product\/path\/to\/keyfile<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">What Perfmerge++ is, based on the original references<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">According to the original article, <strong>Perfmerge++<\/strong> merges two Perforce repositories into a third repository and replaced an older script (<code>perfmerge2.pl<\/code>). The post also states that Perfmerge++ works directly with database files to generate merged database output, rather than operating on checkpoints alone.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because this tooling and documentation are old, confirm current support status and exact usage in up-to-date Perforce documentation before production use.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">References from the original post<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"http:\/\/kb.perforce.com\/article\/911\">http:\/\/kb.perforce.com\/article\/911<\/a><\/li><li><a href=\"ftp:\/\/ftp.perforce.com\/perforce\/tools\/perfmerge\/perfmerge.html\">ftp:\/\/ftp.perforce.com\/perforce\/tools\/perfmerge\/perfmerge.html<\/a><\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Common pitfalls and safeguards<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Do not run <code>obliterate<\/code> first on production; always stage and verify.<\/li><li>Keep immutable backups and checkpoints before each destructive step.<\/li><li>Validate both content and metadata (files, filelog, changelists), not just file presence.<\/li><li>Plan rollback and cutover timing before final destination switch.<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>A practical migration workflow for moving Perforce depot data between servers while preserving history and changelist continuity. Includes a decision table, migration flow diagram, and command examples for backup, cleanup, and validation.<\/p>\n","protected":false},"author":1,"featured_media":3862,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[370],"tags":[1720,1960,2622,2625,2630,1122,2624,2631,545,2627,2623,2636,373,2628,2626,2632,2634,2633,2635,593,2375,2629,104,1452],"class_list":["post-307","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-perforce","tag-between","tag-changelist","tag-depot","tag-depot-migration","tag-depot-migration-between-servers","tag-guide","tag-history","tag-history-and-change-list","tag-how","tag-migrating-servers","tag-migration","tag-moving-depots-across-servers","tag-perforce","tag-perforce-depots","tag-perforce-servers","tag-perforce-servers-guide","tag-perforce-servers-instructions","tag-perforce-servers-tutorials","tag-perforce-tutorials","tag-process","tag-servers","tag-servers-migration","tag-tutorials","tag-ways"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/307","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=307"}],"version-history":[{"count":3,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/307\/revisions"}],"predecessor-version":[{"id":79163,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/307\/revisions\/79163"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/3862"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}