Thread (1 message) 1 message, 1 author, 2018-05-16

Re: [PATCH 1/1] git-p4: add unshelve command

From: Luke Diamand <hidden>
Date: 2018-05-16 20:48:56

On 13 May 2018 at 14:52, Merland Romain [off-list ref] wrote:
Hello Luke,

Very interseting
This is indeed an option we are waiting since the introduction of option --shelve for git p4 submit
What I like most in your approach is the preservation of link to p4/master inducing small changes of git-p4 existing functions already heavily tested.
Also I like the dedicated branch you create, it is cleaner and then we can cherry-pick in other git branches.
Thanks, I'd be interested to know how you get on with it!
We made some basic tries on our side, just adding an option --unshelve to P4Submit (for simplicity, but I like much more your P4Unshelve class)
and trying to use the diff of p4 to generate a patch when possible, then apply it in the current git branch on top of HEAD.
Here it is, hope it can help a bit.
Note it also uses p4 print -o for binary files.
I did try something like this earlier this year (if you look in the
archives you'll find it) but I found that it was getting quite
complicated trying to construct a sensible looking patch file from the
output of p4 describe. Better to let git's existing tools do that, as
they're going to be better than any half-baked attempt I might manage
in Python!

Thanks!
Luke


quoted hunk
diff --git a/git-p4.py b/git-p4.py
index f4a6f3b4c..b466b46e1 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -1353,6 +1353,8 @@ class P4Submit(Command, P4UserMap):
                                      metavar="CHANGELIST",
                                      help="update an existing shelved changelist, implies --shelve, "
                                            "repeat in-order for multiple shelved changelists"),
+                optparse.make_option("--unshelve", dest="unshelve",
+                                     help="unshelve speficied ChangeList into current BRANCH."),
                 optparse.make_option("--commit", dest="commit", metavar="COMMIT",
                                      help="submit only the specified commit(s), one commit or xxx..xxx"),
                 optparse.make_option("--disable-rebase", dest="disable_rebase", action="store_true",
@@ -1367,6 +1369,7 @@ class P4Submit(Command, P4UserMap):
         self.dry_run = False
         self.shelve = False
         self.update_shelve = list()
+        self.unshelve = ""
         self.commit = ""
         self.disable_rebase = False
         self.prepare_p4_only = False
@@ -2083,6 +2086,66 @@ class P4Submit(Command, P4UserMap):
         if self.clientPath == "":
             die("Error: Cannot locate perforce checkout of %s in client view" % self.depotPath)

+        # special case of unshelving
+        # todo: put this code in a class like P4Sync or P4Rebase
+        if self.unshelve != "":
+            git_dir = os.getcwd() + '/'
+            print "Importing shelved CL %s into current git branch %s" % (self.unshelve, self.master)
+            description = p4_describe(self.unshelve)
+
+            # get changed files
+            files = p4CmdList(['files', "@=%s" % self.unshelve])
+            editedFiles = []
+            filesToAdd = []
+            filesToDelete = []
+            binaryFiles = []
+            something_to_commit = False
+            for f in files:
+                if not f["depotFile"].startswith(self.depotPath):
+                    print "WARNING: file %s not in this p4 depot - skipping" % f["depotFile"]
+                    continue
+
+                elif f["action"] == 'delete':
+                    filesToDelete.append(f)
+                    something_to_commit = True
+                elif f["action"] == 'add':
+                    filesToAdd.append(f)
+                    something_to_commit = True
+                elif f["type"] == 'binary':
+                    binaryFiles.append(f)
+                    something_to_commit = True
+                elif f["action"] == 'edit':
+                    editedFiles.append(f)
+                    something_to_commit = True
+
+                f["clientFile"] = f["depotFile"].replace(self.depotPath,self.clientPath)
+                f["gitFile"] = f["depotFile"].replace(self.depotPath,git_dir)
+
+            if not something_to_commit:
+                print "Nothing to commit. Exiting"
+                return True
+
+            # get the diff and copy to diff directory
+            for f in editedFiles:
+                p4diff = p4_read_pipe(['diff2', '-du', f["depotFile"]+'#'+f["rev"], f["depotFile"]+'@='+self.unshelve])
+                p4diff = "\n".join(p4diff.split("\n")[1:])
+                p4diff = '--- '+f["gitFile"]+'\n' + '+++ '+f["gitFile"]+'\n' + p4diff
+                write_pipe(['patch', '-d/', '-p0'], p4diff)
+                write_pipe(['git', 'add', '-f', f["gitFile"]], "")
+            for f in filesToAdd:
+                p4_write_pipe(['print', '-o', f["gitFile"], f["depotFile"]+'@='+self.unshelve], "")
+                write_pipe(['git', 'add', '-f', f["gitFile"]], "")
+            for f in filesToDelete:
+                os.remove(f["gitFile"])
+                write_pipe(['git', 'rm', f["gitFile"]], "")
+            for f in binaryFiles:
+                p4_write_pipe(['print', '-o', f["gitFile"], f["depotFile"]+'@='+self.unshelve], "")
+                write_pipe(['git', 'add', '-f', f["gitFile"]], "")
+
+            # finalize: commit in git
+            write_pipe(['git', 'commit', '-m', description["desc"]], "")
+            return True
+
         print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath)
         self.oldWorkingDirectory = os.getcwd()
Romain



Le samedi 12 mai 2018 à 23:24:48 UTC+2, Luke Diamand [off-list ref] a écrit :





This can be used to "unshelve" a shelved P4 commit into
a git commit.

For example:

  $ git p4 unshelve 12345

The resulting commit ends up in the branch:
  refs/remotes/p4/unshelved/12345

If that branch already exists, it is renamed - for example
the above branch would be saved as p4/unshelved/12345.1.

Caveat:

The unshelving is done against the current "p4/master" branch;
git-p4 uses "p4 print" to get the file contents at the requested
revision, and then fast-import creates a commit relative to p4/master.

Ideally what you would want is for fast-import to create the
commit based on the Perforce "revision" prior to the shelved commit,
but Perforce doesn't have such a concept - to do this, git-p4
would need to figure out the revisions of the individual files
before the shelved changelist, and then construct a temporary
git branch which matched this.

It's possible to do this, but doing so makes this change a lot more
complicated.

This limitation means that if you unshelve a change where some
of the changed files were not based on p4/master, you will get
an amalgam of the change you wanted, and these other changes.

The reference branch can be changed manually with the "--origin"
option.

The change adds a new Unshelve command class. This just runs the
existing P4Sync code tweaked to handle a shelved changelist.

Signed-off-by: Luke Diamand <redacted>
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help