Merge branch 'master' into stable-4.4

* master:
  JGit CLI: allow to call git init with specific directory
  Redirect all Show output to outs
  Support git config [include] section with absolute path(s)
  Added filter for merge and non-merges commits.
  [findBugs] Prevent potential NPE in FS_POSIX.readUmask()
  [findBugs] Fix calculation of host header in SignerV4
  Update Orbit repository to S20160518051658 for Neon RC2
  Fix StashApply regarding handling of untracked files
  GC should not pack objects only referenced by ORIG_HEAD,...
  Make sure to overwrite files when "reset --hard" detects conflicts
  Allow setting FileMode to executable when applying patches in 
    ApplyCommand
  Fix config value get to return last instead of 1st just like git
  Remove UTF-8 checking duplication in Config lib subclasses
  Update Maven plugins
  Fix type parameter in javadoc in TestRepository.delete(String ref)
  TestRepository: Add delete() method
  Make BaseReceivePack.setAtomic public
  ReceivePack: Pass atomic setting from client to BatchRefUpdate

Change-Id: I5c9c5b7ccb23fb48b44b3da10b2c5d876d043d24
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
Matthias Sohn 2016-05-24 16:59:15 +02:00
commit 88524581cf
40 changed files with 632 additions and 57 deletions

View File

