Merge branch 'va/p4-branch-import'

* va/p4-branch-import:
  git-p4: Add simple test case for branch import
  git-p4: Allow branch definition with git config
  git-p4: Allow filtering Perforce branches by user
  git-p4: Correct branch base depot path detection
  git-p4: Process detectCopiesHarder with --bool
  git-p4: Add test case for copy detection
  git-p4: Add test case for rename detection
  git-p4: Add description of rename/copy detection options
  git-p4: Allow setting rename/copy detection threshold
This commit is contained in:
Junio C Hamano 2011-08-28 21:15:34 -07:00
commit cfd2f0f558
3 changed files with 284 additions and 9 deletions

View File

@ -342,6 +342,11 @@ def gitConfig(key, args = None): # set args to "--bool", for instance
_gitConfig[key] = read_pipe(cmd, ignore_error=True).strip() _gitConfig[key] = read_pipe(cmd, ignore_error=True).strip()
return _gitConfig[key] return _gitConfig[key]
def gitConfigList(key):
if not _gitConfig.has_key(key):
_gitConfig[key] = read_pipe("git config --get-all %s" % key, ignore_error=True).strip().split(os.linesep)
return _gitConfig[key]
def p4BranchesInGit(branchesAreInRemotes = True): def p4BranchesInGit(branchesAreInRemotes = True):
branches = {} branches = {}
@ -774,17 +779,22 @@ class P4Submit(Command, P4UserMap):
if not self.detectRenames: if not self.detectRenames:
# If not explicitly set check the config variable # If not explicitly set check the config variable
self.detectRenames = gitConfig("git-p4.detectRenames").lower() == "true" self.detectRenames = gitConfig("git-p4.detectRenames")
if self.detectRenames: if self.detectRenames.lower() == "false" or self.detectRenames == "":
diffOpts = ""
elif self.detectRenames.lower() == "true":
diffOpts = "-M" diffOpts = "-M"
else: else:
diffOpts = "" diffOpts = "-M%s" % self.detectRenames
if gitConfig("git-p4.detectCopies").lower() == "true": detectCopies = gitConfig("git-p4.detectCopies")
if detectCopies.lower() == "true":
diffOpts += " -C" diffOpts += " -C"
elif detectCopies != "" and detectCopies.lower() != "false":
diffOpts += " -C%s" % detectCopies
if gitConfig("git-p4.detectCopiesHarder").lower() == "true": if gitConfig("git-p4.detectCopiesHarder", "--bool") == "true":
diffOpts += " --find-copies-harder" diffOpts += " --find-copies-harder"
diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id)) diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
@ -1450,7 +1460,13 @@ class P4Sync(Command, P4UserMap):
def getBranchMapping(self): def getBranchMapping(self):
lostAndFoundBranches = set() lostAndFoundBranches = set()
for info in p4CmdList("branches"): user = gitConfig("git-p4.branchUser")
if len(user) > 0:
command = "branches -u %s" % user
else:
command = "branches"
for info in p4CmdList(command):
details = p4Cmd("branch -o %s" % info["branch"]) details = p4Cmd("branch -o %s" % info["branch"])
viewIdx = 0 viewIdx = 0
while details.has_key("View%s" % viewIdx): while details.has_key("View%s" % viewIdx):
@ -1479,6 +1495,25 @@ class P4Sync(Command, P4UserMap):
if source not in self.knownBranches: if source not in self.knownBranches:
lostAndFoundBranches.add(source) lostAndFoundBranches.add(source)
# Perforce does not strictly require branches to be defined, so we also
# check git config for a branch list.
#
# Example of branch definition in git config file:
# [git-p4]
# branchList=main:branchA
# branchList=main:branchB
# branchList=branchA:branchC
configBranches = gitConfigList("git-p4.branchList")
for branch in configBranches:
if branch:
(source, destination) = branch.split(":")
self.knownBranches[destination] = source
lostAndFoundBranches.discard(destination)
if source not in self.knownBranches:
lostAndFoundBranches.add(source)
for branch in lostAndFoundBranches: for branch in lostAndFoundBranches:
self.knownBranches[branch] = branch self.knownBranches[branch] = branch
@ -1824,12 +1859,14 @@ class P4Sync(Command, P4UserMap):
else: else:
paths = [] paths = []
for (prev, cur) in zip(self.previousDepotPaths, depotPaths): for (prev, cur) in zip(self.previousDepotPaths, depotPaths):
for i in range(0, min(len(cur), len(prev))): prev_list = prev.split("/")
if cur[i] <> prev[i]: cur_list = cur.split("/")
for i in range(0, min(len(cur_list), len(prev_list))):
if cur_list[i] <> prev_list[i]:
i = i - 1 i = i - 1
break break
paths.append (cur[:i + 1]) paths.append ("/".join(cur_list[:i + 1]))
self.previousDepotPaths = paths self.previousDepotPaths = paths

