{"thread":{"id":"44068","subject":"[PATCH] [git-p4.py] Add --checkpoint-period option to sync/clone","startedAt":"2016-09-12T22:02:33Z","lastAt":"2016-09-16T17:43:53Z","messageCount":7,"participants":["Ori Rawlings","Luke Diamand","Lars Schneider"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"301774","messageId":"1473717733-65682-1-git-send-email-orirawlings@gmail.com","threadId":"44068","inReplyTo":null,"subject":"[PATCH] [git-p4.py] Add --checkpoint-period option to sync/clone","fromName":"Ori Rawlings","fromEmail":"orirawlings@gmail.com","sentAt":"2016-09-12T22:02:12Z","receivedAt":"2016-09-12T22:02:33Z","isPatch":true,"sender":{"key":"orirawlings@gmail.com","avatar":"https://gravatar.com/avatar/e0b03bf25fd033ff21a27f7c801240da759f001b28acfa3087f60532bd4c9fa6?d=mp&s=160"},"body":"Importing a long history from Perforce into git using the git-p4 tool\ncan be especially challenging. The `git p4 clone` operation is based\non an all-or-nothing transactionality guarantee. Under real-world\nconditions like network unreliability or a busy Perforce server,\n`git p4 clone` and  `git p4 sync` operations can easily fail, forcing a\nuser to restart the import process from the beginning. The longer the\nhistory being imported, the more likely a fault occurs during the\nprocess. Long enough imports thus become statistically unlikely to ever\nsucceed.\n\nI'm looking for feedback on a potential approach for addressing the\nproblem. My idea was to leverage the checkpoint feature of git \nfast-import. I've included a patch which exposes a new option to the \nsync/clone commands in the git-p4 tool. The option enables explict \ncheckpoints on a periodic basis (approximately every x seconds).\n\nIf the sync/clone command fails during processing of Perforce changes, \nthe user can craft a new git p4 sync command that will identify \nchanges that have already been imported and proceed with importing \nonly changes more recent than the last successful checkpoint.\n\nAssuming this approach makes sense, there are a few questions/items I\nhave:\n\n  1. To add tests for this option, I'm thinking I'd need to simulate a \n     Perforce server or client that exits abnormally after first \n     processing some operations successfully. I'm looking for \n     suggestions on sane approaches for implementing that.\n  2. From a usability perspective, I think it makes sense to print \n     out a message upon clone/sync failure if the user has enabled the \n     option. This message would describe how long ago the last \n     successful checkpoint was completed and document what command/s \n     to execute to continue importing Perforce changes. Ideally, the \n     commmand to continue would be exactly the same as the command \n     which failed, but today, clone will ignore any commits already \n     imported to git. There are some lingering TODO comments in \n     git-p4.py suggesting that clone should try to avoid reimporting\n     changes. I don't mind taking a stab at addressing the TODO, but \n     am worried I'll quickly encounter edge cases in the clone/sync \n     features I don't understand.\n  3. This is my first attempt at a git contribution, so I'm definitely \n     looking for feedback on commit messages, etc.\n\n\nCheers!\n\nOri Rawlings (1):\n  [git-p4.py] Add --checkpoint-period option to sync/clone\n\n git-p4.py | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\n-- \n2.7.4 (Apple Git-66)\n\n"},{"id":"301775","messageId":"1473717733-65682-2-git-send-email-orirawlings@gmail.com","threadId":"44068","inReplyTo":"1473717733-65682-1-git-send-email-orirawlings@gmail.com","subject":"[PATCH] [git-p4.py] Add --checkpoint-period option to sync/clone","fromName":"Ori Rawlings","fromEmail":"orirawlings@gmail.com","sentAt":"2016-09-12T22:02:13Z","receivedAt":"2016-09-12T22:02:47Z","isPatch":true,"sender":{"key":"orirawlings@gmail.com","avatar":"https://gravatar.com/avatar/e0b03bf25fd033ff21a27f7c801240da759f001b28acfa3087f60532bd4c9fa6?d=mp&s=160"},"body":"Importing a long history from Perforce into git using the git-p4 tool\ncan be especially challenging. The `git p4 clone` operation is based\non an all-or-nothing transactionality guarantee. Under real-world\nconditions like network unreliability or a busy Perforce server,\n`git p4 clone` and  `git p4 sync` operations can easily fail, forcing a\nuser to restart the import process from the beginning. The longer the\nhistory being imported, the more likely a fault occurs during the\nprocess. Long enough imports thus become statistically unlikely to ever\nsucceed.\n\nThe underlying git fast-import protocol supports an explicit checkpoint\ncommand. The idea here is to optionally allow the user to force an\nexplicit checkpoint every <x> seconds. If the sync/clone operation fails\nbranches are left updated at the appropriate commit available during the\nlatest checkpoint. This allows a user to resume importing Perforce\nhistory while only having to repeat at most approximately <x> seconds\nworth of import activity.\n\nSigned-off-by: Ori Rawlings <orirawlings@gmail.com>\n---\n git-p4.py | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/git-p4.py b/git-p4.py\nindex fd5ca52..40cb64f 100755\n--- a/git-p4.py\n+++ b/git-p4.py\n@@ -2244,6 +2244,7 @@ class P4Sync(Command, P4UserMap):\n                 optparse.make_option(\"-/\", dest=\"cloneExclude\",\n                                      action=\"append\", type=\"string\",\n                                      help=\"exclude depot path\"),\n+                optparse.make_option(\"--checkpoint-period\", dest=\"checkpointPeriod\", type=\"int\", help=\"Period in seconds between explict git fast-import checkpoints (by default, no explicit checkpoints are performed)\"),\n         ]\n         self.description = \"\"\"Imports from Perforce into a git repository.\\n\n     example:\n@@ -2276,6 +2277,7 @@ class P4Sync(Command, P4UserMap):\n         self.tempBranches = []\n         self.tempBranchLocation = \"refs/git-p4-tmp\"\n         self.largeFileSystem = None\n+        self.checkpointPeriod = -1\n \n         if gitConfig('git-p4.largeFileSystem'):\n             largeFileSystemConstructor = globals()[gitConfig('git-p4.largeFileSystem')]\n@@ -3031,6 +3033,8 @@ class P4Sync(Command, P4UserMap):\n \n     def importChanges(self, changes):\n         cnt = 1\n+        if self.checkpointPeriod > -1:\n+            self.lastCheckpointTime = time.time()\n         for change in changes:\n             description = p4_describe(change)\n             self.updateOptionDict(description)\n@@ -3107,6 +3111,10 @@ class P4Sync(Command, P4UserMap):\n                                 self.initialParent)\n                     # only needed once, to connect to the previous commit\n                     self.initialParent = \"\"\n+\n+                    if self.checkpointPeriod > -1 and time.time() - self.lastCheckpointTime > self.checkpointPeriod:\n+                        self.checkpoint()\n+                        self.lastCheckpointTime = time.time()\n             except IOError:\n                 print self.gitError.read()\n                 sys.exit(1)\n-- \n2.7.4 (Apple Git-66)\n\n"},{"id":"301838","messageId":"CAE5ih79LCdUsTXXBYXdR-KL=A2wN=TfQ+SSD4g+_o2YDHKsQ3A@mail.gmail.com","threadId":"44068","inReplyTo":"1473717733-65682-2-git-send-email-orirawlings@gmail.com","subject":"Re: [PATCH] [git-p4.py] Add --checkpoint-period option to sync/clone","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2016-09-13T08:10:15Z","receivedAt":"2016-09-13T08:10:23Z","isPatch":true,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"On 12 September 2016 at 23:02, Ori Rawlings <orirawlings@gmail.com> wrote:\n> Importing a long history from Perforce into git using the git-p4 tool\n> can be especially challenging. The `git p4 clone` operation is based\n> on an all-or-nothing transactionality guarantee. Under real-world\n> conditions like network unreliability or a busy Perforce server,\n> `git p4 clone` and  `git p4 sync` operations can easily fail, forcing a\n> user to restart the import process from the beginning. The longer the\n> history being imported, the more likely a fault occurs during the\n> process. Long enough imports thus become statistically unlikely to ever\n> succeed.\n\nThat would never happen :-)\n\nThe usual thing that I find is that my Perforce login session expires.\n\n>\n> The underlying git fast-import protocol supports an explicit checkpoint\n> command. The idea here is to optionally allow the user to force an\n> explicit checkpoint every <x> seconds. If the sync/clone operation fails\n> branches are left updated at the appropriate commit available during the\n> latest checkpoint. This allows a user to resume importing Perforce\n> history while only having to repeat at most approximately <x> seconds\n> worth of import activity.\n\nI think this ought to work, and could be quite useful. It would be\ngood to have some kind of test case for it though, and updated\ndocumentation.\n\nLuke\n\n>\n> Signed-off-by: Ori Rawlings <orirawlings@gmail.com>\n> ---\n>  git-p4.py | 8 ++++++++\n>  1 file changed, 8 insertions(+)\n>\n> diff --git a/git-p4.py b/git-p4.py\n> index fd5ca52..40cb64f 100755\n> --- a/git-p4.py\n> +++ b/git-p4.py\n> @@ -2244,6 +2244,7 @@ class P4Sync(Command, P4UserMap):\n>                  optparse.make_option(\"-/\", dest=\"cloneExclude\",\n>                                       action=\"append\", type=\"string\",\n>                                       help=\"exclude depot path\"),\n> +                optparse.make_option(\"--checkpoint-period\", dest=\"checkpointPeriod\", type=\"int\", help=\"Period in seconds between explict git fast-import checkpoints (by default, no explicit checkpoints are performed)\"),\n>          ]\n>          self.description = \"\"\"Imports from Perforce into a git repository.\\n\n>      example:\n> @@ -2276,6 +2277,7 @@ class P4Sync(Command, P4UserMap):\n>          self.tempBranches = []\n>          self.tempBranchLocation = \"refs/git-p4-tmp\"\n>          self.largeFileSystem = None\n> +        self.checkpointPeriod = -1\n\nOr use None?\n\n>\n>          if gitConfig('git-p4.largeFileSystem'):\n>              largeFileSystemConstructor = globals()[gitConfig('git-p4.largeFileSystem')]\n> @@ -3031,6 +3033,8 @@ class P4Sync(Command, P4UserMap):\n>\n>      def importChanges(self, changes):\n>          cnt = 1\n> +        if self.checkpointPeriod > -1:\n> +            self.lastCheckpointTime = time.time()\n\nCould you just always set the lastCheckpointTime?\n\n>          for change in changes:\n>              description = p4_describe(change)\n>              self.updateOptionDict(description)\n> @@ -3107,6 +3111,10 @@ class P4Sync(Command, P4UserMap):\n>                                  self.initialParent)\n>                      # only needed once, to connect to the previous commit\n>                      self.initialParent = \"\"\n> +\n> +                    if self.checkpointPeriod > -1 and time.time() - self.lastCheckpointTime > self.checkpointPeriod:\n> +                        self.checkpoint()\n> +                        self.lastCheckpointTime = time.time()\n\nIf you use time.time(), then this could fail to work as expected if\nthe system time goes backwards (e.g. NTP updates). However, Python 2\ndoesn't have access to clock_gettime() without jumping through hoops,\nso perhaps we leave this as a bug until git-p4 gets ported to Python\n3.\n\n\n\n>              except IOError:\n>                  print self.gitError.read()\n>                  sys.exit(1)\n> --\n> 2.7.4 (Apple Git-66)\n>\n"},{"id":"302025","messageId":"cover.9c54bbdd9f054215b5432c4ba3081110e2e91724.1473973732.git-series.orirawlings@gmail.com","threadId":"44068","inReplyTo":"1473717733-65682-1-git-send-email-orirawlings@gmail.com","subject":"[PATCH v2 0/1] git-p4: Add --checkpoint-period option to sync/clone","fromName":"Ori Rawlings","fromEmail":"orirawlings@gmail.com","sentAt":"2016-09-15T21:17:17Z","receivedAt":"2016-09-15T21:17:33Z","isPatch":true,"sender":{"key":"orirawlings@gmail.com","avatar":"https://gravatar.com/avatar/e0b03bf25fd033ff21a27f7c801240da759f001b28acfa3087f60532bd4c9fa6?d=mp&s=160"},"body":"Importing a long history from Perforce into git using the git-p4 tool\ncan be especially challenging. The `git p4 clone` operation is based\non an all-or-nothing transactionality guarantee. Under real-world\nconditions like network unreliability or a busy Perforce server,\n`git p4 clone` and  `git p4 sync` operations can easily fail, forcing a\nuser to restart the import process from the beginning. The longer the\nhistory being imported, the more likely a fault occurs during the\nprocess. Long enough imports thus become statistically unlikely to ever\nsucceed.\n\nMy idea was to leverage the checkpoint feature of git fast-import.\nI've included a patch which exposes a new option to the sync/clone\ncommands in the git-p4 tool. The option enables explict checkpoints on\na periodic basis (approximately every x seconds).\n\nIf the sync/clone command fails during processing of Perforce changes,\nthe user can craft a new git p4 sync command that will identify\nchanges that have already been imported and proceed with importing\nonly changes more recent than the last successful checkpoint.\n\nIn v2 of this patch series I've added some basic test scenarios,\ndocumentation, and did some minor clean up of the implementation\nbased on feedback on v1.\n\nOri Rawlings (1):\n  git-p4: Add --checkpoint-period option to sync/clone\n\n Documentation/git-p4.txt            | 12 ++++++-\n git-p4.py                           |  7 ++++-\n t/t9830-git-p4-checkpoint-period.sh | 59 ++++++++++++++++++++++++++++++-\n 3 files changed, 78 insertions(+), 0 deletions(-)\n create mode 100755 t/t9830-git-p4-checkpoint-period.sh\n\n-- \ngit-series 0.8.10\n"},{"id":"302026","messageId":"728dfb8e2bf4aa9f6297eada7b8e8a107fd382e6.1473973732.git-series.orirawlings@gmail.com","threadId":"44068","inReplyTo":"cover.9c54bbdd9f054215b5432c4ba3081110e2e91724.1473973732.git-series.orirawlings@gmail.com","subject":"[PATCH v2 1/1] git-p4: Add --checkpoint-period option to sync/clone","fromName":"Ori Rawlings","fromEmail":"orirawlings@gmail.com","sentAt":"2016-09-15T21:17:18Z","receivedAt":"2016-09-15T21:17:38Z","isPatch":true,"sender":{"key":"orirawlings@gmail.com","avatar":"https://gravatar.com/avatar/e0b03bf25fd033ff21a27f7c801240da759f001b28acfa3087f60532bd4c9fa6?d=mp&s=160"},"body":"Importing a long history from Perforce into git using the git-p4 tool\ncan be especially challenging. The `git p4 clone` operation is based\non an all-or-nothing transactionality guarantee. Under real-world\nconditions like network unreliability or a busy Perforce server,\n`git p4 clone` and  `git p4 sync` operations can easily fail, forcing a\nuser to restart the import process from the beginning. The longer the\nhistory being imported, the more likely a fault occurs during the\nprocess. Long enough imports thus become statistically unlikely to ever\nsucceed.\n\nThe underlying git fast-import protocol supports an explicit checkpoint\ncommand. The idea here is to optionally allow the user to force an\nexplicit checkpoint every <x> seconds. If the sync/clone operation fails\nbranches are left updated at the appropriate commit available during the\nlatest checkpoint. This allows a user to resume importing Perforce\nhistory while only having to repeat at most approximately <x> seconds\nworth of import activity.\n\nSigned-off-by: Ori Rawlings <orirawlings@gmail.com>\n---\n Documentation/git-p4.txt            | 12 ++++++-\n git-p4.py                           |  7 ++++-\n t/t9830-git-p4-checkpoint-period.sh | 59 ++++++++++++++++++++++++++++++-\n 3 files changed, 78 insertions(+), 0 deletions(-)\n create mode 100755 t/t9830-git-p4-checkpoint-period.sh\n\ndiff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt\nindex c83aaf3..e48ed6d 100644\n--- a/Documentation/git-p4.txt\n+++ b/Documentation/git-p4.txt\n@@ -252,6 +252,18 @@ Git repository:\n \tUse a client spec to find the list of interesting files in p4.\n \tSee the \"CLIENT SPEC\" section below.\n \n+--checkpoint-period <n>::\n+\tIssue explicit 'checkpoint' commands to the underlying\n+\tlinkgit:git-fast-import[1] approximately every 'n' seconds. If\n+\tsyncing or cloning from the Perforce server is interrupted, the\n+\tprocess can be resumed from the most recent checkpoint with a\n+\tnew 'sync' invocation. This is useful in the situations where a\n+\tlarge amount of changes are being imported over an unreliable\n+\tnetwork connection. Explicit checkpoints can take up to several\n+\tminutes each, so a suitable value for the checkpoint period is\n+\tapproximately 1200 seconds. By default, no explicit checkpoints \n+\tare performed.\n+\n -/ <path>::\n \tExclude selected depot paths when cloning or syncing.\n \ndiff --git a/git-p4.py b/git-p4.py\nindex fd5ca52..4c84871 100755\n--- a/git-p4.py\n+++ b/git-p4.py\n@@ -2244,6 +2244,7 @@ class P4Sync(Command, P4UserMap):\n                 optparse.make_option(\"-/\", dest=\"cloneExclude\",\n                                      action=\"append\", type=\"string\",\n                                      help=\"exclude depot path\"),\n+                optparse.make_option(\"--checkpoint-period\", dest=\"checkpointPeriod\", type=\"int\", help=\"Period in seconds between explict git fast-import checkpoints (by default, no explicit checkpoints are performed)\"),\n         ]\n         self.description = \"\"\"Imports from Perforce into a git repository.\\n\n     example:\n@@ -2276,6 +2277,7 @@ class P4Sync(Command, P4UserMap):\n         self.tempBranches = []\n         self.tempBranchLocation = \"refs/git-p4-tmp\"\n         self.largeFileSystem = None\n+        self.checkpointPeriod = None\n \n         if gitConfig('git-p4.largeFileSystem'):\n             largeFileSystemConstructor = globals()[gitConfig('git-p4.largeFileSystem')]\n@@ -3031,6 +3033,7 @@ class P4Sync(Command, P4UserMap):\n \n     def importChanges(self, changes):\n         cnt = 1\n+        self.lastCheckpointTime = time.time()\n         for change in changes:\n             description = p4_describe(change)\n             self.updateOptionDict(description)\n@@ -3107,6 +3110,10 @@ class P4Sync(Command, P4UserMap):\n                                 self.initialParent)\n                     # only needed once, to connect to the previous commit\n                     self.initialParent = \"\"\n+\n+                    if self.checkpointPeriod >= 0 and time.time() - self.lastCheckpointTime >= self.checkpointPeriod:\n+                        self.checkpoint()\n+                        self.lastCheckpointTime = time.time()\n             except IOError:\n                 print self.gitError.read()\n                 sys.exit(1)\ndiff --git a/t/t9830-git-p4-checkpoint-period.sh b/t/t9830-git-p4-checkpoint-period.sh\nnew file mode 100755\nindex 0000000..6ba4914\n--- /dev/null\n+++ b/t/t9830-git-p4-checkpoint-period.sh\n@@ -0,0 +1,59 @@\n+#!/bin/sh\n+\n+test_description='git p4 checkpoint-period tests'\n+\n+. ./lib-git-p4.sh\n+\n+p4_submit_each () {\n+\tfor file in $@\n+\tdo\n+\t\techo $file > \"$file\" &&\n+\t\tp4 add \"$file\" &&\n+\t\tp4 submit -d \"$file\"\n+\tdone\n+}\n+\n+test_expect_success 'start p4d' '\n+\tstart_p4d\n+'\n+\n+test_expect_success 'no explicit checkpoints' '\n+\tcd \"$cli\" &&\n+\tp4_submit_each file1 file2 file3 &&\n+\tgit p4 clone --dest=\"$git\" //depot@all &&\n+\ttest_when_finished cleanup_git &&\n+\t(\n+\t\tgit -C \"$git\" reflog refs/remotes/p4/master >lines &&\n+\t\ttest_line_count = 1 lines &&\n+\t\tp4_submit_each file4 file5 file6 &&\n+\t\tgit -C \"$git\" p4 sync &&\n+\t\tgit -C \"$git\" reflog refs/remotes/p4/master >lines &&\n+\t\ttest_line_count = 2 lines\n+\t)\n+'\n+\n+test_expect_success 'restart p4d' '\n+\tkill_p4d &&\n+\tstart_p4d\n+'\n+\n+test_expect_success 'checkpoint every 0 seconds, i.e. every commit' '\n+\tcd \"$cli\" &&\n+\tp4_submit_each file1 file2 file3 &&\n+\tgit p4 clone --dest=\"$git\" --checkpoint-period 0 //depot@all &&\n+\ttest_when_finished cleanup_git &&\n+\t(\n+\t\tgit -C \"$git\" reflog refs/remotes/p4/master >lines &&\n+\t\ttest_line_count = 3 lines &&\n+\t\tp4_submit_each file4 file5 file6 &&\n+\t\tgit -C \"$git\" p4 sync --checkpoint-period 0 &&\n+\t\tgit -C \"$git\" reflog refs/remotes/p4/master >lines &&\n+\t\ttest_line_count = 6 lines\n+\t)\n+'\n+\n+test_expect_success 'kill p4d' '\n+\tkill_p4d\n+'\n+\n+test_done\n-- \ngit-series 0.8.10\n"},{"id":"302054","messageId":"9A490197-3220-4AF9-95DA-89B726A91F92@gmail.com","threadId":"44068","inReplyTo":"728dfb8e2bf4aa9f6297eada7b8e8a107fd382e6.1473973732.git-series.orirawlings@gmail.com","subject":"Re: [PATCH v2 1/1] git-p4: Add --checkpoint-period option to sync/clone","fromName":"Lars Schneider","fromEmail":"larsxschneider@gmail.com","sentAt":"2016-09-16T16:19:15Z","receivedAt":"2016-09-16T16:19:23Z","isPatch":true,"sender":{"key":"larsxschneider@gmail.com","avatar":"https://avatars.githubusercontent.com/u/477434?v=4"},"body":"\n> On 15 Sep 2016, at 23:17, Ori Rawlings <orirawlings@gmail.com> wrote:\n> \n> Importing a long history from Perforce into git using the git-p4 tool\n> can be especially challenging. The `git p4 clone` operation is based\n> on an all-or-nothing transactionality guarantee. Under real-world\n> conditions like network unreliability or a busy Perforce server,\n> `git p4 clone` and  `git p4 sync` operations can easily fail, forcing a\n> user to restart the import process from the beginning. The longer the\n> history being imported, the more likely a fault occurs during the\n> process. Long enough imports thus become statistically unlikely to ever\n> succeed.\n> \n> The underlying git fast-import protocol supports an explicit checkpoint\n> command. The idea here is to optionally allow the user to force an\n> explicit checkpoint every <x> seconds. If the sync/clone operation fails\n> branches are left updated at the appropriate commit available during the\n> latest checkpoint. This allows a user to resume importing Perforce\n> history while only having to repeat at most approximately <x> seconds\n> worth of import activity.\n\nThis looks interesting! I ran into the same issue and added a parameter to the p4 commands to retry (patch not yet proposed to the mailing list):\nhttps://github.com/autodesk-forks/git/commit/fcfc96a7814935ee6cefb9d69e44def30a90eabb\n\nWould it make sense to print the \"git-p4 resume command\" in case an error happens and checkpoints are written?\n\nCheers,\nLars"},{"id":"302062","messageId":"CAPv0x+OB=6ju90unOnChXLK-tbYt0utV5JsguE-Dw9zbd28siA@mail.gmail.com","threadId":"44068","inReplyTo":"9A490197-3220-4AF9-95DA-89B726A91F92@gmail.com","subject":"Re: [PATCH v2 1/1] git-p4: Add --checkpoint-period option to sync/clone","fromName":"Ori Rawlings","fromEmail":"orirawlings@gmail.com","sentAt":"2016-09-16T17:43:26Z","receivedAt":"2016-09-16T17:43:53Z","isPatch":true,"sender":{"key":"orirawlings@gmail.com","avatar":"https://gravatar.com/avatar/e0b03bf25fd033ff21a27f7c801240da759f001b28acfa3087f60532bd4c9fa6?d=mp&s=160"},"body":"On Fri, Sep 16, 2016 at 11:19 AM, Lars Schneider\n<larsxschneider@gmail.com> wrote:\n>\n>\n> This looks interesting! I ran into the same issue and added a parameter to the p4 commands to retry (patch not yet proposed to the mailing list):\n> https://github.com/autodesk-forks/git/commit/fcfc96a7814935ee6cefb9d69e44def30a90eabb\n\nI was unaware of the retry flag to the p4 command, that seems like a\nuseful trick too. I think both approaches might pair nicely together\n(p4 optimistically retrying, but still falling back to the latest git\ncheckpoint if we exhaust our N retry attempts).\n\n> Would it make sense to print the \"git-p4 resume command\" in case an error happens and checkpoints are written?\n\nI was thinking something like this would be a good idea and would\ncertainly aide in usability. Resuming a sync is fairly\nstraight-forward (just re-execute the same command). Resuming a clone\nis a bit more problematic, today if a depot path argument is provided\nto the sync or clone command (and it is always required for clone), no\nattempt is made to examine the existing git branches and limit to only\nPerforce changes missing from git.\n\nThere is a lingering TODO in the script where we check the presence of\nthe depot path argument, with a suggestion that we should always make\nan attempt to continue building upon existing history when it is\navailable. I think there might be a few edge cases around this\nbehavior that I'd need to think through. But, if I'm able to address\nthe TODO, then printing the command to resume the import should be\npretty straight-forward. I'll continue working on that next week.\n"}]}