@ -586,6 +586,31 @@ public <T extends AnyObjectId> T update(String ref, T obj) throws Exception {
} }
} }
/**
* Delete a reference.
*
* @param ref
* the name of the reference to delete. This is normalized
* in the same way as {@link #update(String, AnyObjectId)}.
* @throws Exception
* @since 4.4
*/
public void delete(String ref) throws Exception {
ref = normalizeRef(ref);
RefUpdate u = db.updateRef(ref);
switch (u.delete()) {
case FAST_FORWARD:
case FORCED:
case NEW:
case NO_CHANGE:
updateServerInfo();
return;
default:
throw new IOException("Cannot delete " + ref + " " + u.getResult());
}
}
private static String normalizeRef(String ref) { private static String normalizeRef(String ref) {
if (Constants.HEAD.equals(ref)) { if (Constants.HEAD.equals(ref)) {
// nothing // nothing
@ -959,6 +984,15 @@ public RevCommit update(CommitBuilder to) throws Exception {
public RevCommit update(RevCommit to) throws Exception { public RevCommit update(RevCommit to) throws Exception {
return TestRepository.this.update(ref, to); return TestRepository.this.update(ref, to);
} }
/**
* Delete this branch.
* @throws Exception
* @since 4.4
*/
public void delete() throws Exception {
TestRepository.this.delete(ref);
}
} }
/** Helper to generate a commit. */ /** Helper to generate a commit. */

View File

@ -229,12 +229,12 @@ private static String formatAuthorizationHeader(
private static void addHostHeader(URL url, private static void addHostHeader(URL url,
Map<String, String> headers) { Map<String, String> headers) {
String hostHeader = url.getHost(); StringBuilder hostHeader = new StringBuilder(url.getHost());
int port = url.getPort(); int port = url.getPort();
if (port > -1) { if (port > -1) {
hostHeader.concat(":" + Integer.toString(port)); //$NON-NLS-1$ hostHeader.append(":").append(port); //$NON-NLS-1$
} }
headers.put("Host", hostHeader); //$NON-NLS-1$ headers.put("Host", hostHeader.toString()); //$NON-NLS-1$
} }
private static String canonicalizeHeaderNames( private static String canonicalizeHeaderNames(

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde?> <?pde?>
<!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform --> <!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
<target name="jgit-4.6" sequenceNumber="1462141948"> <target name="jgit-4.6" sequenceNumber="1463612069">
<locations> <locations>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.eclipse.jetty.client" version="9.2.13.v20150730"/> <unit id="org.eclipse.jetty.client" version="9.2.13.v20150730"/>
@ -39,8 +39,8 @@
<unit id="org.kohsuke.args4j.source" version="2.0.21.v201301150030"/> <unit id="org.kohsuke.args4j.source" version="2.0.21.v201301150030"/>
<unit id="org.hamcrest.core" version="1.3.0.v201303031735"/> <unit id="org.hamcrest.core" version="1.3.0.v201303031735"/>
<unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/> <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
<unit id="javaewah" version="0.7.9.v201401101600"/> <unit id="javaewah" version="0.7.9.v201605172130"/>
<unit id="javaewah.source" version="0.7.9.v201401101600"/> <unit id="javaewah.source" version="0.7.9.v201605172130"/>
<unit id="org.objenesis" version="1.0.0.v201505121915"/> <unit id="org.objenesis" version="1.0.0.v201505121915"/>
<unit id="org.objenesis.source" version="1.0.0.v201505121915"/> <unit id="org.objenesis.source" version="1.0.0.v201505121915"/>
<unit id="org.mockito" version="1.8.4.v201303031500"/> <unit id="org.mockito" version="1.8.4.v201303031500"/>
@ -58,7 +58,7 @@
<unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/> <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
<unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/> <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
<unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/> <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
<repository location="http://download.eclipse.org/tools/orbit/downloads/drops/S20160501200945/repository/"/> <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/S20160518051658/repository/"/>
</location> </location>
<location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
<unit id="org.eclipse.osgi" version="0.0.0"/> <unit id="org.eclipse.osgi" version="0.0.0"/>

View File

@ -1,7 +1,7 @@
target "jgit-4.6" with source configurePhase target "jgit-4.6" with source configurePhase
include "projects/jetty-9.2.13.tpd" include "projects/jetty-9.2.13.tpd"
include "orbit/S20160501200945-Neon.tpd" include "orbit/S20160518051658-Neon.tpd"
location "http://download.eclipse.org/releases/neon/" { location "http://download.eclipse.org/releases/neon/" {
org.eclipse.osgi lazy org.eclipse.osgi lazy

View File

@ -1,7 +1,7 @@
target "S20160501200945-Neon" with source configurePhase target "S20160518051658-Neon" with source configurePhase
// see http://download.eclipse.org/tools/orbit/downloads/ // see http://download.eclipse.org/tools/orbit/downloads/
location "http://download.eclipse.org/tools/orbit/downloads/drops/S20160501200945/repository/" { location "http://download.eclipse.org/tools/orbit/downloads/drops/S20160518051658/repository/" {
org.apache.ant [1.9.6.v201510161327,1.9.6.v201510161327] org.apache.ant [1.9.6.v201510161327,1.9.6.v201510161327]
org.apache.ant.source [1.9.6.v201510161327,1.9.6.v201510161327] org.apache.ant.source [1.9.6.v201510161327,1.9.6.v201510161327]
org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400] org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400]
@ -18,8 +18,8 @@ location "http://download.eclipse.org/tools/orbit/downloads/drops/S2016050120094
org.kohsuke.args4j.source [2.0.21.v201301150030,2.0.21.v201301150030] org.kohsuke.args4j.source [2.0.21.v201301150030,2.0.21.v201301150030]
org.hamcrest.core [1.3.0.v201303031735,1.3.0.v201303031735] org.hamcrest.core [1.3.0.v201303031735,1.3.0.v201303031735]
org.hamcrest.core.source [1.3.0.v201303031735,1.3.0.v201303031735] org.hamcrest.core.source [1.3.0.v201303031735,1.3.0.v201303031735]
javaewah [0.7.9.v201401101600,0.7.9.v201401101600] javaewah [0.7.9.v201605172130,0.7.9.v201605172130]
javaewah.source [0.7.9.v201401101600,0.7.9.v201401101600] javaewah.source [0.7.9.v201605172130,0.7.9.v201605172130]
org.objenesis [1.0.0.v201505121915,1.0.0.v201505121915] org.objenesis [1.0.0.v201505121915,1.0.0.v201505121915]
org.objenesis.source [1.0.0.v201505121915,1.0.0.v201505121915] org.objenesis.source [1.0.0.v201505121915,1.0.0.v201505121915]
org.mockito [1.8.4.v201303031500,1.8.4.v201303031500] org.mockito [1.8.4.v201303031500,1.8.4.v201303031500]

View File

@ -59,7 +59,7 @@
<name>JGit Tycho Parent</name> <name>JGit Tycho Parent</name>
<properties> <properties>
<tycho-version>0.23.0</tycho-version> <tycho-version>0.25.0</tycho-version>
<tycho-extras-version>${tycho-version}</tycho-extras-version> <tycho-extras-version>${tycho-version}</tycho-extras-version>
<target-platform>jgit-4.6</target-platform> <target-platform>jgit-4.6</target-platform>
</properties> </properties>
@ -149,7 +149,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId> <artifactId>maven-resources-plugin</artifactId>
<version>2.5</version> <version>2.7</version>
<configuration> <configuration>
<encoding>ISO-8859-1</encoding> <encoding>ISO-8859-1</encoding>
</configuration> </configuration>
@ -216,12 +216,12 @@
<plugin> <plugin>
<groupId>org.eclipse.cbi.maven.plugins</groupId> <groupId>org.eclipse.cbi.maven.plugins</groupId>
<artifactId>eclipse-jarsigner-plugin</artifactId> <artifactId>eclipse-jarsigner-plugin</artifactId>
<version>1.1.2</version> <version>1.1.3</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId> <artifactId>build-helper-maven-plugin</artifactId>
<version>1.9</version> <version>1.10</version>
</plugin> </plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>

View File

@ -25,6 +25,7 @@ Import-Package: org.eclipse.jgit.api;version="[4.4.0,4.5.0)",
org.eclipse.jgit.util;version="[4.4.0,4.5.0)", org.eclipse.jgit.util;version="[4.4.0,4.5.0)",
org.eclipse.jgit.util.io;version="[4.4.0,4.5.0)", org.eclipse.jgit.util.io;version="[4.4.0,4.5.0)",
org.hamcrest.core;bundle-version="[1.1.0,2.0.0)", org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
org.junit;version="[4.4.0,5.0.0)", org.junit;version="[4.11.0,5.0.0)",
org.junit.rules;version="[4.11.0,5.0.0)",
org.kohsuke.args4j;version="[2.0.12,2.1.0)" org.kohsuke.args4j;version="[2.0.12,2.1.0)"
Require-Bundle: org.tukaani.xz;bundle-version="[1.3.0,2.0.0)" Require-Bundle: org.tukaani.xz;bundle-version="[1.3.0,2.0.0)"

View File

@ -0,0 +1,90 @@
/*
* Copyright (C) 2016, Rüdiger Herrmann <ruediger.herrmann@gmx.de>
* 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.pgm;
import static org.junit.Assert.assertArrayEquals;
import java.io.File;
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
public class InitTest extends CLIRepositoryTestCase {
@Rule
public final TemporaryFolder tempFolder = new TemporaryFolder();
@Test
public void testInitBare() throws Exception {
File directory = tempFolder.getRoot();
String[] result = execute(
"git init '" + directory.getCanonicalPath() + "' --bare");
String[] expecteds = new String[] {
"Initialized empty Git repository in "
+ directory.getCanonicalPath(),
"" };
assertArrayEquals(expecteds, result);
}
@Test
public void testInitDirectory() throws Exception {
File workDirectory = tempFolder.getRoot();
File gitDirectory = new File(workDirectory, Constants.DOT_GIT);
String[] result = execute(
"git init '" + workDirectory.getCanonicalPath() + "'");
String[] expecteds = new String[] {
"Initialized empty Git repository in "
+ gitDirectory.getCanonicalPath(),
"" };
assertArrayEquals(expecteds, result);
}
}

View File

@ -4,6 +4,7 @@
* Copyright (C) 2010, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2010, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2010, Sasa Zivkov <sasa.zivkov@sap.com> * Copyright (C) 2010, Sasa Zivkov <sasa.zivkov@sap.com>
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
* Copyright (C) 2016, Rüdiger Herrmann <ruediger.herrmann@gmx.de>
* 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
@ -54,6 +55,7 @@
import org.eclipse.jgit.api.InitCommand; import org.eclipse.jgit.api.InitCommand;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.CLIText;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
@Command(common = true, usage = "usage_CreateAnEmptyGitRepository") @Command(common = true, usage = "usage_CreateAnEmptyGitRepository")
@ -61,6 +63,9 @@ class Init extends TextBuiltin {
@Option(name = "--bare", usage = "usage_CreateABareRepository") @Option(name = "--bare", usage = "usage_CreateABareRepository")
private boolean bare; private boolean bare;
@Argument(index = 0, metaVar = "metaVar_directory")
private String directory;
@Override @Override
protected final boolean requiresRepository() { protected final boolean requiresRepository() {
return false; return false;
@ -70,8 +75,12 @@ protected final boolean requiresRepository() {
protected void run() throws Exception { protected void run() throws Exception {
InitCommand command = Git.init(); InitCommand command = Git.init();
command.setBare(bare); command.setBare(bare);
if (gitdir != null) if (gitdir != null) {
command.setDirectory(new File(gitdir)); command.setDirectory(new File(gitdir));
}
if (directory != null) {
command.setDirectory(new File(directory));
}
Repository repository = command.call().getRepository(); Repository repository = command.call().getRepository();
outw.println(MessageFormat.format( outw.println(MessageFormat.format(
CLIText.get().initializedEmptyGitRepositoryIn, repository CLIText.get().initializedEmptyGitRepositoryIn, repository

View File

@ -63,6 +63,7 @@
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler; import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
@ -81,8 +82,7 @@ class Show extends TextBuiltin {
private final DateFormat fmt; private final DateFormat fmt;
private final DiffFormatter diffFmt = new DiffFormatter( // private DiffFormatter diffFmt;
new BufferedOutputStream(System.out));
@Argument(index = 0, metaVar = "metaVar_object") @Argument(index = 0, metaVar = "metaVar_object")
private String objectName; private String objectName;
@ -165,6 +165,12 @@ void noPrefix(@SuppressWarnings("unused") boolean on) {
fmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZZZZ", Locale.US); //$NON-NLS-1$ fmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZZZZ", Locale.US); //$NON-NLS-1$
} }
@Override
protected void init(final Repository repository, final String gitDir) {
super.init(repository, gitDir);
diffFmt = new DiffFormatter(new BufferedOutputStream(outs));
}
@SuppressWarnings("boxing") @SuppressWarnings("boxing")
@Override @Override
protected void run() throws Exception { protected void run() throws Exception {

View File

@ -51,6 +51,7 @@ Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)",
org.hamcrest;version="[1.1.0,2.0.0)", org.hamcrest;version="[1.1.0,2.0.0)",
org.junit;version="[4.4.0,5.0.0)", org.junit;version="[4.4.0,5.0.0)",
org.junit.experimental.theories;version="[4.4.0,5.0.0)", org.junit.experimental.theories;version="[4.4.0,5.0.0)",
org.junit.rules;version="[4.11.0,5.0.0)",
org.junit.runner;version="[4.4.0,5.0.0)", org.junit.runner;version="[4.4.0,5.0.0)",
org.junit.runners;version="[4.11.0,5.0.0)", org.junit.runners;version="[4.11.0,5.0.0)",
org.slf4j;version="[1.7.2,2.0.0)" org.slf4j;version="[1.7.2,2.0.0)"

View File

@ -44,6 +44,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.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -156,6 +157,33 @@ public void testModifyW() throws Exception {
b.getString(0, b.size(), false)); b.getString(0, b.size(), false));
} }
@Test
public void testAddM1() throws Exception {
ApplyResult result = init("M1", false, true);
assertEquals(1, result.getUpdatedFiles().size());
assertTrue(result.getUpdatedFiles().get(0).canExecute());
checkFile(new File(db.getWorkTree(), "M1"),
b.getString(0, b.size(), false));
}
@Test
public void testModifyM2() throws Exception {
ApplyResult result = init("M2", true, true);
assertEquals(1, result.getUpdatedFiles().size());
assertTrue(result.getUpdatedFiles().get(0).canExecute());
checkFile(new File(db.getWorkTree(), "M2"),
b.getString(0, b.size(), false));
}
@Test
public void testModifyM3() throws Exception {
ApplyResult result = init("M3", true, true);
assertEquals(1, result.getUpdatedFiles().size());
assertFalse(result.getUpdatedFiles().get(0).canExecute());
checkFile(new File(db.getWorkTree(), "M3"),
b.getString(0, b.size(), false));
}
@Test @Test
public void testModifyX() throws Exception { public void testModifyX() throws Exception {
ApplyResult result = init("X"); ApplyResult result = init("X");

View File

@ -53,7 +53,9 @@
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.junit.Test; import org.junit.Test;
public class LogCommandTest extends RepositoryTestCase { public class LogCommandTest extends RepositoryTestCase {
@ -210,4 +212,81 @@ public void logAllCommitsWithSkipAndMaxCount() throws Exception {
assertEquals("commit#2", commit.getShortMessage()); assertEquals("commit#2", commit.getShortMessage());
assertFalse(log.hasNext()); assertFalse(log.hasNext());
} }
@Test
public void logOnlyMergeCommits() throws Exception {
setCommitsAndMerge();
Git git = Git.wrap(db);
Iterable<RevCommit> commits = git.log().all().call();
Iterator<RevCommit> i = commits.iterator();
RevCommit commit = i.next();
assertEquals("merge s0 with m1", commit.getFullMessage());
commit = i.next();
assertEquals("s0", commit.getFullMessage());
commit = i.next();
assertEquals("m1", commit.getFullMessage());
commit = i.next();
assertEquals("m0", commit.getFullMessage());
assertFalse(i.hasNext());
commits = git.log().setRevFilter(RevFilter.ONLY_MERGES).call();
i = commits.iterator();
commit = i.next();
assertEquals("merge s0 with m1", commit.getFullMessage());
assertFalse(i.hasNext());
}
@Test
public void logNoMergeCommits() throws Exception {
setCommitsAndMerge();
Git git = Git.wrap(db);
Iterable<RevCommit> commits = git.log().all().call();
Iterator<RevCommit> i = commits.iterator();
RevCommit commit = i.next();
assertEquals("merge s0 with m1", commit.getFullMessage());
commit = i.next();
assertEquals("s0", commit.getFullMessage());
commit = i.next();
assertEquals("m1", commit.getFullMessage());
commit = i.next();
assertEquals("m0", commit.getFullMessage());
assertFalse(i.hasNext());
commits = git.log().setRevFilter(RevFilter.NO_MERGES).call();
i = commits.iterator();
commit = i.next();
assertEquals("m1", commit.getFullMessage());
commit = i.next();
assertEquals("s0", commit.getFullMessage());
commit = i.next();
assertEquals("m0", commit.getFullMessage());
assertFalse(i.hasNext());
}
private void setCommitsAndMerge() throws Exception {
Git git = Git.wrap(db);
writeTrashFile("file1", "1\n2\n3\n4\n");
git.add().addFilepattern("file1").call();
RevCommit masterCommit0 = git.commit().setMessage("m0").call();
createBranch(masterCommit0, "refs/heads/side");
checkoutBranch("refs/heads/side");
writeTrashFile("file2", "1\n2\n3\n4\n5\n6\n7\n8\n");
git.add().addFilepattern("file2").call();
RevCommit c = git.commit().setMessage("s0").call();
checkoutBranch("refs/heads/master");
writeTrashFile("file3", "1\n2\n");
git.add().addFilepattern("file3").call();
git.commit().setMessage("m1").call();
git.merge().include(c.getId())
.setStrategy(MergeStrategy.RESOLVE)
.setMessage("merge s0 with m1").call();
}
} }

View File

@ -58,6 +58,7 @@
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.MergeResult.MergeStatus;
import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
@ -184,6 +185,40 @@ public void testPullConflict() throws Exception {
.getRepositoryState()); .getRepositoryState());
} }
@Test
public void testPullWithUntrackedStash() throws Exception {
target.pull().call();
// change the source file
writeToFile(sourceFile, "Source change");
source.add().addFilepattern("SomeFile.txt").call();
source.commit().setMessage("Source change in remote").call();
// write untracked file
writeToFile(new File(dbTarget.getWorkTree(), "untracked.txt"),
"untracked");
RevCommit stash = target.stashCreate().setIndexMessage("message here")
.setIncludeUntracked(true).call();
assertNotNull(stash);
assertTrue(target.status().call().isClean());
// pull from source
assertTrue(target.pull().call().isSuccessful());
assertEquals("[SomeFile.txt, mode:100644, content:Source change]",
indexState(dbTarget, CONTENT));
assertFalse(JGitTestUtil.check(dbTarget, "untracked.txt"));
assertEquals("Source change",
JGitTestUtil.read(dbTarget, "SomeFile.txt"));
// apply the stash
target.stashApply().setStashRef(stash.getName()).call();
assertEquals("[SomeFile.txt, mode:100644, content:Source change]",
indexState(dbTarget, CONTENT));
assertEquals("untracked", JGitTestUtil.read(dbTarget, "untracked.txt"));
assertEquals("Source change",
JGitTestUtil.read(dbTarget, "SomeFile.txt"));
}
@Test @Test
public void testPullLocalConflict() throws Exception { public void testPullLocalConflict() throws Exception {
target.branchCreate().setName("basedOnMaster").setStartPoint( target.branchCreate().setName("basedOnMaster").setStartPoint(

View File

@ -156,6 +156,34 @@ public void testHardReset() throws JGitInternalException,
assertEquals(prevHead, db.readOrigHead()); assertEquals(prevHead, db.readOrigHead());
} }
@Test
public void testHardResetWithConflicts_DoOverWriteUntrackedFile()
throws JGitInternalException,
AmbiguousObjectException, IOException, GitAPIException {
setupRepository();
git.rm().setCached(true).addFilepattern("a.txt").call();
assertTrue(new File(db.getWorkTree(), "a.txt").exists());
git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD)
.call();
assertTrue(new File(db.getWorkTree(), "a.txt").exists());
assertEquals("content", read(new File(db.getWorkTree(), "a.txt")));
}
@Test
public void testHardResetWithConflicts_DoDeleteFileFolderConflicts()
throws JGitInternalException,
AmbiguousObjectException, IOException, GitAPIException {
setupRepository();
writeTrashFile("d/c.txt", "x");
git.add().addFilepattern("d/c.txt").call();
FileUtils.delete(new File(db.getWorkTree(), "d"), FileUtils.RECURSIVE);
writeTrashFile("d", "y");
git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD)
.call();
assertFalse(new File(db.getWorkTree(), "d").exists());
}
@Test @Test
public void testResetToNonexistingHEAD() throws JGitInternalException, public void testResetToNonexistingHEAD() throws JGitInternalException,
AmbiguousObjectException, IOException, GitAPIException { AmbiguousObjectException, IOException, GitAPIException {

View File

@ -56,6 +56,9 @@
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
@ -64,18 +67,29 @@
import org.eclipse.jgit.api.MergeCommand.FastForwardMode; import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.junit.MockSystemReader; import org.eclipse.jgit.junit.MockSystemReader;
import org.eclipse.jgit.merge.MergeConfig; import org.eclipse.jgit.merge.MergeConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.SystemReader; import org.eclipse.jgit.util.SystemReader;
import org.junit.After; import org.junit.After;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
/** /**
* Test reading of git config * Test reading of git config
*/ */
public class ConfigTest { public class ConfigTest {
@Rule
public ExpectedException expectedEx = ExpectedException.none();
@Rule
public TemporaryFolder tmp = new TemporaryFolder();
@After @After
public void tearDown() { public void tearDown() {
SystemReader.setInstance(null); SystemReader.setInstance(null);
@ -739,6 +753,81 @@ public void testEmptyValueAtEof() throws Exception {
c.getStringList("a", null, "x")); c.getStringList("a", null, "x"));
} }
@Test
public void testReadMultipleValuesForName() throws ConfigInvalidException {
Config c = parse("[foo]\nbar=false\nbar=true\n");
assertTrue(c.getBoolean("foo", "bar", false));
}
@Test
public void testIncludeInvalidName() throws ConfigInvalidException {
expectedEx.expect(ConfigInvalidException.class);
expectedEx.expectMessage(JGitText.get().invalidLineInConfigFile);
parse("[include]\nbar\n");
}
@Test
public void testIncludeNoValue() throws ConfigInvalidException {
expectedEx.expect(ConfigInvalidException.class);
expectedEx.expectMessage(JGitText.get().invalidLineInConfigFile);
parse("[include]\npath\n");
}
@Test
public void testIncludeEmptyValue() throws ConfigInvalidException {
expectedEx.expect(ConfigInvalidException.class);
expectedEx.expectMessage(JGitText.get().invalidLineInConfigFile);
parse("[include]\npath=\n");
}
@Test
public void testIncludeValuePathNotFound() throws ConfigInvalidException {
String notFound = "/not/found";
expectedEx.expect(ConfigInvalidException.class);
expectedEx.expectMessage(notFound);
parse("[include]\npath=" + notFound + "\n");
}
@Test
public void testIncludeTooManyRecursions() throws IOException {
File config = tmp.newFile("config");
String include = "[include]\npath=" + config.toPath() + "\n";
Files.write(config.toPath(), include.getBytes());
FileBasedConfig fbConfig = new FileBasedConfig(null, config,
FS.DETECTED);
try {
fbConfig.load();
fail();
} catch (ConfigInvalidException cie) {
assertEquals(JGitText.get().tooManyIncludeRecursions,
cie.getCause().getMessage());
}
}
@Test
public void testInclude() throws IOException, ConfigInvalidException {
File config = tmp.newFile("config");
File more = tmp.newFile("config.more");
File other = tmp.newFile("config.other");
String fooBar = "[foo]\nbar=true\n";
String includeMore = "[include]\npath=" + more.toPath() + "\n";
String includeOther = "path=" + other.toPath() + "\n";
String fooPlus = fooBar + includeMore + includeOther;
Files.write(config.toPath(), fooPlus.getBytes());
String fooMore = "[foo]\nmore=bar\n";
Files.write(more.toPath(), fooMore.getBytes());
String otherMore = "[other]\nmore=bar\n";
Files.write(other.toPath(), otherMore.getBytes());
Config parsed = parse("[include]\npath=" + config.toPath() + "\n");
assertTrue(parsed.getBoolean("foo", "bar", false));
assertEquals("bar", parsed.getString("foo", null, "more"));
assertEquals("bar", parsed.getString("other", null, "more"));
}
private static void assertReadLong(long exp) throws ConfigInvalidException { private static void assertReadLong(long exp) throws ConfigInvalidException {
assertReadLong(exp, String.valueOf(exp)); assertReadLong(exp, String.valueOf(exp));
} }

View File

@ -337,6 +337,7 @@ invalidId0=Invalid id
invalidIdLength=Invalid id length {0}; should be {1} invalidIdLength=Invalid id length {0}; should be {1}
invalidIgnoreParamSubmodule=Found invalid ignore param for submodule {0}. invalidIgnoreParamSubmodule=Found invalid ignore param for submodule {0}.
invalidIgnoreRule=Exception caught while parsing ignore rule ''{0}''. invalidIgnoreRule=Exception caught while parsing ignore rule ''{0}''.
invalidIncludedPathInConfigFile=Invalid included path in config file: {0}
invalidIntegerValue=Invalid integer value: {0}.{1}={2} invalidIntegerValue=Invalid integer value: {0}.{1}={2}
invalidKey=Invalid key: {0} invalidKey=Invalid key: {0}
invalidLineInConfigFile=Invalid line in config file invalidLineInConfigFile=Invalid line in config file
@ -592,6 +593,7 @@ tagNameInvalid=tag name {0} is invalid
tagOnRepoWithoutHEADCurrentlyNotSupported=Tag on repository without HEAD currently not supported tagOnRepoWithoutHEADCurrentlyNotSupported=Tag on repository without HEAD currently not supported
theFactoryMustNotBeNull=The factory must not be null theFactoryMustNotBeNull=The factory must not be null
timerAlreadyTerminated=Timer already terminated timerAlreadyTerminated=Timer already terminated
tooManyIncludeRecursions=Too many recursions; circular includes in config file(s)?
topologicalSortRequired=Topological sort required. topologicalSortRequired=Topological sort required.
transactionAborted=transaction aborted transactionAborted=transaction aborted
transportExceptionBadRef=Empty ref: {0}: {1} transportExceptionBadRef=Empty ref: {0}: {1}

View File

@ -58,6 +58,7 @@
import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.patch.FileHeader; import org.eclipse.jgit.patch.FileHeader;
import org.eclipse.jgit.patch.HunkHeader; import org.eclipse.jgit.patch.HunkHeader;
@ -260,6 +261,8 @@ private void apply(File f, FileHeader fh)
FileWriter fw = new FileWriter(f); FileWriter fw = new FileWriter(f);
fw.write(sb.toString()); fw.write(sb.toString());
fw.close(); fw.close();
getRepository().getFS().setExecute(f, fh.getNewMode() == FileMode.EXECUTABLE_FILE);
} }
private static boolean isChanged(List<String> ol, List<String> nl) { private static boolean isChanged(List<String> ol, List<String> nl) {

View File

@ -65,6 +65,7 @@
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.AndRevFilter; import org.eclipse.jgit.revwalk.filter.AndRevFilter;
import org.eclipse.jgit.revwalk.filter.MaxCountRevFilter; import org.eclipse.jgit.revwalk.filter.MaxCountRevFilter;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.revwalk.filter.SkipRevFilter; import org.eclipse.jgit.revwalk.filter.SkipRevFilter;
import org.eclipse.jgit.treewalk.filter.AndTreeFilter; import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
import org.eclipse.jgit.treewalk.filter.PathFilter; import org.eclipse.jgit.treewalk.filter.PathFilter;
@ -104,6 +105,8 @@ public class LogCommand extends GitCommand<Iterable<RevCommit>> {
private boolean startSpecified = false; private boolean startSpecified = false;
private RevFilter revFilter;
private final List<PathFilter> pathFilters = new ArrayList<PathFilter>(); private final List<PathFilter> pathFilters = new ArrayList<PathFilter>();
private int maxCount = -1; private int maxCount = -1;
@ -156,6 +159,11 @@ else if (maxCount > -1)
e); e);
} }
} }
if (this.revFilter != null) {
walk.setRevFilter(this.revFilter);
}
setCallable(false); setCallable(false);
return walk; return walk;
} }
@ -342,4 +350,21 @@ private LogCommand add(boolean include, AnyObjectId start)
, start), e); , start), e);
} }
} }
/**
* Sets a filter for the <code>LogCommand</code>.
*
*
* @param aFilter
* the filter that this instance of <code>LogCommand</code>
* should use
* @return {@code this}
* @since 4.4
*/
public LogCommand setRevFilter(RevFilter aFilter) {
checkCallable();
this.revFilter = aFilter;
return this;
}
} }