View File

@ -232,6 +232,44 @@ git-p4.skipUserNameCheck
When submitting, git-p4 checks that the git commits are authored by the current When submitting, git-p4 checks that the git commits are authored by the current
p4 user, and warns if they are not. This disables the check. p4 user, and warns if they are not. This disables the check.
git-p4.detectRenames
Detect renames when submitting changes to Perforce server. Will enable -M git
argument. Can be optionally set to a number representing the threshold
percentage value of the rename detection.
git config [--global] git-p4.detectRenames true
git config [--global] git-p4.detectRenames 50
git-p4.detectCopies
Detect copies when submitting changes to Perforce server. Will enable -C git
argument. Can be optionally set to a number representing the threshold
percentage value of the copy detection.
git config [--global] git-p4.detectCopies true
git config [--global] git-p4.detectCopies 80
git-p4.detectCopiesHarder
Detect copies even between files that did not change when submitting changes to
Perforce server. Will enable --find-copies-harder git argument.
git config [--global] git-p4.detectCopies true
git-p4.branchUser
Only use branch specifications defined by the selected username.
git config [--global] git-p4.branchUser username
git-p4.branchList
List of branches to be imported when branch detection is enabled.
git config [--global] git-p4.branchList main:branchA
git config [--global] --add git-p4.branchList main:branchB
Implementation Details... Implementation Details...
========================= =========================

View File

