Add "--squash" option to MergeCommand
CQ: 6570 Bug: 351806 Change-Id: I5e47810376419264ecf4247b5a333af5c8945080 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
parent
c4087af65d
commit
2656ac1b5a
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2011, GitHub Inc.
|
* Copyright (C) 2011-2012, GitHub Inc.
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -68,7 +69,7 @@
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests of {@link CommitCommand}
|
* Unit tests of {@link CommitCommand}.
|
||||||
*/
|
*/
|
||||||
public class CommitCommandTest extends RepositoryTestCase {
|
public class CommitCommandTest extends RepositoryTestCase {
|
||||||
|
|
||||||
|
@ -365,4 +366,42 @@ public void commitIgnoresSmudgedEntryWithDifferentId() throws Exception {
|
||||||
assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
|
assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
|
||||||
assertEquals(0, cache.getEntry("file2.txt").getLength());
|
assertEquals(0, cache.getEntry("file2.txt").getLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void commitAfterSquashMerge() throws Exception {
|
||||||
|
Git git = new Git(db);
|
||||||
|
|
||||||
|
writeTrashFile("file1", "file1");
|
||||||
|
git.add().addFilepattern("file1").call();
|
||||||
|
RevCommit first = git.commit().setMessage("initial commit").call();
|
||||||
|
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
createBranch(first, "refs/heads/branch1");
|
||||||
|
checkoutBranch("refs/heads/branch1");
|
||||||
|
|
||||||
|
writeTrashFile("file2", "file2");
|
||||||
|
git.add().addFilepattern("file2").call();
|
||||||
|
git.commit().setMessage("second commit").call();
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
|
||||||
|
checkoutBranch("refs/heads/master");
|
||||||
|
|
||||||
|
MergeResult result = git.merge().include(db.getRef("branch1"))
|
||||||
|
.setSquash(true).call();
|
||||||
|
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
|
||||||
|
result.getMergeStatus());
|
||||||
|
|
||||||
|
// comment not set, should be inferred from SQUASH_MSG
|
||||||
|
RevCommit squashedCommit = git.commit().call();
|
||||||
|
|
||||||
|
assertEquals(1, squashedCommit.getParentCount());
|
||||||
|
assertNull(db.readSquashCommitMsg());
|
||||||
|
assertEquals("commit: Squashed commit of the following:", db
|
||||||
|
.getReflogReader(Constants.HEAD).getLastEntry().getComment());
|
||||||
|
assertEquals("commit: Squashed commit of the following:", db
|
||||||
|
.getReflogReader(db.getBranch()).getLastEntry().getComment());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com>
|
* Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com>
|
||||||
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
|
* Copyright (C) 2010-2012, Christian Halstrick <christian.halstrick@sap.com>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -45,6 +45,7 @@
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
@ -62,6 +63,9 @@
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.eclipse.jgit.util.FS;
|
import org.eclipse.jgit.util.FS;
|
||||||
import org.eclipse.jgit.util.FileUtils;
|
import org.eclipse.jgit.util.FileUtils;
|
||||||
|
import org.eclipse.jgit.util.GitDateFormatter;
|
||||||
|
import org.eclipse.jgit.util.GitDateFormatter.Format;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.experimental.theories.DataPoints;
|
import org.junit.experimental.theories.DataPoints;
|
||||||
import org.junit.experimental.theories.Theories;
|
import org.junit.experimental.theories.Theories;
|
||||||
|
@ -74,6 +78,15 @@ public class MergeCommandTest extends RepositoryTestCase {
|
||||||
public static @DataPoints
|
public static @DataPoints
|
||||||
MergeStrategy[] mergeStrategies = MergeStrategy.get();
|
MergeStrategy[] mergeStrategies = MergeStrategy.get();
|
||||||
|
|
||||||
|
private GitDateFormatter dateFormatter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
dateFormatter = new GitDateFormatter(Format.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMergeInItself() throws Exception {
|
public void testMergeInItself() throws Exception {
|
||||||
Git git = new Git(db);
|
Git git = new Git(db);
|
||||||
|
@ -1096,6 +1109,180 @@ public void testFileModeMergeWithDirtyWorkTree() throws Exception {
|
||||||
assertFalse(canExecute(git, "mergeableButDirty"));
|
assertFalse(canExecute(git, "mergeableButDirty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSquashFastForward() throws Exception {
|
||||||
|
Git git = new Git(db);
|
||||||
|
|
||||||
|
writeTrashFile("file1", "file1");
|
||||||
|
git.add().addFilepattern("file1").call();
|
||||||
|
RevCommit first = git.commit().setMessage("initial commit").call();
|
||||||
|
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
createBranch(first, "refs/heads/branch1");
|
||||||
|
checkoutBranch("refs/heads/branch1");
|
||||||
|
|
||||||
|
writeTrashFile("file2", "file2");
|
||||||
|
git.add().addFilepattern("file2").call();
|
||||||
|
RevCommit second = git.commit().setMessage("second commit").call();
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
|
||||||
|
writeTrashFile("file3", "file3");
|
||||||
|
git.add().addFilepattern("file3").call();
|
||||||
|
RevCommit third = git.commit().setMessage("third commit").call();
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file3").exists());
|
||||||
|
|
||||||
|
checkoutBranch("refs/heads/master");
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
assertFalse(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
assertFalse(new File(db.getWorkTree(), "file3").exists());
|
||||||
|
|
||||||
|
MergeResult result = git.merge().include(db.getRef("branch1"))
|
||||||
|
.setSquash(true).call();
|
||||||
|
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file3").exists());
|
||||||
|
assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
|
||||||
|
result.getMergeStatus());
|
||||||
|
assertEquals(first, result.getNewHead()); // HEAD didn't move
|
||||||
|
assertEquals(first, db.resolve(Constants.HEAD + "^{commit}"));
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"Squashed commit of the following:\n\ncommit "
|
||||||
|
+ third.getName()
|
||||||
|
+ "\nAuthor: "
|
||||||
|
+ third.getAuthorIdent().getName()
|
||||||
|
+ " <"
|
||||||
|
+ third.getAuthorIdent().getEmailAddress()
|
||||||
|
+ ">\nDate: "
|
||||||
|
+ dateFormatter.formatDate(third
|
||||||
|
.getAuthorIdent())
|
||||||
|
+ "\n\n\tthird commit\n\ncommit "
|
||||||
|
+ second.getName()
|
||||||
|
+ "\nAuthor: "
|
||||||
|
+ second.getAuthorIdent().getName()
|
||||||
|
+ " <"
|
||||||
|
+ second.getAuthorIdent().getEmailAddress()
|
||||||
|
+ ">\nDate: "
|
||||||
|
+ dateFormatter.formatDate(second
|
||||||
|
.getAuthorIdent()) + "\n\n\tsecond commit\n",
|
||||||
|
db.readSquashCommitMsg());
|
||||||
|
assertNull(db.readMergeCommitMsg());
|
||||||
|
|
||||||
|
Status stat = git.status().call();
|
||||||
|
assertEquals(StatusCommandTest.set("file2", "file3"), stat.getAdded());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSquashMerge() throws Exception {
|
||||||
|
Git git = new Git(db);
|
||||||
|
|
||||||
|
writeTrashFile("file1", "file1");
|
||||||
|
git.add().addFilepattern("file1").call();
|
||||||
|
RevCommit first = git.commit().setMessage("initial commit").call();
|
||||||
|
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
createBranch(first, "refs/heads/branch1");
|
||||||
|
|
||||||
|
writeTrashFile("file2", "file2");
|
||||||
|
git.add().addFilepattern("file2").call();
|
||||||
|
RevCommit second = git.commit().setMessage("second commit").call();
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
|
||||||
|
checkoutBranch("refs/heads/branch1");
|
||||||
|
|
||||||
|
writeTrashFile("file3", "file3");
|
||||||
|
git.add().addFilepattern("file3").call();
|
||||||
|
RevCommit third = git.commit().setMessage("third commit").call();
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file3").exists());
|
||||||
|
|
||||||
|
checkoutBranch("refs/heads/master");
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
assertFalse(new File(db.getWorkTree(), "file3").exists());
|
||||||
|
|
||||||
|
MergeResult result = git.merge().include(db.getRef("branch1"))
|
||||||
|
.setSquash(true).call();
|
||||||
|
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file3").exists());
|
||||||
|
assertEquals(MergeResult.MergeStatus.MERGED_SQUASHED,
|
||||||
|
result.getMergeStatus());
|
||||||
|
assertEquals(second, result.getNewHead()); // HEAD didn't move
|
||||||
|
assertEquals(second, db.resolve(Constants.HEAD + "^{commit}"));
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"Squashed commit of the following:\n\ncommit "
|
||||||
|
+ third.getName()
|
||||||
|
+ "\nAuthor: "
|
||||||
|
+ third.getAuthorIdent().getName()
|
||||||
|
+ " <"
|
||||||
|
+ third.getAuthorIdent().getEmailAddress()
|
||||||
|
+ ">\nDate: "
|
||||||
|
+ dateFormatter.formatDate(third
|
||||||
|
.getAuthorIdent()) + "\n\n\tthird commit\n",
|
||||||
|
db.readSquashCommitMsg());
|
||||||
|
assertNull(db.readMergeCommitMsg());
|
||||||
|
|
||||||
|
Status stat = git.status().call();
|
||||||
|
assertEquals(StatusCommandTest.set("file3"), stat.getAdded());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSquashMergeConflict() throws Exception {
|
||||||
|
Git git = new Git(db);
|
||||||
|
|
||||||
|
writeTrashFile("file1", "file1");
|
||||||
|
git.add().addFilepattern("file1").call();
|
||||||
|
RevCommit first = git.commit().setMessage("initial commit").call();
|
||||||
|
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
createBranch(first, "refs/heads/branch1");
|
||||||
|
|
||||||
|
writeTrashFile("file2", "master");
|
||||||
|
git.add().addFilepattern("file2").call();
|
||||||
|
RevCommit second = git.commit().setMessage("second commit").call();
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
|
||||||
|
checkoutBranch("refs/heads/branch1");
|
||||||
|
|
||||||
|
writeTrashFile("file2", "branch");
|
||||||
|
git.add().addFilepattern("file2").call();
|
||||||
|
RevCommit third = git.commit().setMessage("third commit").call();
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
|
||||||
|
checkoutBranch("refs/heads/master");
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
|
||||||
|
MergeResult result = git.merge().include(db.getRef("branch1"))
|
||||||
|
.setSquash(true).call();
|
||||||
|
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
assertEquals(MergeResult.MergeStatus.CONFLICTING,
|
||||||
|
result.getMergeStatus());
|
||||||
|
assertNull(result.getNewHead());
|
||||||
|
assertEquals(second, db.resolve(Constants.HEAD + "^{commit}"));
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"Squashed commit of the following:\n\ncommit "
|
||||||
|
+ third.getName()
|
||||||
|
+ "\nAuthor: "
|
||||||
|
+ third.getAuthorIdent().getName()
|
||||||
|
+ " <"
|
||||||
|
+ third.getAuthorIdent().getEmailAddress()
|
||||||
|
+ ">\nDate: "
|
||||||
|
+ dateFormatter.formatDate(third
|
||||||
|
.getAuthorIdent()) + "\n\n\tthird commit\n",
|
||||||
|
db.readSquashCommitMsg());
|
||||||
|
assertEquals("\nConflicts:\n\tfile2\n", db.readMergeCommitMsg());
|
||||||
|
|
||||||
|
Status stat = git.status().call();
|
||||||
|
assertEquals(StatusCommandTest.set("file2"), stat.getConflicting());
|
||||||
|
}
|
||||||
|
|
||||||
private void setExecutable(Git git, String path, boolean executable) {
|
private void setExecutable(Git git, String path, boolean executable) {
|
||||||
FS.DETECTED.setExecute(
|
FS.DETECTED.setExecute(
|
||||||
new File(git.getRepository().getWorkTree(), path), executable);
|
new File(git.getRepository().getWorkTree(), path), executable);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com>
|
* Copyright (C) 2011-2012, Chris Aniszczyk <caniszczyk@gmail.com>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -46,6 +46,7 @@
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
@ -359,6 +360,37 @@ public void testHardResetOnTag() throws Exception {
|
||||||
assertTrue(head.equals(secondCommit));
|
assertTrue(head.equals(secondCommit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHardResetAfterSquashMerge() throws Exception {
|
||||||
|
Git g = new Git(db);
|
||||||
|
|
||||||
|
writeTrashFile("file1", "file1");
|
||||||
|
g.add().addFilepattern("file1").call();
|
||||||
|
RevCommit first = g.commit().setMessage("initial commit").call();
|
||||||
|
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file1").exists());
|
||||||
|
createBranch(first, "refs/heads/branch1");
|
||||||
|
checkoutBranch("refs/heads/branch1");
|
||||||
|
|
||||||
|
writeTrashFile("file2", "file2");
|
||||||
|
g.add().addFilepattern("file2").call();
|
||||||
|
g.commit().setMessage("second commit").call();
|
||||||
|
assertTrue(new File(db.getWorkTree(), "file2").exists());
|
||||||
|
|
||||||
|
checkoutBranch("refs/heads/master");
|
||||||
|
|
||||||
|
MergeResult result = g.merge().include(db.getRef("branch1"))
|
||||||
|
.setSquash(true).call();
|
||||||
|
|
||||||
|
assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
|
||||||
|
result.getMergeStatus());
|
||||||
|
assertNotNull(db.readSquashCommitMsg());
|
||||||
|
|
||||||
|
g.reset().setMode(ResetType.HARD).setRef(first.getName()).call();
|
||||||
|
|
||||||
|
assertNull(db.readSquashCommitMsg());
|
||||||
|
}
|
||||||
|
|
||||||
private void assertReflog(ObjectId prevHead, ObjectId head)
|
private void assertReflog(ObjectId prevHead, ObjectId head)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// Check the reflog for HEAD
|
// Check the reflog for HEAD
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
|
* Copyright (C) 2010-2012 Christian Halstrick <christian.halstrick@sap.com>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -78,7 +78,7 @@ public void testReadWriteMergeHeads() throws IOException {
|
||||||
assertEquals(db.readMergeHeads().size(), 2);
|
assertEquals(db.readMergeHeads().size(), 2);
|
||||||
assertEquals(db.readMergeHeads().get(0), ObjectId.zeroId());
|
assertEquals(db.readMergeHeads().get(0), ObjectId.zeroId());
|
||||||
assertEquals(db.readMergeHeads().get(1), ObjectId.fromString(sampleId));
|
assertEquals(db.readMergeHeads().get(1), ObjectId.fromString(sampleId));
|
||||||
db.writeMergeHeads(Collections.EMPTY_LIST);
|
db.writeMergeHeads(Collections.<ObjectId> emptyList());
|
||||||
assertEquals(read(new File(db.getDirectory(), "MERGE_HEAD")), "");
|
assertEquals(read(new File(db.getDirectory(), "MERGE_HEAD")), "");
|
||||||
assertEquals(db.readMergeHeads(), null);
|
assertEquals(db.readMergeHeads(), null);
|
||||||
fos = new FileOutputStream(new File(db.getDirectory(),
|
fos = new FileOutputStream(new File(db.getDirectory(),
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012, IBM Corporation and others.
|
||||||
|
* 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.lib;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class SquashCommitMsgTest extends RepositoryTestCase {
|
||||||
|
private static final String squashMsg = "squashed commit";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadWriteMergeMsg() throws IOException {
|
||||||
|
assertEquals(db.readSquashCommitMsg(), null);
|
||||||
|
assertFalse(new File(db.getDirectory(), Constants.SQUASH_MSG).exists());
|
||||||
|
db.writeSquashCommitMsg(squashMsg);
|
||||||
|
assertEquals(squashMsg, db.readSquashCommitMsg());
|
||||||
|
assertEquals(read(new File(db.getDirectory(), Constants.SQUASH_MSG)),
|
||||||
|
squashMsg);
|
||||||
|
db.writeSquashCommitMsg(null);
|
||||||
|
assertEquals(db.readSquashCommitMsg(), null);
|
||||||
|
assertFalse(new File(db.getDirectory(), Constants.SQUASH_MSG).exists());
|
||||||
|
FileOutputStream fos = new FileOutputStream(new File(db.getDirectory(),
|
||||||
|
Constants.SQUASH_MSG));
|
||||||
|
try {
|
||||||
|
fos.write(squashMsg.getBytes(Constants.CHARACTER_ENCODING));
|
||||||
|
} finally {
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
assertEquals(db.readSquashCommitMsg(), squashMsg);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012, IBM Corporation and others.
|
||||||
|
* 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.merge;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
import org.eclipse.jgit.lib.SampleDataRepositoryTestCase;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.eclipse.jgit.util.GitDateFormatter;
|
||||||
|
import org.eclipse.jgit.util.GitDateFormatter.Format;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test construction of squash message by {@link SquashMessageFormatterTest}.
|
||||||
|
*/
|
||||||
|
public class SquashMessageFormatterTest extends SampleDataRepositoryTestCase {
|
||||||
|
private GitDateFormatter dateFormatter;
|
||||||
|
private SquashMessageFormatter msgFormatter;
|
||||||
|
private RevCommit revCommit;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
dateFormatter = new GitDateFormatter(Format.DEFAULT);
|
||||||
|
msgFormatter = new SquashMessageFormatter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCommit() throws Exception {
|
||||||
|
Git git = new Git(db);
|
||||||
|
revCommit = git.commit().setMessage("squash_me").call();
|
||||||
|
|
||||||
|
Ref master = db.getRef("refs/heads/master");
|
||||||
|
String message = msgFormatter.format(Arrays.asList(revCommit), master);
|
||||||
|
assertEquals(
|
||||||
|
"Squashed commit of the following:\n\ncommit "
|
||||||
|
+ revCommit.getName() + "\nAuthor: "
|
||||||
|
+ revCommit.getAuthorIdent().getName() + " <"
|
||||||
|
+ revCommit.getAuthorIdent().getEmailAddress()
|
||||||
|
+ ">\nDate: " + dateFormatter.formatDate(author)
|
||||||
|
+ "\n\n\tsquash_me\n", message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -424,6 +424,7 @@ sourceDestinationMustMatch=Source/Destination must match.
|
||||||
sourceIsNotAWildcard=Source is not a wildcard.
|
sourceIsNotAWildcard=Source is not a wildcard.
|
||||||
sourceRefDoesntResolveToAnyObject=Source ref {0} doesn't resolve to any object.
|
sourceRefDoesntResolveToAnyObject=Source ref {0} doesn't resolve to any object.
|
||||||
sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0}
|
sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0}
|
||||||
|
squashCommitNotUpdatingHEAD=Squash commit -- not updating HEAD
|
||||||
staleRevFlagsOn=Stale RevFlags on {0}
|
staleRevFlagsOn=Stale RevFlags on {0}
|
||||||
startingReadStageWithoutWrittenRequestDataPendingIsNotSupported=Starting read stage without written request data pending is not supported
|
startingReadStageWithoutWrittenRequestDataPendingIsNotSupported=Starting read stage without written request data pending is not supported
|
||||||
stashApplyFailed=Applying stashed changes did not successfully complete
|
stashApplyFailed=Applying stashed changes did not successfully complete
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
|
* Copyright (C) 2010-2012, Christian Halstrick <christian.halstrick@sap.com>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -488,9 +488,20 @@ private void processOptions(RepositoryState state) throws NoMessageException {
|
||||||
Constants.MERGE_MSG, e), e);
|
Constants.MERGE_MSG, e), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (state == RepositoryState.SAFE && message == null) {
|
||||||
|
try {
|
||||||
|
message = repo.readSquashCommitMsg();
|
||||||
|
if (message != null)
|
||||||
|
repo.writeSquashCommitMsg(null /* delete */);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JGitInternalException(MessageFormat.format(
|
||||||
|
JGitText.get().exceptionOccurredDuringReadingOfGIT_DIR,
|
||||||
|
Constants.MERGE_MSG, e), e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (message == null)
|
if (message == null)
|
||||||
// as long as we don't suppport -C option we have to have
|
// as long as we don't support -C option we have to have
|
||||||
// an explicit message
|
// an explicit message
|
||||||
throw new NoMessageException(JGitText.get().commitMessageNotSpecified);
|
throw new NoMessageException(JGitText.get().commitMessageNotSpecified);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
|
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
|
||||||
* Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com>
|
* Copyright (C) 2010-2012, Stefan Lay <stefan.lay@sap.com>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -76,8 +76,10 @@
|
||||||
import org.eclipse.jgit.merge.Merger;
|
import org.eclipse.jgit.merge.Merger;
|
||||||
import org.eclipse.jgit.merge.ResolveMerger;
|
import org.eclipse.jgit.merge.ResolveMerger;
|
||||||
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
|
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
|
||||||
|
import org.eclipse.jgit.merge.SquashMessageFormatter;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
import org.eclipse.jgit.revwalk.RevWalkUtils;
|
||||||
import org.eclipse.jgit.treewalk.FileTreeIterator;
|
import org.eclipse.jgit.treewalk.FileTreeIterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,6 +97,8 @@ public class MergeCommand extends GitCommand<MergeResult> {
|
||||||
|
|
||||||
private List<Ref> commits = new LinkedList<Ref>();
|
private List<Ref> commits = new LinkedList<Ref>();
|
||||||
|
|
||||||
|
private boolean squash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param repo
|
* @param repo
|
||||||
*/
|
*/
|
||||||
|
@ -184,18 +188,41 @@ public MergeResult call() throws GitAPIException, NoHeadException,
|
||||||
srcCommit.getTree());
|
srcCommit.getTree());
|
||||||
dco.setFailOnConflict(true);
|
dco.setFailOnConflict(true);
|
||||||
dco.checkout();
|
dco.checkout();
|
||||||
|
String msg = null;
|
||||||
|
ObjectId newHead, base = null;
|
||||||
|
MergeStatus mergeStatus = null;
|
||||||
|
if (!squash) {
|
||||||
updateHead(refLogMessage, srcCommit, headId);
|
updateHead(refLogMessage, srcCommit, headId);
|
||||||
setCallable(false);
|
newHead = base = srcCommit;
|
||||||
return new MergeResult(srcCommit, srcCommit, new ObjectId[] {
|
mergeStatus = MergeStatus.FAST_FORWARD;
|
||||||
headCommit, srcCommit }, MergeStatus.FAST_FORWARD,
|
|
||||||
mergeStrategy, null, null);
|
|
||||||
} else {
|
} else {
|
||||||
|
msg = JGitText.get().squashCommitNotUpdatingHEAD;
|
||||||
String mergeMessage = new MergeMessageFormatter().format(
|
newHead = base = headId;
|
||||||
|
mergeStatus = MergeStatus.FAST_FORWARD_SQUASHED;
|
||||||
|
List<RevCommit> squashedCommits = RevWalkUtils.find(
|
||||||
|
revWalk, srcCommit, headCommit);
|
||||||
|
String squashMessage = new SquashMessageFormatter().format(
|
||||||
|
squashedCommits, head);
|
||||||
|
repo.writeSquashCommitMsg(squashMessage);
|
||||||
|
}
|
||||||
|
setCallable(false);
|
||||||
|
return new MergeResult(newHead, base, new ObjectId[] {
|
||||||
|
headCommit, srcCommit }, mergeStatus, mergeStrategy,
|
||||||
|
null, msg);
|
||||||
|
} else {
|
||||||
|
String mergeMessage = "";
|
||||||
|
if (!squash) {
|
||||||
|
mergeMessage = new MergeMessageFormatter().format(
|
||||||
commits, head);
|
commits, head);
|
||||||
repo.writeMergeCommitMsg(mergeMessage);
|
repo.writeMergeCommitMsg(mergeMessage);
|
||||||
repo.writeMergeHeads(Arrays.asList(ref.getObjectId()));
|
repo.writeMergeHeads(Arrays.asList(ref.getObjectId()));
|
||||||
|
} else {
|
||||||
|
List<RevCommit> squashedCommits = RevWalkUtils.find(
|
||||||
|
revWalk, srcCommit, headCommit);
|
||||||
|
String squashMessage = new SquashMessageFormatter().format(
|
||||||
|
squashedCommits, head);
|
||||||
|
repo.writeSquashCommitMsg(squashMessage);
|
||||||
|
}
|
||||||
Merger merger = mergeStrategy.newMerger(repo);
|
Merger merger = mergeStrategy.newMerger(repo);
|
||||||
boolean noProblems;
|
boolean noProblems;
|
||||||
Map<String, org.eclipse.jgit.merge.MergeResult<?>> lowLevelResults = null;
|
Map<String, org.eclipse.jgit.merge.MergeResult<?>> lowLevelResults = null;
|
||||||
|
@ -223,12 +250,22 @@ public MergeResult call() throws GitAPIException, NoHeadException,
|
||||||
dco.setFailOnConflict(true);
|
dco.setFailOnConflict(true);
|
||||||
dco.checkout();
|
dco.checkout();
|
||||||
|
|
||||||
RevCommit newHead = new Git(getRepository()).commit()
|
String msg = null;
|
||||||
|
RevCommit newHead = null;
|
||||||
|
MergeStatus mergeStatus = null;
|
||||||
|
if (!squash) {
|
||||||
|
newHead = new Git(getRepository()).commit()
|
||||||
.setReflogComment(refLogMessage.toString()).call();
|
.setReflogComment(refLogMessage.toString()).call();
|
||||||
return new MergeResult(newHead.getId(),
|
mergeStatus = MergeStatus.MERGED;
|
||||||
null, new ObjectId[] {
|
} else {
|
||||||
headCommit.getId(), srcCommit.getId() },
|
msg = JGitText.get().squashCommitNotUpdatingHEAD;
|
||||||
MergeStatus.MERGED, mergeStrategy, null, null);
|
newHead = headCommit;
|
||||||
|
mergeStatus = MergeStatus.MERGED_SQUASHED;
|
||||||
|
}
|
||||||
|
return new MergeResult(newHead.getId(), null,
|
||||||
|
new ObjectId[] { headCommit.getId(),
|
||||||
|
srcCommit.getId() }, mergeStatus,
|
||||||
|
mergeStrategy, null, msg);
|
||||||
} else {
|
} else {
|
||||||
if (failingPaths != null) {
|
if (failingPaths != null) {
|
||||||
repo.writeMergeCommitMsg(null);
|
repo.writeMergeCommitMsg(null);
|
||||||
|
@ -334,4 +371,25 @@ public MergeCommand include(String name, AnyObjectId commit) {
|
||||||
return include(new ObjectIdRef.Unpeeled(Storage.LOOSE, name,
|
return include(new ObjectIdRef.Unpeeled(Storage.LOOSE, name,
|
||||||
commit.copy()));
|
commit.copy()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If <code>true</code>, will prepare the next commit in working tree and
|
||||||
|
* index as if a real merge happened, but do not make the commit or move the
|
||||||
|
* HEAD. Otherwise, perform the merge and commit the result.
|
||||||
|
* <p>
|
||||||
|
* In case the merge was successful but this flag was set to
|
||||||
|
* <code>true</code> a {@link MergeResult} with status
|
||||||
|
* {@link MergeStatus#MERGED_SQUASHED} or
|
||||||
|
* {@link MergeStatus#FAST_FORWARD_SQUASHED} is returned.
|
||||||
|
*
|
||||||
|
* @param squash
|
||||||
|
* whether to squash commits or not
|
||||||
|
* @return {@code this}
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
public MergeCommand setSquash(boolean squash) {
|
||||||
|
checkCallable();
|
||||||
|
this.squash = squash;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com>
|
* Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com>
|
||||||
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
|
* Copyright (C) 2010-2012, Christian Halstrick <christian.halstrick@sap.com>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -76,6 +76,20 @@ public boolean isSuccessful() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
FAST_FORWARD_SQUASHED {
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Fast-forward-squashed";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuccessful() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
/** */
|
/** */
|
||||||
ALREADY_UP_TO_DATE {
|
ALREADY_UP_TO_DATE {
|
||||||
@Override
|
@Override
|
||||||
|
@ -112,6 +126,20 @@ public boolean isSuccessful() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
MERGED_SQUASHED {
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Merged-squashed";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuccessful() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
/** */
|
/** */
|
||||||
CONFLICTING {
|
CONFLICTING {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com>
|
* Copyright (C) 2011-2012, Chris Aniszczyk <caniszczyk@gmail.com>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -221,6 +221,8 @@ public Ref call() throws GitAPIException, CheckoutConflictException {
|
||||||
resetMerge();
|
resetMerge();
|
||||||
else if (cherryPicking)
|
else if (cherryPicking)
|
||||||
resetCherryPick();
|
resetCherryPick();
|
||||||
|
else if (repo.readSquashCommitMsg() != null)
|
||||||
|
repo.writeSquashCommitMsg(null /* delete */);
|
||||||
}
|
}
|
||||||
|
|
||||||
setCallable(false);
|
setCallable(false);
|
||||||
|
|
|
@ -484,6 +484,7 @@ public static JGitText get() {
|
||||||
/***/ public String sourceIsNotAWildcard;
|
/***/ public String sourceIsNotAWildcard;
|
||||||
/***/ public String sourceRefDoesntResolveToAnyObject;
|
/***/ public String sourceRefDoesntResolveToAnyObject;
|
||||||
/***/ public String sourceRefNotSpecifiedForRefspec;
|
/***/ public String sourceRefNotSpecifiedForRefspec;
|
||||||
|
/***/ public String squashCommitNotUpdatingHEAD;
|
||||||
/***/ public String staleRevFlagsOn;
|
/***/ public String staleRevFlagsOn;
|
||||||
/***/ public String startingReadStageWithoutWrittenRequestDataPendingIsNotSupported;
|
/***/ public String startingReadStageWithoutWrittenRequestDataPendingIsNotSupported;
|
||||||
/***/ public String stashApplyFailed;
|
/***/ public String stashApplyFailed;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2008, Google Inc.
|
* Copyright (C) 2008, Google Inc.
|
||||||
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
|
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
|
||||||
* Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
|
* Copyright (C) 2006-2012, Shawn O. Pearce <spearce@spearce.org>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -553,6 +553,9 @@ public static byte[] encode(final String str) {
|
||||||
/** name of the file containing the ID of a cherry pick commit in case of conflicts */
|
/** name of the file containing the ID of a cherry pick commit in case of conflicts */
|
||||||
public static final String CHERRY_PICK_HEAD = "CHERRY_PICK_HEAD";
|
public static final String CHERRY_PICK_HEAD = "CHERRY_PICK_HEAD";
|
||||||
|
|
||||||
|
/** name of the file containing the commit msg for a squash commit */
|
||||||
|
public static final String SQUASH_MSG = "SQUASH_MSG";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* name of the ref ORIG_HEAD used by certain commands to store the original
|
* name of the ref ORIG_HEAD used by certain commands to store the original
|
||||||
* value of HEAD
|
* value of HEAD
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
|
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
|
||||||
* Copyright (C) 2008-2010, Google Inc.
|
* Copyright (C) 2008-2010, Google Inc.
|
||||||
* Copyright (C) 2006-2010, Robin Rosenberg <robin.rosenberg@dewire.com>
|
* Copyright (C) 2006-2010, Robin Rosenberg <robin.rosenberg@dewire.com>
|
||||||
* Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
|
* Copyright (C) 2006-2012, Shawn O. Pearce <spearce@spearce.org>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -1125,24 +1125,14 @@ public abstract ReflogReader getReflogReader(String refName)
|
||||||
* See {@link #isBare()}.
|
* See {@link #isBare()}.
|
||||||
*/
|
*/
|
||||||
public String readMergeCommitMsg() throws IOException, NoWorkTreeException {
|
public String readMergeCommitMsg() throws IOException, NoWorkTreeException {
|
||||||
if (isBare() || getDirectory() == null)
|
return readCommitMsgFile(Constants.MERGE_MSG);
|
||||||
throw new NoWorkTreeException();
|
|
||||||
|
|
||||||
File mergeMsgFile = new File(getDirectory(), Constants.MERGE_MSG);
|
|
||||||
try {
|
|
||||||
return RawParseUtils.decode(IO.readFully(mergeMsgFile));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
// MERGE_MSG file has disappeared in the meantime
|
|
||||||
// ignore it
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write new content to the file $GIT_DIR/MERGE_MSG. In this file operations
|
* Write new content to the file $GIT_DIR/MERGE_MSG. In this file operations
|
||||||
* triggering a merge will store a template for the commit message of the
|
* triggering a merge will store a template for the commit message of the
|
||||||
* merge commit. If <code>null</code> is specified as message the file will
|
* merge commit. If <code>null</code> is specified as message the file will
|
||||||
* be deleted
|
* be deleted.
|
||||||
*
|
*
|
||||||
* @param msg
|
* @param msg
|
||||||
* the message which should be written or <code>null</code> to
|
* the message which should be written or <code>null</code> to
|
||||||
|
@ -1152,16 +1142,7 @@ public String readMergeCommitMsg() throws IOException, NoWorkTreeException {
|
||||||
*/
|
*/
|
||||||
public void writeMergeCommitMsg(String msg) throws IOException {
|
public void writeMergeCommitMsg(String msg) throws IOException {
|
||||||
File mergeMsgFile = new File(gitDir, Constants.MERGE_MSG);
|
File mergeMsgFile = new File(gitDir, Constants.MERGE_MSG);
|
||||||
if (msg != null) {
|
writeCommitMsg(mergeMsgFile, msg);
|
||||||
FileOutputStream fos = new FileOutputStream(mergeMsgFile);
|
|
||||||
try {
|
|
||||||
fos.write(msg.getBytes(Constants.CHARACTER_ENCODING));
|
|
||||||
} finally {
|
|
||||||
fos.close();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FileUtils.delete(mergeMsgFile, FileUtils.SKIP_MISSING);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1169,9 +1150,9 @@ public void writeMergeCommitMsg(String msg) throws IOException {
|
||||||
* file operations triggering a merge will store the IDs of all heads which
|
* file operations triggering a merge will store the IDs of all heads which
|
||||||
* should be merged together with HEAD.
|
* should be merged together with HEAD.
|
||||||
*
|
*
|
||||||
* @return a list of commits which IDs are listed in the MERGE_HEAD
|
* @return a list of commits which IDs are listed in the MERGE_HEAD file or
|
||||||
* file or {@code null} if this file doesn't exist. Also if the file
|
* {@code null} if this file doesn't exist. Also if the file exists
|
||||||
* exists but is empty {@code null} will be returned
|
* but is empty {@code null} will be returned
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws NoWorkTreeException
|
* @throws NoWorkTreeException
|
||||||
* if this is bare, which implies it has no working directory.
|
* if this is bare, which implies it has no working directory.
|
||||||
|
@ -1280,6 +1261,65 @@ public ObjectId readOrigHead() throws IOException, NoWorkTreeException {
|
||||||
return raw != null ? ObjectId.fromString(raw, 0) : null;
|
return raw != null ? ObjectId.fromString(raw, 0) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the information stored in the file $GIT_DIR/SQUASH_MSG. In this
|
||||||
|
* file operations triggering a squashed merge will store a template for the
|
||||||
|
* commit message of the squash commit.
|
||||||
|
*
|
||||||
|
* @return a String containing the content of the SQUASH_MSG file or
|
||||||
|
* {@code null} if this file doesn't exist
|
||||||
|
* @throws IOException
|
||||||
|
* @throws NoWorkTreeException
|
||||||
|
* if this is bare, which implies it has no working directory.
|
||||||
|
* See {@link #isBare()}.
|
||||||
|
*/
|
||||||
|
public String readSquashCommitMsg() throws IOException {
|
||||||
|
return readCommitMsgFile(Constants.SQUASH_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write new content to the file $GIT_DIR/SQUASH_MSG. In this file
|
||||||
|
* operations triggering a squashed merge will store a template for the
|
||||||
|
* commit message of the squash commit. If <code>null</code> is specified as
|
||||||
|
* message the file will be deleted.
|
||||||
|
*
|
||||||
|
* @param msg
|
||||||
|
* the message which should be written or <code>null</code> to
|
||||||
|
* delete the file
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void writeSquashCommitMsg(String msg) throws IOException {
|
||||||
|
File squashMsgFile = new File(gitDir, Constants.SQUASH_MSG);
|
||||||
|
writeCommitMsg(squashMsgFile, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readCommitMsgFile(String msgFilename) throws IOException {
|
||||||
|
if (isBare() || getDirectory() == null)
|
||||||
|
throw new NoWorkTreeException();
|
||||||
|
|
||||||
|
File mergeMsgFile = new File(getDirectory(), msgFilename);
|
||||||
|
try {
|
||||||
|
return RawParseUtils.decode(IO.readFully(mergeMsgFile));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
// the file has disappeared in the meantime ignore it
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeCommitMsg(File msgFile, String msg) throws IOException {
|
||||||
|
if (msg != null) {
|
||||||
|
FileOutputStream fos = new FileOutputStream(msgFile);
|
||||||
|
try {
|
||||||
|
fos.write(msg.getBytes(Constants.CHARACTER_ENCODING));
|
||||||
|
} finally {
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FileUtils.delete(msgFile, FileUtils.SKIP_MISSING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a file from the git directory.
|
* Read a file from the git directory.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010, Robin Stocker <robin@nibor.org>
|
* Copyright (C) 2010-2012, Robin Stocker <robin@nibor.org>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -134,7 +134,7 @@ else if (ref.getName().equals(ref.getObjectId().getName()))
|
||||||
public String formatWithConflicts(String message,
|
public String formatWithConflicts(String message,
|
||||||
List<String> conflictingPaths) {
|
List<String> conflictingPaths) {
|
||||||
StringBuilder sb = new StringBuilder(message);
|
StringBuilder sb = new StringBuilder(message);
|
||||||
if (!message.endsWith("\n"))
|
if (!message.endsWith("\n") && message.length() != 0)
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
sb.append("Conflicts:\n");
|
sb.append("Conflicts:\n");
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012, IBM Corporation and others.
|
||||||
|
* 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.merge;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.eclipse.jgit.util.GitDateFormatter;
|
||||||
|
import org.eclipse.jgit.util.GitDateFormatter.Format;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formatter for constructing the commit message for a squashed commit.
|
||||||
|
* <p>
|
||||||
|
* The format should be the same as C Git does it, for compatibility.
|
||||||
|
*/
|
||||||
|
public class SquashMessageFormatter {
|
||||||
|
|
||||||
|
private GitDateFormatter dateFormatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new squash message formatter.
|
||||||
|
*/
|
||||||
|
public SquashMessageFormatter() {
|
||||||
|
dateFormatter = new GitDateFormatter(Format.DEFAULT);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Construct the squashed commit message.
|
||||||
|
*
|
||||||
|
* @param squashedCommits
|
||||||
|
* the squashed commits
|
||||||
|
* @param target
|
||||||
|
* the target branch
|
||||||
|
* @return squashed commit message
|
||||||
|
*/
|
||||||
|
public String format(List<RevCommit> squashedCommits, Ref target) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Squashed commit of the following:\n");
|
||||||
|
for (RevCommit c : squashedCommits) {
|
||||||
|
sb.append("\ncommit ");
|
||||||
|
sb.append(c.getName());
|
||||||
|
sb.append("\n");
|
||||||
|
sb.append(toString(c.getAuthorIdent()));
|
||||||
|
sb.append("\n\t");
|
||||||
|
sb.append(c.getShortMessage());
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toString(PersonIdent author) {
|
||||||
|
final StringBuilder a = new StringBuilder();
|
||||||
|
|
||||||
|
a.append("Author: ");
|
||||||
|
a.append(author.getName());
|
||||||
|
a.append(" <");
|
||||||
|
a.append(author.getEmailAddress());
|
||||||
|
a.append(">\n");
|
||||||
|
a.append("Date: ");
|
||||||
|
a.append(dateFormatter.formatDate(author));
|
||||||
|
a.append("\n");
|
||||||
|
|
||||||
|
return a.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2011, Robin Stocker <robin@nibor.org>
|
* Copyright (C) 2011-2012, Robin Stocker <robin@nibor.org>
|
||||||
* and other copyright owners as documented in the project's IP log.
|
* and other copyright owners as documented in the project's IP log.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available
|
* This program and the accompanying materials are made available
|
||||||
|
@ -44,6 +44,8 @@
|
||||||
package org.eclipse.jgit.revwalk;
|
package org.eclipse.jgit.revwalk;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||||
import org.eclipse.jgit.errors.MissingObjectException;
|
import org.eclipse.jgit.errors.MissingObjectException;
|
||||||
|
@ -83,14 +85,43 @@ private RevWalkUtils() {
|
||||||
public static int count(final RevWalk walk, final RevCommit start,
|
public static int count(final RevWalk walk, final RevCommit start,
|
||||||
final RevCommit end) throws MissingObjectException,
|
final RevCommit end) throws MissingObjectException,
|
||||||
IncorrectObjectTypeException, IOException {
|
IncorrectObjectTypeException, IOException {
|
||||||
|
return find(walk, start, end).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find commits that are reachable from <code>start</code> until a commit
|
||||||
|
* that is reachable from <code>end</code> is encountered. In other words,
|
||||||
|
* Find of commits that are in <code>start</code>, but not in
|
||||||
|
* <code>end</code>.
|
||||||
|
* <p>
|
||||||
|
* Note that this method calls {@link RevWalk#reset()} at the beginning.
|
||||||
|
* Also note that the existing rev filter on the walk is left as-is, so be
|
||||||
|
* sure to set the right rev filter before calling this method.
|
||||||
|
*
|
||||||
|
* @param walk
|
||||||
|
* the rev walk to use
|
||||||
|
* @param start
|
||||||
|
* the commit to start counting from
|
||||||
|
* @param end
|
||||||
|
* the commit where counting should end, or null if counting
|
||||||
|
* should be done until there are no more commits
|
||||||
|
* @return the commits found
|
||||||
|
* @throws MissingObjectException
|
||||||
|
* @throws IncorrectObjectTypeException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static List<RevCommit> find(final RevWalk walk,
|
||||||
|
final RevCommit start, final RevCommit end)
|
||||||
|
throws MissingObjectException, IncorrectObjectTypeException,
|
||||||
|
IOException {
|
||||||
walk.reset();
|
walk.reset();
|
||||||
walk.markStart(start);
|
walk.markStart(start);
|
||||||
if (end != null)
|
if (end != null)
|
||||||
walk.markUninteresting(end);
|
walk.markUninteresting(end);
|
||||||
|
|
||||||
int count = 0;
|
List<RevCommit> commits = new ArrayList<RevCommit>();
|
||||||
for (RevCommit c = walk.next(); c != null; c = walk.next())
|
for (RevCommit c : walk)
|
||||||
count++;
|
commits.add(c);
|
||||||
return count;
|
return commits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue