1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.api;
11
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.PrintStream;
15 import java.text.MessageFormat;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.LinkedList;
20 import java.util.List;
21
22 import org.eclipse.jgit.annotations.NonNull;
23 import org.eclipse.jgit.api.errors.AbortedByHookException;
24 import org.eclipse.jgit.api.errors.CanceledException;
25 import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
26 import org.eclipse.jgit.api.errors.EmptyCommitException;
27 import org.eclipse.jgit.api.errors.GitAPIException;
28 import org.eclipse.jgit.api.errors.JGitInternalException;
29 import org.eclipse.jgit.api.errors.NoFilepatternException;
30 import org.eclipse.jgit.api.errors.NoHeadException;
31 import org.eclipse.jgit.api.errors.NoMessageException;
32 import org.eclipse.jgit.api.errors.ServiceUnavailableException;
33 import org.eclipse.jgit.api.errors.UnmergedPathsException;
34 import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException;
35 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
36 import org.eclipse.jgit.dircache.DirCache;
37 import org.eclipse.jgit.dircache.DirCacheBuildIterator;
38 import org.eclipse.jgit.dircache.DirCacheBuilder;
39 import org.eclipse.jgit.dircache.DirCacheEntry;
40 import org.eclipse.jgit.dircache.DirCacheIterator;
41 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
42 import org.eclipse.jgit.errors.MissingObjectException;
43 import org.eclipse.jgit.errors.UnmergedPathException;
44 import org.eclipse.jgit.hooks.CommitMsgHook;
45 import org.eclipse.jgit.hooks.Hooks;
46 import org.eclipse.jgit.hooks.PostCommitHook;
47 import org.eclipse.jgit.hooks.PreCommitHook;
48 import org.eclipse.jgit.internal.JGitText;
49 import org.eclipse.jgit.lib.CommitBuilder;
50 import org.eclipse.jgit.lib.CommitConfig;
51 import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
52 import org.eclipse.jgit.lib.Constants;
53 import org.eclipse.jgit.lib.FileMode;
54 import org.eclipse.jgit.lib.GpgConfig;
55 import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
56 import org.eclipse.jgit.lib.GpgObjectSigner;
57 import org.eclipse.jgit.lib.GpgSigner;
58 import org.eclipse.jgit.lib.ObjectId;
59 import org.eclipse.jgit.lib.ObjectInserter;
60 import org.eclipse.jgit.lib.PersonIdent;
61 import org.eclipse.jgit.lib.Ref;
62 import org.eclipse.jgit.lib.RefUpdate;
63 import org.eclipse.jgit.lib.RefUpdate.Result;
64 import org.eclipse.jgit.lib.Repository;
65 import org.eclipse.jgit.lib.RepositoryState;
66 import org.eclipse.jgit.revwalk.RevCommit;
67 import org.eclipse.jgit.revwalk.RevObject;
68 import org.eclipse.jgit.revwalk.RevTag;
69 import org.eclipse.jgit.revwalk.RevWalk;
70 import org.eclipse.jgit.transport.CredentialsProvider;
71 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
72 import org.eclipse.jgit.treewalk.FileTreeIterator;
73 import org.eclipse.jgit.treewalk.TreeWalk;
74 import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
75 import org.eclipse.jgit.util.ChangeIdUtil;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79
80
81
82
83
84
85
86
87
88 public class CommitCommand extends GitCommand<RevCommit> {
89 private static final Logger log = LoggerFactory
90 .getLogger(CommitCommand.class);
91
92 private PersonIdent author;
93
94 private PersonIdent committer;
95
96 private String message;
97
98 private boolean all;
99
100 private List<String> only = new ArrayList<>();
101
102 private boolean[] onlyProcessed;
103
104 private boolean amend;
105
106 private boolean insertChangeId;
107
108
109
110
111
112 private List<ObjectId> parents = new LinkedList<>();
113
114 private String reflogComment;
115
116 private boolean useDefaultReflogMessage = true;
117
118
119
120
121 private boolean noVerify;
122
123 private HashMap<String, PrintStream> hookOutRedirect = new HashMap<>(3);
124
125 private HashMap<String, PrintStream> hookErrRedirect = new HashMap<>(3);
126
127 private Boolean allowEmpty;
128
129 private Boolean signCommit;
130
131 private String signingKey;
132
133 private GpgSigner gpgSigner;
134
135 private GpgConfig gpgConfig;
136
137 private CredentialsProvider credentialsProvider;
138
139 private @NonNull CleanupMode cleanupMode = CleanupMode.VERBATIM;
140
141 private boolean cleanDefaultIsStrip = true;
142
143 private Character commentChar;
144
145
146
147
148
149
150
151 protected CommitCommand(Repository repo) {
152 super(repo);
153 this.credentialsProvider = CredentialsProvider.getDefault();
154 }
155
156
157
158
159
160
161
162
163
164
165
166
167
168 @Override
169 public RevCommit call() throws GitAPIException, AbortedByHookException,
170 ConcurrentRefUpdateException, NoHeadException, NoMessageException,
171 ServiceUnavailableException, UnmergedPathsException,
172 WrongRepositoryStateException {
173 checkCallable();
174 Collections.sort(only);
175
176 try (RevWalk rw = new RevWalk(repo)) {
177 RepositoryState state = repo.getRepositoryState();
178 if (!state.canCommit())
179 throw new WrongRepositoryStateException(MessageFormat.format(
180 JGitText.get().cannotCommitOnARepoWithState,
181 state.name()));
182
183 if (!noVerify) {
184 Hooks.preCommit(repo, hookOutRedirect.get(PreCommitHook.NAME),
185 hookErrRedirect.get(PreCommitHook.NAME))
186 .call();
187 }
188
189 processOptions(state, rw);
190
191 if (all && !repo.isBare()) {
192 try (Git git = new Git(repo)) {
193 git.add().addFilepattern(".")
194 .setUpdate(true).call();
195 } catch (NoFilepatternException e) {
196
197 throw new JGitInternalException(e.getMessage(), e);
198 }
199 }
200
201 Ref head = repo.exactRef(Constants.HEAD);
202 if (head == null)
203 throw new NoHeadException(
204 JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported);
205
206
207 ObjectId headId = repo.resolve(Constants.HEAD + "^{commit}");
208 if (headId == null && amend)
209 throw new WrongRepositoryStateException(
210 JGitText.get().commitAmendOnInitialNotPossible);
211
212 if (headId != null) {
213 if (amend) {
214 RevCommit previousCommit = rw.parseCommit(headId);
215 for (RevCommit p : previousCommit.getParents())
216 parents.add(p.getId());
217 if (author == null)
218 author = previousCommit.getAuthorIdent();
219 } else {
220 parents.add(0, headId);
221 }
222 }
223 if (!noVerify) {
224 message = Hooks
225 .commitMsg(repo,
226 hookOutRedirect.get(CommitMsgHook.NAME),
227 hookErrRedirect.get(CommitMsgHook.NAME))
228 .setCommitMessage(message).call();
229 }
230
231 CommitConfig config = null;
232 if (CleanupMode.DEFAULT.equals(cleanupMode)) {
233 config = repo.getConfig().get(CommitConfig.KEY);
234 cleanupMode = config.resolve(cleanupMode, cleanDefaultIsStrip);
235 }
236 char comments = (char) 0;
237 if (CleanupMode.STRIP.equals(cleanupMode)
238 || CleanupMode.SCISSORS.equals(cleanupMode)) {
239 if (commentChar == null) {
240 if (config == null) {
241 config = repo.getConfig().get(CommitConfig.KEY);
242 }
243 if (config.isAutoCommentChar()) {
244
245
246
247 comments = (char) 0;
248 cleanupMode = CleanupMode.WHITESPACE;
249 } else {
250 comments = config.getCommentChar();
251 }
252 } else {
253 comments = commentChar.charValue();
254 }
255 }
256 message = CommitConfig.cleanText(message, cleanupMode, comments);
257
258 RevCommit revCommit;
259 DirCache index = repo.lockDirCache();
260 try (ObjectInserter odi = repo.newObjectInserter()) {
261 if (!only.isEmpty())
262 index = createTemporaryIndex(headId, index, rw);
263
264
265
266
267 ObjectId indexTreeId = index.writeTree(odi);
268
269 if (insertChangeId)
270 insertChangeId(indexTreeId);
271
272 checkIfEmpty(rw, headId, indexTreeId);
273
274
275 CommitBuilder commit = new CommitBuilder();
276 commit.setCommitter(committer);
277 commit.setAuthor(author);
278 commit.setMessage(message);
279 commit.setParentIds(parents);
280 commit.setTreeId(indexTreeId);
281
282 if (signCommit.booleanValue()) {
283 sign(commit);
284 }
285
286 ObjectId commitId = odi.insert(commit);
287 odi.flush();
288 revCommit = rw.parseCommit(commitId);
289
290 updateRef(state, headId, revCommit, commitId);
291 } finally {
292 index.unlock();
293 }
294 try {
295 Hooks.postCommit(repo, hookOutRedirect.get(PostCommitHook.NAME),
296 hookErrRedirect.get(PostCommitHook.NAME)).call();
297 } catch (Exception e) {
298 log.error(MessageFormat.format(
299 JGitText.get().postCommitHookFailed, e.getMessage()),
300 e);
301 }
302 return revCommit;
303 } catch (UnmergedPathException e) {
304 throw new UnmergedPathsException(e);
305 } catch (IOException e) {
306 throw new JGitInternalException(
307 JGitText.get().exceptionCaughtDuringExecutionOfCommitCommand, e);
308 }
309 }
310
311 private void checkIfEmpty(RevWalk rw, ObjectId headId, ObjectId indexTreeId)
312 throws EmptyCommitException, MissingObjectException,
313 IncorrectObjectTypeException, IOException {
314 if (headId != null && !allowEmpty.booleanValue()) {
315 RevCommit headCommit = rw.parseCommit(headId);
316 headCommit.getTree();
317 if (indexTreeId.equals(headCommit.getTree())) {
318 throw new EmptyCommitException(JGitText.get().emptyCommit);
319 }
320 }
321 }
322
323 private void sign(CommitBuilder commit) throws ServiceUnavailableException,
324 CanceledException, UnsupportedSigningFormatException {
325 if (gpgSigner == null) {
326 gpgSigner = GpgSigner.getDefault();
327 if (gpgSigner == null) {
328 throw new ServiceUnavailableException(
329 JGitText.get().signingServiceUnavailable);
330 }
331 }
332 if (signingKey == null) {
333 signingKey = gpgConfig.getSigningKey();
334 }
335 if (gpgSigner instanceof GpgObjectSigner) {
336 ((GpgObjectSigner) gpgSigner).signObject(commit,
337 signingKey, committer, credentialsProvider,
338 gpgConfig);
339 } else {
340 if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) {
341 throw new UnsupportedSigningFormatException(JGitText
342 .get().onlyOpenPgpSupportedForSigning);
343 }
344 gpgSigner.sign(commit, signingKey, committer,
345 credentialsProvider);
346 }
347 }
348
349 private void updateRef(RepositoryState state, ObjectId headId,
350 RevCommit revCommit, ObjectId commitId)
351 throws ConcurrentRefUpdateException, IOException {
352 RefUpdate ru = repo.updateRef(Constants.HEAD);
353 ru.setNewObjectId(commitId);
354 if (!useDefaultReflogMessage) {
355 ru.setRefLogMessage(reflogComment, false);
356 } else {
357 String prefix = amend ? "commit (amend): "
358 : parents.isEmpty() ? "commit (initial): "
359 : "commit: ";
360 ru.setRefLogMessage(prefix + revCommit.getShortMessage(),
361 false);
362 }
363 if (headId != null) {
364 ru.setExpectedOldObjectId(headId);
365 } else {
366 ru.setExpectedOldObjectId(ObjectId.zeroId());
367 }
368 Result rc = ru.forceUpdate();
369 switch (rc) {
370 case NEW:
371 case FORCED:
372 case FAST_FORWARD: {
373 setCallable(false);
374 if (state == RepositoryState.MERGING_RESOLVED
375 || isMergeDuringRebase(state)) {
376
377
378 repo.writeMergeCommitMsg(null);
379 repo.writeMergeHeads(null);
380 } else if (state == RepositoryState.CHERRY_PICKING_RESOLVED) {
381 repo.writeMergeCommitMsg(null);
382 repo.writeCherryPickHead(null);
383 } else if (state == RepositoryState.REVERTING_RESOLVED) {
384 repo.writeMergeCommitMsg(null);
385 repo.writeRevertHead(null);
386 }
387 break;
388 }
389 case REJECTED:
390 case LOCK_FAILURE:
391 throw new ConcurrentRefUpdateException(
392 JGitText.get().couldNotLockHEAD, ru.getRef(), rc);
393 default:
394 throw new JGitInternalException(MessageFormat.format(
395 JGitText.get().updatingRefFailed, Constants.HEAD,
396 commitId.toString(), rc));
397 }
398 }
399
400 private void insertChangeId(ObjectId treeId) {
401 ObjectId firstParentId = null;
402 if (!parents.isEmpty())
403 firstParentId = parents.get(0);
404 ObjectId changeId = ChangeIdUtil.computeChangeId(treeId, firstParentId,
405 author, committer, message);
406 message = ChangeIdUtil.insertId(message, changeId);
407 if (changeId != null)
408 message = message.replaceAll("\nChange-Id: I"
409 + ObjectId.zeroId().getName() + "\n", "\nChange-Id: I"
410 + changeId.getName() + "\n");
411 }
412
413 private DirCache createTemporaryIndex(ObjectId headId, DirCache index,
414 RevWalk rw)
415 throws IOException {
416 ObjectInserter inserter = null;
417
418
419 DirCacheBuilder existingBuilder = index.builder();
420
421
422
423 DirCache inCoreIndex = DirCache.newInCore();
424 DirCacheBuilder tempBuilder = inCoreIndex.builder();
425
426 onlyProcessed = new boolean[only.size()];
427 boolean emptyCommit = true;
428
429 try (TreeWalk treeWalk = new TreeWalk(repo)) {
430 treeWalk.setOperationType(OperationType.CHECKIN_OP);
431 int dcIdx = treeWalk
432 .addTree(new DirCacheBuildIterator(existingBuilder));
433 FileTreeIterator fti = new FileTreeIterator(repo);
434 fti.setDirCacheIterator(treeWalk, 0);
435 int fIdx = treeWalk.addTree(fti);
436 int hIdx = -1;
437 if (headId != null)
438 hIdx = treeWalk.addTree(rw.parseTree(headId));
439 treeWalk.setRecursive(true);
440
441 String lastAddedFile = null;
442 while (treeWalk.next()) {
443 String path = treeWalk.getPathString();
444
445 int pos = lookupOnly(path);
446
447 CanonicalTreeParser hTree = null;
448 if (hIdx != -1)
449 hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);
450
451 DirCacheIterator dcTree = treeWalk.getTree(dcIdx,
452 DirCacheIterator.class);
453
454 if (pos >= 0) {
455
456
457 FileTreeIterator fTree = treeWalk.getTree(fIdx,
458 FileTreeIterator.class);
459
460
461 boolean tracked = dcTree != null || hTree != null;
462 if (!tracked)
463 continue;
464
465
466
467 if (path.equals(lastAddedFile))
468 continue;
469
470 lastAddedFile = path;
471
472 if (fTree != null) {
473
474
475 final DirCacheEntry dcEntry = new DirCacheEntry(path);
476 long entryLength = fTree.getEntryLength();
477 dcEntry.setLength(entryLength);
478 dcEntry.setLastModified(fTree.getEntryLastModifiedInstant());
479 dcEntry.setFileMode(fTree.getIndexFileMode(dcTree));
480
481 boolean objectExists = (dcTree != null
482 && fTree.idEqual(dcTree))
483 || (hTree != null && fTree.idEqual(hTree));
484 if (objectExists) {
485 dcEntry.setObjectId(fTree.getEntryObjectId());
486 } else {
487 if (FileMode.GITLINK.equals(dcEntry.getFileMode()))
488 dcEntry.setObjectId(fTree.getEntryObjectId());
489 else {
490
491 if (inserter == null)
492 inserter = repo.newObjectInserter();
493 long contentLength = fTree
494 .getEntryContentLength();
495 try (InputStream inputStream = fTree
496 .openEntryStream()) {
497 dcEntry.setObjectId(inserter.insert(
498 Constants.OBJ_BLOB, contentLength,
499 inputStream));
500 }
501 }
502 }
503
504
505 existingBuilder.add(dcEntry);
506
507 tempBuilder.add(dcEntry);
508
509 if (emptyCommit
510 && (hTree == null || !hTree.idEqual(fTree)
511 || hTree.getEntryRawMode() != fTree
512 .getEntryRawMode()))
513
514 emptyCommit = false;
515 } else {
516
517
518
519 if (emptyCommit && hTree != null)
520
521 emptyCommit = false;
522 }
523
524
525 onlyProcessed[pos] = true;
526 } else {
527
528 if (hTree != null) {
529
530
531 final DirCacheEntry dcEntry = new DirCacheEntry(path);
532 dcEntry.setObjectId(hTree.getEntryObjectId());
533 dcEntry.setFileMode(hTree.getEntryFileMode());
534
535
536 tempBuilder.add(dcEntry);
537 }
538
539
540 if (dcTree != null)
541 existingBuilder.add(dcTree.getDirCacheEntry());
542 }
543 }
544 }
545
546
547
548 for (int i = 0; i < onlyProcessed.length; i++)
549 if (!onlyProcessed[i])
550 throw new JGitInternalException(MessageFormat.format(
551 JGitText.get().entryNotFoundByPath, only.get(i)));
552
553
554 if (emptyCommit && !allowEmpty.booleanValue())
555
556
557 throw new JGitInternalException(JGitText.get().emptyCommit);
558
559
560 existingBuilder.commit();
561
562 tempBuilder.finish();
563 return inCoreIndex;
564 }
565
566
567
568
569
570
571
572
573
574
575
576
577
578 private int lookupOnly(String pathString) {
579 String p = pathString;
580 while (true) {
581 int position = Collections.binarySearch(only, p);
582 if (position >= 0)
583 return position;
584 int l = p.lastIndexOf('/');
585 if (l < 1)
586 break;
587 p = p.substring(0, l);
588 }
589 return -1;
590 }
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606 private void processOptions(RepositoryState state, RevWalk rw)
607 throws NoMessageException, UnsupportedSigningFormatException {
608 if (committer == null)
609 committer = new PersonIdent(repo);
610 if (author == null && !amend)
611 author = committer;
612 if (allowEmpty == null)
613
614
615
616
617 allowEmpty = (only.isEmpty()) ? Boolean.TRUE : Boolean.FALSE;
618
619
620 if (state == RepositoryState.MERGING_RESOLVED
621 || isMergeDuringRebase(state)) {
622 try {
623 parents = repo.readMergeHeads();
624 if (parents != null)
625 for (int i = 0; i < parents.size(); i++) {
626 RevObject ro = rw.parseAny(parents.get(i));
627 if (ro instanceof RevTag)
628 parents.set(i, rw.peel(ro));
629 }
630 } catch (IOException e) {
631 throw new JGitInternalException(MessageFormat.format(
632 JGitText.get().exceptionOccurredDuringReadingOfGIT_DIR,
633 Constants.MERGE_HEAD, e), e);
634 }
635 if (message == null) {
636 try {
637 message = repo.readMergeCommitMsg();
638 } catch (IOException e) {
639 throw new JGitInternalException(MessageFormat.format(
640 JGitText.get().exceptionOccurredDuringReadingOfGIT_DIR,
641 Constants.MERGE_MSG, e), e);
642 }
643 }
644 } else if (state == RepositoryState.SAFE && message == null) {
645 try {
646 message = repo.readSquashCommitMsg();
647 if (message != null)
648 repo.writeSquashCommitMsg(null );
649 } catch (IOException e) {
650 throw new JGitInternalException(MessageFormat.format(
651 JGitText.get().exceptionOccurredDuringReadingOfGIT_DIR,
652 Constants.MERGE_MSG, e), e);
653 }
654
655 }
656 if (message == null)
657
658
659 throw new NoMessageException(JGitText.get().commitMessageNotSpecified);
660
661 if (gpgConfig == null) {
662 gpgConfig = new GpgConfig(repo.getConfig());
663 }
664 if (signCommit == null) {
665 signCommit = gpgConfig.isSignCommits() ? Boolean.TRUE
666 : Boolean.FALSE;
667 }
668 }
669
670 private boolean isMergeDuringRebase(RepositoryState state) {
671 if (state != RepositoryState.REBASING_INTERACTIVE
672 && state != RepositoryState.REBASING_MERGE)
673 return false;
674 try {
675 return repo.readMergeHeads() != null;
676 } catch (IOException e) {
677 throw new JGitInternalException(MessageFormat.format(
678 JGitText.get().exceptionOccurredDuringReadingOfGIT_DIR,
679 Constants.MERGE_HEAD, e), e);
680 }
681 }
682
683
684
685
686
687
688
689
690 public CommitCommand setMessage(String message) {
691 checkCallable();
692 this.message = message;
693 return this;
694 }
695
696
697
698
699
700
701
702
703
704
705 public CommitCommand setCleanupMode(@NonNull CleanupMode mode) {
706 checkCallable();
707 this.cleanupMode = mode;
708 return this;
709 }
710
711
712
713
714
715
716
717
718
719
720
721
722 public CommitCommand setDefaultClean(boolean strip) {
723 checkCallable();
724 this.cleanDefaultIsStrip = strip;
725 return this;
726 }
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741 public CommitCommand setCommentCharacter(Character commentChar) {
742 checkCallable();
743 this.commentChar = commentChar;
744 return this;
745 }
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766 public CommitCommand setAllowEmpty(boolean allowEmpty) {
767 this.allowEmpty = Boolean.valueOf(allowEmpty);
768 return this;
769 }
770
771
772
773
774
775
776 public String getMessage() {
777 return message;
778 }
779
780
781
782
783
784
785
786
787
788
789
790 public CommitCommand setCommitter(PersonIdent committer) {
791 checkCallable();
792 this.committer = committer;
793 return this;
794 }
795
796
797
798
799
800
801
802
803
804
805
806
807 public CommitCommand setCommitter(String name, String email) {
808 checkCallable();
809 return setCommitter(new PersonIdent(name, email));
810 }
811
812
813
814
815
816
817
818
819
820 public PersonIdent getCommitter() {
821 return committer;
822 }
823
824
825
826
827
828
829
830
831
832
833
834 public CommitCommand setAuthor(PersonIdent author) {
835 checkCallable();
836 this.author = author;
837 return this;
838 }
839
840
841
842
843
844
845
846
847
848
849
850
851 public CommitCommand setAuthor(String name, String email) {
852 checkCallable();
853 return setAuthor(new PersonIdent(name, email));
854 }
855
856
857
858
859
860
861
862
863
864 public PersonIdent getAuthor() {
865 return author;
866 }
867
868
869
870
871
872
873
874
875
876
877
878
879
880 public CommitCommand setAll(boolean all) {
881 checkCallable();
882 if (all && !only.isEmpty())
883 throw new JGitInternalException(MessageFormat.format(
884 JGitText.get().illegalCombinationOfArguments, "--all",
885 "--only"));
886 this.all = all;
887 return this;
888 }
889
890
891
892
893
894
895
896
897
898
899 public CommitCommand setAmend(boolean amend) {
900 checkCallable();
901 this.amend = amend;
902 return this;
903 }
904
905
906
907
908
909
910
911
912
913
914
915
916 public CommitCommand setOnly(String only) {
917 checkCallable();
918 if (all)
919 throw new JGitInternalException(MessageFormat.format(
920 JGitText.get().illegalCombinationOfArguments, "--only",
921 "--all"));
922 String o = only.endsWith("/") ? only.substring(0, only.length() - 1)
923 : only;
924
925 if (!this.only.contains(o))
926 this.only.add(o);
927 return this;
928 }
929
930
931
932
933
934
935
936
937
938
939
940 public CommitCommand setInsertChangeId(boolean insertChangeId) {
941 checkCallable();
942 this.insertChangeId = insertChangeId;
943 return this;
944 }
945
946
947
948
949
950
951
952
953
954 public CommitCommand setReflogComment(String reflogComment) {
955 this.reflogComment = reflogComment;
956 useDefaultReflogMessage = false;
957 return this;
958 }
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974 public CommitCommand setNoVerify(boolean noVerify) {
975 this.noVerify = noVerify;
976 return this;
977 }
978
979
980
981
982
983
984
985
986
987
988
989 public CommitCommand setHookOutputStream(PrintStream hookStdOut) {
990 setHookOutputStream(PreCommitHook.NAME, hookStdOut);
991 setHookOutputStream(CommitMsgHook.NAME, hookStdOut);
992 setHookOutputStream(PostCommitHook.NAME, hookStdOut);
993 return this;
994 }
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006 public CommitCommand setHookErrorStream(PrintStream hookStdErr) {
1007 setHookErrorStream(PreCommitHook.NAME, hookStdErr);
1008 setHookErrorStream(CommitMsgHook.NAME, hookStdErr);
1009 setHookErrorStream(PostCommitHook.NAME, hookStdErr);
1010 return this;
1011 }
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 public CommitCommand setHookOutputStream(String hookName,
1026 PrintStream hookStdOut) {
1027 if (!(PreCommitHook.NAME.equals(hookName)
1028 || CommitMsgHook.NAME.equals(hookName)
1029 || PostCommitHook.NAME.equals(hookName))) {
1030 throw new IllegalArgumentException(
1031 MessageFormat.format(JGitText.get().illegalHookName,
1032 hookName));
1033 }
1034 hookOutRedirect.put(hookName, hookStdOut);
1035 return this;
1036 }
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050 public CommitCommand setHookErrorStream(String hookName,
1051 PrintStream hookStdErr) {
1052 if (!(PreCommitHook.NAME.equals(hookName)
1053 || CommitMsgHook.NAME.equals(hookName)
1054 || PostCommitHook.NAME.equals(hookName))) {
1055 throw new IllegalArgumentException(MessageFormat
1056 .format(JGitText.get().illegalHookName, hookName));
1057 }
1058 hookErrRedirect.put(hookName, hookStdErr);
1059 return this;
1060 }
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078 public CommitCommand setSigningKey(String signingKey) {
1079 checkCallable();
1080 this.signingKey = signingKey;
1081 return this;
1082 }
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094 public CommitCommand setSign(Boolean sign) {
1095 checkCallable();
1096 this.signCommit = sign;
1097 return this;
1098 }
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108 public CommitCommand setGpgSigner(GpgSigner signer) {
1109 checkCallable();
1110 this.gpgSigner = signer;
1111 return this;
1112 }
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124 public CommitCommand setGpgConfig(GpgConfig config) {
1125 checkCallable();
1126 this.gpgConfig = config;
1127 return this;
1128 }
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139 public CommitCommand setCredentialsProvider(
1140 CredentialsProvider credentialsProvider) {
1141 this.credentialsProvider = credentialsProvider;
1142 return this;
1143 }
1144 }