View File

@ -223,8 +223,13 @@ public ObjectId call() throws GitAPIException,
ResolveMerger untrackedMerger = (ResolveMerger) strategy ResolveMerger untrackedMerger = (ResolveMerger) strategy
.newMerger(repo, true); .newMerger(repo, true);
untrackedMerger.setCommitNames(new String[] { untrackedMerger.setCommitNames(new String[] {
"stashed HEAD", "HEAD", "untracked files" }); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ "null", "HEAD", "untracked files" }); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
untrackedMerger.setBase(stashHeadCommit); // There is no common base for HEAD & untracked files
// because the commit for untracked files has no parent. If
// we use stashHeadCommit as common base (as in the other
// merges) we potentially report conflicts for files
// which are not even member of untracked files commit
untrackedMerger.setBase(null);
boolean ok = untrackedMerger.merge(headCommit, boolean ok = untrackedMerger.merge(headCommit,
untrackedCommit); untrackedCommit);
if (ok) if (ok)

View File

@ -354,8 +354,16 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i,
// The index entry is missing // The index entry is missing
if (f != null && !FileMode.TREE.equals(f.getEntryFileMode()) if (f != null && !FileMode.TREE.equals(f.getEntryFileMode())
&& !f.isEntryIgnored()) { && !f.isEntryIgnored()) {
if (failOnConflict) {
// don't overwrite an untracked and not ignored file // don't overwrite an untracked and not ignored file
conflicts.add(walk.getPathString()); conflicts.add(walk.getPathString());
} else {
// failOnConflict is false. Putting something to conflicts
// would mean we delete it. Instead we want the mergeCommit
// content to be checked out.
update(m.getEntryPathString(), m.getEntryObjectId(),
m.getEntryFileMode());
}
} else } else
update(m.getEntryPathString(), m.getEntryObjectId(), update(m.getEntryPathString(), m.getEntryObjectId(),
m.getEntryFileMode()); m.getEntryFileMode());
@ -390,6 +398,9 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i,
if (f != null) { if (f != null) {
// There is a file/folder for that path in the working tree // There is a file/folder for that path in the working tree
if (walk.isDirectoryFileConflict()) { if (walk.isDirectoryFileConflict()) {
// We put it in conflicts. Even if failOnConflict is false
// this would cause the path to be deleted. Thats exactly what
// we want in this situation
conflicts.add(walk.getPathString()); conflicts.add(walk.getPathString());
} else { } else {
// No file/folder conflict exists. All entries are files or // No file/folder conflict exists. All entries are files or

View File

@ -396,6 +396,7 @@ public static JGitText get() {
/***/ public String invalidIdLength; /***/ public String invalidIdLength;
/***/ public String invalidIgnoreParamSubmodule; /***/ public String invalidIgnoreParamSubmodule;
/***/ public String invalidIgnoreRule; /***/ public String invalidIgnoreRule;
/***/ public String invalidIncludedPathInConfigFile;
/***/ public String invalidIntegerValue; /***/ public String invalidIntegerValue;
/***/ public String invalidKey; /***/ public String invalidKey;
/***/ public String invalidLineInConfigFile; /***/ public String invalidLineInConfigFile;
@ -652,6 +653,7 @@ public static JGitText get() {
/***/ public String transactionAborted; /***/ public String transactionAborted;
/***/ public String theFactoryMustNotBeNull; /***/ public String theFactoryMustNotBeNull;
/***/ public String timerAlreadyTerminated; /***/ public String timerAlreadyTerminated;
/***/ public String tooManyIncludeRecursions;
/***/ public String topologicalSortRequired; /***/ public String topologicalSortRequired;
/***/ public String transportExceptionBadRef; /***/ public String transportExceptionBadRef;
/***/ public String transportExceptionEmptyRef; /***/ public String transportExceptionEmptyRef;

View File

@ -241,7 +241,12 @@ private Collection<Ref> getAllRefs() throws IOException {
if (!addl.isEmpty()) { if (!addl.isEmpty()) {
List<Ref> all = new ArrayList<>(refs.size() + addl.size()); List<Ref> all = new ArrayList<>(refs.size() + addl.size());
all.addAll(refs); all.addAll(refs);
all.addAll(addl); // add additional refs which start with refs/
for (Ref r : addl) {
if (r.getName().startsWith(Constants.R_REFS)) {
all.add(r);
}
}
return all; return all;
} }
return refs; return refs;

View File

@ -655,8 +655,12 @@ private Set<ObjectId> listRefLogObjects(Ref ref, long minTime) throws IOExceptio
} }
/** /**
* Returns a collection of all refs and additional refs (e.g. FETCH_HEAD, * Returns a collection of all refs and additional refs.
* MERGE_HEAD, ...) *
* Additional refs which don't start with "refs/" are not returned because
* they should not save objects from being garbage collected. Examples for
* such references are ORIG_HEAD, MERGE_HEAD, FETCH_HEAD and
* CHERRY_PICK_HEAD.
* *
* @return a collection of refs pointing to live objects. * @return a collection of refs pointing to live objects.
* @throws IOException * @throws IOException
@ -668,7 +672,12 @@ private Collection<Ref> getAllRefs() throws IOException {
if (!addl.isEmpty()) { if (!addl.isEmpty()) {
List<Ref> all = new ArrayList<>(refs.size() + addl.size()); List<Ref> all = new ArrayList<>(refs.size() + addl.size());
all.addAll(refs); all.addAll(refs);
all.addAll(addl); // add additional refs which start with refs/
for (Ref r : addl) {
if (r.getName().startsWith(Constants.R_REFS)) {
all.add(r);
}
}
return all; return all;
} }
return refs; return refs;

View File

@ -80,8 +80,7 @@ public BlobBasedConfig(Config base, final byte[] blob)
throws ConfigInvalidException { throws ConfigInvalidException {
super(base); super(base);
final String decoded; final String decoded;
if (blob.length >= 3 && blob[0] == (byte) 0xEF if (isUtf8(blob)) {
&& blob[1] == (byte) 0xBB && blob[2] == (byte) 0xBF) {
decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET, decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET,
blob, 3, blob.length); blob, 3, blob.length);
} else { } else {

View File

@ -51,6 +51,8 @@
package org.eclipse.jgit.lib; package org.eclipse.jgit.lib;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -64,6 +66,8 @@
import org.eclipse.jgit.events.ListenerHandle; import org.eclipse.jgit.events.ListenerHandle;
import org.eclipse.jgit.events.ListenerList; import org.eclipse.jgit.events.ListenerList;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.StringUtils; import org.eclipse.jgit.util.StringUtils;
@ -75,6 +79,7 @@ public class Config {
private static final long KiB = 1024; private static final long KiB = 1024;
private static final long MiB = 1024 * KiB; private static final long MiB = 1024 * KiB;
private static final long GiB = 1024 * MiB; private static final long GiB = 1024 * MiB;
private static final int MAX_DEPTH = 999;
/** the change listeners */ /** the change listeners */
private final ListenerList listeners = new ListenerList(); private final ListenerList listeners = new ListenerList();
@ -633,13 +638,14 @@ protected void fireConfigChangedEvent() {
private String getRawString(final String section, final String subsection, private String getRawString(final String section, final String subsection,
final String name) { final String name) {
String[] lst = getRawStringList(section, subsection, name); String[] lst = getRawStringList(section, subsection, name);
if (lst != null) if (lst != null) {
return lst[0]; return lst[lst.length - 1];
else if (baseConfig != null) } else if (baseConfig != null) {
return baseConfig.getRawString(section, subsection, name); return baseConfig.getRawString(section, subsection, name);
else } else {
return null; return null;
} }
}
private String[] getRawStringList(String section, String subsection, private String[] getRawStringList(String section, String subsection,
String name) { String name) {
@ -1026,6 +1032,15 @@ public String toText() {
* made to {@code this}. * made to {@code this}.
*/ */
public void fromText(final String text) throws ConfigInvalidException { public void fromText(final String text) throws ConfigInvalidException {
state.set(newState(fromTextRecurse(text, 1)));
}
private List<ConfigLine> fromTextRecurse(final String text, int depth)
throws ConfigInvalidException {
if (depth > MAX_DEPTH) {
throw new ConfigInvalidException(
JGitText.get().tooManyIncludeRecursions);
}
final List<ConfigLine> newEntries = new ArrayList<ConfigLine>(); final List<ConfigLine> newEntries = new ArrayList<ConfigLine>();
final StringReader in = new StringReader(text); final StringReader in = new StringReader(text);
ConfigLine last = null; ConfigLine last = null;
@ -1084,11 +1099,38 @@ public void fromText(final String text) throws ConfigInvalidException {
} else } else
e.value = readValue(in, false, -1); e.value = readValue(in, false, -1);
if (e.section.equals("include")) { //$NON-NLS-1$
addIncludedConfig(newEntries, e, depth);
}
} else } else
throw new ConfigInvalidException(JGitText.get().invalidLineInConfigFile); throw new ConfigInvalidException(JGitText.get().invalidLineInConfigFile);
} }
state.set(newState(newEntries)); return newEntries;
}
private void addIncludedConfig(final List<ConfigLine> newEntries,
ConfigLine line, int depth) throws ConfigInvalidException {
if (!line.name.equals("path") || //$NON-NLS-1$
line.value == null || line.value.equals(MAGIC_EMPTY_VALUE)) {
throw new ConfigInvalidException(
JGitText.get().invalidLineInConfigFile);
}
File path = new File(line.value);
try {
byte[] bytes = IO.readFully(path);
String decoded;
if (isUtf8(bytes)) {
decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET,
bytes, 3, bytes.length);
} else {
decoded = RawParseUtils.decode(bytes);
}
newEntries.addAll(fromTextRecurse(decoded, depth + 1));
} catch (IOException ioe) {
throw new ConfigInvalidException(MessageFormat.format(
JGitText.get().invalidIncludedPathInConfigFile, path));
}
} }
private ConfigSnapshot newState() { private ConfigSnapshot newState() {
@ -1108,6 +1150,19 @@ protected void clear() {
state.set(newState()); state.set(newState());
} }
/**
* Check if bytes should be treated as UTF-8 or not.
*
* @param bytes
* the bytes to check encoding for.
* @return true if bytes should be treated as UTF-8, false otherwise.
* @since 4.4
*/
protected boolean isUtf8(final byte[] bytes) {
return bytes.length >= 3 && bytes[0] == (byte) 0xEF
&& bytes[1] == (byte) 0xBB && bytes[2] == (byte) 0xBF;
}
private static String readSectionName(final StringReader in) private static String readSectionName(final StringReader in)
throws ConfigInvalidException { throws ConfigInvalidException {
final StringBuilder name = new StringBuilder(); final StringBuilder name = new StringBuilder();

View File

@ -82,6 +82,7 @@
* <b>Merge filters:</b> * <b>Merge filters:</b>
* <ul> * <ul>
* <li>Skip all merges: {@link #NO_MERGES}.</li> * <li>Skip all merges: {@link #NO_MERGES}.</li>
* <li>Skip all non-merges: {@link #ONLY_MERGES}</li>
* </ul> * </ul>
* *
* <p> * <p>
@ -143,6 +144,37 @@ public String toString() {
} }
} }
/**
* Filter including only merge commits, excluding all commits with less than
* two parents (thread safe).
*
* @since 4.4
*/
public static final RevFilter ONLY_MERGES = new OnlyMergesFilter();
private static final class OnlyMergesFilter extends RevFilter {
@Override
public boolean include(RevWalk walker, RevCommit c) {
return c.getParentCount() >= 2;
}
@Override
public RevFilter clone() {
return this;
}
@Override
public boolean requiresCommitBody() {
return false;
}
@Override
public String toString() {
return "ONLY_MERGES"; //$NON-NLS-1$
}
}
/** Excludes commits with more than one parent (thread safe). */ /** Excludes commits with more than one parent (thread safe). */
public static final RevFilter NO_MERGES = new NoMergesFilter(); public static final RevFilter NO_MERGES = new NoMergesFilter();

View File

@ -147,8 +147,7 @@ public void load() throws IOException, ConfigInvalidException {
snapshot = newSnapshot; snapshot = newSnapshot;
} else { } else {
final String decoded; final String decoded;
if (in.length >= 3 && in[0] == (byte) 0xEF if (isUtf8(in)) {
&& in[1] == (byte) 0xBB && in[2] == (byte) 0xBF) {
decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET, decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET,
in, 3, in.length); in, 3, in.length);
utf8Bom = true; utf8Bom = true;

View File

@ -176,6 +176,12 @@ public Set<String> getCapabilities() {
/** Should an incoming transfer permit non-fast-forward requests? */ /** Should an incoming transfer permit non-fast-forward requests? */
private boolean allowNonFastForwards; private boolean allowNonFastForwards;
/**
* Should the requested ref updates be performed as a single atomic
* transaction?
*/
private boolean atomic;
private boolean allowOfsDelta; private boolean allowOfsDelta;
private boolean allowQuiet = true; private boolean allowQuiet = true;
@ -607,6 +613,25 @@ public void setAllowNonFastForwards(final boolean canRewind) {
allowNonFastForwards = canRewind; allowNonFastForwards = canRewind;
} }
/**
* @return true if the client's commands should be performed as a single
* atomic transaction.
* @since 4.4
*/
public boolean isAtomic() {
return atomic;
}
/**
* @param atomic
* true to perform the client's commands as a single atomic
* transaction.
* @since 4.4
*/
public void setAtomic(boolean atomic) {
this.atomic = atomic;
}
/** @return identity of the user making the changes in the reflog. */ /** @return identity of the user making the changes in the reflog. */
public PersonIdent getRefLogIdent() { public PersonIdent getRefLogIdent() {
return refLogIdent; return refLogIdent;
@ -1483,6 +1508,7 @@ protected void executeCommands() {
BatchRefUpdate batch = db.getRefDatabase().newBatchUpdate(); BatchRefUpdate batch = db.getRefDatabase().newBatchUpdate();
batch.setAllowNonFastForwards(isAllowNonFastForwards()); batch.setAllowNonFastForwards(isAllowNonFastForwards());
batch.setAtomic(isAtomic());
batch.setRefLogIdent(getRefLogIdent()); batch.setRefLogIdent(getRefLogIdent());
batch.setRefLogMessage("push", true); //$NON-NLS-1$ batch.setRefLogMessage("push", true); //$NON-NLS-1$
batch.addCommand(toApply); batch.addCommand(toApply);

View File

@ -201,6 +201,8 @@ private void service() throws IOException {
if (unpackError == null) { if (unpackError == null) {
boolean atomic = isCapabilityEnabled(CAPABILITY_ATOMIC); boolean atomic = isCapabilityEnabled(CAPABILITY_ATOMIC);
setAtomic(atomic);
validateCommands(); validateCommands();
if (atomic && anyRejects()) if (atomic && anyRejects())
failPendingCommands(); failPendingCommands();

View File

@ -122,7 +122,7 @@ private static int readUmask() {
.defaultCharset().name()))) { .defaultCharset().name()))) {
if (p.waitFor() == 0) { if (p.waitFor() == 0) {
String s = lineRead.readLine(); String s = lineRead.readLine();
if (s.matches("0?\\d{3}")) { //$NON-NLS-1$ if (s != null && s.matches("0?\\d{3}")) { //$NON-NLS-1$
return Integer.parseInt(s, 8); return Integer.parseInt(s, 8);
} }
} }

36
pom.xml
View File

@ -206,8 +206,8 @@
<httpclient-version>4.3.6</httpclient-version> <httpclient-version>4.3.6</httpclient-version>
<slf4j-version>1.7.2</slf4j-version> <slf4j-version>1.7.2</slf4j-version>
<log4j-version>1.2.15</log4j-version> <log4j-version>1.2.15</log4j-version>
<maven-javadoc-plugin-version>2.10.1</maven-javadoc-plugin-version> <maven-javadoc-plugin-version>2.10.3</maven-javadoc-plugin-version>
<tycho-extras-version>0.23.0</tycho-extras-version> <tycho-extras-version>0.25.0</tycho-extras-version>
<gson-version>2.2.4</gson-version> <gson-version>2.2.4</gson-version>
<!-- Properties to enable jacoco code coverage analysis --> <!-- Properties to enable jacoco code coverage analysis -->
@ -259,7 +259,7 @@
<plugin> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version> <version>3.5.1</version>
<configuration> <configuration>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<source>1.7</source> <source>1.7</source>
@ -269,13 +269,13 @@
<plugin> <plugin>
<artifactId>maven-clean-plugin</artifactId> <artifactId>maven-clean-plugin</artifactId>
<version>2.6.1</version> <version>3.0.0</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>2.3</version> <version>2.4.3</version>
</plugin> </plugin>
<plugin> <plugin>
@ -293,7 +293,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>2.4</version> <version>3.0.0</version>
</plugin> </plugin>
<plugin> <plugin>
@ -305,7 +305,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version> <version>2.19.1</version>
<configuration> <configuration>
<forkCount>${test-fork-count}</forkCount> <forkCount>${test-fork-count}</forkCount>
<reuseForks>true</reuseForks> <reuseForks>true</reuseForks>
@ -315,13 +315,13 @@
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId> <artifactId>build-helper-maven-plugin</artifactId>
<version>1.9</version> <version>1.10</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId> <artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version> <version>3.0.3</version>
<configuration> <configuration>
<findbugsXmlOutput>true</findbugsXmlOutput> <findbugsXmlOutput>true</findbugsXmlOutput>
<failOnError>false</failOnError> <failOnError>false</failOnError>
@ -338,7 +338,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId> <artifactId>maven-pmd-plugin</artifactId>
<version>3.4</version> <version>3.6</version>
<configuration> <configuration>
<sourceEncoding>utf-8</sourceEncoding> <sourceEncoding>utf-8</sourceEncoding>
<minimumTokens>100</minimumTokens> <minimumTokens>100</minimumTokens>
@ -358,7 +358,7 @@
<plugin> <plugin>
<groupId>org.eclipse.cbi.maven.plugins</groupId> <groupId>org.eclipse.cbi.maven.plugins</groupId>
<artifactId>eclipse-jarsigner-plugin</artifactId> <artifactId>eclipse-jarsigner-plugin</artifactId>
<version>1.1.2</version> <version>1.1.3</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.eclipse.tycho.extras</groupId> <groupId>org.eclipse.tycho.extras</groupId>
@ -373,24 +373,24 @@
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.1.201405082137</version> <version>0.7.6.201602180812</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId> <artifactId>maven-site-plugin</artifactId>
<version>3.4</version> <version>3.5.1</version>
<dependencies> <dependencies>
<dependency><!-- add support for ssh/scp --> <dependency><!-- add support for ssh/scp -->
<groupId>org.apache.maven.wagon</groupId> <groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId> <artifactId>wagon-ssh</artifactId>
<version>2.7</version> <version>2.10</version>
</dependency> </dependency>
</dependencies> </dependencies>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId> <artifactId>maven-surefire-report-plugin</artifactId>
<version>2.18.1</version> <version>2.19.1</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@ -400,7 +400,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId> <artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.8</version> <version>2.9</version>
</plugin> </plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
@ -526,12 +526,12 @@
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId> <artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version> <version>3.0.3</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId> <artifactId>maven-surefire-report-plugin</artifactId>
<version>2.18.1</version> <version>2.19.1</version>
<configuration> <configuration>
<aggregate>true</aggregate> <aggregate>true</aggregate>
<alwaysGenerateSurefireReport>false</alwaysGenerateSurefireReport> <alwaysGenerateSurefireReport>false</alwaysGenerateSurefireReport>