{"thread":{"id":"17767","subject":"[JGIT PATCH 5/6] Don't pass TagOpt to FetchProcess, get it from the Transport","startedAt":"2009-02-12T23:54:34Z","lastAt":"2009-02-13T00:48:08Z","messageCount":10,"participants":["Shawn O. Pearce","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"104456","messageId":"1234482880-1316-1-git-send-email-spearce@spearce.org","threadId":"17767","inReplyTo":null,"subject":"[JGIT PATCH 0/6] Add prune of stale tracking branches to fetch","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-02-12T23:54:34Z","receivedAt":"2009-02-12T23:54:34Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"This series teaches \"jgit fetch\" how to prune stale tracking branches\nthat have been removed from the remote repository.  We can now do\nboth a fetch and a prune in a single network connection.\n\nI wanted to also add this for push, but its going to be more complex.\nThe RefSpec data I need isn't available in the PushProcess code path,\nand the Transport.push() method isn't doing me any favors at making\nit available to me.\n\nI need to move on to some other things today, so I'm posting this\nfetch series now as this looks good as-is.\n\nShawn O. Pearce (6):\n  Fix RefUpdate.delete to update the result status\n  Add setBoolean, setInt to RepositoryConfig\n  Add RefSpec.expandFromDestination for reverse mappings\n  Add the remote.name.mirror flag to RemoteConfig\n  Don't pass TagOpt to FetchProcess, get it from the Transport\n  Teach fetch to prune stale tracking branches\n\n .../org/spearce/jgit/pgm/AbstractFetchCommand.java |    8 ++-\n .../src/org/spearce/jgit/pgm/Fetch.java            |    9 +++\n .../spearce/jgit/transport/RefSpecTestCase.java    |   22 ++++++\n .../src/org/spearce/jgit/lib/RefUpdate.java        |    4 +-\n .../src/org/spearce/jgit/lib/RepositoryConfig.java |   57 +++++++++++++++\n .../org/spearce/jgit/transport/FetchProcess.java   |   55 +++++++++++++--\n .../src/org/spearce/jgit/transport/RefSpec.java    |   73 ++++++++++++++------\n .../org/spearce/jgit/transport/RemoteConfig.java   |   40 +++++++++++-\n .../src/org/spearce/jgit/transport/Transport.java  |   29 ++++++++-\n 9 files changed, 265 insertions(+), 32 deletions(-)\n"},{"id":"104454","messageId":"1234482880-1316-2-git-send-email-spearce@spearce.org","threadId":"17767","inReplyTo":"1234482880-1316-1-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 1/6] Fix RefUpdate.delete to update the result status","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-02-12T23:54:35Z","receivedAt":"2009-02-12T23:54:35Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Some applications may want to use getResult() to obtain the\nstatus of the delete operation, as perhaps they lost access\nto the return value.  This makes delete() more consistent in\nuse with update().\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../src/org/spearce/jgit/lib/RefUpdate.java        |    4 ++--\n 1 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java\nindex 7ad2bab..d1820da 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefUpdate.java\n@@ -401,11 +401,11 @@ public Result delete(final RevWalk walk) throws IOException {\n \t\tif (getName().startsWith(Constants.R_HEADS)) {\n \t\t\tfinal Ref head = db.readRef(Constants.HEAD);\n \t\t\tif (head != null && getName().equals(head.getName()))\n-\t\t\t\treturn Result.REJECTED_CURRENT_BRANCH;\n+\t\t\t\treturn result = Result.REJECTED_CURRENT_BRANCH;\n \t\t}\n \n \t\ttry {\n-\t\t\treturn updateImpl(walk, new DeleteStore());\n+\t\t\treturn result = updateImpl(walk, new DeleteStore());\n \t\t} catch (IOException x) {\n \t\t\tresult = Result.IO_FAILURE;\n \t\t\tthrow x;\n-- \n1.6.2.rc0.226.gf08f\n"},{"id":"104458","messageId":"1234482880-1316-3-git-send-email-spearce@spearce.org","threadId":"17767","inReplyTo":"1234482880-1316-2-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 2/6] Add setBoolean, setInt to RepositoryConfig","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-02-12T23:54:36Z","receivedAt":"2009-02-12T23:54:36Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"This makes it easier for application level code to make edits to the\nconfiguration file, especially when setting boolean or integers into\nany property.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../src/org/spearce/jgit/lib/RepositoryConfig.java |   57 ++++++++++++++++++++\n 1 files changed, 57 insertions(+), 0 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java\nindex 821d8be..87535d1 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java\n@@ -439,6 +439,63 @@ private Object getRawEntry(final String section, final String subsection,\n \t/**\n \t * Add or modify a configuration value. The parameters will result in a\n \t * configuration entry like this.\n+\t * \n+\t * <pre>\n+\t * [section &quot;subsection&quot;]\n+\t *         name = value\n+\t * </pre>\n+\t * \n+\t * @param section\n+\t *            section name, e.g \"branch\"\n+\t * @param subsection\n+\t *            optional subsection value, e.g. a branch name\n+\t * @param name\n+\t *            parameter name, e.g. \"filemode\"\n+\t * @param value\n+\t *            parameter value\n+\t */\n+\tpublic void setInt(final String section, final String subsection,\n+\t\t\tfinal String name, final int value) {\n+\t\tfinal String s;\n+\n+\t\tif ((value % (1024 * 1024 * 1024)) == 0)\n+\t\t\ts = String.valueOf(value / (1024 * 1024 * 1024)) + \" g\";\n+\t\telse if ((value % (1024 * 1024)) == 0)\n+\t\t\ts = String.valueOf(value / (1024 * 1024)) + \" m\";\n+\t\telse if ((value % 1024) == 0)\n+\t\t\ts = String.valueOf(value / 1024) + \" k\";\n+\t\telse\n+\t\t\ts = String.valueOf(value);\n+\n+\t\tsetString(section, subsection, name, s);\n+\t}\n+\n+\t/**\n+\t * Add or modify a configuration value. The parameters will result in a\n+\t * configuration entry like this.\n+\t *\n+\t * <pre>\n+\t * [section &quot;subsection&quot;]\n+\t *         name = value\n+\t * </pre>\n+\t *\n+\t * @param section\n+\t *            section name, e.g \"branch\"\n+\t * @param subsection\n+\t *            optional subsection value, e.g. a branch name\n+\t * @param name\n+\t *            parameter name, e.g. \"filemode\"\n+\t * @param value\n+\t *            parameter value\n+\t */\n+\tpublic void setBoolean(final String section, final String subsection,\n+\t\t\tfinal String name, final boolean value) {\n+\t\tsetString(section, subsection, name, value ? \"true\" : \"false\");\n+\t}\n+\n+\t/**\n+\t * Add or modify a configuration value. The parameters will result in a\n+\t * configuration entry like this.\n \t *\n \t * <pre>\n \t * [section &quot;subsection&quot;]\n-- \n1.6.2.rc0.226.gf08f\n"},{"id":"104457","messageId":"1234482880-1316-4-git-send-email-spearce@spearce.org","threadId":"17767","inReplyTo":"1234482880-1316-3-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 3/6] Add RefSpec.expandFromDestination for reverse mappings","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-02-12T23:54:37Z","receivedAt":"2009-02-12T23:54:37Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"This makes it easy to loop through the destination's refs and see\nif any match up to a source name which doesn't actually exist in\nthe set of available source refs.  In such cases, we may want to\ndelete the destination ref.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../spearce/jgit/transport/RefSpecTestCase.java    |   22 ++++++\n .../src/org/spearce/jgit/transport/RefSpec.java    |   73 ++++++++++++++------\n 2 files changed, 75 insertions(+), 20 deletions(-)\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/RefSpecTestCase.java b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/RefSpecTestCase.java\nindex 341b4a4..11e7cdb 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/RefSpecTestCase.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/RefSpecTestCase.java\n@@ -232,4 +232,26 @@ public void testSetSourceDestination() {\n \t\tassertEquals(\"HEAD\", a.toString());\n \t\tassertEquals(\"refs/heads/*:refs/remotes/origin/*\", b.toString());\n \t}\n+\n+\tpublic void testExpandFromDestination_NonWildcard() {\n+\t\tfinal String src = \"refs/heads/master\";\n+\t\tfinal String dst = \"refs/remotes/origin/master\";\n+\t\tfinal RefSpec a = new RefSpec(src + \":\" + dst);\n+\t\tfinal RefSpec r = a.expandFromDestination(dst);\n+\t\tassertSame(a, r);\n+\t\tassertFalse(r.isWildcard());\n+\t\tassertEquals(src, r.getSource());\n+\t\tassertEquals(dst, r.getDestination());\n+\t}\n+\n+\tpublic void testExpandFromDestination_Wildcard() {\n+\t\tfinal String src = \"refs/heads/master\";\n+\t\tfinal String dst = \"refs/remotes/origin/master\";\n+\t\tfinal RefSpec a = new RefSpec(\"refs/heads/*:refs/remotes/origin/*\");\n+\t\tfinal RefSpec r = a.expandFromDestination(dst);\n+\t\tassertNotSame(a, r);\n+\t\tassertFalse(r.isWildcard());\n+\t\tassertEquals(src, r.getSource());\n+\t\tassertEquals(dst, r.getDestination());\n+\t}\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java b/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java\nindex 521110b..bc6ea3a 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java\n@@ -135,24 +135,6 @@ else if (isWildcard(srcName) || isWildcard(dstName))\n \t\t}\n \t}\n \n-\t/**\n-\t * Expand a wildcard specification.\n-\t * \n-\t * @param p\n-\t *            the wildcard specification we should base ourselves on.\n-\t * @param name\n-\t *            actual name that matched the source of <code>p</code>.\n-\t */\n-\tprotected RefSpec(final RefSpec p, final String name) {\n-\t\tfinal String pdst = p.getDestination();\n-\t\tif (p.getSource() == null || pdst == null)\n-\t\t\tthrow new IllegalArgumentException(\"Cannot expand from \" + p);\n-\t\tforce = p.isForceUpdate();\n-\t\tsrcName = name;\n-\t\tdstName = pdst.substring(0, pdst.length() - 1)\n-\t\t\t\t+ name.substring(p.getSource().length() - 1);\n-\t}\n-\n \tprivate RefSpec(final RefSpec p) {\n \t\tforce = p.isForceUpdate();\n \t\twildcard = p.isWildcard();\n@@ -349,7 +331,16 @@ public boolean matchDestination(final Ref r) {\n \t *         wildcard.\n \t */\n \tpublic RefSpec expandFromSource(final String r) {\n-\t\treturn isWildcard() ? new RefSpec(this, r) : this;\n+\t\treturn isWildcard() ? new RefSpec(this).expandFromSourceImp(r) : this;\n+\t}\n+\n+\tprivate RefSpec expandFromSourceImp(final String name) {\n+\t\tfinal String psrc = srcName, pdst = dstName;\n+\t\twildcard = false;\n+\t\tsrcName = name;\n+\t\tdstName = pdst.substring(0, pdst.length() - 1)\n+\t\t\t\t+ name.substring(psrc.length() - 1);\n+\t\treturn this;\n \t}\n \n \t/**\n@@ -366,7 +357,49 @@ public RefSpec expandFromSource(final String r) {\n \t *         wildcard.\n \t */\n \tpublic RefSpec expandFromSource(final Ref r) {\n-\t\treturn isWildcard() ? new RefSpec(this, r.getName()) : this;\n+\t\treturn expandFromSource(r.getName());\n+\t}\n+\n+\t/**\n+\t * Expand this specification to exactly match a ref name.\n+\t * <p>\n+\t * Callers must first verify the passed ref name matches this specification,\n+\t * otherwise expansion results may be unpredictable.\n+\t * \n+\t * @param r\n+\t *            a ref name that matched our destination specification. Could\n+\t *            be a wildcard also.\n+\t * @return a new specification expanded from provided ref name. Result\n+\t *         specification is wildcard if and only if provided ref name is\n+\t *         wildcard.\n+\t */\n+\tpublic RefSpec expandFromDestination(final String r) {\n+\t\treturn isWildcard() ? new RefSpec(this).expandFromDstImp(r) : this;\n+\t}\n+\n+\tprivate RefSpec expandFromDstImp(final String name) {\n+\t\tfinal String psrc = srcName, pdst = dstName;\n+\t\twildcard = false;\n+\t\tsrcName = psrc.substring(0, psrc.length() - 1)\n+\t\t\t\t+ name.substring(pdst.length() - 1);\n+\t\tdstName = name;\n+\t\treturn this;\n+\t}\n+\n+\t/**\n+\t * Expand this specification to exactly match a ref.\n+\t * <p>\n+\t * Callers must first verify the passed ref matches this specification,\n+\t * otherwise expansion results may be unpredictable.\n+\t * \n+\t * @param r\n+\t *            a ref that matched our destination specification.\n+\t * @return a new specification expanded from provided ref name. Result\n+\t *         specification is wildcard if and only if provided ref name is\n+\t *         wildcard.\n+\t */\n+\tpublic RefSpec expandFromDestination(final Ref r) {\n+\t\treturn expandFromDestination(r.getName());\n \t}\n \n \tprivate boolean match(final String refName, final String s) {\n-- \n1.6.2.rc0.226.gf08f\n"},{"id":"104455","messageId":"1234482880-1316-5-git-send-email-spearce@spearce.org","threadId":"17767","inReplyTo":"1234482880-1316-4-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 4/6] Add the remote.name.mirror flag to RemoteConfig","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-02-12T23:54:38Z","receivedAt":"2009-02-12T23:54:38Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"This flag is currently only honored by \"git push\" to delete remote\nrefs if they are also gone on the source side.  It also causes the\ndefault push spec to be \"+refs/*:refs/*\" if the user hasn't given\nus any other push specs.\n\nThis change only implements the config file parsing for the mirror\nflag, as there's still a chunk of code needed on the transport to\nactually honor it.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../org/spearce/jgit/transport/RemoteConfig.java   |   40 +++++++++++++++++++-\n 1 files changed, 39 insertions(+), 1 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/RemoteConfig.java b/org.spearce.jgit/src/org/spearce/jgit/transport/RemoteConfig.java\nindex 5bbf664..519a8a5 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/RemoteConfig.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/RemoteConfig.java\n@@ -68,6 +68,10 @@\n \n \tprivate static final String KEY_TAGOPT = \"tagopt\";\n \n+\tprivate static final String KEY_MIRROR = \"mirror\";\n+\n+\tprivate static final boolean DEFAULT_MIRROR = false;\n+\n \t/** Default value for {@link #getUploadPack()} if not specified. */\n \tpublic static final String DEFAULT_UPLOAD_PACK = \"git-upload-pack\";\n \n@@ -114,6 +118,8 @@\n \n \tprivate TagOpt tagopt;\n \n+\tprivate boolean mirror;\n+\n \t/**\n \t * Parse a remote block from an existing configuration file.\n \t * <p>\n@@ -163,6 +169,7 @@ public RemoteConfig(final RepositoryConfig rc, final String remoteName)\n \n \t\tval = rc.getString(SECTION, name, KEY_TAGOPT);\n \t\ttagopt = TagOpt.fromOption(val);\n+\t\tmirror = rc.getBoolean(SECTION, name, KEY_MIRROR, DEFAULT_MIRROR);\n \t}\n \n \t/**\n@@ -192,16 +199,29 @@ public void update(final RepositoryConfig rc) {\n \t\tset(rc, KEY_UPLOADPACK, getUploadPack(), DEFAULT_UPLOAD_PACK);\n \t\tset(rc, KEY_RECEIVEPACK, getReceivePack(), DEFAULT_RECEIVE_PACK);\n \t\tset(rc, KEY_TAGOPT, getTagOpt().option(), TagOpt.AUTO_FOLLOW.option());\n+\t\tset(rc, KEY_MIRROR, mirror, DEFAULT_MIRROR);\n \t}\n \n \tprivate void set(final RepositoryConfig rc, final String key,\n \t\t\tfinal String currentValue, final String defaultValue) {\n \t\tif (defaultValue.equals(currentValue))\n-\t\t\trc.unsetString(SECTION, getName(), key);\n+\t\t\tunset(rc, key);\n \t\telse\n \t\t\trc.setString(SECTION, getName(), key, currentValue);\n \t}\n \n+\tprivate void set(final RepositoryConfig rc, final String key,\n+\t\t\tfinal boolean currentValue, final boolean defaultValue) {\n+\t\tif (defaultValue == currentValue)\n+\t\t\tunset(rc, key);\n+\t\telse\n+\t\t\trc.setBoolean(SECTION, getName(), key, currentValue);\n+\t}\n+\n+\tprivate void unset(final RepositoryConfig rc, final String key) {\n+\t\trc.unsetString(SECTION, getName(), key);\n+\t}\n+\n \t/**\n \t * Get the local name this remote configuration is recognized as.\n \t * \n@@ -382,4 +402,22 @@ public TagOpt getTagOpt() {\n \tpublic void setTagOpt(final TagOpt option) {\n \t\ttagopt = option != null ? option : TagOpt.AUTO_FOLLOW;\n \t}\n+\n+\t/**\n+\t * @return true if pushing to the remote automatically deletes remote refs\n+\t *         which don't exist on the source side.\n+\t */\n+\tpublic boolean isMirror() {\n+\t\treturn mirror;\n+\t}\n+\n+\t/**\n+\t * Set the mirror flag to automatically delete remote refs.\n+\t *\n+\t * @param m\n+\t *            true to automatically delete remote refs during push.\n+\t */\n+\tpublic void setMirror(final boolean m) {\n+\t\tmirror = m;\n+\t}\n }\n-- \n1.6.2.rc0.226.gf08f\n"},{"id":"104453","messageId":"1234482880-1316-6-git-send-email-spearce@spearce.org","threadId":"17767","inReplyTo":"1234482880-1316-5-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 5/6] Don't pass TagOpt to FetchProcess, get it from the Transport","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-02-12T23:54:39Z","receivedAt":"2009-02-12T23:54:39Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"We are already passing the transport down.  Its just easier to get\nthe tagopt off the transport than it is to pass it as an argument\nto the constructor.\n\nIn the future as we add more options into the Transport we will also\nneed to obtain those in the FetchProcess, so directly querying the\nTransport will be more consistent.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../org/spearce/jgit/transport/FetchProcess.java   |    7 ++-----\n .../src/org/spearce/jgit/transport/Transport.java  |    2 +-\n 2 files changed, 3 insertions(+), 6 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\nindex 09718eb..2ca8aeb 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\n@@ -69,9 +69,6 @@\n \t/** List of things we want to fetch from the remote repository. */\n \tprivate final Collection<RefSpec> toFetch;\n \n-\t/** How to handle annotated tags, if any are advertised. */\n-\tprivate final TagOpt tagopt;\n-\n \t/** Set of refs we will actually wind up asking to obtain. */\n \tprivate final HashMap<ObjectId, Ref> askFor = new HashMap<ObjectId, Ref>();\n \n@@ -86,10 +83,9 @@\n \n \tprivate FetchConnection conn;\n \n-\tFetchProcess(final Transport t, final Collection<RefSpec> f, final TagOpt o) {\n+\tFetchProcess(final Transport t, final Collection<RefSpec> f) {\n \t\ttransport = t;\n \t\ttoFetch = f;\n-\t\ttagopt = o;\n \t}\n \n \tvoid execute(final ProgressMonitor monitor, final FetchResult result)\n@@ -114,6 +110,7 @@ void execute(final ProgressMonitor monitor, final FetchResult result)\n \t\t\t}\n \n \t\t\tCollection<Ref> additionalTags = Collections.<Ref> emptyList();\n+\t\t\tfinal TagOpt tagopt = transport.getTagOpt();\n \t\t\tif (tagopt == TagOpt.AUTO_FOLLOW)\n \t\t\t\tadditionalTags = expandAutoFollowTags();\n \t\t\telse if (tagopt == TagOpt.FETCH_TAGS)\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\nindex 28700b7..e58b72a 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\n@@ -606,7 +606,7 @@ public FetchResult fetch(final ProgressMonitor monitor,\n \t\t}\n \n \t\tfinal FetchResult result = new FetchResult();\n-\t\tnew FetchProcess(this, toFetch, tagopt).execute(monitor, result);\n+\t\tnew FetchProcess(this, toFetch).execute(monitor, result);\n \t\treturn result;\n \t}\n \n-- \n1.6.2.rc0.226.gf08f\n"},{"id":"104459","messageId":"1234482880-1316-7-git-send-email-spearce@spearce.org","threadId":"17767","inReplyTo":"1234482880-1316-6-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 6/6] Teach fetch to prune stale tracking branches","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-02-12T23:54:40Z","receivedAt":"2009-02-12T23:54:40Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"If the source branch for a local tracking branch has been removed\nfrom the remote repository, users may also want (or need) to delete\nit from the local repository.  A good example is when a branch named\n\"refs/heads/bar\" switches from a file to a directory, and the local\npath name in \"refs/remotes/origin/bar\" must also change.\n\nLocal deletes are done before updates, to handle this special case\nof file to directory (or directory to file) conversions with as few\nerrors as possible.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../org/spearce/jgit/pgm/AbstractFetchCommand.java |    8 ++-\n .../src/org/spearce/jgit/pgm/Fetch.java            |    9 ++++\n .../org/spearce/jgit/transport/FetchProcess.java   |   48 ++++++++++++++++++++\n .../src/org/spearce/jgit/transport/Transport.java  |   27 +++++++++++\n 4 files changed, 89 insertions(+), 3 deletions(-)\n\ndiff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/AbstractFetchCommand.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/AbstractFetchCommand.java\nindex ea6f277..f5a9d65 100644\n--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/AbstractFetchCommand.java\n+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/AbstractFetchCommand.java\n@@ -39,6 +39,7 @@\n \n import org.kohsuke.args4j.Option;\n import org.spearce.jgit.lib.Constants;\n+import org.spearce.jgit.lib.ObjectId;\n import org.spearce.jgit.lib.RefUpdate;\n import org.spearce.jgit.transport.FetchResult;\n import org.spearce.jgit.transport.TrackingRefUpdate;\n@@ -75,9 +76,12 @@ private String longTypeOf(final TrackingRefUpdate u) {\n \t\tfinal RefUpdate.Result r = u.getResult();\n \t\tif (r == RefUpdate.Result.LOCK_FAILURE)\n \t\t\treturn \"[lock fail]\";\n-\n \t\tif (r == RefUpdate.Result.IO_FAILURE)\n \t\t\treturn \"[i/o error]\";\n+\t\tif (r == RefUpdate.Result.REJECTED)\n+\t\t\treturn \"[rejected]\";\n+\t\tif (ObjectId.zeroId().equals(u.getNewObjectId()))\n+\t\t\treturn \"[deleted]\";\n \n \t\tif (r == RefUpdate.Result.NEW) {\n \t\t\tif (u.getRemoteName().startsWith(Constants.R_HEADS))\n@@ -99,8 +103,6 @@ else if (u.getLocalName().startsWith(Constants.R_TAGS))\n \t\t\treturn aOld + \"..\" + aNew;\n \t\t}\n \n-\t\tif (r == RefUpdate.Result.REJECTED)\n-\t\t\treturn \"[rejected]\";\n \t\tif (r == RefUpdate.Result.NO_CHANGE)\n \t\t\treturn \"[up to date]\";\n \t\treturn \"[\" + r.name() + \"]\";\ndiff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java\nindex 8f3f7d5..81d6893 100644\n--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java\n+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java\n@@ -56,6 +56,12 @@ void nofsck(final boolean ignored) {\n \t\tfsck = Boolean.FALSE;\n \t}\n \n+\t@Option(name = \"--prune\", usage = \"prune stale tracking refs\")\n+\tprivate Boolean prune;\n+\n+\t@Option(name = \"--dry-run\")\n+\tprivate boolean dryRun;\n+\n \t@Option(name = \"--thin\", usage = \"fetch thin pack\")\n \tprivate Boolean thin;\n \n@@ -75,6 +81,9 @@ protected void run() throws Exception {\n \t\tfinal Transport tn = Transport.open(db, remote);\n \t\tif (fsck != null)\n \t\t\ttn.setCheckFetchedObjects(fsck.booleanValue());\n+\t\tif (prune != null)\n+\t\t\ttn.setRemoveDeletedRefs(prune.booleanValue());\n+\t\ttn.setDryRun(dryRun);\n \t\tif (thin != null)\n \t\t\ttn.setFetchThin(thin.booleanValue());\n \t\tfinal FetchResult r;\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\nindex 2ca8aeb..df64817 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java\n@@ -59,6 +59,7 @@\n import org.spearce.jgit.lib.ObjectId;\n import org.spearce.jgit.lib.ProgressMonitor;\n import org.spearce.jgit.lib.Ref;\n+import org.spearce.jgit.lib.Repository;\n import org.spearce.jgit.revwalk.ObjectWalk;\n import org.spearce.jgit.revwalk.RevWalk;\n \n@@ -152,6 +153,8 @@ else if (tagopt == TagOpt.FETCH_TAGS)\n \t\t}\n \n \t\tfinal RevWalk walk = new RevWalk(transport.local);\n+\t\tif (transport.isRemoveDeletedRefs())\n+\t\t\tdeleteStaleTrackingRefs(result, walk);\n \t\tfor (TrackingRefUpdate u : localUpdates) {\n \t\t\ttry {\n \t\t\t\tu.update(walk);\n@@ -366,6 +369,51 @@ private TrackingRefUpdate createUpdate(final RefSpec spec,\n \t\treturn new TrackingRefUpdate(transport.local, spec, newId, \"fetch\");\n \t}\n \n+\tprivate void deleteStaleTrackingRefs(final FetchResult result,\n+\t\t\tfinal RevWalk walk) throws TransportException {\n+\t\tfinal Repository db = transport.local;\n+\t\tfor (final Ref ref : db.getAllRefs().values()) {\n+\t\t\tfinal String refname = ref.getName();\n+\t\t\tfor (final RefSpec spec : toFetch) {\n+\t\t\t\tif (spec.matchDestination(refname)) {\n+\t\t\t\t\tfinal RefSpec s = spec.expandFromDestination(refname);\n+\t\t\t\t\tif (result.getAdvertisedRef(s.getSource()) == null) {\n+\t\t\t\t\t\tdeleteTrackingRef(result, db, walk, s, ref);\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tprivate void deleteTrackingRef(final FetchResult result,\n+\t\t\tfinal Repository db, final RevWalk walk, final RefSpec spec,\n+\t\t\tfinal Ref localRef) throws TransportException {\n+\t\tfinal String name = localRef.getName();\n+\t\ttry {\n+\t\t\tfinal TrackingRefUpdate u = new TrackingRefUpdate(db, name, spec\n+\t\t\t\t\t.getSource(), true, ObjectId.zeroId(), \"deleted\");\n+\t\t\tresult.add(u);\n+\t\t\tif (transport.isDryRun()){\n+\t\t\t\treturn;\n+\t\t\t}\n+\t\t\tu.delete(walk);\n+\t\t\tswitch (u.getResult()) {\n+\t\t\tcase NEW:\n+\t\t\tcase NO_CHANGE:\n+\t\t\tcase FAST_FORWARD:\n+\t\t\tcase FORCED:\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tthrow new TransportException(transport.getURI(),\n+\t\t\t\t\t\t\"Cannot delete stale tracking ref \" + name + \": \"\n+\t\t\t\t\t\t\t\t+ u.getResult().name());\n+\t\t\t}\n+\t\t} catch (IOException e) {\n+\t\t\tthrow new TransportException(transport.getURI(),\n+\t\t\t\t\t\"Cannot delete stale tracking ref \" + name, e);\n+\t\t}\n+\t}\n+\n \tprivate static boolean isTag(final Ref r) {\n \t\treturn isTag(r.getName());\n \t}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\nindex e58b72a..3aec5ca 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java\n@@ -355,6 +355,9 @@ private static String findTrackingRefName(final String remoteName,\n \t/** Should an incoming (fetch) transfer validate objects? */\n \tprivate boolean checkFetchedObjects;\n \n+\t/** Should refs no longer on the source be pruned from the destination? */\n+\tprivate boolean removeDeletedRefs;\n+\n \t/**\n \t * Create a new transport instance.\n \t * \n@@ -516,6 +519,30 @@ public void setPushThin(final boolean pushThin) {\n \t}\n \n \t/**\n+\t * @return true if destination refs should be removed if they no longer\n+\t *         exist at the source repository.\n+\t */\n+\tpublic boolean isRemoveDeletedRefs() {\n+\t\treturn removeDeletedRefs;\n+\t}\n+\n+\t/**\n+\t * Set whether or not to remove refs which no longer exist in the source.\n+\t * <p>\n+\t * If true, refs at the destination repository (local for fetch, remote for\n+\t * push) are deleted if they no longer exist on the source side (remote for\n+\t * fetch, local for push).\n+\t * <p>\n+\t * False by default, as this may cause data to become unreachable, and\n+\t * eventually be deleted on the next GC.\n+\t *\n+\t * @param remove true to remove refs that no longer exist.\n+\t */\n+\tpublic void setRemoveDeletedRefs(final boolean remove) {\n+\t\tremoveDeletedRefs = remove;\n+\t}\n+\n+\t/**\n \t * Apply provided remote configuration on this transport.\n \t *\n \t * @param cfg\n-- \n1.6.2.rc0.226.gf08f\n"},{"id":"104461","messageId":"7v7i3vi33b.fsf@gitster.siamese.dyndns.org","threadId":"17767","inReplyTo":"1234482880-1316-1-git-send-email-spearce@spearce.org","subject":"Re: [JGIT PATCH 0/6] Add prune of stale tracking branches to fetch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-13T00:37:44Z","receivedAt":"2009-02-13T00:37:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Shawn O. Pearce\" <spearce@spearce.org> writes:\n\n> This series teaches \"jgit fetch\" how to prune stale tracking branches\n> that have been removed from the remote repository.  We can now do\n> both a fetch and a prune in a single network connection.\n\nI am not sure if that is a good feature.\n\nThe user at the local side may well be using the (now stale) tracking\nbranch as an achoring point to remember where his own development forked\nfrom, and that may be the reason he is fetching but not running \"remote\nprune\", not to lose that anchor.\n"},{"id":"104462","messageId":"20090213004245.GZ30949@spearce.org","threadId":"17767","inReplyTo":"7v7i3vi33b.fsf@gitster.siamese.dyndns.org","subject":"Re: [JGIT PATCH 0/6] Add prune of stale tracking branches to fetch","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-02-13T00:42:45Z","receivedAt":"2009-02-13T00:42:45Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> \"Shawn O. Pearce\" <spearce@spearce.org> writes:\n> \n> > This series teaches \"jgit fetch\" how to prune stale tracking branches\n> > that have been removed from the remote repository.  We can now do\n> > both a fetch and a prune in a single network connection.\n> \n> I am not sure if that is a good feature.\n> \n> The user at the local side may well be using the (now stale) tracking\n> branch as an achoring point to remember where his own development forked\n> from, and that may be the reason he is fetching but not running \"remote\n> prune\", not to lose that anchor.\n\nWell.\n\nIts off by default.\n\nYou have to ask for it with \"jgit fetch --prune origin\".\n\nCompare to asking for it with \"git remote prune origin\".\n\nWe're already opening a #@!*@!* network connection to perform either\nfetch or prune, so we might as well let the user perform both in\none step.  Which is what this patch does.\n\n-- \nShawn.\n"},{"id":"104464","messageId":"7v3aeji2lz.fsf@gitster.siamese.dyndns.org","threadId":"17767","inReplyTo":"20090213004245.GZ30949@spearce.org","subject":"Re: [JGIT PATCH 0/6] Add prune of stale tracking branches to fetch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-13T00:48:08Z","receivedAt":"2009-02-13T00:48:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Shawn O. Pearce\" <spearce@spearce.org> writes:\n\n> Junio C Hamano <gitster@pobox.com> wrote:\n>> \"Shawn O. Pearce\" <spearce@spearce.org> writes:\n>> \n>> > This series teaches \"jgit fetch\" how to prune stale tracking branches\n>> > that have been removed from the remote repository.  We can now do\n>> > both a fetch and a prune in a single network connection.\n>> \n>> I am not sure if that is a good feature.\n>> \n>> The user at the local side may well be using the (now stale) tracking\n>> branch as an achoring point to remember where his own development forked\n>> from, and that may be the reason he is fetching but not running \"remote\n>> prune\", not to lose that anchor.\n>\n> Well.\n>\n> Its off by default.\n>\n> You have to ask for it with \"jgit fetch --prune origin\".\n\nOk, then.  Sorry for the noise.\n"}]}