git-p4: add option to keep empty commits

A changelist that contains only excluded files due to a client spec was imported as an empty commit. Fix that issue by ignoring these commits. Add option "git-p4.keepEmptyCommits" to make the previous behavior available. Signed-off-by: Lars Schneider <larsxschneider@gmail.com> Helped-by: Pete Harlan Acked-by: Luke Diamand <luke@diamand.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Lars Schneider committed Dec 8, 2015 at 10:36 UTC 4ae048e67e5f0d786b9febc438433d95f18e5937
3 files changed +165 -17
Documentation/git-p4.txt
+4
@@ -510,6 +510,10 @@ git-p4.useClientSpec::
510 option '--use-client-spec'. See the "CLIENT SPEC" section above.
511 This variable is a boolean, not the name of a p4 client.
512
513 +git-p4.keepEmptyCommits::
514 + A changelist that contains only excluded files will be imported
515 + as an empty commit if this boolean option is set to true.
516 +
517 Submit variables
518 ~~~~~~~~~~~~~~~~
519 git-p4.detectRenames::
git-p4.py
+27 -17
@@ -2235,12 +2235,6 @@ class P4Sync(Command, P4UserMap):
2235 filesToDelete = []
2236
2237 for f in files:
2238 - # if using a client spec, only add the files that have
2239 - # a path in the client
2240 - if self.clientSpecDirs:
2241 - if self.clientSpecDirs.map_in_client(f['path']) == "":
2242 - continue
2243 -
2238 filesForCommit.append(f)
2239 if f['action'] in self.delete_actions:
2240 filesToDelete.append(f)
@@ -2308,25 +2302,41 @@ class P4Sync(Command, P4UserMap):
2302 gitStream.write(description)
2303 gitStream.write("\n")
2304
2305 + def inClientSpec(self, path):
2306 + if not self.clientSpecDirs:
2307 + return True
2308 + inClientSpec = self.clientSpecDirs.map_in_client(path)
2309 + if not inClientSpec and self.verbose:
2310 + print('Ignoring file outside of client spec: {0}'.format(path))
2311 + return inClientSpec
2312 +
2313 + def hasBranchPrefix(self, path):
2314 + if not self.branchPrefixes:
2315 + return True
2316 + hasPrefix = [p for p in self.branchPrefixes
2317 + if p4PathStartsWith(path, p)]
2318 + if hasPrefix and self.verbose:
2319 + print('Ignoring file outside of prefix: {0}'.format(path))
2320 + return hasPrefix
2321 +
2322 def commit(self, details, files, branch, parent = ""):
2323 epoch = details["time"]
2324 author = details["user"]
2325
2326 if self.verbose:
2316 - print "commit into %s" % branch
2317 -
2318 - # start with reading files; if that fails, we should not
2319 - # create a commit.
2320 - new_files = []
2321 - for f in files:
2322 - if [p for p in self.branchPrefixes if p4PathStartsWith(f['path'], p)]:
2323 - new_files.append (f)
2324 - else:
2325 - sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
2327 + print('commit into {0}'.format(branch))
2328
2329 if self.clientSpecDirs:
2330 self.clientSpecDirs.update_client_spec_path_cache(files)
2331
2332 + files = [f for f in files
2333 + if self.inClientSpec(f['path']) and self.hasBranchPrefix(f['path'])]
2334 +
2335 + if not files and not gitConfigBool('git-p4.keepEmptyCommits'):
2336 + print('Ignoring revision {0} as it would produce an empty commit.'
2337 + .format(details['change']))
2338 + return
2339 +
2340 self.gitStream.write("commit %s\n" % branch)
2341 # gitStream.write("mark :%s\n" % details["change"])
2342 self.committedChanges.add(int(details["change"]))
@@ -2350,7 +2360,7 @@ class P4Sync(Command, P4UserMap):
2360 print "parent %s" % parent
2361 self.gitStream.write("from %s\n" % parent)
2362
2353 - self.streamP4Files(new_files)
2363 + self.streamP4Files(files)
2364 self.gitStream.write("\n")
2365
2366 change = int(details["change"])
t/t9826-git-p4-keep-empty-commits.sh new
+134
@@ -0,0 +1,134 @@
1 +#!/bin/sh
2 +
3 +test_description='Clone repositories and keep empty commits'
4 +
5 +. ./lib-git-p4.sh
6 +
7 +test_expect_success 'start p4d' '
8 + start_p4d
9 +'
10 +
11 +test_expect_success 'Create a repo' '
12 + client_view "//depot/... //client/..." &&
13 + (
14 + cd "$cli" &&
15 +
16 + mkdir -p subdir &&
17 +
18 + >subdir/file1.txt &&
19 + p4 add subdir/file1.txt &&
20 + p4 submit -d "Add file 1" &&
21 +
22 + >file2.txt &&
23 + p4 add file2.txt &&
24 + p4 submit -d "Add file 2" &&
25 +
26 + >subdir/file3.txt &&
27 + p4 add subdir/file3.txt &&
28 + p4 submit -d "Add file 3" &&
29 +
30 + >file4.txt &&
31 + p4 add file4.txt &&
32 + p4 submit -d "Add file 4" &&
33 +
34 + p4 delete subdir/file3.txt &&
35 + p4 submit -d "Remove file 3" &&
36 +
37 + p4 delete file4.txt &&
38 + p4 submit -d "Remove file 4"
39 + )
40 +'
41 +
42 +test_expect_success 'Clone repo root path with all history' '
43 + client_view "//depot/... //client/..." &&
44 + test_when_finished cleanup_git &&
45 + (
46 + cd "$git" &&
47 + git init . &&
48 + git p4 clone --use-client-spec --destination="$git" //depot@all &&
49 + cat >expect <<-\EOF &&
50 +Remove file 4
51 +[git-p4: depot-paths = "//depot/": change = 6]
52 +
53 +Remove file 3
54 +[git-p4: depot-paths = "//depot/": change = 5]
55 +
56 +Add file 4
57 +[git-p4: depot-paths = "//depot/": change = 4]
58 +
59 +Add file 3
60 +[git-p4: depot-paths = "//depot/": change = 3]
61 +
62 +Add file 2
63 +[git-p4: depot-paths = "//depot/": change = 2]
64 +
65 +Add file 1
66 +[git-p4: depot-paths = "//depot/": change = 1]
67 +
68 + EOF
69 + git log --format=%B >actual &&
70 + test_cmp expect actual
71 + )
72 +'
73 +
74 +test_expect_success 'Clone repo subdir with all history but keep empty commits' '
75 + client_view "//depot/subdir/... //client/subdir/..." &&
76 + test_when_finished cleanup_git &&
77 + (
78 + cd "$git" &&
79 + git init . &&
80 + git config git-p4.keepEmptyCommits true &&
81 + git p4 clone --use-client-spec --destination="$git" //depot@all &&
82 + cat >expect <<-\EOF &&
83 +Remove file 4
84 +[git-p4: depot-paths = "//depot/": change = 6]
85 +
86 +Remove file 3
87 +[git-p4: depot-paths = "//depot/": change = 5]
88 +
89 +Add file 4
90 +[git-p4: depot-paths = "//depot/": change = 4]
91 +
92 +Add file 3
93 +[git-p4: depot-paths = "//depot/": change = 3]
94 +
95 +Add file 2
96 +[git-p4: depot-paths = "//depot/": change = 2]
97 +
98 +Add file 1
99 +[git-p4: depot-paths = "//depot/": change = 1]
100 +
101 + EOF
102 + git log --format=%B >actual &&
103 + test_cmp expect actual
104 + )
105 +'
106 +
107 +test_expect_success 'Clone repo subdir with all history' '
108 + client_view "//depot/subdir/... //client/subdir/..." &&
109 + test_when_finished cleanup_git &&
110 + (
111 + cd "$git" &&
112 + git init . &&
113 + git p4 clone --use-client-spec --destination="$git" --verbose //depot@all &&
114 + cat >expect <<-\EOF &&
115 +Remove file 3
116 +[git-p4: depot-paths = "//depot/": change = 5]
117 +
118 +Add file 3
119 +[git-p4: depot-paths = "//depot/": change = 3]
120 +
121 +Add file 1
122 +[git-p4: depot-paths = "//depot/": change = 1]
123 +
124 + EOF
125 + git log --format=%B >actual &&
126 + test_cmp expect actual
127 + )
128 +'
129 +
130 +test_expect_success 'kill p4d' '
131 + kill_p4d
132 +'
133 +
134 +test_done