def applyCommit()

in git-p4.py [0:0]


    def applyCommit(self, 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)

        diff = read_pipe_lines(
            ["git", "diff-tree", "-r"] + self.diffOpts + ["{}^".format(id), id])
        filesToAdd = set()
        filesToChangeType = set()
        filesToDelete = set()
        editedFiles = set()
        pureRenameCopy = set()
        symlinks = set()
        filesToChangeExecBit = {}
        all_files = list()

        for line in diff:
            diff = parseDiffTreeEntry(line)
            modifier = diff['status']
            path = diff['src']
            all_files.append(path)

            if modifier == "M":
                p4_edit(path)
                if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
                    filesToChangeExecBit[path] = diff['dst_mode']
                editedFiles.add(path)
            elif modifier == "A":
                filesToAdd.add(path)
                filesToChangeExecBit[path] = diff['dst_mode']
                if path in filesToDelete:
                    filesToDelete.remove(path)

                dst_mode = int(diff['dst_mode'], 8)
                if dst_mode == 0o120000:
                    symlinks.add(path)

            elif modifier == "D":
                filesToDelete.add(path)
                if path in filesToAdd:
                    filesToAdd.remove(path)
            elif modifier == "C":
                src, dest = diff['src'], diff['dst']
                all_files.append(dest)
                p4_integrate(src, dest)
                pureRenameCopy.add(dest)
                if diff['src_sha1'] != diff['dst_sha1']:
                    p4_edit(dest)
                    pureRenameCopy.discard(dest)
                if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
                    p4_edit(dest)
                    pureRenameCopy.discard(dest)
                    filesToChangeExecBit[dest] = diff['dst_mode']
                if self.isWindows:
                    # turn off read-only attribute
                    os.chmod(dest, stat.S_IWRITE)
                os.unlink(dest)
                editedFiles.add(dest)
            elif modifier == "R":
                src, dest = diff['src'], diff['dst']
                all_files.append(dest)
                if self.p4HasMoveCommand:
                    p4_edit(src)        # src must be open before move
                    p4_move(src, dest)  # opens for (move/delete, move/add)
                else:
                    p4_integrate(src, dest)
                    if diff['src_sha1'] != diff['dst_sha1']:
                        p4_edit(dest)
                    else:
                        pureRenameCopy.add(dest)
                if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
                    if not self.p4HasMoveCommand:
                        p4_edit(dest)   # with move: already open, writable
                    filesToChangeExecBit[dest] = diff['dst_mode']
                if not self.p4HasMoveCommand:
                    if self.isWindows:
                        os.chmod(dest, stat.S_IWRITE)
                    os.unlink(dest)
                    filesToDelete.add(src)
                editedFiles.add(dest)
            elif modifier == "T":
                filesToChangeType.add(path)
            else:
                die("unknown modifier %s for %s" % (modifier, path))

        diffcmd = "git diff-tree --full-index -p \"%s\"" % (id)
        patchcmd = diffcmd + " | git apply "
        tryPatchCmd = patchcmd + "--check -"
        applyPatchCmd = patchcmd + "--check --apply -"
        patch_succeeded = True

        if verbose:
            print("TryPatch: %s" % tryPatchCmd)

        if os.system(tryPatchCmd) != 0:
            fixed_rcs_keywords = False
            patch_succeeded = False
            print("Unfortunately applying the change failed!")

            # Patch failed, maybe it's just RCS keyword woes. Look through
            # the patch to see if that's possible.
            if gitConfigBool("git-p4.attemptRCSCleanup"):
                file = None
                kwfiles = {}
                for file in editedFiles | filesToDelete:
                    # did this file's delta contain RCS keywords?
                    regexp = p4_keywords_regexp_for_file(file)
                    if regexp:
                        # this file is a possibility...look for RCS keywords.
                        for line in read_pipe_lines(
                                ["git", "diff", "%s^..%s" % (id, id), file],
                                raw=True):
                            if regexp.search(line):
                                if verbose:
                                    print("got keyword match on %s in %s in %s" % (regexp.pattern, line, file))
                                kwfiles[file] = regexp
                                break

                for file, regexp in kwfiles.items():
                    if verbose:
                        print("zapping %s with %s" % (line, regexp.pattern))
                    # File is being deleted, so not open in p4.  Must
                    # disable the read-only bit on windows.
                    if self.isWindows and file not in editedFiles:
                        os.chmod(file, stat.S_IWRITE)
                    self.patchRCSKeywords(file, kwfiles[file])
                    fixed_rcs_keywords = True

            if fixed_rcs_keywords:
                print("Retrying the patch with RCS keywords cleaned up")
                if os.system(tryPatchCmd) == 0:
                    patch_succeeded = True
                    print("Patch succeesed this time with RCS keywords cleaned")

        if not patch_succeeded:
            for f in editedFiles:
                p4_revert(f)
            return False

        #
        # Apply the patch for real, and do add/delete/+x handling.
        #
        system(applyPatchCmd, shell=True)

        for f in filesToChangeType:
            p4_edit(f, "-t", "auto")
        for f in filesToAdd:
            p4_add(f)
        for f in filesToDelete:
            p4_revert(f)
            p4_delete(f)

        # Set/clear executable bits
        for f in filesToChangeExecBit.keys():
            mode = filesToChangeExecBit[f]
            setP4ExecBit(f, mode)

        update_shelve = 0
        if len(self.update_shelve) > 0:
            update_shelve = self.update_shelve.pop(0)
            p4_reopen_in_change(update_shelve, all_files)

        #
        # 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)

        template = self.prepareSubmitTemplate(update_shelve)
        submitTemplate = self.prepareLogMessage(template, logMessage, jobs)

        if self.preserveUser:
            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"
        if not self.prepare_p4_only:
            submitTemplate += separatorLine
            submitTemplate += self.get_diff_description(editedFiles, filesToAdd, symlinks)

        handle, fileName = tempfile.mkstemp()
        tmpFile = os.fdopen(handle, "w+b")
        if self.isWindows:
            submitTemplate = submitTemplate.replace("\n", "\r\n")
        tmpFile.write(encode_text_stream(submitTemplate))
        tmpFile.close()

        submitted = False

        try:
            # Allow the hook to edit the changelist text before presenting it
            # to the user.
            if not run_git_hook("p4-prepare-changelist", [fileName]):
                return False

            if self.prepare_p4_only:
                #
                # Leave the p4 tree prepared, and the submit template around
                # and let the user decide what to do next
                #
                submitted = True
                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("")
                sys.stdout.flush()
                return True

            if self.edit_template(fileName):
                if not self.no_verify:
                    if not run_git_hook("p4-changelist", [fileName]):
                        print("The p4-changelist hook failed.")
                        sys.stdout.flush()
                        return False

                # read the edited message and submit
                tmpFile = open(fileName, "rb")
                message = decode_text_stream(tmpFile.read())
                tmpFile.close()
                if self.isWindows:
                    message = message.replace("\r\n", "\n")
                if message.find(separatorLine) != -1:
                    submitTemplate = message[:message.index(separatorLine)]
                else:
                    submitTemplate = message

                if len(submitTemplate.strip()) == 0:
                    print("Changelist is empty, aborting this changelist.")
                    sys.stdout.flush()
                    return False

                if update_shelve:
                    p4_write_pipe(['shelve', '-r', '-i'], submitTemplate)
                elif self.shelve:
                    p4_write_pipe(['shelve', '-i'], submitTemplate)
                else:
                    p4_write_pipe(['submit', '-i'], submitTemplate)
                    # The rename/copy happened by applying a patch that created a
                    # new file.  This leaves it writable, which confuses p4.
                    for f in pureRenameCopy:
                        p4_sync(f, "-f")

                if self.preserveUser:
                    if p4User:
                        # Get last changelist number. Cannot easily get it from
                        # the submit command output as the output is
                        # unmarshalled.
                        changelist = self.lastP4Changelist()
                        self.modifyChangelistUser(changelist, p4User)

                submitted = True

                run_git_hook("p4-post-changelist")
        finally:
            # Revert changes if we skip this patch
            if not submitted or self.shelve:
                if self.shelve:
                    print("Reverting shelved files.")
                else:
                    print("Submission cancelled, undoing p4 changes.")
                sys.stdout.flush()
                for f in editedFiles | filesToDelete:
                    p4_revert(f)
                for f in filesToAdd:
                    p4_revert(f)
                    os.remove(f)

            if not self.prepare_p4_only:
                os.remove(fileName)
        return submitted