]> source.dussan.org Git - gitblit.git/commitdiff
RepositoryModel will use String rather than RefModel to track the current 5/head
authorPhilip L. McMahon <philip.l.mcmahon@gmail.com>
Sat, 28 Jan 2012 18:37:04 +0000 (10:37 -0800)
committerPhilip L. McMahon <philip.l.mcmahon@gmail.com>
Sat, 28 Jan 2012 18:57:39 +0000 (10:57 -0800)
symbolic head and available heads.

Added convenience methods to JGitUtils to support retrieving available
heads as List<String>.
When resolving the symbolic head target as a String, if the head is
detached, attempt to match the commit SHA1 against the known tags, using
the most recent tag if more than one matches.
Revised error messaging to better reflect actual outcome.
Adjusted tab indexes on edit repository page to include default head combo
box.
Updated message key for default head combo box to use uppercase "HEAD".

src/com/gitblit/GitBlit.java
src/com/gitblit/models/RepositoryModel.java
src/com/gitblit/utils/JGitUtils.java
src/com/gitblit/wicket/GitBlitWebApp.properties
src/com/gitblit/wicket/pages/EditRepositoryPage.html
src/com/gitblit/wicket/pages/EditRepositoryPage.java

index b6bf7bf930aa5cbe21e337e185ca55097f790a07..721612632ef49e61cdc45183872ec591ee3634d7 100644 (file)
@@ -69,7 +69,6 @@ import com.gitblit.models.FederationModel;
 import com.gitblit.models.FederationProposal;\r
 import com.gitblit.models.FederationSet;\r
 import com.gitblit.models.Metric;\r
-import com.gitblit.models.RefModel;\r
 import com.gitblit.models.RepositoryModel;\r
 import com.gitblit.models.ServerSettings;\r
 import com.gitblit.models.ServerStatus;\r
@@ -787,10 +786,8 @@ public class GitBlit implements ServletContextListener {
                        model.mailingLists = new ArrayList<String>(Arrays.asList(config.getStringList(\r
                                        "gitblit", null, "mailingList")));\r
                }\r
-               model.defaultHead = JGitUtils.getDefaultHead(r);\r
-               model.availableHeads = new ArrayList<RefModel>();\r
-               model.availableHeads.addAll(JGitUtils.getLocalBranches(r, true, -1));\r
-               model.availableHeads.addAll(JGitUtils.getTags(r, true, -1));\r
+               model.defaultHead = JGitUtils.getSymbolicHeadTarget(r);\r
+               model.availableHeads = JGitUtils.getAvailableHeadTargets(r);\r
                r.close();\r
                return model;\r
        }\r
