Browse Source

Add option to allow empty commits to CommitCommand

CommitCommand should allow to specify whether empty commits (commits
having the same tree as the sole predecessor commit) are allowed or not.
Similar to native git's "--allow-empty" flag.

The defaults differ between JGit and native git even after this change.
When not specifying paths then by default JGit allows to create empty
commits while native git does not. It would be API breaking to change
this now.

Bug: 460301
Change-Id: I88feb0c3ffb2c686b1d0594e669729b065cda4cb
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
stable-4.3
Christian Halstrick 9 years ago committed by Matthias Sohn
parent
commit
da43d8d798
  1. 31
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
  2. 42
      org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
  3. 62
      org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmtpyCommitException.java

31
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java

@ -46,12 +46,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.eclipse.jgit.api.errors.EmtpyCommitException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.dircache.DirCache;
@ -476,6 +479,34 @@ public class CommitCommandTest extends RepositoryTestCase {
assertEquals("newauthor@example.org", amendedAuthor.getEmailAddress());
}
@Test
public void commitEmptyCommits() throws Exception {
try (Git git = new Git(db)) {
writeTrashFile("file1", "file1");
git.add().addFilepattern("file1").call();
RevCommit initial = git.commit().setMessage("initial commit")
.call();
RevCommit emptyFollowUp = git.commit()
.setAuthor("New Author", "newauthor@example.org")
.setMessage("no change").call();
assertNotEquals(initial.getId(), emptyFollowUp.getId());
assertEquals(initial.getTree().getId(),
emptyFollowUp.getTree().getId());
try {
git.commit().setAuthor("New Author", "newauthor@example.org")
.setMessage("again no change").setAllowEmpty(false)
.call();
fail("Didn't get the expected EmtpyCommitException");
} catch (EmtpyCommitException e) {
// expect this exception
}
}
}
@Test
public void commitOnlyShouldCommitUnmergedPathAndNotAffectOthers()
throws Exception {

42
org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java

@ -53,6 +53,7 @@ import java.util.List;
import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.EmtpyCommitException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
@ -130,6 +131,8 @@ public class CommitCommand extends GitCommand<RevCommit> {
private PrintStream hookOutRedirect;
private Boolean allowEmpty;
/**
* @param repo
*/
@ -231,6 +234,16 @@ public class CommitCommand extends GitCommand<RevCommit> {
if (insertChangeId)
insertChangeId(indexTreeId);
// Check for empty commits
if (headId != null && !allowEmpty.booleanValue()) {
RevCommit headCommit = rw.parseCommit(headId);
headCommit.getTree();
if (indexTreeId.equals(headCommit.getTree())) {
throw new EmtpyCommitException(
JGitText.get().emptyCommit);
}
}
// Create a Commit object, populate it and write it
CommitBuilder commit = new CommitBuilder();
commit.setCommitter(committer);
@ -457,6 +470,8 @@ public class CommitCommand extends GitCommand<RevCommit> {
// there must be at least one change
if (emptyCommit)
// Would like to throw a EmptyCommitException. But this would break the API
// TODO(ch): Change this in the next release
throw new JGitInternalException(JGitText.get().emptyCommit);
// update index
@ -510,6 +525,12 @@ public class CommitCommand extends GitCommand<RevCommit> {
committer = new PersonIdent(repo);
if (author == null && !amend)
author = committer;
if (allowEmpty == null)
// JGit allows empty commits by default. Only when pathes are
// specified the commit should not be empty. This behaviour differs
// from native git but can only be adapted in the next release.
// TODO(ch) align the defaults with native git
allowEmpty = (only.isEmpty()) ? Boolean.TRUE : Boolean.FALSE;
// when doing a merge commit parse MERGE_HEAD and MERGE_MSG files
if (state == RepositoryState.MERGING_RESOLVED
@ -578,6 +599,27 @@ public class CommitCommand extends GitCommand<RevCommit> {
return this;
}
/**
* @param allowEmpty
* whether it should be allowed to create a commit which has the
* same tree as it's sole predecessor (a commit which doesn't
* change anything). By default when creating standard commits
* (without specifying paths) JGit allows to create such commits.
* When this flag is set to false an attempt to create an "empty"
* standard commit will lead to an EmptyCommitException.
* <p>
* By default when creating a commit containing only specified
* paths an attempt to create an empty commit leads to a
* {@link JGitInternalException}. By setting this flag to
* <code>true</code> this exception will not be thrown.
* @return {@code this}
* @since 4.2
*/
public CommitCommand setAllowEmpty(boolean allowEmpty) {
this.allowEmpty = Boolean.valueOf(allowEmpty);
return this;
}
/**
* @return the commit message used for the <code>commit</code>
*/

62
org.eclipse.jgit/src/org/eclipse/jgit/api/errors/EmtpyCommitException.java

@ -0,0 +1,62 @@
/*
* Copyright (C) 2015, Christian Halstrick <christian.halstrick@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v1.0 which accompanies this
* distribution, is reproduced below, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api.errors;
/**
* Exception thrown when a newly created commit does not contain any changes
*
* @since 4.2
*/
public class EmtpyCommitException extends GitAPIException {
private static final long serialVersionUID = 1L;
/**
* @param message
* @param cause
*/
public EmtpyCommitException(String message, Throwable cause) {
super(message, cause);
}
/**
* @param message
*/
public EmtpyCommitException(String message) {
super(message);
}
}
Loading…
Cancel
Save