Merge branch 'pw/p4-submit-conflicts'

Add '--conflict' option to git-p4 subcommand to specify what action
to take when conflicts are found during 'p4 submit'.

* pw/p4-submit-conflicts:
  git-p4: add submit --conflict option and config varaiable
  git p4: add submit --prepare-p4-only option
  git p4: add submit --dry-run option
  git p4: accept -v for --verbose
  git p4: revert deleted files after submit cancel
  git p4: rearrange submit template construction
  git p4: test clean-up after failed submit, fix added files
  git p4: standardize submit cancel due to unchanged template
  git p4: move conflict prompt into run, add [q]uit input
  git p4: remove submit failure options [a]pply and [w]rite
  git p4: gracefully fail if some commits could not be applied
  git p4 test: remove bash-ism of combined export/assignment
This commit is contained in:
Junio C Hamano 2012-09-18 14:36:17 -07:00
Родитель 3387423870 6bbfd1372d
Коммит 8db3865936
7 изменённых файлов: 709 добавлений и 107 удалений

Просмотреть файл

@ -163,7 +163,7 @@ All commands except clone accept these options.
--git-dir <dir>::
Set the 'GIT_DIR' environment variable. See linkgit:git[1].
--verbose::
--verbose, -v::
Provide more progress information.
Sync options
@ -269,6 +269,24 @@ These options can be used to modify 'git p4 submit' behavior.
Export tags from git as p4 labels. Tags found in git are applied
to the perforce working directory.
--dry-run, -n::
Show just what commits would be submitted to p4; do not change
state in git or p4.
--prepare-p4-only::
Apply a commit to the p4 workspace, opening, adding and deleting
files in p4 as for a normal submit operation. Do not issue the
final "p4 submit", but instead print a message about how to
submit manually or revert. This option always stops after the
first (oldest) commit. Git tags are not exported to p4.
--conflict=(ask|skip|quit)::
Conflicts can occur when applying a commit to p4. When this
happens, the default behavior ("ask") is to prompt whether to
skip this commit and continue, or quit. This option can be used
to bypass the prompt, causing conflicting commits to be automatically
skipped, or to quit trying to apply commits, without prompting.
Rebase options
~~~~~~~~~~~~~~
These options can be used to modify 'git p4 rebase' behavior.
@ -519,6 +537,10 @@ git-p4.labelExportRegexp::
Only p4 labels matching this regular expression will be exported. The
default value is '[a-zA-Z0-9_\-.]+$'.
git-p4.conflict::
Specify submit behavior when a conflict with p4 is found, as per
--conflict. The default behavior is 'ask'.
IMPLEMENTATION DETAILS
----------------------
* Changesets from p4 are imported using git fast-import.

239
git-p4.py
Просмотреть файл

