Under certain circumstances, gitCommitByP4Change() can enter an infinite
loop resulting in `git p4 sync` hanging forever.
The problem is that
`git rev-list --bisect <latest> ^<earliest>` can return `<latest>`,
which would result in reinspecting <latest> and potentially an infinite loop.
This can happen when importing just a subset of P4 repository
and/or with explicit "--changesfile" option.
A real-life example:
"""
looking in ref refs/remotes/p4/mybranch for change 26894 using bisect...
Reading pipe: git rev-parse refs/remotes/p4/mybranch
trying: earliest latest 4daff81c520a82678e1ef347f2b5e97258101ae1
Reading pipe: git rev-list --bisect 4daff81c520a82678e1ef347f2b5e97258101ae1
Reading pipe: git cat-file commit 147f5d3292af2e1cc4a56a7b96db845144c68486
current change 25339
trying: earliest ^147f5d3292af2e1cc4a56a7b96db845144c68486 latest
4daff81c520a82678e1ef347f2b5e97258101ae1
Reading pipe: git rev-list --bisect
4daff81c520a82678e1ef347f2b5e97258101ae1
^147f5d3292af2e1cc4a56a7b96db845144c68486
Reading pipe: git cat-file commit 51db83df9d588010d0bd995641c85aa0408a5bb9
current change 25420
trying: earliest ^51db83df9d588010d0bd995641c85aa0408a5bb9 latest
4daff81c520a82678e1ef347f2b5e97258101ae1
Reading pipe: git rev-list --bisect
4daff81c520a82678e1ef347f2b5e97258101ae1
^51db83df9d588010d0bd995641c85aa0408a5bb9
Reading pipe: git cat-file commit e8f83909ceb570f5a7e48c2853f3c5d8207cea52
current change 25448
trying: earliest ^e8f83909ceb570f5a7e48c2853f3c5d8207cea52 latest
4daff81c520a82678e1ef347f2b5e97258101ae1
Reading pipe: git rev-list --bisect
4daff81c520a82678e1ef347f2b5e97258101ae1
^e8f83909ceb570f5a7e48c2853f3c5d8207cea52
Reading pipe: git cat-file commit 09a48eb7acd594dce52e06681be9c366e1844d66
current change 25521
trying: earliest ^09a48eb7acd594dce52e06681be9c366e1844d66 latest
4daff81c520a82678e1ef347f2b5e97258101ae1
Reading pipe: git rev-list --bisect
4daff81c520a82678e1ef347f2b5e97258101ae1
^09a48eb7acd594dce52e06681be9c366e1844d66
Reading pipe: git cat-file commit 4daff81c520a82678e1ef347f2b5e97258101ae1
current change 26907
trying: earliest ^09a48eb7acd594dce52e06681be9c366e1844d66 latest
4daff81c520a82678e1ef347f2b5e97258101ae1
Reading pipe: git rev-list --bisect
4daff81c520a82678e1ef347f2b5e97258101ae1
^09a48eb7acd594dce52e06681be9c366e1844d66
Reading pipe: git cat-file commit 4daff81c520a82678e1ef347f2b5e97258101ae1
current change 26907
trying: earliest ^09a48eb7acd594dce52e06681be9c366e1844d66 latest
4daff81c520a82678e1ef347f2b5e97258101ae1
Reading pipe: git rev-list --bisect
4daff81c520a82678e1ef347f2b5e97258101ae1
^09a48eb7acd594dce52e06681be9c366e1844d66
Reading pipe: git cat-file commit 4daff81c520a82678e1ef347f2b5e97258101ae1
current change 26907
...
"""
The fix is two-fold:
* detect an infinite loop and die right away
instead of looping forever;
* make sure, `git rev-list --bisect` can't return "latestCommit" again
by excluding it from the rev-list range explicitly.
Signed-off-by: Andrey Mazo <[email protected]>
---
Notes:
I don't have a simple test-case for this yet,
and I was able to perform a few complex initial `git p4 sync` runs
without hitting this problem.
I suspect, I had somehow messed up with branch definitions
and --changesfile option at some point.
git-p4.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/git-p4.py b/git-p4.py
index 5b79920f46..c0a3068b6f 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -3323,11 +3323,13 @@ def gitCommitByP4Change(self, ref, change):
return next
if currentChange < change:
earliestCommit = "^%s" % next
else:
- latestCommit = "%s" % next
+ if next == latestCommit:
+ die("Infinite loop while looking in ref %s for change %s.
Check your branch mappings" % (ref, change))
+ latestCommit = "%s^@" % next
return ""
def importNewBranch(self, branch, maxChange):
# make fast-import flush all changes to disk and update the refs using
the checkpoint
--
2.19.2