@@ -986,8 +983,10 @@ public class GitBlit implements ServletContextListener {
                // update settings\r
                if (r != null) {\r
                        updateConfiguration(r, repository);\r
-                       if (repository.defaultHead != null) {\r
-                               JGitUtils.setDefaultHead(r, repository.defaultHead.reference);\r
+                       // only update symbolic head if it changes\r
+                       if (!StringUtils.isEmpty(repository.defaultHead) &&\r
+                                       !repository.defaultHead.equals(JGitUtils.getSymbolicHeadTarget(r))) {\r
+                               JGitUtils.setSymbolicHeadTarget(r, repository.defaultHead);\r
                        }\r
                        r.close();\r
                }\r
index d3e91588b0fc58b2ba60cd00d13cd17cc9bb1c67..e7a0880d65a56ed9cbd01e59df198821bf59413a 100644 (file)
@@ -58,8 +58,8 @@ public class RepositoryModel implements Serializable, Comparable<RepositoryModel
        public List<String> preReceiveScripts;\r
        public List<String> postReceiveScripts;\r
        public List<String> mailingLists;\r
-       public RefModel defaultHead;\r
-       public List<RefModel> availableHeads;\r
+       public String defaultHead;\r
+       public List<String> availableHeads;\r
 \r
        private String displayName;\r
        \r
index 05c0852c8d81d2a77c2570dbcb0378827add7270..6470634c1cac6ab6766d76aefacef6c2f4dfaeaa 100644 (file)
@@ -1156,49 +1156,60 @@ public class JGitUtils {
        }\r
 \r
        /**\r
-        * Returns the default HEAD for a repository. Normally returns the ref HEAD points to, but if HEAD points to nothing\r
-        * it returns null.\r
+        * Returns the target of the symbolic HEAD reference for a repository.\r
+        * Normally returns a branch reference name, but when HEAD is detached,\r
+        * the commit is matched against the known tags. The most recent matching\r
+        * tag ref name will be returned if it references the HEAD commit. If\r
+        * no match is found, the SHA1 is returned.\r
         *\r
         * @param repository\r
-        * @return the refmodel for HEAD or null\r
+        * @return the ref name or the SHA1 for detached HEADs\r
         */\r
-       public static RefModel getDefaultHead(Repository repository) {\r
-               RefModel ref = null;\r
+       public static String getSymbolicHeadTarget(Repository repository) {\r
+               String target = null;\r
                try {\r
-                       Ref head = repository.getRef(Constants.HEAD);\r
-                       if (head != null) {\r
-                               Ref target = head.getTarget();\r
-                               RevWalk rw = new RevWalk(repository);\r
-                               ObjectId targetId = target.getObjectId();\r
-                               if (targetId != null) {\r
-                                       RevObject object = rw.parseAny(targetId);\r
-                                       ref = new RefModel(target.getName(), target, object);\r
+                       target = repository.getFullBranch();\r
+                       if (!target.startsWith(Constants.R_HEADS)) {\r
+                               // refers to an actual commit, probably a tag\r
+                               // find latest tag that matches the commit, if any\r
+                               List<RefModel> tagModels = getTags(repository, true, -1);\r
+                               if (tagModels.size() > 0) {\r
+                                       RefModel tag = null;\r
+                                       Date lastDate = new Date(0);\r
+                                       for (RefModel tagModel : tagModels) {\r
+                                               if (tagModel.getReferencedObjectId().getName().equals(target) &&\r
+                                                               tagModel.getDate().after(lastDate)) {\r
+                                                       tag = tagModel;\r
+                                                       lastDate = tag.getDate();\r
+                                               }\r
+                                       }\r
+                                       target = tag.getName();\r
                                }\r
-                               rw.dispose();\r
                        }\r
                } catch (Throwable t) {\r
-                       LOGGER.error("Failed to get default head!", t);\r
+                       error(t, repository, "{0} failed to get symbolic HEAD target");\r
                }\r
-               return ref;\r
+               return target;\r
        }\r
-\r
+       \r
        /**\r
-        * Sets the default HEAD symbolic ref for a repository.\r
+        * Sets the HEAD symbolic ref name for a repository. The HEAD will\r
+        * be detached if the name does not reference a branch.\r
         *\r
         * @param repository\r
-        * @param ref\r
+        * @param name\r
         */\r
-       public static void setDefaultHead(Repository repository, Ref ref) {\r
+       public static void setSymbolicHeadTarget(Repository repository, String name) {\r
                try {\r
-                       boolean detach = !ref.getName().startsWith(Constants.R_HEADS); // detach if not a branch\r
+                       boolean detach = !name.startsWith(Constants.R_HEADS); // detach if not a branch\r
                        RefUpdate.Result result;\r
                        RefUpdate head = repository.updateRef(Constants.HEAD, detach);\r
                        if (detach) { // Tag\r
-                               RevCommit commit = getCommit(repository, ref.getObjectId().getName());\r
+                               RevCommit commit = getCommit(repository, name);\r
                                head.setNewObjectId(commit.getId());\r
                                result = head.forceUpdate();\r
                        } else {\r
-                               result = head.link(ref.getName());\r
+                               result = head.link(name);\r
                        }\r
                        switch (result) {\r
                        case NEW:\r
@@ -1207,12 +1218,35 @@ public class JGitUtils {
                        case FAST_FORWARD:\r
                                break;\r
                        default:\r
-                               LOGGER.error(MessageFormat.format("{0} failed to set default head to {1} ({2})",\r
-                                               repository.getDirectory().getAbsolutePath(), ref.getName(), result));\r
+                               LOGGER.error(MessageFormat.format("{0} symbolic HEAD update to {1} returned result {2}",\r
+                                               repository.getDirectory().getAbsolutePath(), name, result));\r
                        }\r
                } catch (Throwable t) {\r
-                       error(t, repository, "{0} failed to set default head to {1}", ref.getName());\r
+                       error(t, repository, "{0} failed to set symbolic HEAD to {1}", name);\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Get the full branch and tag ref names for any potential symbolic head targets.\r
+        *\r
+        * @param repository\r
+        * @return a list of ref names\r
+        */\r
+       public static List<String> getAvailableHeadTargets(Repository repository) {\r
+               List<String> targets = new ArrayList<String>();\r
+               List<RefModel> branchModels = JGitUtils.getLocalBranches(repository, true, -1);\r
+               if (branchModels.size() > 0) {\r
+                       for (RefModel branchModel : branchModels) {\r
+                               targets.add(branchModel.getName());\r
+                       }\r
+               }\r
+               List<RefModel> tagModels = JGitUtils.getTags(repository, true, -1);\r
+               if (tagModels.size() > 0) {\r
+                       for (RefModel tagModel : tagModels) {\r
+                               targets.add(tagModel.getName());\r
+                       }\r
                }\r
+               return targets;\r
        }\r
 \r
        /**\r
index b6e45236445730e009630aa3aea0c4ca8646388e..f039a36a722ad13d1d60322a8bd516586bb6c862 100644 (file)
@@ -131,7 +131,7 @@ gb.registrations = federation registrations
 gb.sendProposal propose\r
 gb.status = status\r
 gb.origin = origin\r
-gb.defaultHead = default head\r
+gb.defaultHead = default HEAD\r
 gb.defaultHeadDescription = current branch after clone. e.g. refs/heads/master\r
 gb.federationStrategy = federation strategy\r
 gb.federationRegistration = federation registration\r
index 9878930401ed7897a01b1c19a81e57d2595e86a4..9bd8c5150393527d0896e4559afa8783f7b6a003 100644 (file)
                                <tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input class="span6" type="text" wicket:id="name" id="name" size="40" tabindex="1" /> &nbsp;<span class="help-inline"><wicket:message key="gb.nameDescription"></wicket:message></span></td></tr>\r
                                <tr><th><wicket:message key="gb.description"></wicket:message></th><td class="edit"><input class="span6" type="text" wicket:id="description" size="40" tabindex="2" /></td></tr>\r
                                <tr><th><wicket:message key="gb.origin"></wicket:message></th><td class="edit"><input class="span7" type="text" wicket:id="origin" size="80" tabindex="3" /></td></tr>\r
-                               <tr><th><wicket:message key="gb.defaultHead"></wicket:message></th><td class="edit"><select wicket:id="defaultHead" /> &nbsp;<span class="help-inline"><wicket:message key="gb.defaultHeadDescription"></wicket:message></span></td></tr>\r
-                               <tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><select wicket:id="owner" tabindex="4" /> &nbsp;<span class="help-inline"><wicket:message key="gb.ownerDescription"></wicket:message></span></td></tr>\r
-                               <tr><th><wicket:message key="gb.enableTickets"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useTickets" tabindex="5" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useTicketsDescription"></wicket:message></span></td></tr>\r
-                               <tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useDocs" tabindex="6" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useDocsDescription"></wicket:message></span></td></tr>\r
-                               <tr><th><wicket:message key="gb.showRemoteBranches"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="showRemoteBranches" tabindex="7" /> &nbsp;<span class="help-inline"><wicket:message key="gb.showRemoteBranchesDescription"></wicket:message></span></td></tr>\r
-                               <tr><th><wicket:message key="gb.showReadme"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="showReadme" tabindex="8" /> &nbsp;<span class="help-inline"><wicket:message key="gb.showReadmeDescription"></wicket:message></span></td></tr>\r
-                               <tr><th><wicket:message key="gb.skipSizeCalculation"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="skipSizeCalculation" tabindex="9" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSizeCalculationDescription"></wicket:message></span></td></tr>\r
-                               <tr><th><wicket:message key="gb.skipSummaryMetrics"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="skipSummaryMetrics" tabindex="10" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSummaryMetricsDescription"></wicket:message></span></td></tr>\r
-                               <tr><th><wicket:message key="gb.isFrozen"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="isFrozen" tabindex="11" /> &nbsp;<span class="help-inline"><wicket:message key="gb.isFrozenDescription"></wicket:message></span></td></tr>\r
-                               <tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span14" type="text" wicket:id="mailingLists" size="40" tabindex="12" /></td></tr>\r
+                               <tr><th><wicket:message key="gb.defaultHead"></wicket:message></th><td class="edit"><select wicket:id="defaultHead" tabindex="4" /> &nbsp;<span class="help-inline"><wicket:message key="gb.defaultHeadDescription"></wicket:message></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><select wicket:id="owner" tabindex="5" /> &nbsp;<span class="help-inline"><wicket:message key="gb.ownerDescription"></wicket:message></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.enableTickets"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useTickets" tabindex="6" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useTicketsDescription"></wicket:message></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useDocs" tabindex="7" /> &nbsp;<span class="help-inline"><wicket:message key="gb.useDocsDescription"></wicket:message></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.showRemoteBranches"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="showRemoteBranches" tabindex="8" /> &nbsp;<span class="help-inline"><wicket:message key="gb.showRemoteBranchesDescription"></wicket:message></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.showReadme"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="showReadme" tabindex="9" /> &nbsp;<span class="help-inline"><wicket:message key="gb.showReadmeDescription"></wicket:message></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.skipSizeCalculation"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="skipSizeCalculation" tabindex="10" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSizeCalculationDescription"></wicket:message></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.skipSummaryMetrics"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="skipSummaryMetrics" tabindex="11" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSummaryMetricsDescription"></wicket:message></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.isFrozen"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="isFrozen" tabindex="12" /> &nbsp;<span class="help-inline"><wicket:message key="gb.isFrozenDescription"></wicket:message></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span14" type="text" wicket:id="mailingLists" size="40" tabindex="13" /></td></tr>\r
                                <tr><td colspan="2" style="padding-top:15px"><h3><wicket:message key="gb.accessPermissions"></wicket:message> &nbsp;<small><wicket:message key="gb.accessPermissionsDescription"></wicket:message></small></h3></td></tr>       \r
-                               <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span6" wicket:id="accessRestriction" tabindex="13" /></td></tr>                                \r
+                               <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span6" wicket:id="accessRestriction" tabindex="14" /></td></tr>                                \r
                                <tr><th style="vertical-align: top;"><wicket:message key="gb.permittedUsers"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr>\r
                                <tr><th style="vertical-align: top;"><wicket:message key="gb.permittedTeams"></wicket:message></th><td style="padding:2px;"><span wicket:id="teams"></span></td></tr>\r
                                <tr><td colspan="2"><h3><wicket:message key="gb.federation"></wicket:message> &nbsp;<small><wicket:message key="gb.federationRepositoryDescription"></wicket:message></small></h3></td></tr>    \r
-                               <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span6" wicket:id="federationStrategy" tabindex="14" /></td></tr>\r
+                               <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span6" wicket:id="federationStrategy" tabindex="15" /></td></tr>\r
                                <tr><th style="vertical-align: top;"><wicket:message key="gb.federationSets"></wicket:message></th><td style="padding:2px;"><span wicket:id="federationSets"></span></td></tr>\r
                                <tr><td colspan="2"><h3><wicket:message key="gb.hookScripts"></wicket:message> &nbsp;<small><wicket:message key="gb.hookScriptsDescription"></wicket:message></small></h3></td></tr>    \r
                                <tr><th style="vertical-align: top;"><wicket:message key="gb.preReceiveScripts"></wicket:message><p></p><span wicket:id="inheritedPreReceive"></span></th><td style="padding:2px;"><span wicket:id="preReceiveScripts"></span></td></tr>\r
                                <tr><th style="vertical-align: top;"><wicket:message key="gb.postReceiveScripts"></wicket:message><p></p><span wicket:id="inheritedPostReceive"></span></th><td style="padding:2px;"><span wicket:id="postReceiveScripts"></span></td></tr>\r
-                               <tr><td colspan='2'><div class="actions" "><input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" tabindex="15" /> &nbsp; <input class="btn primary" type="submit" value="Save" wicket:message="value:gb.save" wicket:id="save" tabindex="16" /></div></td></tr>\r
+                               <tr><td colspan='2'><div class="actions" "><input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" tabindex="16" /> &nbsp; <input class="btn primary" type="submit" value="Save" wicket:message="value:gb.save" wicket:id="save" tabindex="16" /></div></td></tr>\r
                        </tbody>\r
                </table>\r
        </form> \r
index 6c042497676ac3c1a062cc4ad9fb4ed33798e623..a16d7e40318ceffe30dfc9a5c065efb762a8f677 100644 (file)
@@ -45,7 +45,6 @@ import com.gitblit.Constants.FederationStrategy;
 import com.gitblit.GitBlit;\r
 import com.gitblit.GitBlitException;\r
 import com.gitblit.Keys;\r
-import com.gitblit.models.RefModel;\r
 import com.gitblit.models.RepositoryModel;\r
 import com.gitblit.models.UserModel;\r
 import com.gitblit.utils.ArrayUtils;\r
@@ -273,8 +272,7 @@ public class EditRepositoryPage extends RootSubPage {
                // TODO enable origin definition\r
                form.add(new TextField<String>("origin").setEnabled(false/* isCreate */));\r
                // enable alteration of the default branch after clone\r
-               form.add(new DropDownChoice<RefModel>("defaultHead", repositoryModel.availableHeads,\r
-                               new RefModelRenderer()).setEnabled(GitBlitWebSession.get().canAdmin()));\r
+               form.add(new DropDownChoice<String>("defaultHead", repositoryModel.availableHeads));\r
 \r
                // federation strategies - remove ORIGIN choice if this repository has\r
                // no origin.\r
@@ -365,21 +363,6 @@ public class EditRepositoryPage extends RootSubPage {
                }\r
        }\r
 \r
-       private class RefModelRenderer implements IChoiceRenderer<RefModel> {\r
-\r
-               private static final long serialVersionUID = 1L;\r
-\r
-               @Override\r
-               public String getDisplayValue(RefModel type) {\r
-                       return type.displayName;\r
-               }\r
-\r
-               @Override\r
-               public String getIdValue(RefModel type, int index) {\r
-                       return type.getName();\r
-               }\r
-       }\r
-\r
        private class AccessRestrictionRenderer implements IChoiceRenderer<AccessRestrictionType> {\r
 \r
                private static final long serialVersionUID = 1L;\r