{"thread":{"id":"30134","subject":"[PATCHv1] git-p4: label import, tag export","startedAt":"2012-04-03T07:38:33Z","lastAt":"2012-04-05T06:54:43Z","messageCount":5,"participants":["Luke Diamand","Vitor Antunes"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"188390","messageId":"1333438715-14902-1-git-send-email-luke@diamand.org","threadId":"30134","inReplyTo":null,"subject":"[PATCHv1] git-p4: label import, tag export","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2012-04-03T07:38:33Z","receivedAt":"2012-04-03T07:38:33Z","isPatch":false,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"This is an updated version of my earlier RFC/patch for importing\np4 labels into git, incorporating comments from Pete Wyckoff,\nand git export support.\n\nIt operates by getting the sets of git tags and p4 labels, finding\nout what is missing, and creating tags/labels as necessary. This\nis in contrast to the existing detect-labels code which looks\nfor p4 labels associated with the changelist being imported and\nwhich therefore misses tags on older changelists.\n\nGit tag export is done during the sync phase because that's when\nthe commit/changelist mapping is first known.\n\nThere is also a small fix to t9800 for a problem I found while\ntesting this.\n\nLuke Diamand (2):\n  git-p4: fix t9800 editor check\n  git-p4: import/export of labels to/from p4\n\n Documentation/git-p4.txt       |   39 ++++++-\n contrib/fast-import/git-p4     |  249 ++++++++++++++++++++++++++++++++++------\n t/t9800-git-p4-basic.sh        |    4 +-\n t/t9811-git-p4-label-import.sh |  145 +++++++++++++++++++++++\n 4 files changed, 400 insertions(+), 37 deletions(-)\n create mode 100755 t/t9811-git-p4-label-import.sh\n\n-- \n1.7.10.rc0.158.gd9e55\n"},{"id":"188391","messageId":"1333438715-14902-2-git-send-email-luke@diamand.org","threadId":"30134","inReplyTo":"1333438715-14902-1-git-send-email-luke@diamand.org","subject":"[PATCHv1 1/2] git-p4: fix t9800 editor check","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2012-04-03T07:38:34Z","receivedAt":"2012-04-03T07:38:34Z","isPatch":false,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"Use the skipEdit flag rather than the skipEditCheck flag as\nthe latter only worked if P4EDITOR happened to be unset.\n\nSigned-off-by: Luke Diamand <luke@diamand.org>\n---\n t/t9800-git-p4-basic.sh |    4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh\nindex 486c8ee..40f0b5c 100755\n--- a/t/t9800-git-p4-basic.sh\n+++ b/t/t9800-git-p4-basic.sh\n@@ -335,7 +335,7 @@ test_expect_success 'detect renames' '\n \ttest_when_finished cleanup_git &&\n \t(\n \t\tcd \"$git\" &&\n-\t\tgit config git-p4.skipSubmitEditCheck true &&\n+\t\tgit config git-p4.skipSubmitEdit true &&\n \n \t\tgit mv file1 file4 &&\n \t\tgit commit -a -m \"Rename file1 to file4\" &&\n@@ -394,7 +394,7 @@ test_expect_success 'detect copies' '\n \ttest_when_finished cleanup_git &&\n \t(\n \t\tcd \"$git\" &&\n-\t\tgit config git-p4.skipSubmitEditCheck true &&\n+\t\tgit config git-p4.skipSubmitEdit true &&\n \n \t\tcp file2 file8 &&\n \t\tgit add file8 &&\n-- \n1.7.10.rc0.158.gd9e55\n"},{"id":"188392","messageId":"1333438715-14902-3-git-send-email-luke@diamand.org","threadId":"30134","inReplyTo":"1333438715-14902-1-git-send-email-luke@diamand.org","subject":"[PATCHv1 2/2] git-p4: import/export of labels to/from p4","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2012-04-03T07:38:35Z","receivedAt":"2012-04-03T07:38:35Z","isPatch":false,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"The existing label import code looks at each commit being\nimported, and then checks for labels at that commit. This\ndoesn't work in the real world though because it will drop\nlabels applied on changelists that have already been imported,\na common pattern.\n\nThis change adds a new --import-labels option. With this option,\nat the end of the sync, git-p4 gets sets of labels in p4 and git,\nand then creates a git tag for each missing p4 label.\n\nThis means that tags created on older changelists are\nstill imported.\n\nTags that could not be imported are added to an ignore\nlist.\n\nThe same sets of git and p4 tags and labels can also be used to\nderive a list of git tags to export to p4. This is enabled with\n--export-tags.\n\nSigned-off-by: Luke Diamand <luke@diamand.org>\n---\n Documentation/git-p4.txt       |   39 ++++++-\n contrib/fast-import/git-p4     |  249 ++++++++++++++++++++++++++++++++++------\n t/t9811-git-p4-label-import.sh |  145 +++++++++++++++++++++++\n 3 files changed, 398 insertions(+), 35 deletions(-)\n create mode 100755 t/t9811-git-p4-label-import.sh\n\ndiff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt\nindex b7c7929..04fd0da 100644\n--- a/Documentation/git-p4.txt\n+++ b/Documentation/git-p4.txt\n@@ -205,7 +205,16 @@ git repository:\n \n --detect-labels::\n \tQuery p4 for labels associated with the depot paths, and add\n-\tthem as tags in git.\n+\tthem as tags in git. Limited usefulness as only imports labels\n+\tassociated with new changelists. Deprecated.\n+\n+--import-labels::\n+\tImport labels from p4 into git.\n+\n+--export-tags:\n+\tExport tags from git into p4. It only makes sense to do this\n+\tin the sync phase, as that is when the newly updated git\n+\tcommits, with their p4 changelist, are first available.\n \n --import-local::\n \tBy default, p4 branches are stored in 'refs/remotes/p4/',\n@@ -270,6 +279,15 @@ These options can be used to modify 'git p4 submit' behavior.\n \tRe-author p4 changes before submitting to p4.  This option\n \trequires p4 admin privileges.\n \n+Rebase options\n+~~~~~~~~~~~~~~\n+These options can be used to modify 'git p4 rebase' behavior.\n+\n+--import-labels::\n+\tImport p4 labels\n+\n+--export-tags::\n+\tExport git tags to p4\n \n DEPOT PATH SYNTAX\n -----------------\n@@ -434,6 +452,25 @@ git-p4.branchList::\n \tenabled.  Each entry should be a pair of branch names separated\n \tby a colon (:).  This example declares that both branchA and\n \tbranchB were created from main:\n+\n+git-p4.ignoredP4Labels::\n+\tList of p4 labels to ignore. This is built automatically as\n+\tunimportable labels are discovered.\n+\n+git-p4.importLabels::\n+\tImport p4 labels into git, as per --import-labels.\n+\n+git-p4.exportTags::\n+\tExport git tags to p4, as per --export-tags.\n+\n+git-p4.validLabelRegexp::\n+\tOnly p4 labels matching this regular expression will be imported. The\n+\tdefault value is '[A-Z0-9_\\-.]+$'.\n+\n+git-p4.validTagRegexp::\n+\tOnly git tags matching this regular expression will be exported. Default\n+\tas for validLabelRegexp.\n+\n -------------\n git config       git-p4.branchList main:branchA\n git config --add git-p4.branchList main:branchB\ndiff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4\nindex c5362c4..433bac9 100755\n--- a/contrib/fast-import/git-p4\n+++ b/contrib/fast-import/git-p4\n@@ -253,6 +253,24 @@ def getP4OpenedType(file):\n     else:\n         die(\"Could not determine file type for %s (result: '%s')\" % (file, result))\n \n+# Return the set of all p4 labels\n+def getP4Labels(depotPaths):\n+    labels = set()\n+\n+    for l in p4CmdList([\"labels\"] + [\"%s...\" % p for p in depotPaths]):\n+        label = l['label']\n+        labels.add(label)\n+        \n+    return labels\n+\n+# Return the set of all git tags\n+def getGitTags():\n+    gitTags = set()\n+    for line in read_pipe_lines([\"git\", \"tag\"]):\n+        tag = line.strip()\n+        gitTags.add(tag)\n+    return gitTags\n+\n def diffTreePattern():\n     # This is a simple generator for the diff tree regex pattern. This could be\n     # a class variable if this and parseDiffTreeEntry were a part of a class.\n@@ -1544,6 +1562,8 @@ class P4Sync(Command, P4UserMap):\n                 optparse.make_option(\"--changesfile\", dest=\"changesFile\"),\n                 optparse.make_option(\"--silent\", dest=\"silent\", action=\"store_true\"),\n                 optparse.make_option(\"--detect-labels\", dest=\"detectLabels\", action=\"store_true\"),\n+                optparse.make_option(\"--import-labels\", dest=\"importLabels\", action=\"store_true\"),\n+                optparse.make_option(\"--export-tags\", dest=\"exportTags\", action=\"store_true\"),\n                 optparse.make_option(\"--verbose\", dest=\"verbose\", action=\"store_true\"),\n                 optparse.make_option(\"--import-local\", dest=\"importIntoRemotes\", action=\"store_false\",\n                                      help=\"Import into refs/heads/ , not refs/remotes\"),\n@@ -1568,6 +1588,8 @@ class P4Sync(Command, P4UserMap):\n         self.branch = \"\"\n         self.detectBranches = False\n         self.detectLabels = False\n+        self.importLabels = False\n+        self.exportTags = False\n         self.changesFile = \"\"\n         self.syncWithOrigin = True\n         self.verbose = False\n@@ -1583,6 +1605,7 @@ class P4Sync(Command, P4UserMap):\n         self.clientSpecDirs = None\n         self.tempBranches = []\n         self.tempBranchLocation = \"git-p4-tmp\"\n+        self.defaultLabelRegexp = r'[A-Z0-9_\\-.]+$'\n \n         if gitConfig(\"git-p4.syncFromOrigin\") == \"false\":\n             self.syncWithOrigin = False\n@@ -1829,6 +1852,33 @@ class P4Sync(Command, P4UserMap):\n         else:\n             return \"%s <a@b>\" % userid\n \n+    # Stream a p4 tag\n+    def streamTag(self, gitStream, labelName, labelDetails, commit, epoch):\n+        if verbose:\n+            print \"writing tag %s for commit %s\" % (labelName, commit)\n+        gitStream.write(\"tag %s\\n\" % labelName)\n+        gitStream.write(\"from %s\\n\" % commit)\n+\n+        if labelDetails.has_key('Owner'):\n+            owner = labelDetails[\"Owner\"]\n+        else:\n+            owner = None\n+\n+        # Try to use the owner of the p4 label, or failing that,\n+        # the current p4 user id.\n+        if owner:\n+            email = self.make_email(owner)\n+        else:\n+            email = self.make_email(self.p4UserId())\n+        tagger = \"%s %s %s\" % (email, epoch, self.tz)\n+\n+        gitStream.write(\"tagger %s\\n\" % tagger)\n+\n+        description = labelDetails[\"Description\"]\n+        gitStream.write(\"data %d\\n\" % len(description))\n+        gitStream.write(description)\n+        gitStream.write(\"\\n\")\n+\n     def commit(self, details, files, branch, branchPrefixes, parent = \"\"):\n         epoch = details[\"time\"]\n         author = details[\"user\"]\n@@ -1893,25 +1943,7 @@ class P4Sync(Command, P4UserMap):\n                     cleanedFiles[info[\"depotFile\"]] = info[\"rev\"]\n \n                 if cleanedFiles == labelRevisions:\n-                    self.gitStream.write(\"tag tag_%s\\n\" % labelDetails[\"label\"])\n-                    self.gitStream.write(\"from %s\\n\" % branch)\n-\n-                    owner = labelDetails[\"Owner\"]\n-\n-                    # Try to use the owner of the p4 label, or failing that,\n-                    # the current p4 user id.\n-                    if owner:\n-                        email = self.make_email(owner)\n-                    else:\n-                        email = self.make_email(self.p4UserId())\n-                    tagger = \"%s %s %s\" % (email, epoch, self.tz)\n-\n-                    self.gitStream.write(\"tagger %s\\n\" % tagger)\n-\n-                    description = labelDetails[\"Description\"]\n-                    self.gitStream.write(\"data %d\\n\" % len(description))\n-                    self.gitStream.write(description)\n-                    self.gitStream.write(\"\\n\")\n+                    self.streamTag(self.gitStream, 'tag_%s' % labelDetails['label'], labelDetails, branch, epoch)\n \n                 else:\n                     if not self.silent:\n@@ -1923,6 +1955,7 @@ class P4Sync(Command, P4UserMap):\n                     print (\"Tag %s does not match with change %s: file count is different.\"\n                            % (labelDetails[\"label\"], change))\n \n+    # Build a dictionary of changelists and labels, for \"detect-labels\" option.\n     def getLabels(self):\n         self.labels = {}\n \n@@ -1949,6 +1982,130 @@ class P4Sync(Command, P4UserMap):\n         if self.verbose:\n             print \"Label changes: %s\" % self.labels.keys()\n \n+    # Export git tags as p4 labels. Create a p4 label and then tag\n+    # with that.\n+    def exportGitTags(self, gitTags):\n+        validTagRegexp = gitConfig(\"git-p4.validTagRegexp\")\n+        if len(validTagRegexp) == 0:\n+            validTagRegexp = self.defaultLabelRegexp\n+        m = re.compile(validTagRegexp)\n+        commit_re = re.compile(r'\\s*\\[git-p4:.*change = (\\d+)\\s*\\]')\n+\n+        for name in gitTags:\n+\n+            if not m.match(name):\n+                if verbose:\n+                    print \"tag %s does not match regexp %s\" % (name, validTagRegexp)\n+                continue\n+\n+            # Get the p4 commit this corresponds to\n+            changelist = None\n+            for l in read_pipe_lines([\"git\", \"log\", \"--max-count=1\", name]):\n+                match = commit_re.match(l)\n+                if match:\n+                    changelist = match.group(1)\n+\n+            if not changelist:\n+                # a tag pointing to something not sent to p4; ignore\n+                if verbose:\n+                    print \"git tag %s does not give a p4 commit\" % name\n+                continue\n+\n+            # Get the tag details.\n+            inHeader = True\n+            isAnnotated = False\n+            body = []\n+            for l in read_pipe_lines([\"git\", \"cat-file\", \"-p\", name]): \n+                if inHeader:\n+                    if re.match(r'tag\\s+', l):\n+                        isAnnotated = True\n+                elif re.match(r'^\\s*$', l):\n+                        inHeader = False\n+                        continue\n+                else:\n+                    body.append(l)\n+\n+            if not isAnnotated:\n+                body = [\"lightweight tag imported by git p4\\n\"]\n+\n+            # Create the label\n+            labelTemplate  = \"Label: %s\\n\" % name\n+            labelTemplate += \"Description:\\n\"\n+            for b in body:\n+                labelTemplate += \"\\t\" + b\n+            labelTemplate += \"View:\\n\"\n+            for p in self.depotPaths:\n+                labelTemplate += \"\\t%s...\\n\" % p\n+\n+            p4_write_pipe([\"label\", \"-i\"], labelTemplate)\n+\n+            # Use the label\n+            p4_system([\"tag\", \"-l\", name] +\n+                      [\"%s...@%s\" % (p, changelist) for p in self.depotPaths])\n+\n+            if verbose:\n+                print \"created p4 label for tag %s\" % name\n+            \n+    # Import p4 labels as git tags. A direct mapping does not\n+    # exist, so assume that if all the files are at the same revision\n+    # then we can use that, or it's something more complicated we should\n+    # just ignore.\n+    def importP4Labels(self, stream, p4Labels):\n+        ignoredP4Labels = gitConfigList(\"git-p4.ignoredP4Labels\")\n+        validLabelRegexp = gitConfig(\"git-p4.validLabelRegexp\")\n+        if len(validLabelRegexp) == 0:\n+            validLabelRegexp = self.defaultLabelRegexp\n+        m = re.compile(validLabelRegexp)\n+\n+        for name in p4Labels:\n+            commitFound = False\n+\n+            if not m.match(name):\n+                if verbose:\n+                    print \"label %s does not match regexp %s\" % (name,validLabelRegexp)\n+                continue\n+\n+            if name in ignoredP4Labels:\n+                continue\n+\n+            labelDetails = p4CmdList(['label', \"-o\", name])[0]\n+\n+            # get the most recent changelist for each file in this label\n+            change = p4Cmd([\"changes\", \"-m\", \"1\"] + [\"%s...@%s\" % (p, name)\n+                                for p in self.depotPaths])\n+\n+            if change.has_key('change'):\n+                # find the corresponding git commit; take the oldest commit\n+                changelist = int(change['change'])\n+                gitCommit = read_pipe([\"git\", \"rev-list\", \"--max-count=1\",\n+                     \"--reverse\", \":/\\[git-p4:.*change = %d\\]\" % changelist])\n+                if len(gitCommit) == 0:\n+                    print \"could not find git commit for changelist %d\" % changelist\n+                else:\n+                    gitCommit = gitCommit.strip()\n+                    commitFound = True\n+                    # Convert from p4 time format\n+                    try:\n+                        tmwhen = time.strptime(labelDetails['Update'], \"%Y/%m/%d %H:%M:%S\")\n+                    except ValueError:\n+                        print \"Could not convert label time %s\" % labelDetail['Update']\n+                        tmwhen = 1\n+\n+                    when = int(time.mktime(tmwhen))\n+                    self.streamTag(stream, name, labelDetails, gitCommit, when)\n+                    if verbose:\n+                        print \"p4 label %s mapped to git commit %s\" % (name, gitCommit)\n+            else:\n+                if verbose:\n+                    print \"Label %s has no changelists - possibly deleted?\" % name\n+\n+            if not commitFound:\n+                # We can't import this label; don't try again as it will get very\n+                # expensive repeatedly fetching all the files for labels that will\n+                # never be imported. If the label is moved in the future, the\n+                # ignore will need to be removed manually.\n+                system([\"git\", \"config\", \"--add\", \"git-p4.ignoredP4Labels\", name])\n+\n     def guessProjectName(self):\n         for p in self.depotPaths:\n             if p.endswith(\"/\"):\n@@ -2425,7 +2582,6 @@ class P4Sync(Command, P4UserMap):\n \n         self.depotPaths = newPaths\n \n-\n         self.loadUserMapFromCache()\n         self.labels = {}\n         if self.detectLabels:\n@@ -2489,22 +2645,39 @@ class P4Sync(Command, P4UserMap):\n             if len(changes) == 0:\n                 if not self.silent:\n                     print \"No changes to import!\"\n-                return True\n+            else:\n+                if not self.silent and not self.detectBranches:\n+                    print \"Import destination: %s\" % self.branch\n \n-            if not self.silent and not self.detectBranches:\n-                print \"Import destination: %s\" % self.branch\n+                self.updatedBranches = set()\n \n-            self.updatedBranches = set()\n+                self.importChanges(changes)\n \n-            self.importChanges(changes)\n+                if not self.silent:\n+                    print \"\"\n+                    if len(self.updatedBranches) > 0:\n+                        sys.stdout.write(\"Updated branches: \")\n+                        for b in self.updatedBranches:\n+                            sys.stdout.write(\"%s \" % b)\n+                        sys.stdout.write(\"\\n\")\n \n-            if not self.silent:\n-                print \"\"\n-                if len(self.updatedBranches) > 0:\n-                    sys.stdout.write(\"Updated branches: \")\n-                    for b in self.updatedBranches:\n-                        sys.stdout.write(\"%s \" % b)\n-                    sys.stdout.write(\"\\n\")\n+        if gitConfig(\"git-p4.importLabels\", \"--bool\") == \"true\":\n+            self.importLabels = true\n+\n+        if gitConfig(\"git-p4.exportTags\", \"--bool\") == \"true\":\n+            self.exportTags = true\n+\n+        if self.importLabels or self.exportTags:\n+            p4Labels = getP4Labels(self.depotPaths)\n+            gitTags = getGitTags()\n+\n+            if self.importLabels:\n+                missingP4Labels = p4Labels - gitTags\n+                self.importP4Labels(self.gitStream, missingP4Labels)\n+\n+            if self.exportTags:\n+                missingGitTags = gitTags - p4Labels\n+                self.exportGitTags(missingGitTags)\n \n         self.gitStream.close()\n         if importProcess.wait() != 0:\n@@ -2523,13 +2696,21 @@ class P4Sync(Command, P4UserMap):\n class P4Rebase(Command):\n     def __init__(self):\n         Command.__init__(self)\n-        self.options = [ ]\n+        self.options = [\n+                optparse.make_option(\"--import-labels\", dest=\"importLabels\", action=\"store_true\"),\n+                optparse.make_option(\"--export-tags\", dest=\"exportTags\", action=\"store_true\"),\n+                optparse.make_option(\"--verbose\", dest=\"verbose\", action=\"store_true\"),\n+        ]\n+        self.verbose = False\n+        self.importLabels = False\n+        self.exportTags = False\n         self.description = (\"Fetches the latest revision from perforce and \"\n                             + \"rebases the current work (branch) against it\")\n-        self.verbose = False\n \n     def run(self, args):\n         sync = P4Sync()\n+        sync.importLabels = self.importLabels\n+        sync.exportTags = self.exportTags\n         sync.run([])\n \n         return self.rebase()\ndiff --git a/t/t9811-git-p4-label-import.sh b/t/t9811-git-p4-label-import.sh\nnew file mode 100755\nindex 0000000..860d844\n--- /dev/null\n+++ b/t/t9811-git-p4-label-import.sh\n@@ -0,0 +1,145 @@\n+#!/bin/sh\n+\n+test_description='git-p4 p4 label tests'\n+\n+. ./lib-git-p4.sh\n+\n+test_expect_success 'start p4d' '\n+\tstart_p4d\n+'\n+\n+# Basic p4 label import tests.\n+#\n+test_expect_success 'basic p4 labels' '\n+\ttest_when_finished cleanup_git &&\n+\t(\n+\t\tcd \"$cli\" &&\n+\t\tmkdir -p main &&\n+\n+\t\techo f1 >main/f1 &&\n+\t\tp4 add main/f1 &&\n+\t\tp4 submit -d \"main/f1\" &&\n+\n+\t\techo f2 >main/f2 &&\n+\t\tp4 add main/f2 &&\n+\t\tp4 submit -d \"main/f2\" &&\n+\n+\t\techo f3 >main/file_with_\\$metachar &&\n+\t\tp4 add main/file_with_\\$metachar &&\n+\t\tp4 submit -d \"file with metachar\" &&\n+\n+\t\tp4 tag -l TAG_F1_ONLY main/f1 &&\n+\t\tp4 tag -l TAG_WITH\\$_SHELL_CHAR main/... &&\n+\t\tp4 tag -l this_tag_will_be_skipped main/... &&\n+\n+\t\techo f4 >main/f4 &&\n+\t\tp4 add main/f4 &&\n+\t\tp4 submit -d \"main/f4\" &&\n+\n+\t\tp4 label -i <<-EOF &&\n+\t\tLabel: TAG_LONG_LABEL\n+\t\tDescription:\n+\t\t   A Label first line\n+\t\t   A Label second line\n+\t\tView:\t//depot/...\n+\t\tEOF\n+\n+\t\tp4 tag -l TAG_LONG_LABEL ... &&\n+\n+\t\tp4 labels ... &&\n+\t\t\n+\t\t\"$GITP4\" clone --dest=\"$git\" //depot@all &&\n+\t\tcd \"$git\" &&\n+\t\tgit config git-p4.validLabelRegexp \".*TAG.*\" &&\n+\t\t\"$GITP4\" sync --import-labels --verbose &&\n+\n+\t\tgit tag &&\n+\t\tgit tag >taglist &&\n+\t\ttest_line_count = 3 taglist &&\n+\n+\t\tcd main &&\n+\t\tgit checkout TAG_F1_ONLY &&\n+\t\t! test -f f2 &&\n+\t\tgit checkout TAG_WITH\\$_SHELL_CHAR &&\n+\t\ttest -f f1 && test -f f2 && test -f file_with_\\$metachar &&\n+\n+\t\tgit show TAG_LONG_LABEL | grep -q \"A Label second line\"\n+\t)\n+'\n+# Test some label corner cases:\n+#\n+# - two tags on the same file; both should be available\n+# - a tag that is only on one file; this kind of tag\n+#   cannot be imported (at least not easily).\n+\n+test_expect_success 'two labels on the same changelist' '\n+\ttest_when_finished cleanup_git &&\n+\t(\n+\t\tcd \"$cli\" &&\n+\t\tmkdir -p main &&\n+\n+\t\tp4 edit main/f1 main/f2 &&\n+\t\techo \"hello world\" >main/f1 &&\n+\t\techo \"not in the tag\" >main/f2 &&\n+\t\tp4 submit -d \"main/f[12]: testing two labels\" &&\n+\n+\t\tp4 tag -l TAG_F1_1 main/... &&\n+\t\tp4 tag -l TAG_F1_2 main/... &&\n+\n+\t\tp4 labels ... &&\n+\n+\t\t\"$GITP4\" clone --dest=\"$git\" //depot@all &&\n+\t\tcd \"$git\" &&\n+\t\t\"$GITP4\" sync --import-labels &&\n+\n+\t\tgit tag | grep TAG_F1 &&\n+\t\tgit tag | grep -q TAG_F1_1 &&\n+\t\tgit tag | grep -q TAG_F1_2 &&\n+\n+\t\tcd main &&\n+\n+\t\tgit checkout TAG_F1_1 &&\n+\t\tls &&\n+\t\ttest -f f1 &&\n+\n+\t\tgit checkout TAG_F1_2 &&\n+\t\tls &&\n+\t\ttest -f f1\n+\t)\n+'\n+\n+# Export some git tags to p4\n+test_expect_success 'export git tags to p4' '\n+\ttest_when_finished cleanup_git &&\n+\t\"$GITP4\" clone --dest=\"$git\" //depot@all &&\n+\t(\t\n+\t\tcd \"$git\" &&\n+\t\tgit tag -m \"A tag created in git\" GIT_TAG_1 &&\n+\t\techo \"hello world\" >main/f10 &&\n+\t\tgit add main/f10 &&\n+\t\tgit commit -m \"Adding file for export test\" &&\n+\t\tgit config git-p4.skipSubmitEdit true &&\n+\t\t\"$GITP4\" submit &&\n+\t\tgit tag -m \"Another git tag\" GIT_TAG_2 &&\n+\t\tgit tag LIGHTWEIGHT_TAG &&\n+\t\t\"$GITP4\" sync --import-labels --export-tags --verbose\n+\t) &&\n+\t(\n+\t \tcd \"$cli\" &&\n+\t\tp4 sync ... &&\n+\t\tp4 labels ... | grep GIT_TAG_1 &&\n+\t\tp4 labels ... | grep GIT_TAG_2 &&\n+\t\tp4 labels ... | grep LIGHTWEIGHT_TAG &&\n+\t\tp4 label -o GIT_TAG_1 | grep \"tag created in git\" &&\n+\t\tp4 sync ...@GIT_TAG_1 &&\n+\t\t! test -f main/f10\n+\t\tp4 sync ...@GIT_TAG_2 &&\n+\t\ttest -f main/f10\n+\t)\n+'\n+\n+test_expect_success 'kill p4d' '\n+\tkill_p4d\n+'\n+\n+test_done\n-- \n1.7.10.rc0.158.gd9e55\n"},{"id":"188448","messageId":"20120403235247.02c85147@fenix.utopia.dhis.org","threadId":"30134","inReplyTo":"1333438715-14902-3-git-send-email-luke@diamand.org","subject":"Re: [PATCHv1 2/2] git-p4: import/export of labels to/from p4","fromName":"Vitor Antunes","fromEmail":"vitor.hda@gmail.com","sentAt":"2012-04-03T22:52:47Z","receivedAt":"2012-04-03T22:52:47Z","isPatch":false,"sender":{"key":"vitor.hda@gmail.com","avatar":"https://avatars.githubusercontent.com/u/606876?v=4"},"body":"On Tue,  3 Apr 2012 08:38:35 +0100\nLuke Diamand <luke@diamand.org> wrote:\n\n> The existing label import code looks at each commit being\n> imported, and then checks for labels at that commit. This\n> doesn't work in the real world though because it will drop\n> labels applied on changelists that have already been imported,\n> a common pattern.\n> \n> This change adds a new --import-labels option. With this option,\n> at the end of the sync, git-p4 gets sets of labels in p4 and git,\n> and then creates a git tag for each missing p4 label.\n> \n> This means that tags created on older changelists are\n> still imported.\n> \n> Tags that could not be imported are added to an ignore\n> list.\n> \n> The same sets of git and p4 tags and labels can also be used to\n> derive a list of git tags to export to p4. This is enabled with\n> --export-tags.\n> \n> Signed-off-by: Luke Diamand <luke@diamand.org>\n> ---\n>  Documentation/git-p4.txt       |   39 ++++++-\n>  contrib/fast-import/git-p4     |  249\n> ++++++++++++++++++++++++++++++++++------ t/t9811-git-p4-label-import.sh\n> |  145 +++++++++++++++++++++++ 3 files changed, 398 insertions(+), 35\n> deletions(-) create mode 100755 t/t9811-git-p4-label-import.sh\n> \n\nWould it be possible to only export git tags during commit?\n\nI don't think it is intuitive to make changes in P4 during sync operation.\nAnd because it is possible to configure git-p4 to always export tags it will\nbe easy to forget that while sync'ing we are also updating P4.\n\nI still did not test the patch in my branch environment, so I may have more\nupdates later. But for now, everything else seems ok by me.\n\nVitor\n"},{"id":"188552","messageId":"4F7D41B3.7010202@diamand.org","threadId":"30134","inReplyTo":"20120403235247.02c85147@fenix.utopia.dhis.org","subject":"Re: [PATCHv1 2/2] git-p4: import/export of labels to/from p4","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2012-04-05T06:54:43Z","receivedAt":"2012-04-05T06:54:43Z","isPatch":false,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"On 03/04/12 23:52, Vitor Antunes wrote:\n> On Tue,  3 Apr 2012 08:38:35 +0100\n> Luke Diamand<luke@diamand.org>  wrote:\n>\n>> The existing label import code looks at each commit being\n>> imported, and then checks for labels at that commit. This\n>> doesn't work in the real world though because it will drop\n>> labels applied on changelists that have already been imported,\n>> a common pattern.\n>>\n>> This change adds a new --import-labels option. With this option,\n>> at the end of the sync, git-p4 gets sets of labels in p4 and git,\n>> and then creates a git tag for each missing p4 label.\n>>\n\n<snip>\n\n>>\n>\n> Would it be possible to only export git tags during commit?\n>\n> I don't think it is intuitive to make changes in P4 during sync operation.\n> And because it is possible to configure git-p4 to always export tags it will\n> be easy to forget that while sync'ing we are also updating P4.\n\nCommit isn't a great time to do it because you don't know the p4 \nchangelist number for your git commits.\n\ne.g.\n\ngit commit -m 'Some change'\ngit tag -a MYTAG -m 'whatever'\ngit-p4 submit [--export-tags]\n\n======= the tag must be ignored here ========\n======= as you don't know the p4 cl  ========\n\ngit-p4 sync --export-tags\n======= *Now* you know the p4 cl     ========\n\nSo it either has to be part of sync/rebase, or we add a new command, \ne.g. git-p4 export-tags (and presumably git-p4 import-tags). But that \nseems awkward as well.\n\n\n>\n> I still did not test the patch in my branch environment, so I may have more\n> updates later. But for now, everything else seems ok by me.\n>\n\nThanks,\nLuke\n"}]}