From 30f9d25d77ccb5cd978d4cf8fa389ec819e90e95 Mon Sep 17 00:00:00 2001 From: Philip L. McMahon <philip.l.mcmahon@gmail.com> Date: Fri, 27 Jan 2012 02:02:19 -0500 Subject: [PATCH] Correct update of HEAD symbolic reference when target is a tag. --- src/com/gitblit/utils/JGitUtils.java | 538 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 476 insertions(+), 62 deletions(-) diff --git a/src/com/gitblit/utils/JGitUtils.java b/src/com/gitblit/utils/JGitUtils.java index 03a5d00..05c0852 100644 --- a/src/com/gitblit/utils/JGitUtils.java +++ b/src/com/gitblit/utils/JGitUtils.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -36,6 +37,8 @@ import org.eclipse.jgit.api.CloneCommand; import org.eclipse.jgit.api.FetchCommand; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.ResetCommand; +import org.eclipse.jgit.api.ResetCommand.ResetType; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.diff.DiffFormatter; @@ -44,23 +47,30 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.StopWalkException; +import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefUpdate.Result; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryCache.FileKey; import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.lib.TreeFormatter; import org.eclipse.jgit.revwalk.RevBlob; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevSort; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.revwalk.filter.CommitTimeRevFilter; import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.storage.file.FileRepository; +import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.treewalk.TreeWalk; @@ -91,6 +101,29 @@ static final Logger LOGGER = LoggerFactory.getLogger(JGitUtils.class); /** + * Log an error message and exception. + * + * @param t + * @param repository + * if repository is not null it MUST be the {0} parameter in the + * pattern. + * @param pattern + * @param objects + */ + private static void error(Throwable t, Repository repository, String pattern, Object... objects) { + List<Object> parameters = new ArrayList<Object>(); + if (objects != null && objects.length > 0) { + for (Object o : objects) { + parameters.add(o); + } + } + if (repository != null) { + parameters.add(0, repository.getDirectory().getAbsolutePath()); + } + LOGGER.error(MessageFormat.format(pattern, parameters.toArray()), t); + } + + /** * Returns the displayable name of the person in the form "Real Name <email * address>". If the email address is empty, just "Real Name" is returned. * @@ -110,6 +143,15 @@ } /** + * Encapsulates the result of cloning or pulling from a repository. + */ + public static class CloneResult { + public String name; + public FetchResult fetchResult; + public boolean createdRepository; + } + + /** * Clone or Fetch a repository. If the local repository does not exist, * clone is called. If the repository does exist, fetch is called. By * default the clone/fetch retrieves the remote heads, tags, and notes. @@ -117,33 +159,65 @@ * @param repositoriesFolder * @param name * @param fromUrl - * @return FetchResult + * @return CloneResult * @throws Exception */ - public static FetchResult cloneRepository(File repositoriesFolder, String name, String fromUrl) + public static CloneResult cloneRepository(File repositoriesFolder, String name, String fromUrl) throws Exception { - FetchResult result = null; - if (!name.toLowerCase().endsWith(Constants.DOT_GIT_EXT)) { - name += Constants.DOT_GIT_EXT; + return cloneRepository(repositoriesFolder, name, fromUrl, true, null); + } + + /** + * Clone or Fetch a repository. If the local repository does not exist, + * clone is called. If the repository does exist, fetch is called. By + * default the clone/fetch retrieves the remote heads, tags, and notes. + * + * @param repositoriesFolder + * @param name + * @param fromUrl + * @param bare + * @param credentialsProvider + * @return CloneResult + * @throws Exception + */ + public static CloneResult cloneRepository(File repositoriesFolder, String name, String fromUrl, + boolean bare, CredentialsProvider credentialsProvider) throws Exception { + CloneResult result = new CloneResult(); + if (bare) { + // bare repository, ensure .git suffix + if (!name.toLowerCase().endsWith(Constants.DOT_GIT_EXT)) { + name += Constants.DOT_GIT_EXT; + } + } else { + // normal repository, strip .git suffix + if (name.toLowerCase().endsWith(Constants.DOT_GIT_EXT)) { + name = name.substring(0, name.indexOf(Constants.DOT_GIT_EXT)); + } } + result.name = name; + File folder = new File(repositoriesFolder, name); if (folder.exists()) { File gitDir = FileKey.resolve(new File(repositoriesFolder, name), FS.DETECTED); FileRepository repository = new FileRepository(gitDir); - result = fetchRepository(repository); + result.fetchResult = fetchRepository(credentialsProvider, repository); repository.close(); } else { CloneCommand clone = new CloneCommand(); - clone.setBare(true); + clone.setBare(bare); clone.setCloneAllBranches(true); clone.setURI(fromUrl); clone.setDirectory(folder); + if (credentialsProvider != null) { + clone.setCredentialsProvider(credentialsProvider); + } clone.call(); // Now we have to fetch because CloneCommand doesn't fetch // refs/notes nor does it allow manual RefSpec. File gitDir = FileKey.resolve(new File(repositoriesFolder, name), FS.DETECTED); FileRepository repository = new FileRepository(gitDir); - result = fetchRepository(repository); + result.createdRepository = true; + result.fetchResult = fetchRepository(credentialsProvider, repository); repository.close(); } return result; @@ -153,13 +227,14 @@ * Fetch updates from the remote repository. If refSpecs is unspecifed, * remote heads, tags, and notes are retrieved. * + * @param credentialsProvider * @param repository * @param refSpecs * @return FetchResult * @throws Exception */ - public static FetchResult fetchRepository(Repository repository, RefSpec... refSpecs) - throws Exception { + public static FetchResult fetchRepository(CredentialsProvider credentialsProvider, + Repository repository, RefSpec... refSpecs) throws Exception { Git git = new Git(repository); FetchCommand fetch = git.fetch(); List<RefSpec> specs = new ArrayList<RefSpec>(); @@ -170,8 +245,32 @@ } else { specs.addAll(Arrays.asList(refSpecs)); } + if (credentialsProvider != null) { + fetch.setCredentialsProvider(credentialsProvider); + } fetch.setRefSpecs(specs); - FetchResult result = fetch.call(); + FetchResult fetchRes = fetch.call(); + return fetchRes; + } + + /** + * Reset HEAD to the latest remote tracking commit. + * + * @param repository + * @param remoteRef + * the remote tracking reference (e.g. origin/master) + * @return Ref + * @throws Exception + */ + public static Ref resetHEAD(Repository repository, String remoteRef) throws Exception { + if (!remoteRef.startsWith(Constants.R_REMOTES)) { + remoteRef = Constants.R_REMOTES + remoteRef; + } + Git git = new Git(repository); + ResetCommand reset = git.reset(); + reset.setMode(ResetType.SOFT); + reset.setRef(remoteRef); + Ref result = reset.call(); return result; } @@ -206,7 +305,7 @@ } list.addAll(getRepositoryList(repositoriesFolder.getAbsolutePath(), repositoriesFolder, exportAll, searchSubfolders)); - Collections.sort(list); + StringUtils.sortRepositorynames(list); return list; } @@ -263,19 +362,24 @@ if (!hasCommits(repository)) { return null; } - if (StringUtils.isEmpty(branch)) { - branch = Constants.HEAD; - } RevCommit commit = null; try { + // resolve branch + ObjectId branchObject; + if (StringUtils.isEmpty(branch)) { + branchObject = getDefaultBranch(repository); + } else { + branchObject = repository.resolve(branch); + } + RevWalk walk = new RevWalk(repository); walk.sort(RevSort.REVERSE); - RevCommit head = walk.parseCommit(repository.resolve(branch)); + RevCommit head = walk.parseCommit(branchObject); walk.markStart(head); commit = walk.next(); walk.dispose(); } catch (Throwable t) { - LOGGER.error("Failed to determine first commit", t); + error(t, repository, "{0} failed to determine first commit"); } return commit; } @@ -310,7 +414,7 @@ * @return true if the repository has commits */ public static boolean hasCommits(Repository repository) { - if (repository != null && repository.getDirectory().exists()) { + if (repository != null && repository.getDirectory().exists()) { return (new File(repository.getDirectory(), "objects").list().length > 2) || (new File(repository.getDirectory(), "objects/pack").list().length > 0); } @@ -324,7 +428,7 @@ * * @param repository * @param branch - * if unspecified, HEAD is assumed. + * if unspecified, all branches are checked. * @return */ public static Date getLastChange(Repository repository, String branch) { @@ -337,8 +441,23 @@ return new Date(repository.getDirectory().lastModified()); } if (StringUtils.isEmpty(branch)) { - branch = Constants.HEAD; + List<RefModel> branchModels = getLocalBranches(repository, true, -1); + if (branchModels.size() > 0) { + // find most recent branch update + Date lastChange = new Date(0); + for (RefModel branchModel : branchModels) { + if (branchModel.getDate().after(lastChange)) { + lastChange = branchModel.getDate(); + } + } + return lastChange; + } else { + // try to find head + branch = Constants.HEAD; + } } + + // lookup specified branch RevCommit commit = getCommit(repository, branch); return getCommitDate(commit); } @@ -347,10 +466,26 @@ * Retrieves a Java Date from a Git commit. * * @param commit - * @return date of the commit + * @return date of the commit or Date(0) if the commit is null */ public static Date getCommitDate(RevCommit commit) { + if (commit == null) { + return new Date(0); + } return new Date(commit.getCommitTime() * 1000L); + } + + /** + * Retrieves a Java Date from a Git commit. + * + * @param commit + * @return date of the commit or Date(0) if the commit is null + */ + public static Date getAuthorDate(RevCommit commit) { + if (commit == null) { + return new Date(0); + } + return commit.getAuthorIdent().getWhen(); } /** @@ -368,16 +503,19 @@ } RevCommit commit = null; try { + // resolve object id + ObjectId branchObject; if (StringUtils.isEmpty(objectId)) { - objectId = Constants.HEAD; + branchObject = getDefaultBranch(repository); + } else { + branchObject = repository.resolve(objectId); } - ObjectId object = repository.resolve(objectId); RevWalk walk = new RevWalk(repository); - RevCommit rev = walk.parseCommit(object); + RevCommit rev = walk.parseCommit(branchObject); commit = rev; walk.dispose(); } catch (Throwable t) { - LOGGER.error("Failed to get commit " + objectId, t); + error(t, repository, "{0} failed to get commit {1}", objectId); } return commit; } @@ -398,7 +536,7 @@ byte[] content = null; try { if (tree == null) { - ObjectId object = repository.resolve(Constants.HEAD); + ObjectId object = getDefaultBranch(repository); RevCommit commit = rw.parseCommit(object); tree = commit.getTree(); } @@ -424,7 +562,7 @@ content = os.toByteArray(); } } catch (Throwable t) { - LOGGER.error("Can't find " + path + " in tree " + tree.name(), t); + error(t, repository, "{0} can't find {1} in tree {2}", path, tree.name()); } finally { rw.dispose(); tw.release(); @@ -473,7 +611,7 @@ in.close(); content = os.toByteArray(); } catch (Throwable t) { - LOGGER.error("Can't find blob " + objectId, t); + error(t, repository, "{0} can't find blob {1}", objectId); } finally { rw.dispose(); } @@ -514,7 +652,7 @@ return list; } if (commit == null) { - commit = getCommit(repository, Constants.HEAD); + commit = getCommit(repository, null); } final TreeWalk tw = new TreeWalk(repository); try { @@ -543,7 +681,7 @@ } } } catch (IOException e) { - LOGGER.error("Failed to get files for commit " + commit.getName(), e); + error(e, repository, "{0} failed to get files for commit {1}", commit.getName()); } finally { tw.release(); } @@ -568,7 +706,7 @@ RevWalk rw = new RevWalk(repository); try { if (commit == null) { - ObjectId object = repository.resolve(Constants.HEAD); + ObjectId object = getDefaultBranch(repository); commit = rw.parseCommit(object); } @@ -602,7 +740,7 @@ } } } catch (Throwable t) { - LOGGER.error("failed to determine files in commit!", t); + error(t, repository, "{0} failed to determine files in commit!"); } finally { rw.dispose(); } @@ -623,7 +761,7 @@ if (!hasCommits(repository)) { return list; } - RevCommit commit = getCommit(repository, Constants.HEAD); + RevCommit commit = getCommit(repository, null); final TreeWalk tw = new TreeWalk(repository); try { tw.addTree(commit.getTree()); @@ -645,7 +783,7 @@ list.add(getPathModel(tw, null, commit)); } } catch (IOException e) { - LOGGER.error("Failed to get documents for commit " + commit.getName(), e); + error(e, repository, "{0} failed to get documents for commit {1}", commit.getName()); } finally { tw.release(); } @@ -674,7 +812,7 @@ size = tw.getObjectReader().getObjectSize(tw.getObjectId(0), Constants.OBJ_BLOB); } } catch (Throwable t) { - LOGGER.error("Failed to retrieve blob size", t); + error(t, null, "failed to retrieve blob size for " + tw.getPathString()); } return new PathModel(name, tw.getPathString(), size, tw.getFileMode(0).getBits(), commit.getName()); @@ -705,6 +843,45 @@ } /** + * Returns a list of commits since the minimum date starting from the + * specified object id. + * + * @param repository + * @param objectId + * if unspecified, HEAD is assumed. + * @param minimumDate + * @return list of commits + */ + public static List<RevCommit> getRevLog(Repository repository, String objectId, Date minimumDate) { + List<RevCommit> list = new ArrayList<RevCommit>(); + if (!hasCommits(repository)) { + return list; + } + try { + // resolve branch + ObjectId branchObject; + if (StringUtils.isEmpty(objectId)) { + branchObject = getDefaultBranch(repository); + } else { + branchObject = repository.resolve(objectId); + } + + RevWalk rw = new RevWalk(repository); + rw.markStart(rw.parseCommit(branchObject)); + rw.setRevFilter(CommitTimeRevFilter.after(minimumDate)); + Iterable<RevCommit> revlog = rw; + for (RevCommit rev : revlog) { + list.add(rev); + } + rw.dispose(); + } catch (Throwable t) { + error(t, repository, "{0} failed to get {1} revlog for minimum date {2}", objectId, + minimumDate); + } + return list; + } + + /** * Returns a list of commits starting from HEAD and working backwards. * * @param repository @@ -713,7 +890,7 @@ * @return list of commits */ public static List<RevCommit> getRevLog(Repository repository, int maxCount) { - return getRevLog(repository, Constants.HEAD, 0, maxCount); + return getRevLog(repository, null, 0, maxCount); } /** @@ -762,12 +939,16 @@ return list; } try { + // resolve branch + ObjectId branchObject; if (StringUtils.isEmpty(objectId)) { - objectId = Constants.HEAD; + branchObject = getDefaultBranch(repository); + } else { + branchObject = repository.resolve(objectId); } + RevWalk rw = new RevWalk(repository); - ObjectId object = repository.resolve(objectId); - rw.markStart(rw.parseCommit(object)); + rw.markStart(rw.parseCommit(branchObject)); if (!StringUtils.isEmpty(path)) { TreeFilter filter = AndTreeFilter.create( PathFilterGroup.createFromStrings(Collections.singleton(path)), @@ -796,30 +977,53 @@ } rw.dispose(); } catch (Throwable t) { - LOGGER.error("Failed to get revlog", t); + error(t, repository, "{0} failed to get {1} revlog for path {2}", objectId, path); } return list; } /** - * Enumeration of the search types. + * Returns a list of commits for the repository within the range specified + * by startRangeId and endRangeId. If the repository does not exist or is + * empty, an empty list is returned. + * + * @param repository + * @param startRangeId + * the first commit (not included in results) + * @param endRangeId + * the end commit (included in results) + * @return a list of commits */ - public static enum SearchType { - AUTHOR, COMMITTER, COMMIT; + public static List<RevCommit> getRevLog(Repository repository, String startRangeId, + String endRangeId) { + List<RevCommit> list = new ArrayList<RevCommit>(); + if (!hasCommits(repository)) { + return list; + } + try { + ObjectId endRange = repository.resolve(endRangeId); + ObjectId startRange = repository.resolve(startRangeId); - public static SearchType forName(String name) { - for (SearchType type : values()) { - if (type.name().equalsIgnoreCase(name)) { - return type; - } + RevWalk rw = new RevWalk(repository); + rw.markStart(rw.parseCommit(endRange)); + if (startRange.equals(ObjectId.zeroId())) { + // maybe this is a tag or an orphan branch + list.add(rw.parseCommit(endRange)); + rw.dispose(); + return list; + } else { + rw.markUninteresting(rw.parseCommit(startRange)); } - return COMMIT; - } - @Override - public String toString() { - return name().toLowerCase(); + Iterable<RevCommit> revlog = rw; + for (RevCommit rev : revlog) { + list.add(rev); + } + rw.dispose(); + } catch (Throwable t) { + error(t, repository, "{0} failed to get revlog for {1}..{2}", startRangeId, endRangeId); } + return list; } /** @@ -840,7 +1044,7 @@ * @return matching list of commits */ public static List<RevCommit> searchRevlogs(Repository repository, String objectId, - String value, final SearchType type, int offset, int maxCount) { + String value, final com.gitblit.Constants.SearchType type, int offset, int maxCount) { final String lcValue = value.toLowerCase(); List<RevCommit> list = new ArrayList<RevCommit>(); if (maxCount == 0) { @@ -850,9 +1054,14 @@ return list; } try { + // resolve branch + ObjectId branchObject; if (StringUtils.isEmpty(objectId)) { - objectId = Constants.HEAD; + branchObject = getDefaultBranch(repository); + } else { + branchObject = repository.resolve(objectId); } + RevWalk rw = new RevWalk(repository); rw.setRevFilter(new RevFilter() { @@ -887,8 +1096,7 @@ } }); - ObjectId object = repository.resolve(objectId); - rw.markStart(rw.parseCommit(object)); + rw.markStart(rw.parseCommit(branchObject)); Iterable<RevCommit> revlog = rw; if (offset > 0) { int count = 0; @@ -911,9 +1119,100 @@ } rw.dispose(); } catch (Throwable t) { - LOGGER.error("Failed to search revlogs", t); + error(t, repository, "{0} failed to {1} search revlogs for {2}", type.name(), value); } return list; + } + + /** + * Returns the default branch to use for a repository. Normally returns + * whatever branch HEAD points to, but if HEAD points to nothing it returns + * the most recently updated branch. + * + * @param repository + * @return the objectid of a branch + * @throws Exception + */ + public static ObjectId getDefaultBranch(Repository repository) throws Exception { + ObjectId object = repository.resolve(Constants.HEAD); + if (object == null) { + // no HEAD + // perhaps non-standard repository, try local branches + List<RefModel> branchModels = getLocalBranches(repository, true, -1); + if (branchModels.size() > 0) { + // use most recently updated branch + RefModel branch = null; + Date lastDate = new Date(0); + for (RefModel branchModel : branchModels) { + if (branchModel.getDate().after(lastDate)) { + branch = branchModel; + lastDate = branch.getDate(); + } + } + object = branch.getReferencedObjectId(); + } + } + return object; + } + + /** + * Returns the default HEAD for a repository. Normally returns the ref HEAD points to, but if HEAD points to nothing + * it returns null. + * + * @param repository + * @return the refmodel for HEAD or null + */ + public static RefModel getDefaultHead(Repository repository) { + RefModel ref = null; + try { + Ref head = repository.getRef(Constants.HEAD); + if (head != null) { + Ref target = head.getTarget(); + RevWalk rw = new RevWalk(repository); + ObjectId targetId = target.getObjectId(); + if (targetId != null) { + RevObject object = rw.parseAny(targetId); + ref = new RefModel(target.getName(), target, object); + } + rw.dispose(); + } + } catch (Throwable t) { + LOGGER.error("Failed to get default head!", t); + } + return ref; + } + + /** + * Sets the default HEAD symbolic ref for a repository. + * + * @param repository + * @param ref + */ + public static void setDefaultHead(Repository repository, Ref ref) { + try { + boolean detach = !ref.getName().startsWith(Constants.R_HEADS); // detach if not a branch + RefUpdate.Result result; + RefUpdate head = repository.updateRef(Constants.HEAD, detach); + if (detach) { // Tag + RevCommit commit = getCommit(repository, ref.getObjectId().getName()); + head.setNewObjectId(commit.getId()); + result = head.forceUpdate(); + } else { + result = head.link(ref.getName()); + } + switch (result) { + case NEW: + case FORCED: + case NO_CHANGE: + case FAST_FORWARD: + break; + default: + LOGGER.error(MessageFormat.format("{0} failed to set default head to {1} ({2})", + repository.getDirectory().getAbsolutePath(), ref.getName(), result)); + } + } catch (Throwable t) { + error(t, repository, "{0} failed to set default head to {1}", ref.getName()); + } } /** @@ -1044,9 +1343,53 @@ list = new ArrayList<RefModel>(list.subList(0, maxCount)); } } catch (IOException e) { - LOGGER.error("Failed to retrieve " + refs, e); + error(e, repository, "{0} failed to retrieve {1}", refs); } return list; + } + + /** + * Returns a RefModel for the gh-pages branch in the repository. If the + * branch can not be found, null is returned. + * + * @param repository + * @return a refmodel for the gh-pages branch or null + */ + public static RefModel getPagesBranch(Repository repository) { + return getBranch(repository, "gh-pages"); + } + + /** + * Returns a RefModel for a specific branch name in the repository. If the + * branch can not be found, null is returned. + * + * @param repository + * @return a refmodel for the branch or null + */ + public static RefModel getBranch(Repository repository, String name) { + RefModel branch = null; + try { + // search for the branch in local heads + for (RefModel ref : JGitUtils.getLocalBranches(repository, false, -1)) { + if (ref.displayName.endsWith(name)) { + branch = ref; + break; + } + } + + // search for the branch in remote heads + if (branch == null) { + for (RefModel ref : JGitUtils.getRemoteBranches(repository, false, -1)) { + if (ref.displayName.endsWith(name)) { + branch = ref; + break; + } + } + } + } catch (Throwable t) { + LOGGER.error(MessageFormat.format("Failed to find {0} branch!", name), t); + } + return branch; } /** @@ -1082,6 +1425,77 @@ } /** + * Create an orphaned branch in a repository. + * + * @param repository + * @param branchName + * @param author + * if unspecified, Gitblit will be the author of this new branch + * @return true if successful + */ + public static boolean createOrphanBranch(Repository repository, String branchName, + PersonIdent author) { + boolean success = false; + String message = "Created branch " + branchName; + if (author == null) { + author = new PersonIdent("Gitblit", "gitblit@localhost"); + } + try { + ObjectInserter odi = repository.newObjectInserter(); + try { + // Create a blob object to insert into a tree + ObjectId blobId = odi.insert(Constants.OBJ_BLOB, + message.getBytes(Constants.CHARACTER_ENCODING)); + + // Create a tree object to reference from a commit + TreeFormatter tree = new TreeFormatter(); + tree.append("NEWBRANCH", FileMode.REGULAR_FILE, blobId); + ObjectId treeId = odi.insert(tree); + + // Create a commit object + CommitBuilder commit = new CommitBuilder(); + commit.setAuthor(author); + commit.setCommitter(author); + commit.setEncoding(Constants.CHARACTER_ENCODING); + commit.setMessage(message); + commit.setTreeId(treeId); + + // Insert the commit into the repository + ObjectId commitId = odi.insert(commit); + odi.flush(); + + RevWalk revWalk = new RevWalk(repository); + try { + RevCommit revCommit = revWalk.parseCommit(commitId); + if (!branchName.startsWith("refs/")) { + branchName = "refs/heads/" + branchName; + } + RefUpdate ru = repository.updateRef(branchName); + ru.setNewObjectId(commitId); + ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); + Result rc = ru.forceUpdate(); + switch (rc) { + case NEW: + case FORCED: + case FAST_FORWARD: + success = true; + break; + default: + success = false; + } + } finally { + revWalk.release(); + } + } finally { + odi.release(); + } + } catch (Throwable t) { + error(t, repository, "Failed to create orphan branch {1} in repository {0}", branchName); + } + return success; + } + + /** * Returns a StoredConfig object for the repository. * * @param repository @@ -1092,9 +1506,9 @@ try { c.load(); } catch (ConfigInvalidException cex) { - LOGGER.error("Repository configuration is invalid!", cex); + error(cex, repository, "{0} configuration is invalid!"); } catch (IOException cex) { - LOGGER.error("Could not open repository configuration!", cex); + error(cex, repository, "Could not open configuration for {0}!"); } return c; } @@ -1154,7 +1568,7 @@ zos.finish(); success = true; } catch (IOException e) { - LOGGER.error("Failed to zip files from commit " + commit.getName(), e); + error(e, repository, "{0} failed to zip files from commit {1}", commit.getName()); } finally { tw.release(); rw.dispose(); -- Gitblit v1.9.1