@ -844,6 +844,9 @@ class P4RollBack(Command):
return True
class P4Submit(Command, P4UserMap):
conflict_behavior_choices = ("ask", "skip", "quit")
def __init__(self):
Command.__init__(self)
P4UserMap.__init__(self)
@ -853,12 +856,19 @@ class P4Submit(Command, P4UserMap):
# preserve the user, requires relevant p4 permissions
optparse.make_option("--preserve-user", dest="preserveUser", action="store_true"),
optparse.make_option("--export-labels", dest="exportLabels", action="store_true"),
optparse.make_option("--dry-run", "-n", dest="dry_run", action="store_true"),
optparse.make_option("--prepare-p4-only", dest="prepare_p4_only", action="store_true"),
optparse.make_option("--conflict", dest="conflict_behavior",
choices=self.conflict_behavior_choices)
]
self.description = "Submit changes from git to the perforce depot."
self.usage += " [name of git branch to submit into perforce depot]"
self.origin = ""
self.detectRenames = False
self.preserveUser = gitConfig("git-p4.preserveUser").lower() == "true"
self.dry_run = False
self.prepare_p4_only = False
self.conflict_behavior = None
self.isWindows = (platform.system() == "Windows")
self.exportLabels = False
self.p4HasMoveCommand = p4_has_command("move")
@ -1088,7 +1098,10 @@ class P4Submit(Command, P4UserMap):
return False
def applyCommit(self, id):
print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
"""Apply one commit, return True if it succeeded."""
print "Applying", read_pipe(["git", "show", "-s",
"--format=format:%h %s", id])
(p4User, gitEmail) = self.p4UserForCommit(id)
@ -1195,34 +1208,13 @@ class P4Submit(Command, P4UserMap):
patch_succeeded = True
if not patch_succeeded:
print "What do you want to do?"
response = "x"
while response != "s" and response != "a" and response != "w":
response = raw_input("[s]kip this patch / [a]pply the patch forcibly "
"and with .rej files / [w]rite the patch to a file (patch.txt) ")
if response == "s":
print "Skipping! Good luck with the next patches..."
for f in editedFiles:
p4_revert(f)
for f in filesToAdd:
os.remove(f)
return
elif response == "a":
os.system(applyPatchCmd)
if len(filesToAdd) > 0:
print "You may also want to call p4 add on the following files:"
print " ".join(filesToAdd)
if len(filesToDelete):
print "The following files should be scheduled for deletion with p4 delete:"
print " ".join(filesToDelete)
die("Please resolve and submit the conflict manually and "
+ "continue afterwards with git p4 submit --continue")
elif response == "w":
system(diffcmd + " > patch.txt")
print "Patch saved to patch.txt in %s !" % self.clientPath
die("Please resolve and submit the conflict manually and "
"continue afterwards with git p4 submit --continue")
for f in editedFiles:
p4_revert(f)
return False
#
# Apply the patch for real, and do add/delete/+x handling.
#
system(applyPatchCmd)
for f in filesToAdd:
@ -1236,6 +1228,10 @@ class P4Submit(Command, P4UserMap):
mode = filesToChangeExecBit[f]
setP4ExecBit(f, mode)
#
# Build p4 change description, starting with the contents
# of the git commit message.
#
logMessage = extractLogMessageFromGitCommit(id)
logMessage = logMessage.strip()
(logMessage, jobs) = self.separate_jobs_from_description(logMessage)
@ -1244,8 +1240,16 @@ class P4Submit(Command, P4UserMap):
submitTemplate = self.prepareLogMessage(template, logMessage, jobs)
if self.preserveUser:
submitTemplate = submitTemplate + ("\n######## Actual user %s, modified after commit\n" % p4User)
submitTemplate += "\n######## Actual user %s, modified after commit\n" % p4User
if self.checkAuthorship and not self.p4UserIsMe(p4User):
submitTemplate += "######## git author %s does not match your p4 account.\n" % gitEmail
submitTemplate += "######## Use option --preserve-user to modify authorship.\n"
submitTemplate += "######## Variable git-p4.skipUserNameCheck hides this message.\n"
separatorLine = "######## everything below this line is just the diff #######\n"
# diff
if os.environ.has_key("P4DIFF"):
del(os.environ["P4DIFF"])
diff = ""
@ -1253,6 +1257,7 @@ class P4Submit(Command, P4UserMap):
diff += p4_read_pipe(['diff', '-du',
wildcard_encode(editedFile)])
# new file diff
newdiff = ""
for newFile in filesToAdd:
newdiff += "==== new file ====\n"
@ -1263,13 +1268,7 @@ class P4Submit(Command, P4UserMap):
newdiff += "+" + line
f.close()
if self.checkAuthorship and not self.p4UserIsMe(p4User):
submitTemplate += "######## git author %s does not match your p4 account.\n" % gitEmail
submitTemplate += "######## Use option --preserve-user to modify authorship.\n"
submitTemplate += "######## Variable git-p4.skipUserNameCheck hides this message.\n"
separatorLine = "######## everything below this line is just the diff #######\n"
# change description file: submitTemplate, separatorLine, diff, newdiff
(handle, fileName) = tempfile.mkstemp()
tmpFile = os.fdopen(handle, "w+")
if self.isWindows:
@ -1279,8 +1278,47 @@ class P4Submit(Command, P4UserMap):
tmpFile.write(submitTemplate + separatorLine + diff + newdiff)
tmpFile.close()
if self.prepare_p4_only:
#
# Leave the p4 tree prepared, and the submit template around
# and let the user decide what to do next
#
print
print "P4 workspace prepared for submission."
print "To submit or revert, go to client workspace"
print " " + self.clientPath
print
print "To submit, use \"p4 submit\" to write a new description,"
print "or \"p4 submit -i %s\" to use the one prepared by" \
" \"git p4\"." % fileName
print "You can delete the file \"%s\" when finished." % fileName
if self.preserveUser and p4User and not self.p4UserIsMe(p4User):
print "To preserve change ownership by user %s, you must\n" \
"do \"p4 change -f <change>\" after submitting and\n" \
"edit the User field."
if pureRenameCopy:
print "After submitting, renamed files must be re-synced."
print "Invoke \"p4 sync -f\" on each of these files:"
for f in pureRenameCopy:
print " " + f
print
print "To revert the changes, use \"p4 revert ...\", and delete"
print "the submit template file \"%s\"" % fileName
if filesToAdd:
print "Since the commit adds new files, they must be deleted:"
for f in filesToAdd:
print " " + f
print
return True
#
# Let the user edit the change description, then submit it.
#
if self.edit_template(fileName):
# read the edited message and submit
ret = True
tmpFile = open(fileName, "rb")
message = tmpFile.read()
tmpFile.close()
@ -1304,14 +1342,18 @@ class P4Submit(Command, P4UserMap):
else:
# skip this patch
ret = False
print "Submission cancelled, undoing p4 changes."
for f in editedFiles:
p4_revert(f)
for f in filesToAdd:
p4_revert(f)
os.remove(f)
for f in filesToDelete:
p4_revert(f)
os.remove(fileName)
return ret
# Export git tags as p4 labels. Create a p4 label and then tag
# with that.
@ -1369,14 +1411,20 @@ class P4Submit(Command, P4UserMap):
for mapping in clientSpec.mappings:
labelTemplate += "\t%s\n" % mapping.depot_side.path
p4_write_pipe(["label", "-i"], labelTemplate)
if self.dry_run:
print "Would create p4 label %s for tag" % name
elif self.prepare_p4_only:
print "Not creating p4 label %s for tag due to option" \
" --prepare-p4-only" % name
else:
p4_write_pipe(["label", "-i"], labelTemplate)
# Use the label
p4_system(["tag", "-l", name] +
["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings])
# Use the label
p4_system(["tag", "-l", name] +
["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings])
if verbose:
print "created p4 label for tag %s" % name
if verbose:
print "created p4 label for tag %s" % name
def run(self, args):
if len(args) == 0:
@ -1403,6 +1451,16 @@ class P4Submit(Command, P4UserMap):
if not self.canChangeChangelists():
die("Cannot preserve user names without p4 super-user or admin permissions")
# if not set from the command line, try the config file
if self.conflict_behavior is None:
val = gitConfig("git-p4.conflict")
if val:
if val not in self.conflict_behavior_choices:
die("Invalid value '%s' for config git-p4.conflict" % val)
else:
val = "ask"
self.conflict_behavior = val
if self.verbose:
print "Origin branch is " + self.origin
@ -1435,12 +1493,15 @@ class P4Submit(Command, P4UserMap):
os.makedirs(self.clientPath)
chdir(self.clientPath)
print "Synchronizing p4 checkout..."
if new_client_dir:
# old one was destroyed, and maybe nobody told p4
p4_sync("...", "-f")
if self.dry_run:
print "Would synchronize p4 checkout in %s" % self.clientPath
else:
p4_sync("...")
print "Synchronizing p4 checkout..."
if new_client_dir:
# old one was destroyed, and maybe nobody told p4
p4_sync("...", "-f")
else:
p4_sync("...")
self.check()
commits = []
@ -1487,14 +1548,64 @@ class P4Submit(Command, P4UserMap):
if gitConfig("git-p4.detectCopiesHarder", "--bool") == "true":
self.diffOpts += " --find-copies-harder"
while len(commits) > 0:
commit = commits[0]
commits = commits[1:]
self.applyCommit(commit)
#
# Apply the commits, one at a time. On failure, ask if should
# continue to try the rest of the patches, or quit.
#
if self.dry_run:
print "Would apply"
applied = []
last = len(commits) - 1
for i, commit in enumerate(commits):
if self.dry_run:
print " ", read_pipe(["git", "show", "-s",
"--format=format:%h %s", commit])
ok = True
else:
ok = self.applyCommit(commit)
if ok:
applied.append(commit)
else:
if self.prepare_p4_only and i < last:
print "Processing only the first commit due to option" \
" --prepare-p4-only"
break
if i < last:
quit = False
while True:
# prompt for what to do, or use the option/variable
if self.conflict_behavior == "ask":
print "What do you want to do?"
response = raw_input("[s]kip this commit but apply"
" the rest, or [q]uit? ")
if not response:
continue
elif self.conflict_behavior == "skip":
response = "s"
elif self.conflict_behavior == "quit":
response = "q"
else:
die("Unknown conflict_behavior '%s'" %
self.conflict_behavior)
if len(commits) == 0:
print "All changes applied!"
chdir(self.oldWorkingDirectory)
if response[0] == "s":
print "Skipping this commit, but applying the rest"
break
if response[0] == "q":
print "Quitting"
quit = True
break
if quit:
break
chdir(self.oldWorkingDirectory)
if self.dry_run:
pass
elif self.prepare_p4_only:
pass
elif len(commits) == len(applied):
print "All commits applied!"
sync = P4Sync()
sync.run([])
@ -1502,6 +1613,20 @@ class P4Submit(Command, P4UserMap):
rebase = P4Rebase()
rebase.rebase()
else:
if len(applied) == 0:
print "No commits applied."
else:
print "Applied only the commits marked with '*':"
for c in commits:
if c in applied:
star = "*"
else:
star = " "
print star, read_pipe(["git", "show", "-s",
"--format=format:%h %s", c])
print "You will have to do 'git p4 sync' and rebase."
if gitConfig("git-p4.exportLabels", "--bool") == "true":
self.exportLabels = True
@ -1512,6 +1637,10 @@ class P4Submit(Command, P4UserMap):
missingGitTags = gitTags - p4Labels
self.exportGitTags(missingGitTags)
# exit with error unless everything applied perfecly
if len(commits) != len(applied):
sys.exit(1)
return True
class View(object):
@ -3015,7 +3144,7 @@ def main():
args = sys.argv[2:]
options.append(optparse.make_option("--verbose", dest="verbose", action="store_true"))
options.append(optparse.make_option("--verbose", "-v", dest="verbose", action="store_true"))
if cmd.needsGit:
options.append(optparse.make_option("--git-dir", dest="gitdir"))

Просмотреть файл

@ -26,9 +26,10 @@ testid=${this_test#t}
git_p4_test_start=9800
P4DPORT=$((10669 + ($testid - $git_p4_test_start)))
export P4PORT=localhost:$P4DPORT
export P4CLIENT=client
export P4EDITOR=:
P4PORT=localhost:$P4DPORT
P4CLIENT=client
P4EDITOR=:
export P4PORT P4CLIENT P4EDITOR
db="$TRASH_DIRECTORY/db"
cli=$(test-path-utils real_path "$TRASH_DIRECTORY/cli")

Просмотреть файл

@ -38,7 +38,7 @@ test_expect_success 'no config, unedited, say no' '
cd "$git" &&
echo line >>file1 &&
git commit -a -m "change 3 (not really)" &&
printf "bad response\nn\n" | git p4 submit &&
printf "bad response\nn\n" | test_expect_code 1 git p4 submit &&
p4 changes //depot/... >wc &&
test_line_count = 2 wc
)

Просмотреть файл

@ -54,6 +54,47 @@ test_expect_success 'submit --origin' '
)
'
test_expect_success 'submit --dry-run' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
test_commit "dry-run1" &&
test_commit "dry-run2" &&
git p4 submit --dry-run >out &&
test_i18ngrep "Would apply" out
) &&
(
cd "$cli" &&
test_path_is_missing "dry-run1.t" &&
test_path_is_missing "dry-run2.t"
)
'
test_expect_success 'submit --dry-run --export-labels' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo dry-run1 >dry-run1 &&
git add dry-run1 &&
git commit -m "dry-run1" dry-run1 &&
git config git-p4.skipSubmitEdit true &&
git p4 submit &&
echo dry-run2 >dry-run2 &&
git add dry-run2 &&
git commit -m "dry-run2" dry-run2 &&
git tag -m "dry-run-tag1" dry-run-tag1 HEAD^ &&
git p4 submit --dry-run --export-labels >out &&
test_i18ngrep "Would create p4 label" out
) &&
(
cd "$cli" &&
test_path_is_file "dry-run1" &&
test_path_is_missing "dry-run2"
)
'
test_expect_success 'submit with allowSubmit' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
@ -334,6 +375,30 @@ test_expect_success 'description with Jobs section and bogus following text' '
make_job $(cat jobname) &&
test_must_fail git p4 submit 2>err &&
test_i18ngrep "Unknown field name" err
) &&
(
cd "$cli" &&
p4 revert desc6 &&
rm desc6
)
'
test_expect_success 'submit --prepare-p4-only' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo prep-only-add >prep-only-add &&
git add prep-only-add &&
git commit -m "prep only add" &&
git p4 submit --prepare-p4-only >out &&
test_i18ngrep "prepared for submission" out &&
test_i18ngrep "must be deleted" out
) &&
(
cd "$cli" &&
test_path_is_file prep-only-add &&
p4 fstat -T action prep-only-add | grep -w add
)
'

