git-p4: update multiple shelved change lists
--update-shelve can now be specified multiple times on the command-line, to update multiple shelved changelists in a single submit. This then means that a git patch series can be mirrored to a sequence of shelved changelists, and (relatively easily) kept in sync as changes are made in git. Note that Perforce does not really support overlapping shelved changelists where one change touches the files modified by another. Trying to do this will result in merge conflicts. Signed-off-by: Luke Diamand <luke@diamand.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Luke Diamand committed
Dec 21, 2017 at 11:06 UTC
8cf422dbf1b4bc14a970b7ff5c5fa555f61dd9ed
3 files changed
+47
-26
Documentation/git-p4.txt
+7
-1
@@ -157,6 +157,12 @@ The p4 changes will be created as the user invoking 'git p4 submit'. The
157
according to the author of the Git commit. This option requires admin
158
privileges in p4, which can be granted using 'p4 protect'.
159
160
+To shelve changes instead of submitting, use `--shelve` and `--update-shelve`:
161
+
162
+----
163
+$ git p4 submit --shelve
164
+$ git p4 submit --update-shelve 1234 --update-shelve 2345
165
+----
166
167
OPTIONS
168
-------
@@ -310,7 +316,7 @@ These options can be used to modify 'git p4 submit' behavior.
316
317
--update-shelve CHANGELIST::
318
Update an existing shelved changelist with this commit. Implies
313
- --shelve.
319
+ --shelve. Repeat for multiple shelved changelists.
320
321
--conflict=(ask|skip|quit)::
322
Conflicts can occur when applying a commit to p4. When this
git-p4.py
+26
-15
@@ -1178,6 +1178,12 @@ class Command:
1178
self.needsGit = True
1179
self.verbose = False
1180
1181
+ # This is required for the "append" cloneExclude action
1182
+ def ensure_value(self, attr, value):
1183
+ if not hasattr(self, attr) or getattr(self, attr) is None:
1184
+ setattr(self, attr, value)
1185
+ return getattr(self, attr)
1186
+
1187
class P4UserMap:
1188
def __init__(self):
1189
self.userMapFromPerforceServer = False
@@ -1343,9 +1349,10 @@ class P4Submit(Command, P4UserMap):
1349
optparse.make_option("--shelve", dest="shelve", action="store_true",
1350
help="Shelve instead of submit. Shelved files are reverted, "
1351
"restoring the workspace to the state before the shelve"),
1346
- optparse.make_option("--update-shelve", dest="update_shelve", action="store", type="int",
1352
+ optparse.make_option("--update-shelve", dest="update_shelve", action="append", type="int",
1353
metavar="CHANGELIST",
1348
- help="update an existing shelved changelist, implies --shelve")
1354
+ help="update an existing shelved changelist, implies --shelve, "
1355
+ "repeat in-order for multiple shelved changelists")
1356
]
1357
self.description = "Submit changes from git to the perforce depot."
1358
self.usage += " [name of git branch to submit into perforce depot]"
@@ -1354,7 +1361,7 @@ class P4Submit(Command, P4UserMap):
1361
self.preserveUser = gitConfigBool("git-p4.preserveUser")
1362
self.dry_run = False
1363
self.shelve = False
1357
- self.update_shelve = None
1364
+ self.update_shelve = list()
1365
self.prepare_p4_only = False
1366
self.conflict_behavior = None
1367
self.isWindows = (platform.system() == "Windows")
@@ -1809,9 +1816,10 @@ class P4Submit(Command, P4UserMap):
1816
mode = filesToChangeExecBit[f]
1817
setP4ExecBit(f, mode)
1818
1812
- if self.update_shelve:
1813
- print("all_files = %s" % str(all_files))
1814
- p4_reopen_in_change(self.update_shelve, all_files)
1819
+ update_shelve = 0
1820
+ if len(self.update_shelve) > 0:
1821
+ update_shelve = self.update_shelve.pop(0)
1822
+ p4_reopen_in_change(update_shelve, all_files)
1823
1824
#
1825
# Build p4 change description, starting with the contents
@@ -1821,7 +1829,7 @@ class P4Submit(Command, P4UserMap):
1829
logMessage = logMessage.strip()
1830
(logMessage, jobs) = self.separate_jobs_from_description(logMessage)
1831
1824
- template = self.prepareSubmitTemplate(self.update_shelve)
1832
+ template = self.prepareSubmitTemplate(update_shelve)
1833
submitTemplate = self.prepareLogMessage(template, logMessage, jobs)
1834
1835
if self.preserveUser:
@@ -1894,7 +1902,7 @@ class P4Submit(Command, P4UserMap):
1902
message = message.replace("\r\n", "\n")
1903
submitTemplate = message[:message.index(separatorLine)]
1904
1897
- if self.update_shelve:
1905
+ if update_shelve:
1906
p4_write_pipe(['shelve', '-r', '-i'], submitTemplate)
1907
elif self.shelve:
1908
p4_write_pipe(['shelve', '-i'], submitTemplate)
@@ -2012,6 +2020,10 @@ class P4Submit(Command, P4UserMap):
2020
else:
2021
return False
2022
2023
+ for i in self.update_shelve:
2024
+ if i <= 0:
2025
+ sys.exit("invalid changelist %d" % i)
2026
+
2027
if self.master:
2028
allowSubmit = gitConfig("git-p4.allowSubmit")
2029
if len(allowSubmit) > 0 and not self.master in allowSubmit.split(","):
@@ -2022,7 +2034,7 @@ class P4Submit(Command, P4UserMap):
2034
if len(self.origin) == 0:
2035
self.origin = upstream
2036
2025
- if self.update_shelve:
2037
+ if len(self.update_shelve) > 0:
2038
self.shelve = True
2039
2040
if self.preserveUser:
@@ -2134,6 +2146,11 @@ class P4Submit(Command, P4UserMap):
2146
if gitConfigBool("git-p4.detectCopiesHarder"):
2147
self.diffOpts += " --find-copies-harder"
2148
2149
+ num_shelves = len(self.update_shelve)
2150
+ if num_shelves > 0 and num_shelves != len(commits):
2151
+ sys.exit("number of commits (%d) must match number of shelved changelist (%d)" %
2152
+ (len(commits), num_shelves))
2153
+
2154
#
2155
# Apply the commits, one at a time. On failure, ask if should
2156
# continue to try the rest of the patches, or quit.
@@ -2404,12 +2421,6 @@ class P4Sync(Command, P4UserMap):
2421
if gitConfig("git-p4.syncFromOrigin") == "false":
2422
self.syncWithOrigin = False
2423
2407
- # This is required for the "append" cloneExclude action
2408
- def ensure_value(self, attr, value):
2409
- if not hasattr(self, attr) or getattr(self, attr) is None:
2410
- setattr(self, attr, value)
2411
- return getattr(self, attr)
2412
-
2424
# Force a checkpoint in fast-import and wait for it to finish
2425
def checkpoint(self):
2426
self.gitStream.write("checkpoint\n\n")
t/t9807-git-p4-submit.sh
+14
-10
@@ -460,7 +460,13 @@ test_expect_success 'submit --shelve' '
460
)
461
'
462
463
-# Update an existing shelved changelist
463
+make_shelved_cl() {
464
+ test_commit "$1" >/dev/null &&
465
+ git p4 submit --origin HEAD^ --shelve >/dev/null &&
466
+ p4 -G changes -s shelved -m 1 | marshal_dump change
467
+}
468
+
469
+# Update existing shelved changelists
470
471
test_expect_success 'submit --update-shelve' '
472
test_when_finished cleanup_git &&
@@ -470,21 +476,19 @@ test_expect_success 'submit --update-shelve' '
476
p4 revert ... &&
477
cd "$git" &&
478
git config git-p4.skipSubmitEdit true &&
473
- test_commit "test-update-shelved-change" &&
474
- git p4 submit --origin=HEAD^ --shelve &&
479
+ shelved_cl0=$(make_shelved_cl "shelved-change-0") &&
480
+ echo shelved_cl0=$shelved_cl0 &&
481
+ shelved_cl1=$(make_shelved_cl "shelved-change-1") &&
482
476
- shelf_cl=$(p4 -G changes -s shelved -m 1 |\
477
- marshal_dump change) &&
478
- test -n $shelf_cl &&
479
- echo "updating shelved change list $shelf_cl" &&
483
+ echo "updating shelved change lists $shelved_cl0 and $shelved_cl1" &&
484
485
echo "updated-line" >>shelf.t &&
486
echo added-file.t >added-file.t &&
487
git add shelf.t added-file.t &&
484
- git rm -f test-update-shelved-change.t &&
488
+ git rm -f shelved-change-1.t &&
489
git commit --amend -C HEAD &&
490
git show --stat HEAD &&
487
- git p4 submit -v --origin HEAD^ --update-shelve $shelf_cl &&
491
+ git p4 submit -v --origin HEAD~2 --update-shelve $shelved_cl0 --update-shelve $shelved_cl1 &&
492
echo "done git p4 submit"
493
) &&
494
(
@@ -494,7 +498,7 @@ test_expect_success 'submit --update-shelve' '
498
p4 unshelve -c $change -s $change &&
499
grep -q updated-line shelf.t &&
500
p4 describe -S $change | grep added-file.t &&
497
- test_path_is_missing test-update-shelved-change.t
501
+ test_path_is_missing shelved-change-1.t
502
)
503
'
504