* Re: Can `git config` override entries in .gitconfig?
From: Johan Herland @ 2008-12-23 17:59 UTC (permalink / raw)
To: Nicholas LaRoche; +Cc: git
In-Reply-To: <4950D41A.5050009@vt.edu>
On Tuesday 23 December 2008, Nicholas LaRoche wrote:
> Is there a direct way to change the user.email entry for a git
> repository for one user (applied to all previous commits)?
>
> I tried `git config --unset user.email` followed by `git config
> user.email email2` but it just sets a second field called user.email
> that shows up in `git config -l` as a duplicate. My ~/.gitconfig file
> contains email1 for the user.email entry.
>
> Also, when the repository is created can I specify a second set of
> contact information (i.e. using a project specific email) which isn't a
> part of ~/.gitconfig?
>
> output of `git config -l`:
> user.email=email1
> ..
> ..
> user.email=email2
Hi,
Use git-config's --global option to set options in your ~/.gitconfig.
Otherwise, your config changes are stored in the current repo's config
(.git/config).
In your case, when you did `git config --unset user.email`, you unset the
(non-existing) user.email in your repo config, without touching the one in
~/.gitconfig, and when you did `git config user.email email2`, you set
user.email in the repo config (without changing the one in your
~/.gitconfig).
Although `git config -l` displays options from both ~/.gitconfig and the
repo config, AFAIK the repo config does _override_ the ~/.gitconfig, so
when you have user.email set in both, your new commits will use the one in
the repo config (i.e. "email2").
As for rewriting your email address in all previous commits, that is
impossible to do without rewriting your entire history. Rewriting your
history is probably not something you want to do if you have published your
repo, and other people have started working on top of your commits. If you
_do_ want to rewrite your history, you should look at the "git
filter-branch" command.
Have fun!
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply
* [JGIT PATCH 0/5] Add jgit init, clone, receive-pack; transport fixes
From: Shawn O. Pearce @ 2008-12-23 18:03 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
Define a "jgit init", "jgit clone" commands from the command line.
Add "jgit receive-pack". This now works from C git:
git push --receive-pack='jgit receive-pack' dst.git
Fix issue #22, causing jgit to fetch too many objects during an
initial clone/fetch of a repository.
Change "jgit daemon" so it can run outside of a repository, making
it slightly more useful.
Shawn O. Pearce (5):
Add "jgit receive-pack" and permit commands to start not in a
repository
Add "jgit init" command to create a new repository
Modify "jgit daemon" so it can run outside of a repository
Add "jgit clone" to support cloning off URLs that are JGit specific
Fix "fetch pulled too many objects" when auto-following tags
.../services/org.spearce.jgit.pgm.TextBuiltin | 3 +
.../org/spearce/jgit/pgm/AbstractFetchCommand.java | 126 ++++++++++++++
.../src/org/spearce/jgit/pgm/Clone.java | 177 ++++++++++++++++++++
.../src/org/spearce/jgit/pgm/Daemon.java | 33 +---
.../src/org/spearce/jgit/pgm/Fetch.java | 83 +---------
.../src/org/spearce/jgit/pgm/Init.java | 60 +++++++
.../src/org/spearce/jgit/pgm/Main.java | 19 ++-
.../src/org/spearce/jgit/pgm/ReceivePack.java | 67 ++++++++
.../src/org/spearce/jgit/pgm/TextBuiltin.java | 24 +++-
.../jgit/transport/BaseFetchConnection.java | 26 ++-
.../jgit/transport/BasePackFetchConnection.java | 25 +++-
.../spearce/jgit/transport/FetchConnection.java | 21 ++-
.../org/spearce/jgit/transport/FetchProcess.java | 6 +-
.../spearce/jgit/transport/TransportBundle.java | 3 +-
.../jgit/transport/WalkFetchConnection.java | 14 ++-
15 files changed, 544 insertions(+), 143 deletions(-)
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/AbstractFetchCommand.java
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Clone.java
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Init.java
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/ReceivePack.java
^ permalink raw reply
* [JGIT PATCH 2/5] Add "jgit init" command to create a new repository
From: Shawn O. Pearce @ 2008-12-23 18:03 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1230055423-9944-2-git-send-email-spearce@spearce.org>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../services/org.spearce.jgit.pgm.TextBuiltin | 1 +
.../src/org/spearce/jgit/pgm/Init.java | 60 ++++++++++++++++++++
2 files changed, 61 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Init.java
diff --git a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
index 0e7e7d8..4a2b605 100644
--- a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
+++ b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
@@ -4,6 +4,7 @@ org.spearce.jgit.pgm.DiffTree
org.spearce.jgit.pgm.Fetch
org.spearce.jgit.pgm.Glog
org.spearce.jgit.pgm.IndexPack
+org.spearce.jgit.pgm.Init
org.spearce.jgit.pgm.Log
org.spearce.jgit.pgm.LsRemote
org.spearce.jgit.pgm.LsTree
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Init.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Init.java
new file mode 100644
index 0000000..197864d
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Init.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.pgm;
+
+import java.io.File;
+
+import org.spearce.jgit.lib.Repository;
+
+@Command(common = true, usage = "Create an empty git repository")
+class Init extends TextBuiltin {
+ @Override
+ protected final boolean requiresRepository() {
+ return false;
+ }
+
+ @Override
+ protected void run() throws Exception {
+ if (gitdir == null)
+ gitdir = new File(".git");
+ db = new Repository(gitdir);
+ db.create();
+ out.println("Initialized empty Git repository in "
+ + gitdir.getAbsolutePath());
+ }
+}
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* [JGIT PATCH 1/5] Add "jgit receive-pack" and permit commands to start not in a repository
From: Shawn O. Pearce @ 2008-12-23 18:03 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1230055423-9944-1-git-send-email-spearce@spearce.org>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../services/org.spearce.jgit.pgm.TextBuiltin | 1 +
.../src/org/spearce/jgit/pgm/Main.java | 19 +++---
.../src/org/spearce/jgit/pgm/ReceivePack.java | 67 ++++++++++++++++++++
.../src/org/spearce/jgit/pgm/TextBuiltin.java | 24 ++++++-
4 files changed, 99 insertions(+), 12 deletions(-)
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/ReceivePack.java
diff --git a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
index 5fb0953..0e7e7d8 100644
--- a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
+++ b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
@@ -9,6 +9,7 @@ org.spearce.jgit.pgm.LsRemote
org.spearce.jgit.pgm.LsTree
org.spearce.jgit.pgm.MergeBase
org.spearce.jgit.pgm.Push
+org.spearce.jgit.pgm.ReceivePack
org.spearce.jgit.pgm.RevList
org.spearce.jgit.pgm.Rm
org.spearce.jgit.pgm.ShowRev
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Main.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Main.java
index c8bade8..8de4ae9 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Main.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Main.java
@@ -143,15 +143,18 @@ private void execute(final String[] argv) throws Exception {
System.exit(1);
}
- if (gitdir == null)
- gitdir = findGitDir();
- if (gitdir == null || !gitdir.isDirectory()) {
- System.err.println("error: can't find git directory");
- System.exit(1);
- }
-
final TextBuiltin cmd = subcommand;
- cmd.init(new Repository(gitdir));
+ if (cmd.requiresRepository()) {
+ if (gitdir == null)
+ gitdir = findGitDir();
+ if (gitdir == null || !gitdir.isDirectory()) {
+ System.err.println("error: can't find git directory");
+ System.exit(1);
+ }
+ cmd.init(new Repository(gitdir), gitdir);
+ } else {
+ cmd.init(null, gitdir);
+ }
try {
cmd.execute(arguments.toArray(new String[arguments.size()]));
} finally {
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/ReceivePack.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/ReceivePack.java
new file mode 100644
index 0000000..579f893
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/ReceivePack.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.pgm;
+
+import java.io.File;
+
+import org.kohsuke.args4j.Argument;
+import org.spearce.jgit.lib.Repository;
+
+@Command(common = false, usage = "Server side backend for 'jgit push'")
+class ReceivePack extends TextBuiltin {
+ @Argument(index = 0, required = true, metaVar = "DIRECTORY", usage = "Repository to receive into")
+ File gitdir;
+
+ @Override
+ protected final boolean requiresRepository() {
+ return false;
+ }
+
+ @Override
+ protected void run() throws Exception {
+ final org.spearce.jgit.transport.ReceivePack rp;
+
+ if (new File(gitdir, ".git").isDirectory())
+ gitdir = new File(gitdir, ".git");
+ db = new Repository(gitdir);
+ if (!db.getObjectsDirectory().isDirectory())
+ throw die("'" + gitdir.getPath() + "' not a git repository");
+ rp = new org.spearce.jgit.transport.ReceivePack(db);
+ rp.receive(System.in, System.out, System.err);
+ }
+}
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java
index 1f3a136..d3e32b3 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java
@@ -43,6 +43,7 @@
import static org.spearce.jgit.lib.Constants.R_TAGS;
import java.io.BufferedWriter;
+import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
@@ -77,6 +78,9 @@
/** Git repository the command was invoked within. */
protected Repository db;
+ /** Directory supplied via --git-dir command line option. */
+ protected File gitdir;
+
/** RevWalk used during command line parsing, if it was required. */
protected RevWalk argWalk;
@@ -84,10 +88,15 @@ final void setCommandName(final String name) {
commandName = name;
}
- void init(final Repository repo) {
+ /** @return true if {@link #db}/{@link #getRepository()} is required. */
+ protected boolean requiresRepository() {
+ return true;
+ }
+
+ void init(final Repository repo, final File gd) {
try {
- String outputEncoding = repo.getConfig().getString("i18n", null,
- "logOutputEncoding");
+ final String outputEncoding = repo != null ? repo.getConfig()
+ .getString("i18n", null, "logOutputEncoding") : null;
if (outputEncoding != null)
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(System.out, outputEncoding)));
@@ -97,7 +106,14 @@ void init(final Repository repo) {
} catch (IOException e) {
throw die("cannot create output stream");
}
- db = repo;
+
+ if (repo != null) {
+ db = repo;
+ gitdir = repo.getDirectory();
+ } else {
+ db = null;
+ gitdir = gd;
+ }
}
/**
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* [JGIT PATCH 3/5] Modify "jgit daemon" so it can run outside of a repository
From: Shawn O. Pearce @ 2008-12-23 18:03 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1230055423-9944-3-git-send-email-spearce@spearce.org>
We no longer export the current repository, but instead export the
directory trees given. This behavior is more closely matches that
of "git daemon".
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/pgm/Daemon.java | 33 +++++--------------
1 files changed, 9 insertions(+), 24 deletions(-)
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Daemon.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Daemon.java
index aafc82e..39b43b2 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Daemon.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Daemon.java
@@ -44,7 +44,6 @@
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
-import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.transport.DaemonService;
@Command(common = true, usage = "Export repositories over git://")
@@ -67,10 +66,15 @@
@Option(name = "--forbid-override", metaVar = "SERVICE", usage = "configure the service in daemon.servicename", multiValued = true)
final List<String> forbidOverride = new ArrayList<String>();
- @Argument(metaVar = "DIRECTORY", usage = "directories to export")
+ @Argument(required = true, metaVar = "DIRECTORY", usage = "directories to export")
final List<File> directory = new ArrayList<File>();
@Override
+ protected boolean requiresRepository() {
+ return false;
+ }
+
+ @Override
protected void run() throws Exception {
final org.spearce.jgit.transport.Daemon d;
@@ -88,13 +92,9 @@ protected void run() throws Exception {
for (final String n : forbidOverride)
service(d, n).setOverridable(false);
- if (directory.isEmpty()) {
- export(d, db);
- } else {
- for (final File f : directory) {
- out.println("Exporting " + f.getAbsolutePath());
- d.exportDirectory(f);
- }
+ for (final File f : directory) {
+ out.println("Exporting " + f.getAbsolutePath());
+ d.exportDirectory(f);
}
d.start();
out.println("Listening on " + d.getAddress());
@@ -107,19 +107,4 @@ private DaemonService service(final org.spearce.jgit.transport.Daemon d,
throw die("Service '" + n + "' not supported");
return svc;
}
-
- private void export(final org.spearce.jgit.transport.Daemon daemon,
- final Repository repo) {
- File d = repo.getDirectory();
- String name = d.getName();
- while (name.equals(".git") || name.equals(".")) {
- d = d.getParentFile();
- name = d.getName();
- }
- if (!name.endsWith(".git"))
- name += ".git";
-
- out.println("Exporting current repository as \"" + name + "\"");
- daemon.exportRepository(name, repo);
- }
}
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* [JGIT PATCH 4/5] Add "jgit clone" to support cloning off URLs that are JGit specific
From: Shawn O. Pearce @ 2008-12-23 18:03 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1230055423-9944-4-git-send-email-spearce@spearce.org>
The amazon-s3:// protocol is unique to JGit, and is not supported
by any other Git implementation. The easiest way to clone off of
one of those URLs is to use "jgit clone". This program also acts
as a simple example for any IDE developers who want to implement
a clone feature, as it is the minimum effort required to make a
user reasonably happy with the resulting repository.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../services/org.spearce.jgit.pgm.TextBuiltin | 1 +
.../org/spearce/jgit/pgm/AbstractFetchCommand.java | 126 ++++++++++++++
.../src/org/spearce/jgit/pgm/Clone.java | 177 ++++++++++++++++++++
.../src/org/spearce/jgit/pgm/Fetch.java | 83 +---------
4 files changed, 306 insertions(+), 81 deletions(-)
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/AbstractFetchCommand.java
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Clone.java
diff --git a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
index 4a2b605..40177f9 100644
--- a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
+++ b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
@@ -1,4 +1,5 @@
org.spearce.jgit.pgm.Branch
+org.spearce.jgit.pgm.Clone
org.spearce.jgit.pgm.Daemon
org.spearce.jgit.pgm.DiffTree
org.spearce.jgit.pgm.Fetch
diff --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
new file mode 100644
index 0000000..ea6f277
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/AbstractFetchCommand.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ *
+ * 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 Git Development Community 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.spearce.jgit.pgm;
+
+import org.kohsuke.args4j.Option;
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.RefUpdate;
+import org.spearce.jgit.transport.FetchResult;
+import org.spearce.jgit.transport.TrackingRefUpdate;
+import org.spearce.jgit.transport.Transport;
+
+abstract class AbstractFetchCommand extends TextBuiltin {
+ @Option(name = "--verbose", aliases = { "-v" }, usage = "be more verbose")
+ private boolean verbose;
+
+ protected void showFetchResult(final Transport tn, final FetchResult r) {
+ boolean shownURI = false;
+ for (final TrackingRefUpdate u : r.getTrackingRefUpdates()) {
+ if (!verbose && u.getResult() == RefUpdate.Result.NO_CHANGE)
+ continue;
+
+ final char type = shortTypeOf(u.getResult());
+ final String longType = longTypeOf(u);
+ final String src = abbreviateRef(u.getRemoteName(), false);
+ final String dst = abbreviateRef(u.getLocalName(), true);
+
+ if (!shownURI) {
+ out.print("From ");
+ out.print(tn.getURI());
+ out.println();
+ shownURI = true;
+ }
+
+ out.format(" %c %-17s %-10s -> %s", type, longType, src, dst);
+ out.println();
+ }
+ }
+
+ private String longTypeOf(final TrackingRefUpdate u) {
+ final RefUpdate.Result r = u.getResult();
+ if (r == RefUpdate.Result.LOCK_FAILURE)
+ return "[lock fail]";
+
+ if (r == RefUpdate.Result.IO_FAILURE)
+ return "[i/o error]";
+
+ if (r == RefUpdate.Result.NEW) {
+ if (u.getRemoteName().startsWith(Constants.R_HEADS))
+ return "[new branch]";
+ else if (u.getLocalName().startsWith(Constants.R_TAGS))
+ return "[new tag]";
+ return "[new]";
+ }
+
+ if (r == RefUpdate.Result.FORCED) {
+ final String aOld = u.getOldObjectId().abbreviate(db).name();
+ final String aNew = u.getNewObjectId().abbreviate(db).name();
+ return aOld + "..." + aNew;
+ }
+
+ if (r == RefUpdate.Result.FAST_FORWARD) {
+ final String aOld = u.getOldObjectId().abbreviate(db).name();
+ final String aNew = u.getNewObjectId().abbreviate(db).name();
+ return aOld + ".." + aNew;
+ }
+
+ if (r == RefUpdate.Result.REJECTED)
+ return "[rejected]";
+ if (r == RefUpdate.Result.NO_CHANGE)
+ return "[up to date]";
+ return "[" + r.name() + "]";
+ }
+
+ private static char shortTypeOf(final RefUpdate.Result r) {
+ if (r == RefUpdate.Result.LOCK_FAILURE)
+ return '!';
+ if (r == RefUpdate.Result.IO_FAILURE)
+ return '!';
+ if (r == RefUpdate.Result.NEW)
+ return '*';
+ if (r == RefUpdate.Result.FORCED)
+ return '+';
+ if (r == RefUpdate.Result.FAST_FORWARD)
+ return ' ';
+ if (r == RefUpdate.Result.REJECTED)
+ return '!';
+ if (r == RefUpdate.Result.NO_CHANGE)
+ return '=';
+ return ' ';
+ }
+}
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Clone.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Clone.java
new file mode 100644
index 0000000..51dd95d
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Clone.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.pgm;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+import org.spearce.jgit.errors.NotSupportedException;
+import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.Commit;
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.GitIndex;
+import org.spearce.jgit.lib.Ref;
+import org.spearce.jgit.lib.RefComparator;
+import org.spearce.jgit.lib.RefUpdate;
+import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.lib.TextProgressMonitor;
+import org.spearce.jgit.lib.Tree;
+import org.spearce.jgit.lib.WorkDirCheckout;
+import org.spearce.jgit.transport.FetchResult;
+import org.spearce.jgit.transport.RefSpec;
+import org.spearce.jgit.transport.RemoteConfig;
+import org.spearce.jgit.transport.Transport;
+import org.spearce.jgit.transport.URIish;
+
+@Command(common = true, usage = "Clone a repository into a new directory")
+class Clone extends AbstractFetchCommand {
+ @Option(name = "--origin", aliases = { "-o" }, metaVar = "name", usage = "use <name> instead of 'origin' to track upstream")
+ private String remoteName = "origin";
+
+ @Argument(index = 0, required = true, metaVar = "uri-ish")
+ private String sourceUri;
+
+ @Argument(index = 1, metaVar = "directory")
+ private String localName;
+
+ @Override
+ protected final boolean requiresRepository() {
+ return false;
+ }
+
+ @Override
+ protected void run() throws Exception {
+ if (localName != null && gitdir != null)
+ throw die("conflicting usage of --git-dir and arguments");
+
+ final URIish uri = new URIish(sourceUri);
+ if (localName == null) {
+ String p = uri.getPath();
+ while (p.endsWith("/"))
+ p = p.substring(0, p.length() - 1);
+ final int s = p.lastIndexOf('/');
+ if (s < 0)
+ throw die("cannot guess local name from " + sourceUri);
+ localName = p.substring(s + 1);
+ if (localName.endsWith(".git"))
+ localName = localName.substring(0, localName.length() - 4);
+ }
+ if (gitdir == null)
+ gitdir = new File(localName, ".git");
+ db = new Repository(gitdir);
+ db.create();
+ out.println("Initialized empty Git repository in "
+ + gitdir.getAbsolutePath());
+ out.flush();
+
+ saveRemote(uri);
+ final FetchResult r = runFetch();
+ final Ref branch = guessHEAD(r);
+ doCheckout(branch);
+ }
+
+ private void saveRemote(final URIish uri) throws URISyntaxException,
+ IOException {
+ final RemoteConfig rc = new RemoteConfig(db.getConfig(), remoteName);
+ rc.addURI(uri);
+ rc.addFetchRefSpec(new RefSpec().setForceUpdate(true)
+ .setSourceDestination(Constants.R_HEADS + "*",
+ Constants.R_REMOTES + remoteName + "/*"));
+ rc.update(db.getConfig());
+ db.getConfig().save();
+ }
+
+ private FetchResult runFetch() throws NotSupportedException,
+ URISyntaxException, TransportException {
+ final Transport tn = Transport.open(db, remoteName);
+ final FetchResult r;
+ try {
+ r = tn.fetch(new TextProgressMonitor(), null);
+ } finally {
+ tn.close();
+ }
+ showFetchResult(tn, r);
+ return r;
+ }
+
+ private Ref guessHEAD(final FetchResult result) {
+ final Ref idHEAD = result.getAdvertisedRef(Constants.HEAD);
+ final List<Ref> availableRefs = new ArrayList<Ref>();
+ Ref head = null;
+ for (final Ref r : result.getAdvertisedRefs()) {
+ final String n = r.getName();
+ if (!n.startsWith(Constants.R_HEADS))
+ continue;
+ availableRefs.add(r);
+ if (idHEAD == null || head != null)
+ continue;
+ if (r.getObjectId().equals(idHEAD.getObjectId()))
+ head = r;
+ }
+ Collections.sort(availableRefs, RefComparator.INSTANCE);
+ if (idHEAD != null && head == null)
+ head = idHEAD;
+ return head;
+ }
+
+ private void doCheckout(final Ref branch) throws IOException {
+ if (branch == null)
+ throw die("cannot checkout; no HEAD advertised by remote");
+ if (!Constants.HEAD.equals(branch.getName()))
+ db.writeSymref(Constants.HEAD, branch.getName());
+
+ final Commit commit = db.mapCommit(branch.getObjectId());
+ final RefUpdate u = db.updateRef(Constants.HEAD);
+ u.setNewObjectId(commit.getCommitId());
+ u.forceUpdate();
+
+ final GitIndex index = new GitIndex(db);
+ final Tree tree = commit.getTree();
+ final WorkDirCheckout co;
+
+ co = new WorkDirCheckout(db, db.getWorkDir(), index, tree);
+ co.checkout();
+ index.write();
+ }
+}
diff --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
index e9d3260..8f3f7d5 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
@@ -41,19 +41,13 @@
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
-import org.spearce.jgit.lib.Constants;
-import org.spearce.jgit.lib.RefUpdate;
import org.spearce.jgit.lib.TextProgressMonitor;
import org.spearce.jgit.transport.FetchResult;
import org.spearce.jgit.transport.RefSpec;
-import org.spearce.jgit.transport.TrackingRefUpdate;
import org.spearce.jgit.transport.Transport;
@Command(common = true, usage = "Update remote refs from another repository")
-class Fetch extends TextBuiltin {
- @Option(name = "--verbose", aliases = { "-v" }, usage = "be more verbose")
- private boolean verbose;
-
+class Fetch extends AbstractFetchCommand {
@Option(name = "--fsck", usage = "perform fsck style checks on receive")
private Boolean fsck;
@@ -91,79 +85,6 @@ protected void run() throws Exception {
} finally {
tn.close();
}
-
- boolean shownURI = false;
- for (final TrackingRefUpdate u : r.getTrackingRefUpdates()) {
- if (!verbose && u.getResult() == RefUpdate.Result.NO_CHANGE)
- continue;
-
- final char type = shortTypeOf(u.getResult());
- final String longType = longTypeOf(u);
- final String src = abbreviateRef(u.getRemoteName(), false);
- final String dst = abbreviateRef(u.getLocalName(), true);
-
- if (!shownURI) {
- out.print("From ");
- out.print(tn.getURI());
- out.println();
- shownURI = true;
- }
-
- out.format(" %c %-17s %-10s -> %s", type, longType, src, dst);
- out.println();
- }
- }
-
- private String longTypeOf(final TrackingRefUpdate u) {
- final RefUpdate.Result r = u.getResult();
- if (r == RefUpdate.Result.LOCK_FAILURE)
- return "[lock fail]";
-
- if (r == RefUpdate.Result.IO_FAILURE)
- return "[i/o error]";
-
- if (r == RefUpdate.Result.NEW) {
- if (u.getRemoteName().startsWith(Constants.R_HEADS))
- return "[new branch]";
- else if (u.getLocalName().startsWith(Constants.R_TAGS))
- return "[new tag]";
- return "[new]";
- }
-
- if (r == RefUpdate.Result.FORCED) {
- final String aOld = u.getOldObjectId().abbreviate(db).name();
- final String aNew = u.getNewObjectId().abbreviate(db).name();
- return aOld + "..." + aNew;
- }
-
- if (r == RefUpdate.Result.FAST_FORWARD) {
- final String aOld = u.getOldObjectId().abbreviate(db).name();
- final String aNew = u.getNewObjectId().abbreviate(db).name();
- return aOld + ".." + aNew;
- }
-
- if (r == RefUpdate.Result.REJECTED)
- return "[rejected]";
- if (r == RefUpdate.Result.NO_CHANGE)
- return "[up to date]";
- return "[" + r.name() + "]";
- }
-
- private static char shortTypeOf(final RefUpdate.Result r) {
- if (r == RefUpdate.Result.LOCK_FAILURE)
- return '!';
- if (r == RefUpdate.Result.IO_FAILURE)
- return '!';
- if (r == RefUpdate.Result.NEW)
- return '*';
- if (r == RefUpdate.Result.FORCED)
- return '+';
- if (r == RefUpdate.Result.FAST_FORWARD)
- return ' ';
- if (r == RefUpdate.Result.REJECTED)
- return '!';
- if (r == RefUpdate.Result.NO_CHANGE)
- return '=';
- return ' ';
+ showFetchResult(tn, r);
}
}
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* [JGIT PATCH 5/5] Fix "fetch pulled too many objects" when auto-following tags
From: Shawn O. Pearce @ 2008-12-23 18:03 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1230055423-9944-5-git-send-email-spearce@spearce.org>
If we don't take into consideration the objects obtained during
the first connection when we open a second to auto-follow tags
we will download a large chunk of the repository a second time.
This is very wasteful of network bandwidth, and is an abuse of
the server.
Because we delay all ref updates until the very end of the fetch
process we need to hold onto the set of objects we requested in
the first connection, and pass that set into the subsequent one
so it can be considered reachable.
Issue: http://code.google.com/p/egit/issues/detail?id=22
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../jgit/transport/BaseFetchConnection.java | 26 ++++++++++++-------
.../jgit/transport/BasePackFetchConnection.java | 25 +++++++++++++++----
.../spearce/jgit/transport/FetchConnection.java | 21 +++++++++++----
.../org/spearce/jgit/transport/FetchProcess.java | 6 ++++-
.../spearce/jgit/transport/TransportBundle.java | 3 +-
.../jgit/transport/WalkFetchConnection.java | 14 ++++++++--
6 files changed, 69 insertions(+), 26 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java
index 6709bfc..bb81296 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BaseFetchConnection.java
@@ -38,8 +38,10 @@
package org.spearce.jgit.transport;
import java.util.Collection;
+import java.util.Set;
import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.ProgressMonitor;
import org.spearce.jgit.lib.Ref;
@@ -54,9 +56,10 @@
abstract class BaseFetchConnection extends BaseConnection implements
FetchConnection {
public final void fetch(final ProgressMonitor monitor,
- final Collection<Ref> want) throws TransportException {
+ final Collection<Ref> want, final Set<ObjectId> have)
+ throws TransportException {
markStartedOperation();
- doFetch(monitor, want);
+ doFetch(monitor, want, have);
}
/**
@@ -68,19 +71,22 @@ public boolean didFetchIncludeTags() {
}
/**
- * Implementation of {@link #fetch(ProgressMonitor, Collection)} without
- * checking for multiple fetch.
+ * Implementation of {@link #fetch(ProgressMonitor, Collection, Set)}
+ * without checking for multiple fetch.
*
* @param monitor
- * as in {@link #fetch(ProgressMonitor, Collection)}
+ * as in {@link #fetch(ProgressMonitor, Collection, Set)}
* @param want
- * as in {@link #fetch(ProgressMonitor, Collection)}
+ * as in {@link #fetch(ProgressMonitor, Collection, Set)}
+ * @param have
+ * as in {@link #fetch(ProgressMonitor, Collection, Set)}
* @throws TransportException
- * as in {@link #fetch(ProgressMonitor, Collection)}, but
+ * as in {@link #fetch(ProgressMonitor, Collection, Set)}, but
* implementation doesn't have to care about multiple
- * {@link #fetch(ProgressMonitor, Collection)} calls, as it is
- * checked in this class.
+ * {@link #fetch(ProgressMonitor, Collection, Set)} calls, as it
+ * is checked in this class.
*/
protected abstract void doFetch(final ProgressMonitor monitor,
- final Collection<Ref> want) throws TransportException;
+ final Collection<Ref> want, final Set<ObjectId> have)
+ throws TransportException;
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
index 542a8a9..2cb9b64 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
@@ -41,10 +41,12 @@
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
+import java.util.Set;
import org.spearce.jgit.errors.TransportException;
import org.spearce.jgit.lib.AnyObjectId;
import org.spearce.jgit.lib.MutableObjectId;
+import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.ProgressMonitor;
import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.revwalk.RevCommit;
@@ -137,9 +139,10 @@ BasePackFetchConnection(final PackTransport packTransport) {
}
public final void fetch(final ProgressMonitor monitor,
- final Collection<Ref> want) throws TransportException {
+ final Collection<Ref> want, final Set<ObjectId> have)
+ throws TransportException {
markStartedOperation();
- doFetch(monitor, want);
+ doFetch(monitor, want, have);
}
public boolean didFetchIncludeTags() {
@@ -151,10 +154,11 @@ public boolean didFetchTestConnectivity() {
}
protected void doFetch(final ProgressMonitor monitor,
- final Collection<Ref> want) throws TransportException {
+ final Collection<Ref> want, final Set<ObjectId> have)
+ throws TransportException {
try {
markRefsAdvertised();
- markReachable(maxTimeWanted(want));
+ markReachable(have, maxTimeWanted(want));
if (sendWants(want)) {
negotiate(monitor);
@@ -193,7 +197,8 @@ private int maxTimeWanted(final Collection<Ref> wants) {
return maxTime;
}
- private void markReachable(final int maxTime) throws IOException {
+ private void markReachable(final Set<ObjectId> have, final int maxTime)
+ throws IOException {
for (final Ref r : local.getAllRefs().values()) {
try {
final RevCommit o = walk.parseCommit(r.getObjectId());
@@ -204,6 +209,16 @@ private void markReachable(final int maxTime) throws IOException {
}
}
+ for (final ObjectId id : have) {
+ try {
+ final RevCommit o = walk.parseCommit(id);
+ o.add(REACHABLE);
+ reachableCommits.add(o);
+ } catch (IOException readError) {
+ // If we cannot read the value of the ref skip it.
+ }
+ }
+
if (maxTime > 0) {
// Mark reachable commits until we reach maxTime. These may
// wind up later matching up against things we want and we
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java
index a56ca6c..61ef219 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchConnection.java
@@ -38,8 +38,10 @@
package org.spearce.jgit.transport;
import java.util.Collection;
+import java.util.Set;
import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.ProgressMonitor;
import org.spearce.jgit.lib.Ref;
@@ -85,23 +87,29 @@
* @param want
* one or more refs advertised by this connection that the caller
* wants to store locally.
+ * @param have
+ * additional objects known to exist in the destination
+ * repository, especially if they aren't yet reachable by the ref
+ * database. Connections should take this set as an addition to
+ * what is reachable through all Refs, not in replace of it.
* @throws TransportException
* objects could not be copied due to a network failure,
* protocol error, or error on remote side, or connection was
* already used for fetch.
*/
- public void fetch(final ProgressMonitor monitor, final Collection<Ref> want)
+ public void fetch(final ProgressMonitor monitor,
+ final Collection<Ref> want, final Set<ObjectId> have)
throws TransportException;
/**
- * Did the last {@link #fetch(ProgressMonitor, Collection)} get tags?
+ * Did the last {@link #fetch(ProgressMonitor, Collection, Set)} get tags?
* <p>
* Some Git aware transports are able to implicitly grab an annotated tag if
* {@link TagOpt#AUTO_FOLLOW} or {@link TagOpt#FETCH_TAGS} was selected and
* the object the tag peels to (references) was transferred as part of the
- * last {@link #fetch(ProgressMonitor, Collection)} call. If it is possible
- * for such tags to have been included in the transfer this method returns
- * true, allowing the caller to attempt tag discovery.
+ * last {@link #fetch(ProgressMonitor, Collection, Set)} call. If it is
+ * possible for such tags to have been included in the transfer this method
+ * returns true, allowing the caller to attempt tag discovery.
* <p>
* By returning only true/false (and not the actual list of tags obtained)
* the transport itself does not need to be aware of whether or not tags
@@ -113,7 +121,8 @@ public void fetch(final ProgressMonitor monitor, final Collection<Ref> want)
public boolean didFetchIncludeTags();
/**
- * Did the last {@link #fetch(ProgressMonitor, Collection)} validate graph?
+ * Did the last {@link #fetch(ProgressMonitor, Collection, Set)} validate
+ * graph?
* <p>
* Some transports walk the object graph on the client side, with the client
* looking for what objects it is missing and requesting them individually
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
index bb2d051..09718eb 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
@@ -75,6 +75,9 @@
/** Set of refs we will actually wind up asking to obtain. */
private final HashMap<ObjectId, Ref> askFor = new HashMap<ObjectId, Ref>();
+ /** Objects we know we have locally. */
+ private final HashSet<ObjectId> have = new HashSet<ObjectId>();
+
/** Updates to local tracking branches (if any). */
private final ArrayList<TrackingRefUpdate> localUpdates = new ArrayList<TrackingRefUpdate>();
@@ -133,6 +136,7 @@ else if (tagopt == TagOpt.FETCH_TAGS)
// There are more tags that we want to follow, but
// not all were asked for on the initial request.
//
+ have.addAll(askFor.keySet());
askFor.clear();
for (final Ref r : additionalTags) {
final ObjectId id = r.getPeeledObjectId();
@@ -173,7 +177,7 @@ else if (tagopt == TagOpt.FETCH_TAGS)
private void fetchObjects(final ProgressMonitor monitor)
throws TransportException {
- conn.fetch(monitor, askFor.values());
+ conn.fetch(monitor, askFor.values(), have);
if (transport.isCheckFetchedObjects()
&& !conn.didFetchTestConnectivity() && !askForIsComplete())
throw new TransportException(transport.getURI(),
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java
index 7d38b02..1734d94 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java
@@ -171,7 +171,8 @@ public boolean didFetchTestConnectivity() {
@Override
protected void doFetch(final ProgressMonitor monitor,
- final Collection<Ref> want) throws TransportException {
+ final Collection<Ref> want, final Set<ObjectId> have)
+ throws TransportException {
verifyPrerequisites();
try {
final IndexPack ip = newIndexPack();
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java
index d089f7b..91c5ea8 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkFetchConnection.java
@@ -195,8 +195,9 @@ public boolean didFetchTestConnectivity() {
@Override
protected void doFetch(final ProgressMonitor monitor,
- final Collection<Ref> want) throws TransportException {
- markLocalRefsComplete();
+ final Collection<Ref> want, final Set<ObjectId> have)
+ throws TransportException {
+ markLocalRefsComplete(have);
queueWants(want);
while (!monitor.isCancelled() && !workQueue.isEmpty()) {
@@ -642,7 +643,7 @@ private void saveLooseObject(final AnyObjectId id, final byte[] compressed)
return null;
}
- private void markLocalRefsComplete() throws TransportException {
+ private void markLocalRefsComplete(final Set<ObjectId> have) throws TransportException {
for (final Ref r : local.getAllRefs().values()) {
try {
markLocalObjComplete(revWalk.parseAny(r.getObjectId()));
@@ -651,6 +652,13 @@ private void markLocalRefsComplete() throws TransportException {
+ " is missing object(s).", readError);
}
}
+ for (final ObjectId id : have) {
+ try {
+ markLocalObjComplete(revWalk.parseAny(id));
+ } catch (IOException readError) {
+ throw new TransportException("Missing assumed "+id.name(), readError);
+ }
+ }
}
private void markLocalObjComplete(RevObject obj) throws IOException {
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* Re: [PATCH] strbuf_readlink semantics update.
From: Linus Torvalds @ 2008-12-23 18:16 UTC (permalink / raw)
To: Pierre Habouzit; +Cc: git, Junio C Hamano
In-Reply-To: <20081223102127.GA21485@artemis.corp>
On Tue, 23 Dec 2008, Pierre Habouzit wrote:
>
> when readlink fails, the strbuf shall not be destroyed. It's not how
> read_file_or_gitlink works for example.
I disagree.
This patch just makes things worse. Just leave the "strbuf_release()" in
_one_ place.
Look:
6 files changed, 15 insertions(+), 5 deletions(-)
you added ten unnecessary lines, and you made the interface harder to use.
What was the gain here?
> Fix read_old_data possible leaks in case of errors, since even when no
> data has been read, the strbufs may have grown to prepare the reads.
> strbuf_release must be called on them.
That's a separate error, and quite frankly, the best approach to that is
likely to instead of breaking strbuf_readlink(), just make the S_IFREG()
case release it.
I'd suggest that strbuf_read_file() should probably also do a
strbuf_release() if it returns a negative error value, but that's a
separate issue (and still leaves "read_old_data()" having to release
things, since read_old_data() wants to see exactly st_size bytes. Although
I suspect we might want to change that, and just make it test for
negative too).
Linus
^ permalink raw reply
* Re: 'Theirs' merge between branches on a binary file.
From: René Scharfe @ 2008-12-23 18:31 UTC (permalink / raw)
To: Tim Visher; +Cc: Junio C Hamano, git
In-Reply-To: <c115fd3c0812230605x369af9c0n372db761fa11ce39@mail.gmail.com>
Tim Visher schrieb:
> I'm now working on
> compiling git under cygwin as the latest version cygwin installs for
> you is 0.4!
Have you seen msysgit (http://code.google.com/p/msysgit/), the easy
route to git on Windows? It has all you need to check out and compile
the latest version of git.
René
^ permalink raw reply
* [JGIT PATCH] Teach TransportLocal how to use our own ReceivePack implementation
From: Shawn O. Pearce @ 2008-12-23 18:34 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
If the user hasn't reconfigured git receive-pack on this remote
then we can use our internal implementation instead of forking
out to the C implementation. It may be faster to stay within
the JVM then to start the external process.
In-memory pipes are constructed to copy the data between the
calling client thread and the background ReceivePack worker.
In certain cases we may even be able to do a faster copy by
directly hard-linking object files and/or packs, but that
isn't traditionally how Git behaves, so we use the standard
network protocol anyway.
Since our ReceivePack process doesn't fire hooks by default
we no longer will invoke any hooks during a push to a local
repository.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../org/spearce/jgit/transport/TransportLocal.java | 88 +++++++++++++++++++-
1 files changed, 85 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
index d74f1b3..b5dd5fc 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
@@ -43,6 +43,8 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
import org.spearce.jgit.errors.NotSupportedException;
import org.spearce.jgit.errors.TransportException;
@@ -90,7 +92,10 @@ public FetchConnection openFetch() throws TransportException {
@Override
public PushConnection openPush() throws NotSupportedException,
TransportException {
- return new LocalPushConnection();
+ final String rp = getOptionReceivePack();
+ if ("git-receive-pack".equals(rp) || "git receive-pack".equals(rp))
+ return new InternalLocalPushConnection();
+ return new ForkLocalPushConnection();
}
@Override
@@ -151,10 +156,87 @@ public void close() {
}
}
- class LocalPushConnection extends BasePackPushConnection {
+ class InternalLocalPushConnection extends BasePackPushConnection {
+ private Thread worker;
+
+ InternalLocalPushConnection() throws TransportException {
+ super(TransportLocal.this);
+
+ final Repository dst;
+ try {
+ dst = new Repository(remoteGitDir);
+ } catch (IOException err) {
+ throw new TransportException(uri, "not a git directory");
+ }
+
+ final PipedInputStream in_r;
+ final PipedOutputStream in_w;
+
+ final PipedInputStream out_r;
+ final PipedOutputStream out_w;
+ try {
+ in_r = new PipedInputStream();
+ in_w = new PipedOutputStream(in_r);
+
+ out_r = new PipedInputStream();
+ out_w = new PipedOutputStream(out_r);
+ } catch (IOException err) {
+ dst.close();
+ throw new TransportException(uri, "cannot connect pipes", err);
+ }
+
+ worker = new Thread("JGit-Receive-Pack") {
+ public void run() {
+ try {
+ final ReceivePack rp = new ReceivePack(dst);
+ rp.receive(out_r, in_w, System.err);
+ } catch (IOException err) {
+ // Client side of the pipes should report the problem.
+ } catch (RuntimeException err) {
+ // Clients side will notice we went away, and report.
+ } finally {
+ try {
+ out_r.close();
+ } catch (IOException e2) {
+ // Ignore close failure, we probably crashed above.
+ }
+
+ try {
+ in_w.close();
+ } catch (IOException e2) {
+ // Ignore close failure, we probably crashed above.
+ }
+
+ dst.close();
+ }
+ }
+ };
+ worker.start();
+
+ init(in_r, out_w);
+ readAdvertisedRefs();
+ }
+
+ @Override
+ public void close() {
+ super.close();
+
+ if (worker != null) {
+ try {
+ worker.join();
+ } catch (InterruptedException ie) {
+ // Stop waiting and return anyway.
+ } finally {
+ worker = null;
+ }
+ }
+ }
+ }
+
+ class ForkLocalPushConnection extends BasePackPushConnection {
private Process receivePack;
- LocalPushConnection() throws TransportException {
+ ForkLocalPushConnection() throws TransportException {
super(TransportLocal.this);
receivePack = startProcessWithErrStream(getOptionReceivePack());
init(receivePack.getInputStream(), receivePack.getOutputStream());
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* [JGIT PATCH 0/5] Add "jgit upload-pack" for fetch service
From: Shawn O. Pearce @ 2008-12-23 22:56 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
And uh, now we can act as a true git server, providing fetch and
clone support over git:// with our own daemon, or through the use of
"git fetch --upload-pack='jgit upload-pack'".
Roughly tested by cloning the Linux kernel and WebKit (both about
500 MB packed). Kernel takes a while to enumerate the objects,
but eh, it works. :-)
Shawn O. Pearce (5):
Sort Ref objects by OrigName and not Name
Permit subclass of ObjectId (e.g. RevObject) when calling PackWriter
Implement "jgit upload-pack" to support fetching from jgit
Fix BaseFetchPackConnection's output of selected capabilities
Switch local fetch connection to use our own UploadPack
.../services/org.spearce.jgit.pgm.TextBuiltin | 1 +
.../src/org/spearce/jgit/pgm/UploadPack.java | 67 +++
.../src/org/spearce/jgit/lib/PackWriter.java | 94 +++-
.../src/org/spearce/jgit/lib/RefComparator.java | 2 +-
.../spearce/jgit/transport/BasePackConnection.java | 3 +-
.../jgit/transport/BasePackFetchConnection.java | 4 +
.../jgit/transport/BasePackPushConnection.java | 2 +-
.../src/org/spearce/jgit/transport/Daemon.java | 36 ++-
.../org/spearce/jgit/transport/PacketLineOut.java | 19 +-
.../jgit/transport/SideBandInputStream.java | 6 +-
.../jgit/transport/SideBandOutputStream.java | 93 ++++
.../jgit/transport/SideBandProgressMonitor.java | 150 ++++++
.../org/spearce/jgit/transport/TransportLocal.java | 96 ++++-
.../src/org/spearce/jgit/transport/UploadPack.java | 491 ++++++++++++++++++++
14 files changed, 1018 insertions(+), 46 deletions(-)
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/UploadPack.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/SideBandOutputStream.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/SideBandProgressMonitor.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/UploadPack.java
^ permalink raw reply
* [JGIT PATCH 1/5] Sort Ref objects by OrigName and not Name
From: Shawn O. Pearce @ 2008-12-23 22:56 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1230073007-17337-1-git-send-email-spearce@spearce.org>
This avoids sorting symrefs by their target; instead we sort the
symref by the symref's own name, thus placing "HEAD" before the
standard "refs/heads/..." namespace.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/lib/RefComparator.java | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefComparator.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefComparator.java
index 95e3e0f..940a7ec 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefComparator.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefComparator.java
@@ -54,7 +54,7 @@
public static final RefComparator INSTANCE = new RefComparator();
public int compare(final Ref o1, final Ref o2) {
- return o1.getName().compareTo(o2.getName());
+ return o1.getOrigName().compareTo(o2.getOrigName());
}
/**
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* [JGIT PATCH 2/5] Permit subclass of ObjectId (e.g. RevObject) when calling PackWriter
From: Shawn O. Pearce @ 2008-12-23 22:56 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1230073007-17337-2-git-send-email-spearce@spearce.org>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/lib/PackWriter.java | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java b/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java
index 32bf738..32394f2 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java
@@ -436,8 +436,9 @@ public void preparePack(final Iterator<RevObject> objectsSource)
* @throws IOException
* when some I/O problem occur during reading objects.
*/
- public void preparePack(final Collection<ObjectId> interestingObjects,
- final Collection<ObjectId> uninterestingObjects,
+ public void preparePack(
+ final Collection<? extends ObjectId> interestingObjects,
+ final Collection<? extends ObjectId> uninterestingObjects,
final boolean thin, final boolean ignoreMissingUninteresting)
throws IOException {
ObjectWalk walker = setUpWalker(interestingObjects,
@@ -727,8 +728,8 @@ private void writeChecksum() throws IOException {
}
private ObjectWalk setUpWalker(
- final Collection<ObjectId> interestingObjects,
- final Collection<ObjectId> uninterestingObjects,
+ final Collection<? extends ObjectId> interestingObjects,
+ final Collection<? extends ObjectId> uninterestingObjects,
final boolean thin, final boolean ignoreMissingUninteresting)
throws MissingObjectException, IOException,
IncorrectObjectTypeException {
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* [JGIT PATCH 4/5] Fix BaseFetchPackConnection's output of selected capabilities
From: Shawn O. Pearce @ 2008-12-23 22:56 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1230073007-17337-4-git-send-email-spearce@spearce.org>
When we output the first "have ..." line for an upload-pack server
process we need to dump "have $id $cap1 $cap2 ..", where there is
a space between the SHA-1 $id and the first capability name $cap1.
If we don't dump that space we run into errors with our own version
of upload-pack not being able to parse the SHA-1 out of the line,
as the line was split incorrectly.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../spearce/jgit/transport/BasePackConnection.java | 3 +--
.../jgit/transport/BasePackPushConnection.java | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java
index e9df30e..c9232ce 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java
@@ -207,8 +207,7 @@ protected boolean isCapableOf(final String option) {
protected boolean wantCapability(final StringBuilder b, final String option) {
if (!isCapableOf(option))
return false;
- if (b.length() > 0)
- b.append(' ');
+ b.append(' ');
b.append(option);
return true;
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
index 17f6915..a078d7e 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
@@ -181,7 +181,7 @@ private String enableCapabilities() {
capableReport = wantCapability(line, CAPABILITY_REPORT_STATUS);
capableDeleteRefs = wantCapability(line, CAPABILITY_DELETE_REFS);
if (line.length() > 0)
- line.insert(0, '\0');
+ line.setCharAt(0, '\0');
return line.toString();
}
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* [JGIT PATCH 3/5] Implement "jgit upload-pack" to support fetching from jgit
From: Shawn O. Pearce @ 2008-12-23 22:56 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1230073007-17337-3-git-send-email-spearce@spearce.org>
All current options, with the exception of shallow fetch, are
supported by this implementation.
"jgit upload-pack" is included to support remote server side
execution. "jgit daemon" has also had the upload-pack service
added to its service table, making fetch over git:// possible.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../services/org.spearce.jgit.pgm.TextBuiltin | 1 +
.../src/org/spearce/jgit/pgm/UploadPack.java | 67 +++
.../src/org/spearce/jgit/lib/PackWriter.java | 85 +++-
.../jgit/transport/BasePackFetchConnection.java | 2 +
.../src/org/spearce/jgit/transport/Daemon.java | 36 ++-
.../org/spearce/jgit/transport/PacketLineOut.java | 19 +-
.../jgit/transport/SideBandInputStream.java | 6 +-
.../jgit/transport/SideBandOutputStream.java | 93 ++++
.../jgit/transport/SideBandProgressMonitor.java | 150 ++++++
.../src/org/spearce/jgit/transport/UploadPack.java | 491 ++++++++++++++++++++
10 files changed, 915 insertions(+), 35 deletions(-)
create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/UploadPack.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/SideBandOutputStream.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/SideBandProgressMonitor.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/UploadPack.java
diff --git a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
index 40177f9..1ba29e6 100644
--- a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
+++ b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
@@ -16,6 +16,7 @@ org.spearce.jgit.pgm.RevList
org.spearce.jgit.pgm.Rm
org.spearce.jgit.pgm.ShowRev
org.spearce.jgit.pgm.Tag
+org.spearce.jgit.pgm.UploadPack
org.spearce.jgit.pgm.Version
org.spearce.jgit.pgm.debug.MakeCacheTree
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/UploadPack.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/UploadPack.java
new file mode 100644
index 0000000..d6f6d7c
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/UploadPack.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.pgm;
+
+import java.io.File;
+
+import org.kohsuke.args4j.Argument;
+import org.spearce.jgit.lib.Repository;
+
+@Command(common = false, usage = "Server side backend for 'jgit fetch'")
+class UploadPack extends TextBuiltin {
+ @Argument(index = 0, required = true, metaVar = "DIRECTORY", usage = "Repository to read from")
+ File gitdir;
+
+ @Override
+ protected final boolean requiresRepository() {
+ return false;
+ }
+
+ @Override
+ protected void run() throws Exception {
+ final org.spearce.jgit.transport.UploadPack rp;
+
+ if (new File(gitdir, ".git").isDirectory())
+ gitdir = new File(gitdir, ".git");
+ db = new Repository(gitdir);
+ if (!db.getObjectsDirectory().isDirectory())
+ throw die("'" + gitdir.getPath() + "' not a git repository");
+ rp = new org.spearce.jgit.transport.UploadPack(db);
+ rp.upload(System.in, System.out, System.err);
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java b/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java
index 32394f2..89460f2 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/PackWriter.java
@@ -173,7 +173,9 @@
private final Deflater deflater;
- private final ProgressMonitor monitor;
+ private ProgressMonitor initMonitor;
+
+ private ProgressMonitor writeMonitor;
private final byte[] buf = new byte[16384]; // 16 KB
@@ -200,18 +202,41 @@
* <p>
* Objects for packing are specified in {@link #preparePack(Iterator)} or
* {@link #preparePack(Collection, Collection, boolean, boolean)}.
- *
+ *
* @param repo
* repository where objects are stored.
* @param monitor
* operations progress monitor, used within
* {@link #preparePack(Iterator)},
- * {@link #preparePack(Collection, Collection, boolean, boolean)},
- * or {@link #writePack(OutputStream)}.
+ * {@link #preparePack(Collection, Collection, boolean, boolean)}
+ * , or {@link #writePack(OutputStream)}.
*/
public PackWriter(final Repository repo, final ProgressMonitor monitor) {
+ this(repo, monitor, monitor);
+ }
+
+ /**
+ * Create writer for specified repository.
+ * <p>
+ * Objects for packing are specified in {@link #preparePack(Iterator)} or
+ * {@link #preparePack(Collection, Collection, boolean, boolean)}.
+ *
+ * @param repo
+ * repository where objects are stored.
+ * @param imonitor
+ * operations progress monitor, used within
+ * {@link #preparePack(Iterator)},
+ * {@link #preparePack(Collection, Collection, boolean, boolean)}
+ * ;
+ * @param wmonitor
+ * operations progress monitor, used within
+ * {@link #writePack(OutputStream)}.
+ */
+ public PackWriter(final Repository repo, final ProgressMonitor imonitor,
+ final ProgressMonitor wmonitor) {
this.db = repo;
- this.monitor = monitor;
+ initMonitor = imonitor;
+ writeMonitor = wmonitor;
this.deflater = new Deflater(db.getConfig().getCore().getCompression());
}
@@ -447,6 +472,17 @@ public void preparePack(
}
/**
+ * Determine if the pack file will contain the requested object.
+ *
+ * @param id
+ * the object to test the existence of.
+ * @return true if the object will appear in the output pack file.
+ */
+ public boolean willInclude(final AnyObjectId id) {
+ return objectsMap.get(id) != null;
+ }
+
+ /**
* Computes SHA-1 of lexicographically sorted objects ids written in this
* pack, as used to name a pack file in repository.
*
@@ -529,23 +565,23 @@ public void writePack(OutputStream packStream) throws IOException {
countingOut = new CountingOutputStream(packStream);
out = new DigestOutputStream(countingOut, Constants.newMessageDigest());
- monitor.beginTask(WRITING_OBJECTS_PROGRESS, getObjectsNumber());
+ writeMonitor.beginTask(WRITING_OBJECTS_PROGRESS, getObjectsNumber());
writeHeader();
writeObjects();
writeChecksum();
out.flush();
windowCursor.release();
- monitor.endTask();
+ writeMonitor.endTask();
}
private void searchForReuse() throws IOException {
- monitor.beginTask(SEARCHING_REUSE_PROGRESS, getObjectsNumber());
+ initMonitor.beginTask(SEARCHING_REUSE_PROGRESS, getObjectsNumber());
final Collection<PackedObjectLoader> reuseLoaders = new LinkedList<PackedObjectLoader>();
for (List<ObjectToPack> list : objectsLists) {
for (ObjectToPack otp : list) {
- if (monitor.isCancelled())
+ if (initMonitor.isCancelled())
throw new IOException(
"Packing cancelled during objects writing");
reuseLoaders.clear();
@@ -557,11 +593,11 @@ private void searchForReuse() throws IOException {
if (reuseObjects && !otp.hasReuseLoader()) {
selectObjectReuseForObject(otp, reuseLoaders);
}
- monitor.update(1);
+ initMonitor.update(1);
}
}
- monitor.endTask();
+ initMonitor.endTask();
}
private void selectDeltaReuseForObject(final ObjectToPack otp,
@@ -625,7 +661,7 @@ private void writeHeader() throws IOException {
private void writeObjects() throws IOException {
for (List<ObjectToPack> list : objectsLists) {
for (ObjectToPack otp : list) {
- if (monitor.isCancelled())
+ if (writeMonitor.isCancelled())
throw new IOException(
"Packing cancelled during objects writing");
if (!otp.isWritten())
@@ -663,7 +699,7 @@ private void writeObject(final ObjectToPack otp) throws IOException {
else
writeWholeObject(otp);
- monitor.update(1);
+ writeMonitor.update(1);
}
private void writeWholeObject(final ObjectToPack otp) throws IOException {
@@ -760,21 +796,34 @@ private ObjectWalk setUpWalker(
private void findObjectsToPack(final ObjectWalk walker)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {
- monitor.beginTask(COUNTING_OBJECTS_PROGRESS, ProgressMonitor.UNKNOWN);
+ initMonitor.beginTask(COUNTING_OBJECTS_PROGRESS,
+ ProgressMonitor.UNKNOWN);
RevObject o;
while ((o = walker.next()) != null) {
addObject(o);
- monitor.update(1);
+ initMonitor.update(1);
}
while ((o = walker.nextObject()) != null) {
addObject(o);
- monitor.update(1);
+ initMonitor.update(1);
}
- monitor.endTask();
+ initMonitor.endTask();
}
- private void addObject(RevObject object)
+ /**
+ * Include one object to the output file.
+ * <p>
+ * Objects are written in the order they are added. If the same object is
+ * added twice, it may be written twice, creating a larger than necessary
+ * file.
+ *
+ * @param object
+ * the object to add.
+ * @throws IncorrectObjectTypeException
+ * the object is an unsupported type.
+ */
+ public void addObject(final RevObject object)
throws IncorrectObjectTypeException {
if (object.has(RevFlag.UNINTERESTING)) {
edgeObjects.add(object);
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
index 2cb9b64..1fe504b 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
@@ -100,6 +100,8 @@
static final String OPTION_SHALLOW = "shallow";
+ static final String OPTION_NO_PROGRESS = "no-progress";
+
private final RevWalk walk;
/** All commits that are immediately reachable by a local ref. */
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Daemon.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Daemon.java
index c225740..b5097ef 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/Daemon.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Daemon.java
@@ -41,6 +41,7 @@
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
@@ -96,15 +97,32 @@ public Daemon(final InetSocketAddress addr) {
exportBase = new ArrayList<File>();
processors = new ThreadGroup("Git-Daemon");
- services = new DaemonService[] { new DaemonService("receive-pack",
- "receivepack") {
- @Override
- protected void execute(final DaemonClient dc, final Repository db)
- throws IOException {
- final ReceivePack rp = new ReceivePack(db);
- rp.receive(dc.getInputStream(), dc.getOutputStream(), null);
- }
- } };
+ services = new DaemonService[] {
+ new DaemonService("upload-pack", "uploadpack") {
+ {
+ setEnabled(true);
+ }
+
+ @Override
+ protected void execute(final DaemonClient dc,
+ final Repository db) throws IOException {
+ final UploadPack rp = new UploadPack(db);
+ final InputStream in = dc.getInputStream();
+ rp.upload(in, dc.getOutputStream(), null);
+ }
+ }, new DaemonService("receive-pack", "receivepack") {
+ {
+ setEnabled(false);
+ }
+
+ @Override
+ protected void execute(final DaemonClient dc,
+ final Repository db) throws IOException {
+ final ReceivePack rp = new ReceivePack(db);
+ final InputStream in = dc.getInputStream();
+ rp.receive(in, dc.getOutputStream(), null);
+ }
+ } };
}
/** @return the address connections are received on. */
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PacketLineOut.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PacketLineOut.java
index d37b217..aae4be5 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PacketLineOut.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PacketLineOut.java
@@ -50,7 +50,7 @@
PacketLineOut(final OutputStream i) {
out = i;
- lenbuffer = new byte[4];
+ lenbuffer = new byte[5];
}
void writeString(final String s) throws IOException {
@@ -58,12 +58,22 @@ void writeString(final String s) throws IOException {
}
void writePacket(final byte[] packet) throws IOException {
- writeLength(packet.length + 4);
+ formatLength(packet.length + 4);
+ out.write(lenbuffer, 0, 4);
out.write(packet);
}
+ void writeChannelPacket(final int channel, final byte[] buf, int off,
+ int len) throws IOException {
+ formatLength(len + 5);
+ lenbuffer[4] = (byte) channel;
+ out.write(lenbuffer, 0, 5);
+ out.write(buf, off, len);
+ }
+
void end() throws IOException {
- writeLength(0);
+ formatLength(0);
+ out.write(lenbuffer, 0, 4);
flush();
}
@@ -74,7 +84,7 @@ void flush() throws IOException {
private static final byte[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- private void writeLength(int w) throws IOException {
+ private void formatLength(int w) {
int o = 3;
while (o >= 0 && w != 0) {
lenbuffer[o--] = hexchar[w & 0xf];
@@ -82,6 +92,5 @@ private void writeLength(int w) throws IOException {
}
while (o >= 0)
lenbuffer[o--] = '0';
- out.write(lenbuffer, 0, 4);
}
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/SideBandInputStream.java b/org.spearce.jgit/src/org/spearce/jgit/transport/SideBandInputStream.java
index 3ec9bff..b08cf4d 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/SideBandInputStream.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/SideBandInputStream.java
@@ -66,11 +66,11 @@
* @see PacketLineIn#sideband(ProgressMonitor)
*/
class SideBandInputStream extends InputStream {
- private static final int CH_DATA = 1;
+ static final int CH_DATA = 1;
- private static final int CH_PROGRESS = 2;
+ static final int CH_PROGRESS = 2;
- private static final int CH_ERROR = 3;
+ static final int CH_ERROR = 3;
private static Pattern P_UNBOUNDED = Pattern.compile(
".*?([\\w ]+): (\\d+)(, done)?.*", Pattern.DOTALL);
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/SideBandOutputStream.java b/org.spearce.jgit/src/org/spearce/jgit/transport/SideBandOutputStream.java
new file mode 100644
index 0000000..31c9f5d
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/SideBandOutputStream.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.transport;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Multiplexes data and progress messages
+ * <p>
+ * To correctly use this class you must wrap it in a BufferedOutputStream with a
+ * buffer size no larger than either {@link #SMALL_BUF} or {@link #MAX_BUF},
+ * minus {@link #HDR_SIZE}.
+ */
+class SideBandOutputStream extends OutputStream {
+ static final int CH_DATA = SideBandInputStream.CH_DATA;
+
+ static final int CH_PROGRESS = SideBandInputStream.CH_PROGRESS;
+
+ static final int CH_ERROR = SideBandInputStream.CH_ERROR;
+
+ static final int SMALL_BUF = 1000;
+
+ static final int MAX_BUF = 65520;
+
+ static final int HDR_SIZE = 5;
+
+ private final int channel;
+
+ private final PacketLineOut pckOut;
+
+ private byte[] singleByteBuffer;
+
+ SideBandOutputStream(final int chan, final PacketLineOut out) {
+ channel = chan;
+ pckOut = out;
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (channel != CH_DATA)
+ pckOut.flush();
+ }
+
+ @Override
+ public void write(final byte[] b, final int off, final int len)
+ throws IOException {
+ pckOut.writeChannelPacket(channel, b, off, len);
+ }
+
+ @Override
+ public void write(final int b) throws IOException {
+ if (singleByteBuffer == null)
+ singleByteBuffer = new byte[1];
+ singleByteBuffer[0] = (byte) b;
+ write(singleByteBuffer);
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/SideBandProgressMonitor.java b/org.spearce.jgit/src/org/spearce/jgit/transport/SideBandProgressMonitor.java
new file mode 100644
index 0000000..5cda7c5
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/SideBandProgressMonitor.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.transport;
+
+import java.io.BufferedOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.ProgressMonitor;
+
+/** Write progress messages out to the sideband channel. */
+class SideBandProgressMonitor implements ProgressMonitor {
+ private PrintWriter out;
+
+ private boolean output;
+
+ private long taskBeganAt;
+
+ private long lastOutput;
+
+ private String msg;
+
+ private int lastWorked;
+
+ private int totalWork;
+
+ SideBandProgressMonitor(final PacketLineOut pckOut) {
+ final int bufsz = SideBandOutputStream.SMALL_BUF
+ - SideBandOutputStream.HDR_SIZE;
+ out = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(
+ new SideBandOutputStream(SideBandOutputStream.CH_PROGRESS,
+ pckOut), bufsz), Constants.CHARSET));
+ }
+
+ public void start(final int totalTasks) {
+ // Ignore the number of tasks.
+ taskBeganAt = System.currentTimeMillis();
+ lastOutput = taskBeganAt;
+ }
+
+ public void beginTask(final String title, final int total) {
+ endTask();
+ msg = title;
+ lastWorked = 0;
+ totalWork = total;
+ }
+
+ public void update(final int completed) {
+ if (msg == null)
+ return;
+
+ final int cmp = lastWorked + completed;
+ final long now = System.currentTimeMillis();
+ if (!output && now - taskBeganAt < 500)
+ return;
+ if (totalWork == UNKNOWN) {
+ if (now - lastOutput >= 500) {
+ display(cmp, null);
+ lastOutput = now;
+ }
+ } else {
+ if ((cmp * 100 / totalWork) != (lastWorked * 100) / totalWork
+ || now - lastOutput >= 500) {
+ display(cmp, null);
+ lastOutput = now;
+ }
+ }
+ lastWorked = cmp;
+ output = true;
+ }
+
+ private void display(final int cmp, final String eol) {
+ final StringBuilder m = new StringBuilder();
+ m.append(msg);
+ m.append(": ");
+
+ if (totalWork == UNKNOWN) {
+ m.append(cmp);
+ } else {
+ final int pcnt = (cmp * 100 / totalWork);
+ if (pcnt < 100)
+ m.append(' ');
+ if (pcnt < 10)
+ m.append(' ');
+ m.append(pcnt);
+ m.append("% (");
+ m.append(cmp);
+ m.append("/");
+ m.append(totalWork);
+ m.append(")");
+ }
+ if (eol != null)
+ m.append(eol);
+ else
+ m.append(" \r");
+ out.print(m);
+ out.flush();
+ }
+
+ public boolean isCancelled() {
+ return false;
+ }
+
+ public void endTask() {
+ if (output) {
+ if (totalWork == UNKNOWN)
+ display(lastWorked, ", done\n");
+ else
+ display(totalWork, "\n");
+ }
+ output = false;
+ msg = null;
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/UploadPack.java b/org.spearce.jgit/src/org/spearce/jgit/transport/UploadPack.java
new file mode 100644
index 0000000..4401951
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/UploadPack.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.transport;
+
+import java.io.BufferedOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.spearce.jgit.errors.PackProtocolException;
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.NullProgressMonitor;
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.PackWriter;
+import org.spearce.jgit.lib.ProgressMonitor;
+import org.spearce.jgit.lib.Ref;
+import org.spearce.jgit.lib.RefComparator;
+import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.revwalk.RevCommit;
+import org.spearce.jgit.revwalk.RevFlag;
+import org.spearce.jgit.revwalk.RevFlagSet;
+import org.spearce.jgit.revwalk.RevObject;
+import org.spearce.jgit.revwalk.RevTag;
+import org.spearce.jgit.revwalk.RevWalk;
+
+/**
+ * Implements the server side of a fetch connection, transmitting objects.
+ */
+public class UploadPack {
+ static final String OPTION_INCLUDE_TAG = BasePackFetchConnection.OPTION_INCLUDE_TAG;
+
+ static final String OPTION_MULTI_ACK = BasePackFetchConnection.OPTION_MULTI_ACK;
+
+ static final String OPTION_THIN_PACK = BasePackFetchConnection.OPTION_THIN_PACK;
+
+ static final String OPTION_SIDE_BAND = BasePackFetchConnection.OPTION_SIDE_BAND;
+
+ static final String OPTION_SIDE_BAND_64K = BasePackFetchConnection.OPTION_SIDE_BAND_64K;
+
+ static final String OPTION_OFS_DELTA = BasePackFetchConnection.OPTION_OFS_DELTA;
+
+ static final String OPTION_NO_PROGRESS = BasePackFetchConnection.OPTION_NO_PROGRESS;
+
+ /** Database we read the objects from. */
+ private final Repository db;
+
+ /** Revision traversal support over {@link #db}. */
+ private final RevWalk walk;
+
+ private InputStream rawIn;
+
+ private OutputStream rawOut;
+
+ private PacketLineIn pckIn;
+
+ private PacketLineOut pckOut;
+
+ /** The refs we advertised as existing at the start of the connection. */
+ private Map<String, Ref> refs;
+
+ /** Capabilities requested by the client. */
+ private final Set<String> options = new HashSet<String>();
+
+ /** Objects the client wants to obtain. */
+ private final List<RevObject> wantAll = new ArrayList<RevObject>();
+
+ /** Objects the client wants to obtain. */
+ private final List<RevCommit> wantCommits = new ArrayList<RevCommit>();
+
+ /** Objects on both sides, these don't have to be sent. */
+ private final List<RevObject> commonBase = new ArrayList<RevObject>();
+
+ /** Marked on objects we sent in our advertisement list. */
+ private final RevFlag ADVERTISED;
+
+ /** Marked on objects the client has asked us to give them. */
+ private final RevFlag WANT;
+
+ /** Marked on objects both we and the client have. */
+ private final RevFlag PEER_HAS;
+
+ /** Marked on objects in {@link #commonBase}. */
+ private final RevFlag COMMON;
+
+ private final RevFlagSet SAVE;
+
+ private boolean multiAck;
+
+ /**
+ * Create a new pack upload for an open repository.
+ *
+ * @param copyFrom
+ * the source repository.
+ */
+ public UploadPack(final Repository copyFrom) {
+ db = copyFrom;
+ walk = new RevWalk(db);
+
+ ADVERTISED = walk.newFlag("ADVERTISED");
+ WANT = walk.newFlag("WANT");
+ PEER_HAS = walk.newFlag("PEER_HAS");
+ COMMON = walk.newFlag("COMMON");
+ walk.carry(PEER_HAS);
+
+ SAVE = new RevFlagSet();
+ SAVE.add(ADVERTISED);
+ SAVE.add(WANT);
+ SAVE.add(PEER_HAS);
+ }
+
+ /** @return the repository this receive completes into. */
+ public final Repository getRepository() {
+ return db;
+ }
+
+ /** @return the RevWalk instance used by this connection. */
+ public final RevWalk getRevWalk() {
+ return walk;
+ }
+
+ /**
+ * Execute the upload task on the socket.
+ *
+ * @param input
+ * raw input to read client commands from. Caller must ensure the
+ * input is buffered, otherwise read performance may suffer.
+ * @param output
+ * response back to the Git network client, to write the pack
+ * data onto. Caller must ensure the output is buffered,
+ * otherwise write performance may suffer.
+ * @param messages
+ * secondary "notice" channel to send additional messages out
+ * through. When run over SSH this should be tied back to the
+ * standard error channel of the command execution. For most
+ * other network connections this should be null.
+ * @throws IOException
+ */
+ public void upload(final InputStream input, final OutputStream output,
+ final OutputStream messages) throws IOException {
+ rawIn = input;
+ rawOut = output;
+
+ pckIn = new PacketLineIn(rawIn);
+ pckOut = new PacketLineOut(rawOut);
+ service();
+ }
+
+ private void service() throws IOException {
+ sendAdvertisedRefs();
+ recvWants();
+ if (wantAll.isEmpty())
+ return;
+ multiAck = options.contains(OPTION_MULTI_ACK);
+ negotiate();
+ sendPack();
+ }
+
+ private void sendAdvertisedRefs() throws IOException {
+ refs = db.getAllRefs();
+
+ final StringBuilder m = new StringBuilder(100);
+ final char[] idtmp = new char[2 * Constants.OBJECT_ID_LENGTH];
+ final Iterator<Ref> i = RefComparator.sort(refs.values()).iterator();
+ if (i.hasNext()) {
+ final Ref r = i.next();
+ final RevObject o = safeParseAny(r.getObjectId());
+ if (o != null) {
+ advertise(m, idtmp, o, r.getOrigName());
+ m.append('\0');
+ m.append(' ');
+ m.append(OPTION_INCLUDE_TAG);
+ m.append(' ');
+ m.append(OPTION_MULTI_ACK);
+ m.append(' ');
+ m.append(OPTION_OFS_DELTA);
+ m.append(' ');
+ m.append(OPTION_SIDE_BAND);
+ m.append(' ');
+ m.append(OPTION_SIDE_BAND_64K);
+ m.append(' ');
+ m.append(OPTION_THIN_PACK);
+ m.append(' ');
+ m.append(OPTION_NO_PROGRESS);
+ m.append(' ');
+ writeAdvertisedRef(m);
+ if (o instanceof RevTag)
+ writeAdvertisedTag(m, idtmp, o, r.getName());
+ }
+ }
+ while (i.hasNext()) {
+ final Ref r = i.next();
+ final RevObject o = safeParseAny(r.getObjectId());
+ if (o != null) {
+ advertise(m, idtmp, o, r.getOrigName());
+ writeAdvertisedRef(m);
+ if (o instanceof RevTag)
+ writeAdvertisedTag(m, idtmp, o, r.getName());
+ }
+ }
+ pckOut.end();
+ }
+
+ private RevObject safeParseAny(final ObjectId id) {
+ try {
+ return walk.parseAny(id);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ private void advertise(final StringBuilder m, final char[] idtmp,
+ final RevObject o, final String name) {
+ o.add(ADVERTISED);
+ m.setLength(0);
+ o.getId().copyTo(idtmp, m);
+ m.append(' ');
+ m.append(name);
+ }
+
+ private void writeAdvertisedRef(final StringBuilder m) throws IOException {
+ m.append('\n');
+ pckOut.writeString(m.toString());
+ }
+
+ private void writeAdvertisedTag(final StringBuilder m, final char[] idtmp,
+ final RevObject tag, final String name) throws IOException {
+ RevObject o = tag;
+ while (o instanceof RevTag) {
+ // Fully unwrap here so later on we have these already parsed.
+ try {
+ walk.parse(((RevTag) o).getObject());
+ } catch (IOException err) {
+ return;
+ }
+ o = ((RevTag) o).getObject();
+ o.add(ADVERTISED);
+ }
+ advertise(m, idtmp, ((RevTag) tag).getObject(), name + "^{}");
+ writeAdvertisedRef(m);
+ }
+
+ private void recvWants() throws IOException {
+ boolean isFirst = true;
+ for (;; isFirst = false) {
+ String line;
+ try {
+ line = pckIn.readString();
+ } catch (EOFException eof) {
+ if (isFirst)
+ break;
+ throw eof;
+ }
+
+ if (line.length() == 0)
+ break;
+ if (!line.startsWith("want ") || line.length() < 45)
+ throw new PackProtocolException("expected want; got " + line);
+
+ if (isFirst) {
+ final int sp = line.indexOf(' ', 45);
+ if (sp >= 0) {
+ for (String c : line.substring(sp + 1).split(" "))
+ options.add(c);
+ line = line.substring(0, sp);
+ }
+ }
+
+ final ObjectId id = ObjectId.fromString(line.substring(5));
+ final RevObject o;
+ try {
+ o = walk.parseAny(id);
+ } catch (IOException e) {
+ throw new PackProtocolException(id.name() + " not valid", e);
+ }
+ if (!o.has(ADVERTISED))
+ throw new PackProtocolException(id.name() + " not valid");
+ want(o);
+ }
+ }
+
+ private void want(RevObject o) {
+ if (!o.has(WANT)) {
+ o.add(WANT);
+ wantAll.add(o);
+
+ if (o instanceof RevCommit)
+ wantCommits.add((RevCommit) o);
+
+ else if (o instanceof RevTag) {
+ do {
+ o = ((RevTag) o).getObject();
+ } while (o instanceof RevTag);
+ if (o instanceof RevCommit)
+ want(o);
+ }
+ }
+ }
+
+ private void negotiate() throws IOException {
+ ObjectId last = ObjectId.zeroId();
+ for (;;) {
+ String line;
+ try {
+ line = pckIn.readString();
+ } catch (EOFException eof) {
+ throw eof;
+ }
+
+ if (line.length() == 0) {
+ if (commonBase.isEmpty() || multiAck)
+ pckOut.writeString("NAK\n");
+
+ } else if (line.startsWith("have ") && line.length() == 45) {
+ final ObjectId id = ObjectId.fromString(line.substring(5));
+ if (matchHave(id)) {
+ // Both sides have the same object; let the client know.
+ //
+ if (multiAck) {
+ last = id;
+ pckOut.writeString("ACK " + id.name() + " continue\n");
+ } else if (commonBase.size() == 1)
+ pckOut.writeString("ACK " + id.name() + "\n");
+ } else {
+ // They have this object; we don't.
+ //
+ if (multiAck && okToGiveUp())
+ pckOut.writeString("ACK " + id.name() + " continue\n");
+ }
+
+ } else if (line.equals("done")) {
+ if (commonBase.isEmpty())
+ pckOut.writeString("NAK\n");
+
+ else if (multiAck)
+ pckOut.writeString("ACK " + last.name() + "\n");
+ break;
+
+ } else {
+ throw new PackProtocolException("expected have; got " + line);
+ }
+ }
+ }
+
+ private boolean matchHave(final ObjectId id) {
+ final RevObject o;
+ try {
+ o = walk.parseAny(id);
+ } catch (IOException err) {
+ return false;
+ }
+
+ if (!o.has(PEER_HAS)) {
+ o.add(PEER_HAS);
+ if (o instanceof RevCommit)
+ ((RevCommit) o).carry(PEER_HAS);
+ if (!o.has(COMMON)) {
+ o.add(COMMON);
+ commonBase.add(o);
+ }
+ }
+ return true;
+ }
+
+ private boolean okToGiveUp() throws PackProtocolException {
+ if (commonBase.isEmpty())
+ return false;
+
+ try {
+ for (final Iterator<RevCommit> i = wantCommits.iterator(); i
+ .hasNext();) {
+ final RevCommit want = i.next();
+ if (wantSatisfied(want))
+ i.remove();
+ }
+ } catch (IOException e) {
+ throw new PackProtocolException("internal revision error", e);
+ }
+ return wantCommits.isEmpty();
+ }
+
+ private boolean wantSatisfied(final RevCommit want) throws IOException {
+ walk.resetRetain(SAVE);
+ walk.markStart(want);
+ for (;;) {
+ final RevCommit c = walk.next();
+ if (c == null)
+ break;
+ if (c.has(PEER_HAS)) {
+ if (!c.has(COMMON)) {
+ c.add(COMMON);
+ commonBase.add(c);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void sendPack() throws IOException {
+ final boolean thin = options.contains(OPTION_THIN_PACK);
+ final boolean progress = !options.contains(OPTION_NO_PROGRESS);
+ final boolean sideband = options.contains(OPTION_SIDE_BAND)
+ || options.contains(OPTION_SIDE_BAND_64K);
+
+ ProgressMonitor pm = NullProgressMonitor.INSTANCE;
+ OutputStream packOut = rawOut;
+
+ if (sideband) {
+ int bufsz = SideBandOutputStream.SMALL_BUF;
+ if (options.contains(OPTION_SIDE_BAND_64K))
+ bufsz = SideBandOutputStream.MAX_BUF;
+ bufsz -= SideBandOutputStream.HDR_SIZE;
+
+ packOut = new BufferedOutputStream(new SideBandOutputStream(
+ SideBandOutputStream.CH_DATA, pckOut), bufsz);
+
+ if (progress)
+ pm = new SideBandProgressMonitor(pckOut);
+ }
+
+ final PackWriter pw;
+ pw = new PackWriter(db, pm, NullProgressMonitor.INSTANCE);
+ pw.setDeltaBaseAsOffset(options.contains(OPTION_OFS_DELTA));
+ pw.preparePack(wantAll, commonBase, thin, true);
+ if (options.contains(OPTION_INCLUDE_TAG)) {
+ for (final Ref r : refs.values()) {
+ final RevObject o;
+ try {
+ o = walk.parseAny(r.getObjectId());
+ } catch (IOException e) {
+ continue;
+ }
+ if (o.has(WANT) || !(o instanceof RevTag))
+ continue;
+ final RevTag t = (RevTag) o;
+ if (!pw.willInclude(t) && pw.willInclude(t.getObject()))
+ pw.addObject(t);
+ }
+ }
+ pw.writePack(packOut);
+
+ if (sideband) {
+ packOut.flush();
+ pckOut.end();
+ } else {
+ rawOut.flush();
+ }
+ }
+}
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* [JGIT PATCH 5/5] Switch local fetch connection to use our own UploadPack
From: Shawn O. Pearce @ 2008-12-23 22:56 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1230073007-17337-5-git-send-email-spearce@spearce.org>
Just like with push, we now use our own version of upload pack to
perform a fetch from a local repository.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../jgit/transport/BasePackFetchConnection.java | 2 +
.../org/spearce/jgit/transport/TransportLocal.java | 96 +++++++++++++++++++-
2 files changed, 95 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
index 1fe504b..19ac161 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
@@ -86,6 +86,8 @@
*/
private static final int MAX_HAVES = 256;
+ protected static final int MAX_CLIENT_BUFFER = MAX_HAVES * 46 + 1024;
+
static final String OPTION_INCLUDE_TAG = "include-tag";
static final String OPTION_MULTI_ACK = "multi_ack";
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
index b5dd5fc..17d95c2 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
@@ -86,7 +86,10 @@ TransportLocal(final Repository local, final URIish uri) {
@Override
public FetchConnection openFetch() throws TransportException {
- return new LocalFetchConnection();
+ final String up = getOptionUploadPack();
+ if ("git-upload-pack".equals(up) || "git upload-pack".equals(up))
+ return new InternalLocalFetchConnection();
+ return new ForkLocalFetchConnection();
}
@Override
@@ -130,10 +133,97 @@ protected Process startProcessWithErrStream(final String cmd)
}
}
- class LocalFetchConnection extends BasePackFetchConnection {
+ class InternalLocalFetchConnection extends BasePackFetchConnection {
+ private Thread worker;
+
+ InternalLocalFetchConnection() throws TransportException {
+ super(TransportLocal.this);
+
+ final Repository dst;
+ try {
+ dst = new Repository(remoteGitDir);
+ } catch (IOException err) {
+ throw new TransportException(uri, "not a git directory");
+ }
+
+ final PipedInputStream in_r;
+ final PipedOutputStream in_w;
+
+ final PipedInputStream out_r;
+ final PipedOutputStream out_w;
+ try {
+ in_r = new PipedInputStream();
+ in_w = new PipedOutputStream(in_r);
+
+ out_r = new PipedInputStream() {
+ // The client (BasePackFetchConnection) can write
+ // a huge burst before it reads again. We need to
+ // force the buffer to be big enough, otherwise it
+ // will deadlock both threads.
+ {
+ buffer = new byte[MAX_CLIENT_BUFFER];
+ }
+ };
+ out_w = new PipedOutputStream(out_r);
+ } catch (IOException err) {
+ dst.close();
+ throw new TransportException(uri, "cannot connect pipes", err);
+ }
+
+ worker = new Thread("JGit-Upload-Pack") {
+ public void run() {
+ try {
+ final UploadPack rp = new UploadPack(dst);
+ rp.upload(out_r, in_w, null);
+ } catch (IOException err) {
+ // Client side of the pipes should report the problem.
+ err.printStackTrace();
+ } catch (RuntimeException err) {
+ // Clients side will notice we went away, and report.
+ err.printStackTrace();
+ } finally {
+ try {
+ out_r.close();
+ } catch (IOException e2) {
+ // Ignore close failure, we probably crashed above.
+ }
+
+ try {
+ in_w.close();
+ } catch (IOException e2) {
+ // Ignore close failure, we probably crashed above.
+ }
+
+ dst.close();
+ }
+ }
+ };
+ worker.start();
+
+ init(in_r, out_w);
+ readAdvertisedRefs();
+ }
+
+ @Override
+ public void close() {
+ super.close();
+
+ if (worker != null) {
+ try {
+ worker.join();
+ } catch (InterruptedException ie) {
+ // Stop waiting and return anyway.
+ } finally {
+ worker = null;
+ }
+ }
+ }
+ }
+
+ class ForkLocalFetchConnection extends BasePackFetchConnection {
private Process uploadPack;
- LocalFetchConnection() throws TransportException {
+ ForkLocalFetchConnection() throws TransportException {
super(TransportLocal.this);
uploadPack = startProcessWithErrStream(getOptionUploadPack());
init(uploadPack.getInputStream(), uploadPack.getOutputStream());
--
1.6.1.rc4.301.g5497a
^ permalink raw reply related
* Re: Git merge conflicts and encoding of logs
From: Junichi Uekawa @ 2008-12-23 23:37 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Johannes Sixt, Junichi Uekawa, git
In-Reply-To: <7vlju7fbqu.fsf@gitster.siamese.dyndns.org>
At Tue, 23 Dec 2008 02:04:57 -0800,
Junio C Hamano wrote:
>
> Johannes Sixt <j.sixt@viscovery.net> writes:
>
> > Junio C Hamano schrieb:
> >> <<<<<<< HEAD:foo
> >> これはサイドブランチの変更です。
> >> やはり JIS コードで書いてます。
> >> =======
> >> 日本語のファイルです。
> >> JIS コードで書いてます。
> >>>>>>>>> master:foo
> >>
> >> The above will probably come out as UTF-8 in this mail text, but the point
> >> is that the confict side markers do not have anything but filename and the
> >> branch name. I am still scratching my head trying to see where in the
> >> merge-recursive codepath you got snippet of log message.
> >
> > Try rebase -i instead of merge: This should put summary lines onto the
> > conflict markers.
>
> Ah, that's cherry-pick.
>
> The fix should be around the area this weather-balloon patch touches.
>
> Note that this does not correctly work yet, and it seems that somewhere the
> string is truncated.
Hi, I've read patches from Alexander Gavrilov which try to support
per-file encoding in gitattributes (encoding), I assume such features
are not in yet.
My git repository has mixture of iso-2022-jp(platex source), EUC-JP
(some graph source code and other things), UTF-8, so log output format
unification to iso-2022-jp is not ideal. That way, I'd have to guess
which file is going to have a conflict through cherry-pick and define
the logoutput encoding.
regards,
junichi
--
dancer@{netfort.gr.jp,debian.org}
^ permalink raw reply
* Re: [PATCH 2/2] gitweb: support hiding projects from user-visible lists
From: Matt McCutchen @ 2008-12-24 1:40 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <m3ljujg2eh.fsf@localhost.localdomain>
On Sat, 2008-12-13 at 14:02 -0800, Jakub Narebski wrote:
> Cannot you do this with new $export_auth_hook gitweb configuration
> variable, added by Alexander Gavrilov in
> dd7f5f1 (gitweb: Add a per-repository authorization hook.)
> It is used in check_export_ok subroutine, and is is checked also when
> getting list of project from file
>
> >From gitweb/INSTALL
>
> - Finally, it is possible to specify an arbitrary perl subroutine that
> will be called for each project to determine if it can be exported.
> The subroutine receives an absolute path to the project as its only
> parameter.
>
> For example, if you use mod_perl to run the script, and have dumb
> http protocol authentication configured for your repositories, you
> can use the following hook to allow access only if the user is
> authorized to read the files:
>
> $export_auth_hook = sub {
> use Apache2::SubRequest ();
> use Apache2::Const -compile => qw(HTTP_OK);
> my $path = "$_[0]/HEAD";
> my $r = Apache2::RequestUtil->request;
> my $sub = $r->lookup_file($path);
> return $sub->filename eq $path
> && $sub->status == Apache2::Const::HTTP_OK;
> };
$export_auth_hook would work, and it would have the nice (but not
essential) feature of including private projects in the list shown to
suitably authenticated users. The only problem is that my Web host
doesn't support mod_perl. Is there a practical way to accomplish the
same thing as the above example in a CGI script? I would like to avoid
reimplementing Apache authentication-checking functionality if at all
possible.
--
Matt
^ permalink raw reply
* Re: [PATCH] Simplified GIT usage guide
From: Valdis.Kletnieks @ 2008-12-24 4:35 UTC (permalink / raw)
To: paulmck
Cc: Junio C Hamano, Johannes Schindelin, David Howells, torvalds, git,
linux-kernel
In-Reply-To: <20081219012723.GI6912@linux.vnet.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 941 bytes --]
On Thu, 18 Dec 2008 17:27:23 PST, "Paul E. McKenney" said:
> I would be OK with it being in linux-2.6.git rather than git.git,
> if that helps. Certainly there seems to be room for a description
> of how to use git within the Linux community.
What might help a lot of people (me, for one) would be a cookbook listing
how to do things that those of us on the fringe might want to do. For example:
"type this to pull Linus's tree, and this to bisect it" (I already know how
to do this one, actually)
"type this to pull a linux-next tree, and this to bisect it" (Last time I tried,
the pull went OK, but I couldn't figure out how to give 'git bisect' a
start/end commit that it was happy with).
"'git log foo/bar/baz.c' is your friend if you're chasing a recently added
bug/regression in baz.c"
Hmm... it occurs to me that my only actual use for git is to find a commit
ID so when I whinge to a developer, we're on the same page... ;)
[-- Attachment #2: Type: application/pgp-signature, Size: 226 bytes --]
^ permalink raw reply
* Re: [PATCH] strbuf_readlink semantics update.
From: Pierre Habouzit @ 2008-12-24 10:11 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git, Junio C Hamano
In-Reply-To: <alpine.LFD.2.00.0812231009220.3535@localhost.localdomain>
[-- Attachment #1: Type: text/plain, Size: 1420 bytes --]
On Tue, Dec 23, 2008 at 06:16:01PM +0000, Linus Torvalds wrote:
>
>
> On Tue, 23 Dec 2008, Pierre Habouzit wrote:
> >
> > when readlink fails, the strbuf shall not be destroyed. It's not how
> > read_file_or_gitlink works for example.
>
> I disagree.
>
> This patch just makes things worse. Just leave the "strbuf_release()" in
> _one_ place.
The "problem" is that the strbuf API usually works that way: functions
append things to a buffer, or do nothing, but always keep the buffer in
a state where you can append more stuff to it.
If read_file_or_gitlink or strbuf_readlink destroy the buffer, then you
break the second expectation people (should) have about the strbuf API.
The reason is that if you built things in the buffer, you really don't
want it to be undone just because the last bit you add went wrong for
some reason. Or if you have a buffer that is reused in a loop, you don't
want the buffer you allocated to be dropped just because one error
occurred.
Alternatively, we could pass a flag to tell function performing reads
(fread, read, readlink, whatever) that those should destroy the buffer
on error or just report it. I don't really know. It sounds like
over-engineering though.
--
·O· Pierre Habouzit
··O madcoder@debian.org
OOO http://www.madism.org
[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* Re: What's cooking in git.git (Dec 2008, #03; Sun, 21)
From: Johannes Schindelin @ 2008-12-24 11:55 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, git
In-Reply-To: <20081223173438.GA25699@coredump.intra.peff.net>
Hi,
On Tue, 23 Dec 2008, Jeff King wrote:
> On Tue, Dec 23, 2008 at 05:52:54PM +0100, Johannes Schindelin wrote:
>
> > However, note that without something like core.notesref you will never
> > be able to have private and public notes.
> >
> > And I very much want to have private notes _and_ public notes on the
> > very same commits of the very same branches.
>
> Right. I think core.notesref doesn't go far enough, because it doesn't
> provide a way to talk about notes from two sources at the same time.
> Like:
>
> git log --pretty=format:'%N(my-private-notes:foo) %N(public-notes:bar)'
Ah. That should be easy to do incrementally, by adding a ref_name
parameter to the functions in notes.h, which can be NULL (falling back to
the default ref).
> > And while I am almost sure that there is a stupid bug lurking that
> > will kick the performance again, I think the basic design is sound,
> > and it should be easy to modify no matter which way you want to change
> > the behavior with regards to trees/blobs or refs.
>
> I agree that the data structure is sound, so I can probably work on top
> of what you posted, too. I was planning on doing git-notes in C, though.
Sure. git-notes.sh is only in shell script to provide a proof-of-concept,
and an example how to have an ultra-narrow "checkout" of the notes ref's
tree.
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH] strbuf_readlink semantics update.
From: René Scharfe @ 2008-12-24 15:20 UTC (permalink / raw)
To: Pierre Habouzit; +Cc: Linus Torvalds, git, Junio C Hamano
In-Reply-To: <20081224101146.GA10008@artemis.corp>
Pierre Habouzit schrieb:
> On Tue, Dec 23, 2008 at 06:16:01PM +0000, Linus Torvalds wrote:
>>
>> On Tue, 23 Dec 2008, Pierre Habouzit wrote:
>>> when readlink fails, the strbuf shall not be destroyed. It's not how
>>> read_file_or_gitlink works for example.
>> I disagree.
>>
>> This patch just makes things worse. Just leave the "strbuf_release()" in
>> _one_ place.
>
> The "problem" is that the strbuf API usually works that way: functions
> append things to a buffer, or do nothing, but always keep the buffer in
> a state where you can append more stuff to it.
>
> If read_file_or_gitlink or strbuf_readlink destroy the buffer, then you
> break the second expectation people (should) have about the strbuf API.
The "append or do nothing" rule is broken by strbuf_getline(), but I agree
to your reasoning. How about refining this rule a bit to "do your thing
and roll back changes if an error occurs"? I think it's not worth to undo
allocation extensions, but making reverting first time allocations seems
like a good idea. Something like this?
René
PS: only nine lines! ;-)
strbuf.c | 17 +++++++++++++----
1 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/strbuf.c b/strbuf.c
index bdf4954..6ed0684 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -256,18 +256,21 @@ size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
{
size_t res;
+ size_t oldalloc = sb->alloc;
strbuf_grow(sb, size);
res = fread(sb->buf + sb->len, 1, size, f);
- if (res > 0) {
+ if (res > 0)
strbuf_setlen(sb, sb->len + res);
- }
+ else if (res < 0 && oldalloc == 0)
+ strbuf_release(sb);
return res;
}
ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
{
size_t oldlen = sb->len;
+ size_t oldalloc = sb->alloc;
strbuf_grow(sb, hint ? hint : 8192);
for (;;) {
@@ -275,7 +278,10 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
if (cnt < 0) {
- strbuf_setlen(sb, oldlen);
+ if (oldalloc == 0)
+ strbuf_release(sb);
+ else
+ strbuf_setlen(sb, oldlen);
return -1;
}
if (!cnt)
@@ -292,6 +298,8 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
{
+ size_t oldalloc = sb->alloc;
+
if (hint < 32)
hint = 32;
@@ -311,7 +319,8 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
/* .. the buffer was too small - try again */
hint *= 2;
}
- strbuf_release(sb);
+ if (oldalloc == 0)
+ strbuf_release(sb);
return -1;
}
^ permalink raw reply related
* [PATCH] builtin-shortlog.c: use string_list_append() instead of duplicating its code
From: Adeodato Simó @ 2008-12-24 16:34 UTC (permalink / raw)
To: git, gitster; +Cc: Adeodato Simó
Also, when clearing the "onelines" string lists, do not free the "util"
member: with string_list_append() is not initialized to any value (and
was being initialized to NULL previously anyway).
NB: The duplicated code in builtin-shortlog.c predated the appearance of
string_list_append().
Signed-off-by: Adeodato Simó <dato@net.com.org.es>
---
builtin-shortlog.c | 14 ++------------
1 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index d03f14f..4c5d761 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -36,7 +36,6 @@ static void insert_one_record(struct shortlog *log,
const char *dot3 = log->common_repo_prefix;
char *buffer, *p;
struct string_list_item *item;
- struct string_list *onelines;
char namebuf[1024];
size_t len;
const char *eol;
@@ -104,16 +103,7 @@ static void insert_one_record(struct shortlog *log,
}
}
- onelines = item->util;
- if (onelines->nr >= onelines->alloc) {
- onelines->alloc = alloc_nr(onelines->nr);
- onelines->items = xrealloc(onelines->items,
- onelines->alloc
- * sizeof(struct string_list_item));
- }
-
- onelines->items[onelines->nr].util = NULL;
- onelines->items[onelines->nr++].string = buffer;
+ string_list_append(buffer, item->util);
}
static void read_from_stdin(struct shortlog *log)
@@ -323,7 +313,7 @@ void shortlog_output(struct shortlog *log)
}
onelines->strdup_strings = 1;
- string_list_clear(onelines, 1);
+ string_list_clear(onelines, 0);
free(onelines);
log->list.items[i].util = NULL;
}
--
1.6.0.4
^ permalink raw reply related
* [PATCH] builtin-shortlog.c: do not unnecessarily strdup before insertion in list
From: Adeodato Simó @ 2008-12-24 16:34 UTC (permalink / raw)
To: git, gitster; +Cc: Adeodato Simó
The log->list always has "strdup_strings" activated, hence strdup'ing
namebuf was unnecessary. This change also removes a latent memory leak
in the old code.
Signed-off-by: Adeodato Simó <dato@net.com.org.es>
---
builtin-shortlog.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index 4c5d761..90e76ae 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -67,12 +67,9 @@ static void insert_one_record(struct shortlog *log,
snprintf(namebuf + len, room, " %.*s", maillen, boemail);
}
- buffer = xstrdup(namebuf);
- item = string_list_insert(buffer, &log->list);
+ item = string_list_insert(namebuf, &log->list);
if (item->util == NULL)
item->util = xcalloc(1, sizeof(struct string_list));
- else
- free(buffer);
/* Skip any leading whitespace, including any blank lines. */
while (*oneline && isspace(*oneline))
--
1.6.0.4
^ permalink raw reply related
* Re: Git with Hudson
From: R. Tyler Ballance @ 2008-12-24 20:59 UTC (permalink / raw)
To: Stephen Haberman; +Cc: Tim Visher, Indy Nagpal, git
In-Reply-To: <20081222210018.f21d9e07.stephen@exigencecorp.com>
[-- Attachment #1: Type: text/plain, Size: 679 bytes --]
On Mon, 2008-12-22 at 21:00 -0600, Stephen Haberman wrote:
> > I'm interested! Please publish away!
>
> Here's the "git2" Hudson plugin that worked well for us:
>
> http://github.com/stephenh/hudson-git2
>
> There is a git.hpi file checked into the target directory so that you
> don't have to build it yourself.
I decided that I'd check this out, as the existing Git plugin chokes on
our git-rev-list(1) on our enormous Git repository.
Correct me if I'm wrong, but did you actually upload or check in the
target/ directory? Your .markdown references target/git.hpi as well, but
I can't seem to find it :-/
Cheers
--
-R. Tyler Ballance
Slide, Inc.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox