From 91780e2e17a8020872c8da2d8941114e098ef2a4 Mon Sep 17 00:00:00 2001 From: James Moger <james.moger@gitblit.com> Date: Thu, 16 Feb 2012 07:39:48 -0500 Subject: [PATCH] Merge pull request #7 from plm/protect_refs_hook --- src/com/gitblit/utils/JGitUtils.java | 113 +++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 71 insertions(+), 42 deletions(-) diff --git a/src/com/gitblit/utils/JGitUtils.java b/src/com/gitblit/utils/JGitUtils.java index 05c0852..1c155ff 100644 --- a/src/com/gitblit/utils/JGitUtils.java +++ b/src/com/gitblit/utils/JGitUtils.java @@ -290,21 +290,21 @@ * Returns a list of repository names in the specified folder. * * @param repositoriesFolder - * @param exportAll - * if true, all repositories are listed. If false only the - * repositories with a "git-daemon-export-ok" file are included + * @param onlyBare + * if true, only bare repositories repositories are listed. If + * false all repositories are included. * @param searchSubfolders * recurse into subfolders to find grouped repositories * @return list of repository names */ - public static List<String> getRepositoryList(File repositoriesFolder, boolean exportAll, + public static List<String> getRepositoryList(File repositoriesFolder, boolean onlyBare, boolean searchSubfolders) { List<String> list = new ArrayList<String>(); if (repositoriesFolder == null || !repositoriesFolder.exists()) { return list; } list.addAll(getRepositoryList(repositoriesFolder.getAbsolutePath(), repositoriesFolder, - exportAll, searchSubfolders)); + onlyBare, searchSubfolders)); StringUtils.sortRepositorynames(list); return list; } @@ -316,33 +316,30 @@ * basePath is stripped from the repository name as repositories * are relative to this path * @param searchFolder - * @param exportAll - * if true all repositories are listed. If false only the - * repositories with a "git-daemon-export-ok" file are included + * @param onlyBare + * if true only bare repositories will be listed. if false all + * repositories are included. * @param searchSubfolders * recurse into subfolders to find grouped repositories * @return */ private static List<String> getRepositoryList(String basePath, File searchFolder, - boolean exportAll, boolean searchSubfolders) { + boolean onlyBare, boolean searchSubfolders) { List<String> list = new ArrayList<String>(); for (File file : searchFolder.listFiles()) { if (file.isDirectory()) { File gitDir = FileKey.resolve(new File(searchFolder, file.getName()), FS.DETECTED); if (gitDir != null) { - boolean exportRepository = exportAll - || new File(gitDir, "git-daemon-export-ok").exists(); - - if (!exportRepository) { + if (onlyBare && gitDir.getName().equals(".git")) { continue; } // determine repository name relative to base path String repository = StringUtils.getRelativePath(basePath, file.getAbsolutePath()); list.add(repository); - } else if (searchSubfolders) { + } else if (searchSubfolders && file.canRead()) { // look for repositories in subfolders - list.addAll(getRepositoryList(basePath, file, exportAll, searchSubfolders)); + list.addAll(getRepositoryList(basePath, file, onlyBare, searchSubfolders)); } } } @@ -1156,63 +1153,95 @@ } /** - * Returns the default HEAD for a repository. Normally returns the ref HEAD points to, but if HEAD points to nothing - * it returns null. + * Returns the target of the symbolic HEAD reference for a repository. + * Normally returns a branch reference name, but when HEAD is detached, + * the commit is matched against the known tags. The most recent matching + * tag ref name will be returned if it references the HEAD commit. If + * no match is found, the SHA1 is returned. * * @param repository - * @return the refmodel for HEAD or null + * @return the ref name or the SHA1 for a detached HEAD */ - public static RefModel getDefaultHead(Repository repository) { - RefModel ref = null; + public static String getHEADRef(Repository repository) { + String target = 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); + target = repository.getFullBranch(); + if (!target.startsWith(Constants.R_HEADS)) { + // refers to an actual commit, probably a tag + // find latest tag that matches the commit, if any + List<RefModel> tagModels = getTags(repository, true, -1); + if (tagModels.size() > 0) { + RefModel tag = null; + Date lastDate = new Date(0); + for (RefModel tagModel : tagModels) { + if (tagModel.getReferencedObjectId().getName().equals(target) && + tagModel.getDate().after(lastDate)) { + tag = tagModel; + lastDate = tag.getDate(); + } + } + target = tag.getName(); } - rw.dispose(); } } catch (Throwable t) { - LOGGER.error("Failed to get default head!", t); + error(t, repository, "{0} failed to get symbolic HEAD target"); } - return ref; + return target; } - + /** - * Sets the default HEAD symbolic ref for a repository. + * Sets the symbolic ref HEAD to the specified target ref. The + * HEAD will be detached if the target ref is not a branch. * * @param repository - * @param ref + * @param targetRef + * @return true if successful */ - public static void setDefaultHead(Repository repository, Ref ref) { + public static boolean setHEADtoRef(Repository repository, String targetRef) { try { - boolean detach = !ref.getName().startsWith(Constants.R_HEADS); // detach if not a branch + // detach HEAD if target ref is not a branch + boolean detach = !targetRef.startsWith(Constants.R_HEADS); RefUpdate.Result result; RefUpdate head = repository.updateRef(Constants.HEAD, detach); if (detach) { // Tag - RevCommit commit = getCommit(repository, ref.getObjectId().getName()); + RevCommit commit = getCommit(repository, targetRef); head.setNewObjectId(commit.getId()); result = head.forceUpdate(); } else { - result = head.link(ref.getName()); + result = head.link(targetRef); } switch (result) { case NEW: case FORCED: case NO_CHANGE: case FAST_FORWARD: - break; + return true; default: - LOGGER.error(MessageFormat.format("{0} failed to set default head to {1} ({2})", - repository.getDirectory().getAbsolutePath(), ref.getName(), result)); + LOGGER.error(MessageFormat.format("{0} HEAD update to {1} returned result {2}", + repository.getDirectory().getAbsolutePath(), targetRef, result)); } } catch (Throwable t) { - error(t, repository, "{0} failed to set default head to {1}", ref.getName()); + error(t, repository, "{0} failed to set HEAD to {1}", targetRef); } + return false; + } + + /** + * Get the full branch and tag ref names for any potential HEAD targets. + * + * @param repository + * @return a list of ref names + */ + public static List<String> getAvailableHeadTargets(Repository repository) { + List<String> targets = new ArrayList<String>(); + for (RefModel branchModel : JGitUtils.getLocalBranches(repository, true, -1)) { + targets.add(branchModel.getName()); + } + + for (RefModel tagModel : JGitUtils.getTags(repository, true, -1)) { + targets.add(tagModel.getName()); + } + return targets; } /** -- Gitblit v1.9.1