Просмотреть файл

@ -160,9 +160,6 @@ test_expect_success 'cleanup after failure' '
# the cli file so that submit will get a conflict. Make sure that
# scrubbing doesn't make a mess of things.
#
# Assumes that git-p4 exits leaving the p4 file open, with the
# conflict-generating patch unapplied.
#
# This might happen only if the git repo is behind the p4 repo at
# submit time, and there is a conflict.
#
@ -181,14 +178,11 @@ test_expect_success 'do not scrub plain text' '
sed -i "s/^line5/line5 p4 edit/" file_text &&
p4 submit -d "file5 p4 edit"
) &&
! git p4 submit &&
echo s | test_expect_code 1 git p4 submit &&
(
# exepct something like:
# file_text - file(s) not opened on this client
# but not copious diff output
# make sure the file is not left open
cd "$cli" &&
p4 diff file_text >wc &&
test_line_count = 1 wc
! p4 fstat -T action file_text
)
)
'
@ -343,44 +337,6 @@ test_expect_failure 'Add keywords in git which do not match the default p4 value
)
'
# Check that the existing merge conflict handling still works.
# Modify kwfile1.c in git, and delete in p4. We should be able
# to skip the git commit.
#
test_expect_success 'merge conflict handling still works' '
test_when_finished cleanup_git &&
(
cd "$cli" &&
echo "Hello:\$Id\$" >merge2.c &&
echo "World" >>merge2.c &&
p4 add -t ktext merge2.c &&
p4 submit -d "add merge test file"
) &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
sed -e "/Hello/d" merge2.c >merge2.c.tmp &&
mv merge2.c.tmp merge2.c &&
git add merge2.c &&
git commit -m "Modifying merge2.c"
) &&
(
cd "$cli" &&
p4 delete merge2.c &&
p4 submit -d "remove merge test file"
) &&
(
cd "$git" &&
test -f merge2.c &&
git config git-p4.skipSubmitEdit true &&
git config git-p4.attemptRCSCleanup true &&
!(echo "s" | git p4 submit) &&
git rebase --skip &&
! test -f merge2.c
)
'
test_expect_success 'kill p4d' '
kill_p4d
'