@ -269,6 +269,206 @@ test_expect_success 'initial import time from top change time' '
test $p4time = $gittime test $p4time = $gittime
' '
# Rename a file and confirm that rename is not detected in P4.
# Rename the new file again with detectRenames option enabled and confirm that
# this is detected in P4.
# Rename the new file again adding an extra line, configure a big threshold in
# detectRenames and confirm that rename is not detected in P4.
# Repeat, this time with a smaller threshold and confirm that the rename is
# detected in P4.
test_expect_success 'detect renames' '
"$GITP4" clone --dest="$git" //depot@all &&
test_when_finished cleanup_git &&
cd "$git" &&
git config git-p4.skipSubmitEditCheck true &&
git mv file1 file4 &&
git commit -a -m "Rename file1 to file4" &&
git diff-tree -r -M HEAD &&
"$GITP4" submit &&
p4 filelog //depot/file4 &&
! p4 filelog //depot/file4 | grep -q "branch from" &&
git mv file4 file5 &&
git commit -a -m "Rename file4 to file5" &&
git diff-tree -r -M HEAD &&
git config git-p4.detectRenames true &&
"$GITP4" submit &&
p4 filelog //depot/file5 &&
p4 filelog //depot/file5 | grep -q "branch from //depot/file4" &&
git mv file5 file6 &&
echo update >>file6 &&
git add file6 &&
git commit -a -m "Rename file5 to file6 with changes" &&
git diff-tree -r -M HEAD &&
level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
git config git-p4.detectRenames $((level + 2)) &&
"$GITP4" submit &&
p4 filelog //depot/file6 &&
! p4 filelog //depot/file6 | grep -q "branch from" &&
git mv file6 file7 &&
echo update >>file7 &&
git add file7 &&
git commit -a -m "Rename file6 to file7 with changes" &&
git diff-tree -r -M HEAD &&
level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
git config git-p4.detectRenames $((level - 2)) &&
"$GITP4" submit &&
p4 filelog //depot/file7 &&
p4 filelog //depot/file7 | grep -q "branch from //depot/file6"
'
# Copy a file and confirm that copy is not detected in P4.
# Copy a file with detectCopies option enabled and confirm that copy is not
# detected in P4.
# Modify and copy a file with detectCopies option enabled and confirm that copy
# is detected in P4.
# Copy a file with detectCopies and detectCopiesHarder options enabled and
# confirm that copy is detected in P4.
# Modify and copy a file, configure a bigger threshold in detectCopies and
# confirm that copy is not detected in P4.
# Modify and copy a file, configure a smaller threshold in detectCopies and
# confirm that copy is detected in P4.
test_expect_success 'detect copies' '
"$GITP4" clone --dest="$git" //depot@all &&
test_when_finished cleanup_git &&
cd "$git" &&
git config git-p4.skipSubmitEditCheck true &&
cp file2 file8 &&
git add file8 &&
git commit -a -m "Copy file2 to file8" &&
git diff-tree -r -C HEAD &&
"$GITP4" submit &&
p4 filelog //depot/file8 &&
! p4 filelog //depot/file8 | grep -q "branch from" &&
cp file2 file9 &&
git add file9 &&
git commit -a -m "Copy file2 to file9" &&
git diff-tree -r -C HEAD &&
git config git-p4.detectCopies true &&
"$GITP4" submit &&
p4 filelog //depot/file9 &&
! p4 filelog //depot/file9 | grep -q "branch from" &&
echo "file2" >>file2 &&
cp file2 file10 &&
git add file2 file10 &&
git commit -a -m "Modify and copy file2 to file10" &&
git diff-tree -r -C HEAD &&
"$GITP4" submit &&
p4 filelog //depot/file10 &&
p4 filelog //depot/file10 | grep -q "branch from //depot/file" &&
cp file2 file11 &&
git add file11 &&
git commit -a -m "Copy file2 to file11" &&
git diff-tree -r -C --find-copies-harder HEAD &&
src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
test "$src" = file10 &&
git config git-p4.detectCopiesHarder true &&
"$GITP4" submit &&
p4 filelog //depot/file11 &&
p4 filelog //depot/file11 | grep -q "branch from //depot/file" &&
cp file2 file12 &&
echo "some text" >>file12 &&
git add file12 &&
git commit -a -m "Copy file2 to file12 with changes" &&
git diff-tree -r -C --find-copies-harder HEAD &&
level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
test "$src" = file10 &&
git config git-p4.detectCopies $((level + 2)) &&
"$GITP4" submit &&
p4 filelog //depot/file12 &&
! p4 filelog //depot/file12 | grep -q "branch from" &&
cp file2 file13 &&
echo "different text" >>file13 &&
git add file13 &&
git commit -a -m "Copy file2 to file13 with changes" &&
git diff-tree -r -C --find-copies-harder HEAD &&
level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") &&
test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
test "$src" = file10 &&
git config git-p4.detectCopies $((level - 2)) &&
"$GITP4" submit &&
p4 filelog //depot/file13 &&
p4 filelog //depot/file13 | grep -q "branch from //depot/file"
'
# Create a simple branch structure in P4 depot to check if it is correctly
# cloned.
test_expect_success 'add simple p4 branches' '
cd "$cli" &&
mkdir branch1 &&
cd branch1 &&
echo file1 >file1 &&
echo file2 >file2 &&
p4 add file* &&
p4 submit -d "branch1" &&
p4 integrate //depot/branch1/... //depot/branch2/... &&
p4 submit -d "branch2" &&
echo file3 >file3 &&
p4 add file3 &&
p4 submit -d "add file3 in branch1" &&
p4 open file2 &&
echo update >>file2 &&
p4 submit -d "update file2 in branch1" &&
p4 integrate //depot/branch1/... //depot/branch3/... &&
p4 submit -d "branch3" &&
cd "$TRASH_DIRECTORY"
'
# Configure branches through git-config and clone them.
# All files are tested to make sure branches were cloned correctly.
# Finally, make an update to branch1 on P4 side to check if it is imported
# correctly by git-p4.
test_expect_success 'git-p4 clone simple branches' '
git init "$git" &&
cd "$git" &&
git config git-p4.branchList branch1:branch2 &&
git config --add git-p4.branchList branch1:branch3 &&
cd "$TRASH_DIRECTORY" &&
"$GITP4" clone --dest="$git" --detect-branches //depot@all &&
cd "$git" &&
git log --all --graph --decorate --stat &&
git reset --hard p4/depot/branch1 &&
test -f file1 &&
test -f file2 &&
test -f file3 &&
grep -q update file2 &&
git reset --hard p4/depot/branch2 &&
test -f file1 &&
test -f file2 &&
test \! -z file3 &&
! grep -q update file2 &&
git reset --hard p4/depot/branch3 &&
test -f file1 &&
test -f file2 &&
test -f file3 &&
grep -q update file2 &&
cd "$cli" &&
cd branch1 &&
p4 edit file2 &&
echo file2_ >> file2 &&
p4 submit -d "update file2 in branch3" &&
cd "$git" &&
git reset --hard p4/depot/branch1 &&
"$GITP4" rebase &&
grep -q file2_ file2 &&
cd "$TRASH_DIRECTORY" &&
rm -rf "$git" && mkdir "$git"
'
test_expect_success 'shutdown' ' test_expect_success 'shutdown' '
pid=`pgrep -f p4d` && pid=`pgrep -f p4d` &&
test -n "$pid" && test -n "$pid" &&