429
t/t9815-git-p4-submit-fail.sh Executable file
Просмотреть файл

@ -0,0 +1,429 @@
#!/bin/sh
test_description='git p4 submit failure handling'
. ./lib-git-p4.sh
test_expect_success 'start p4d' '
start_p4d
'
test_expect_success 'init depot' '
(
cd "$cli" &&
p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i &&
echo line1 >file1 &&
p4 add file1 &&
p4 submit -d "line1 in file1"
)
'
test_expect_success 'conflict on one commit' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$cli" &&
p4 open file1 &&
echo line2 >>file1 &&
p4 submit -d "line2 in file1"
) &&
(
# now this commit should cause a conflict
cd "$git" &&
git config git-p4.skipSubmitEdit true &&
echo line3 >>file1 &&
git add file1 &&
git commit -m "line3 in file1 will conflict" &&
test_expect_code 1 git p4 submit >out &&
test_i18ngrep "No commits applied" out
)
'
test_expect_success 'conflict on second of two commits' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$cli" &&
p4 open file1 &&
echo line3 >>file1 &&
p4 submit -d "line3 in file1"
) &&
(
cd "$git" &&
git config git-p4.skipSubmitEdit true &&
# this commit is okay
test_commit "first_commit_okay" &&
# now this submit should cause a conflict
echo line4 >>file1 &&
git add file1 &&
git commit -m "line4 in file1 will conflict" &&
test_expect_code 1 git p4 submit >out &&
test_i18ngrep "Applied only the commits" out
)
'
test_expect_success 'conflict on first of two commits, skip' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$cli" &&
p4 open file1 &&
echo line4 >>file1 &&
p4 submit -d "line4 in file1"
) &&
(
cd "$git" &&
git config git-p4.skipSubmitEdit true &&
# this submit should cause a conflict
echo line5 >>file1 &&
git add file1 &&
git commit -m "line5 in file1 will conflict" &&
# but this commit is okay
test_commit "okay_commit_after_skip" &&
echo s | test_expect_code 1 git p4 submit >out &&
test_i18ngrep "Applied only the commits" out
)
'
test_expect_success 'conflict on first of two commits, quit' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$cli" &&
p4 open file1 &&
echo line7 >>file1 &&
p4 submit -d "line7 in file1"
) &&
(
cd "$git" &&
git config git-p4.skipSubmitEdit true &&
# this submit should cause a conflict
echo line8 >>file1 &&
git add file1 &&
git commit -m "line8 in file1 will conflict" &&
# but this commit is okay
test_commit "okay_commit_after_quit" &&
echo q | test_expect_code 1 git p4 submit >out &&
test_i18ngrep "No commits applied" out
)
'
test_expect_success 'conflict cli and config options' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
git p4 submit --conflict=ask &&
git p4 submit --conflict=skip &&
git p4 submit --conflict=quit &&
test_expect_code 2 git p4 submit --conflict=foo &&
test_expect_code 2 git p4 submit --conflict &&
git config git-p4.conflict foo &&
test_expect_code 1 git p4 submit &&
git config --unset git-p4.conflict &&
git p4 submit
)
'
test_expect_success 'conflict on first of two commits, --conflict=skip' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$cli" &&
p4 open file1 &&
echo line9 >>file1 &&
p4 submit -d "line9 in file1"
) &&
(
cd "$git" &&
git config git-p4.skipSubmitEdit true &&
# this submit should cause a conflict
echo line10 >>file1 &&
git add file1 &&
git commit -m "line10 in file1 will conflict" &&
# but this commit is okay
test_commit "okay_commit_after_auto_skip" &&
test_expect_code 1 git p4 submit --conflict=skip >out &&
test_i18ngrep "Applied only the commits" out
)
'
test_expect_success 'conflict on first of two commits, --conflict=quit' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$cli" &&
p4 open file1 &&
echo line11 >>file1 &&
p4 submit -d "line11 in file1"
) &&
(
cd "$git" &&
git config git-p4.skipSubmitEdit true &&
# this submit should cause a conflict
echo line12 >>file1 &&
git add file1 &&
git commit -m "line12 in file1 will conflict" &&
# but this commit is okay
test_commit "okay_commit_after_auto_quit" &&
test_expect_code 1 git p4 submit --conflict=quit >out &&
test_i18ngrep "No commits applied" out
)
'
#
# Cleanup after submit fail, all cases. Some modifications happen
# before trying to apply the patch. Make sure these are unwound
# properly. Put each one in a diff along with something that will
# obviously conflict. Make sure it is back to normal after.
#
test_expect_success 'cleanup edit p4 populate' '
(
cd "$cli" &&
echo text file >text &&
p4 add text &&
echo text+x file >text+x &&
chmod 755 text+x &&
p4 add text+x &&
p4 submit -d "populate p4"
)
'
setup_conflict() {
# clone before modifying file1 to force it to conflict
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
# ticks outside subshells
test_tick &&
(
cd "$cli" &&
p4 open file1 &&
echo $test_tick >>file1 &&
p4 submit -d "$test_tick in file1"
) &&
test_tick &&
(
cd "$git" &&
git config git-p4.skipSubmitEdit true &&
# easy conflict
echo $test_tick >>file1 &&
git add file1
# caller will add more and submit
)
}
test_expect_success 'cleanup edit after submit fail' '
setup_conflict &&
(
cd "$git" &&
echo another line >>text &&
git add text &&
git commit -m "conflict" &&
test_expect_code 1 git p4 submit
) &&
(
cd "$cli" &&
# make sure it is not open
! p4 fstat -T action text
)
'
test_expect_success 'cleanup add after submit fail' '
setup_conflict &&
(
cd "$git" &&
echo new file >textnew &&
git add textnew &&
git commit -m "conflict" &&
test_expect_code 1 git p4 submit
) &&
(
cd "$cli" &&
# make sure it is not there
# and that p4 thinks it is not added
# P4 returns 0 both for "not there but added" and
# "not there", so grep.
test_path_is_missing textnew &&
p4 fstat -T action textnew 2>&1 | grep "no such file"
)
'
test_expect_success 'cleanup delete after submit fail' '
setup_conflict &&
(
cd "$git" &&
git rm text+x &&
git commit -m "conflict" &&
test_expect_code 1 git p4 submit
) &&
(
cd "$cli" &&
# make sure it is there
test_path_is_file text+x &&
! p4 fstat -T action text+x
)
'
test_expect_success 'cleanup copy after submit fail' '
setup_conflict &&
(
cd "$git" &&
cp text text2 &&
git add text2 &&
git commit -m "conflict" &&
git config git-p4.detectCopies true &&
git config git-p4.detectCopiesHarder true &&
# make sure setup is okay
git diff-tree -r -C --find-copies-harder HEAD | grep text2 | grep C100 &&
test_expect_code 1 git p4 submit
) &&
(
cd "$cli" &&
test_path_is_missing text2 &&
p4 fstat -T action text2 2>&1 | grep "no such file"
)
'
test_expect_success 'cleanup rename after submit fail' '
setup_conflict &&
(
cd "$git" &&
git mv text text2 &&
git commit -m "conflict" &&
git config git-p4.detectRenames true &&
# make sure setup is okay
git diff-tree -r -M HEAD | grep text2 | grep R100 &&
test_expect_code 1 git p4 submit
) &&
(
cd "$cli" &&
test_path_is_missing text2 &&
p4 fstat -T action text2 2>&1 | grep "no such file"
)
'
#
# Cleanup after deciding not to submit during editTemplate. This
# involves unwinding more work, because files have been added, deleted
# and chmod-ed now. Same approach as above.
#
test_expect_success 'cleanup edit after submit cancel' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo line >>text &&
git add text &&
git commit -m text &&
echo n | test_expect_code 1 git p4 submit &&
git reset --hard HEAD^
) &&
(
cd "$cli" &&
! p4 fstat -T action text &&
test_cmp "$git"/text text
)
'
test_expect_success 'cleanup add after submit cancel' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
echo line >textnew &&
git add textnew &&
git commit -m textnew &&
echo n | test_expect_code 1 git p4 submit
) &&
(
cd "$cli" &&
test_path_is_missing textnew &&
p4 fstat -T action textnew 2>&1 | grep "no such file"
)
'
test_expect_success 'cleanup delete after submit cancel' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
git rm text &&
git commit -m "rm text" &&
echo n | test_expect_code 1 git p4 submit
) &&
(
cd "$cli" &&
test_path_is_file text &&
! p4 fstat -T action text
)
'
test_expect_success 'cleanup copy after submit cancel' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
cp text text2 &&
git add text2 &&
git commit -m text2 &&
git config git-p4.detectCopies true &&
git config git-p4.detectCopiesHarder true &&
git diff-tree -r -C --find-copies-harder HEAD | grep text2 | grep C100 &&
echo n | test_expect_code 1 git p4 submit
) &&
(
cd "$cli" &&
test_path_is_missing text2 &&
p4 fstat -T action text2 2>&1 | grep "no such file"
)
'
test_expect_success 'cleanup rename after submit cancel' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
git mv text text2 &&
git commit -m text2 &&
git config git-p4.detectRenames true &&
git diff-tree -r -M HEAD | grep text2 | grep R100 &&
echo n | test_expect_code 1 git p4 submit
) &&
(
cd "$cli" &&
test_path_is_missing text2 &&
p4 fstat -T action text2 2>&1 | grep "no such file"
test_path_is_file text &&
! p4 fstat -T action text
)
'
test_expect_success 'cleanup chmod after submit cancel' '
test_when_finished cleanup_git &&
git p4 clone --dest="$git" //depot &&
(
cd "$git" &&
chmod u+x text &&
chmod u-x text+x &&
git add text text+x &&
git commit -m "chmod texts" &&
echo n | test_expect_code 1 git p4 submit
) &&
(
cd "$cli" &&
test_path_is_file text &&
! p4 fstat -T action text &&
stat --format=%A text | egrep ^-r-- &&
test_path_is_file text+x &&
! p4 fstat -T action text+x &&
stat --format=%A text+x | egrep ^-r-x
)
'
test_expect_success 'kill p4d' '
kill_p4d
'
test_done