* Re: I want to release a "git-1.0"
From: Petr Baudis @ 2005-06-03 9:47 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Linus Torvalds, Eric W. Biederman, Git Mailing List
In-Reply-To: <Pine.LNX.4.21.0506011742560.30848-100000@iabervon.org>
Dear diary, on Thu, Jun 02, 2005 at 12:00:55AM CEST, I got a letter
where Daniel Barkalow <barkalow@iabervon.org> told me that...
> It shouldn't be hard to do one, except that locking with rsync is going to
> be a pain. I had a patch to make it work with the rpush/rpull pair, but I
> didn't get its dependancies in at the time.
Was that the patch I was replying to recently? It didn't seem to have
any dependencies.
> I can dust those patches off again if you want that functionality included.
>
> The patches are essentially:
>
> - make the transport protocol handle things other than objects
> - library procedure for locking atomic update of refs files
> - fetching refs in general
> - rpull/rpush that updates a specified ref file atomically
>
> At least the first would be very nice to get in before 1.0, since it is an
> incompatible change to the protocol.
I would like to have this a lot too. Pulling tags now is a PITA, and I
definitively want to go in this way. So it will land at least in git-pb.
:-) (But that's a little troublesome if you say it's incompatible
change.)
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
^ permalink raw reply
* Re: [PATCH] git-tar-tree: add a test case (resent)
From: Rene Scharfe @ 2005-06-03 11:25 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git, Petr Baudis, Junio C Hamano
In-Reply-To: <Pine.LNX.4.58.0506021830340.1876@ppc970.osdl.org>
Linus Torvalds schrieb:
>
> On Thu, 2 Jun 2005, Rene Scharfe wrote:
>
>>git-tar-tree: add a simple test case.
>
>
> I get:
>
> * FAIL 6: extract tar archive (cd b && tar xf -) <b.tar
> * FAIL 7: validate filenames (cd b/a && find .) | sort >b.lst &&
> * FAIL 8: validate file contents diff -r a b/a
> * FAIL 11: validate filenames with prefix (cd c/prefix/a && find .) | sort >c.lst &&
> * FAIL 12: validate file contents with prefix diff -r a c/prefix/a
Meine Fresse, what a stoopid bug. Fortunately I introduced it with one
of the other two patches sent together with the test case patch, namely
"[PATCH] git-tar-tree: cleanup write_trailer() (resent)". Of course I
only wanted to demonstrate how useful those tests really are. ;-)
Btw., I got it right the first time and messed up when resending..
write_trailer() writes the last 10k (a full block) of the tar archive.
write_if_needed() writes out a block *if* it is full and then sets
the offset to 0. In nine out of ten cases the messed up write_trailer()
function didn't manage to fill the block thus not writing anything at
all, truncating the archive. I was "lucky" to hit the other case and so
my testing ran OK.
Here's a patch.
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
--- a/tar-tree.c
+++ b/tar-tree.c
@@ -77,7 +77,7 @@
write_if_needed();
get_record();
write_if_needed();
- if (offset) {
+ while (offset) {
get_record();
write_if_needed();
}
^ permalink raw reply
* [PATCH] simple one-liner for README file
From: Konstantin Antselovich @ 2005-06-03 11:22 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
[-- Attachment #1: Type: text/plain, Size: 290 bytes --]
Hi Petr,
I noticed a very small error in README file.
I'm not sure if I should submit is as a patch, as
it's just a change to one line. (but I attached a patch anyways)
Regards,
-Konstantin
--
Konstantin Antselovich
mailto: konstantin@antselovich.com
http://konstantin.antselovich.com
[-- Attachment #2: readme.patch --]
[-- Type: text/x-patch, Size: 1093 bytes --]
Simple one-liner for an error in README file.
Suggested command
'cg-clone -s rsync://rsync.kernel.org/pub/scm/cogito/cogito.git cogitodir'
leads to: cg-clone: specifying both -s and DESTDIR makes no sense
So, just delete directory name from the end of line
---
commit a8f5b28c32978d7b0c996172e15e61f3e63b6ff4
tree fc5ee658a6fedd886d43c6342e9df184fd751fbd
parent d140154ad84eb3fc89c4d7cb2019412bcf8e3ed7
author Konstantin Antselovich <konstantin@antselovich.com> Fri, 03 Jun 2005 04:11:59 -0700
committer Konstantin Antselovich <konstantin@antselovich.com> Fri, 03 Jun 2005 04:11:59 -0700
README | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/README b/README
--- a/README
+++ b/README
@@ -106,7 +106,7 @@ If, instead, you want to clone the repos
first make sure you are in an empty directory. Then give the following
command:
- $ cg-clone -s rsync://rsync.kernel.org/pub/scm/cogito/cogito.git cogitodir
+ $ cg-clone -s rsync://rsync.kernel.org/pub/scm/cogito/cogito.git
When you get your prompt back, do an ls to see the source tree and .git
directory.
^ permalink raw reply
* Re: qgit-0.3
From: Radoslaw Szkodzinski @ 2005-06-03 12:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: git
In-Reply-To: <1117770909.31082.121.camel@gaston>
Benjamin Herrenschmidt wrote:
>On Wed, 2005-06-01 at 13:19 +0200, Marco Costalba wrote:
>
>
>>New version of qgit, the QT/C++ git viewer.
>>
>>Download at:
>>
>>http://prdownloads.sourceforge.net/qgit/qgit-0.3.tar.gz?download
>>
>>This time we use scons instead of qmake as build system (many thanks to Stanislav Karchebny), I
>>hope people have less problems compiling it.
>>
>>As before just run make and copy the bin in the path.
>>
>>New feature is async loading of diff and file blobs, should be much faster navigate the logs with
>>secondary windows (double click on logs or file names to show) opened.
>>
>>
>
>I spent 1/2h and never managed to build it. When it doesn't find some
>includes, it doesn't look for some Qt related binaries in the right
>path, or whatever, it's just basically unbuildable.
>
>Ben.
>
>
>
>
It is buildable, but you need to install your own scons in the correct
paths, e.g.
on Gentoo:
emerge scons
And then build it by hand with:
./configure
scons
Then you get bin/qgit which is ready to run and/or copy.
AstralStorm
^ permalink raw reply
* Re: [PATCH] git-tar-tree: add a test case (resent)
From: Linus Torvalds @ 2005-06-03 14:31 UTC (permalink / raw)
To: Rene Scharfe; +Cc: git
In-Reply-To: <429FEBD5.5040306@lsrfire.ath.cx>
On Fri, 3 Jun 2005, Rene Scharfe wrote:
>
> What version of tar do you use?
torvalds@ppc970:~> tar --version
tar (GNU tar) 1.13.25
Copyright © 2001 Free Software Foundation, Inc.
This program comes with NO WARRANTY, to the extent permitted by law.
You may redistribute it under the terms of the GNU General Public License;
see the file named COPYING for details.
Written by John Gilmore and Jay Fenlason.
> Also, can you please send me the output
> the following?
>
> cd t; sh t5000-tar-tree.sh; cd trash; tar tvf b.tar
I get
?rw------- git/git 52 1969-12-31 16:00:00 pax_global_header unknown file type `g'
drwxr-xr-x git/git 0 2005-05-27 15:00:00 a/
-rw-r--r-- git/git 18 2005-05-27 15:00:00 a/1.......10........20........30........40......481.......10........20........30........40........50
?rw------- git/git 111 2005-05-27 15:00:00 37e07bc886b166ad2525f1cc7a2df9bda0e07a02.paxheader unknown file type `x'
-rw-r--r-- git/git 18 2005-05-27 15:00:00 37e07bc886b166ad2525f1cc7a2df9bda0e07a02.data
?rw------- git/git 112 2005-05-27 15:00:00 f72c8a14fa272506e5de2d779cfe088769158b61.paxheader unknown file type `x'
-rw-r--r-- git/git 18 2005-05-27 15:00:00 f72c8a14fa272506e5de2d779cfe088769158b61.data
?rw------- git/git 113 2005-05-27 15:00:00 b53ac87f1a63ea1a2eec65cc8b5bed9130b8c114.paxheader unknown file type `x'
-rw-r--r-- git/git 18 2005-05-27 15:00:00 b53ac87f1a63ea1a2eec65cc8b5bed9130b8c114.data
-rw-r--r-- git/git 16 2005-05-27 15:00:00 a/a
drwxr-xr-x git/git 0 2005-05-27 15:00:00 a/bin/
-rwxr-xr-x git/git 719924 2005-05-27 15:00:00 a/bin/sh
tar: Unexpected EOF in archive
tar: Error is not recoverable: exiting now
which doesn't tell me anything, except I assume it means that my tar
doesn't understand extended headers.
Linus
^ permalink raw reply
* Re: [PATCH] git-tar-tree: add a test case (resent)
From: Rene Scharfe @ 2005-06-03 14:43 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0506030728120.1876@ppc970.osdl.org>
Linus Torvalds schrieb:
> torvalds@ppc970:~> tar --version
> tar (GNU tar) 1.13.25
> Copyright © 2001 Free Software Foundation, Inc.
> This program comes with NO WARRANTY, to the extent permitted by law.
> You may redistribute it under the terms of the GNU General Public License;
> see the file named COPYING for details.
> Written by John Gilmore and Jay Fenlason.
[...]
> I get
>
> ?rw------- git/git 52 1969-12-31 16:00:00 pax_global_header unknown file type `g'
> drwxr-xr-x git/git 0 2005-05-27 15:00:00 a/
> -rw-r--r-- git/git 18 2005-05-27 15:00:00 a/1.......10........20........30........40......481.......10........20........30........40........50
> ?rw------- git/git 111 2005-05-27 15:00:00 37e07bc886b166ad2525f1cc7a2df9bda0e07a02.paxheader unknown file type `x'
> -rw-r--r-- git/git 18 2005-05-27 15:00:00 37e07bc886b166ad2525f1cc7a2df9bda0e07a02.data
> ?rw------- git/git 112 2005-05-27 15:00:00 f72c8a14fa272506e5de2d779cfe088769158b61.paxheader unknown file type `x'
> -rw-r--r-- git/git 18 2005-05-27 15:00:00 f72c8a14fa272506e5de2d779cfe088769158b61.data
> ?rw------- git/git 113 2005-05-27 15:00:00 b53ac87f1a63ea1a2eec65cc8b5bed9130b8c114.paxheader unknown file type `x'
> -rw-r--r-- git/git 18 2005-05-27 15:00:00 b53ac87f1a63ea1a2eec65cc8b5bed9130b8c114.data
> -rw-r--r-- git/git 16 2005-05-27 15:00:00 a/a
> drwxr-xr-x git/git 0 2005-05-27 15:00:00 a/bin/
> -rwxr-xr-x git/git 719924 2005-05-27 15:00:00 a/bin/sh
> tar: Unexpected EOF in archive
> tar: Error is not recoverable: exiting now
>
> which doesn't tell me anything, except I assume it means that my tar
> doesn't understand extended headers.
That's true, but you don't need them if all your pathes' lengths are 100
or shorter. Of course the test exercising long paths will always fail
with your version of tar. I should split it out better, so you will at
least get a positive result for short paths. I just didn't expect such
an old version of tar to be in use anymore. :-P
But your output shows a more serious problem: "Unexpected EOF" means the
archive is missing a piece. I sent you a patch for that bug in my
previous mail.
Thanks,
Rene
^ permalink raw reply
* Re: [PATCH] git-tar-tree: add a test case (resent)
From: Linus Torvalds @ 2005-06-03 14:46 UTC (permalink / raw)
To: Rene Scharfe; +Cc: git, Petr Baudis, Junio C Hamano
In-Reply-To: <42A03E1E.5060204@lsrfire.ath.cx>
On Fri, 3 Jun 2005, Rene Scharfe wrote:
>
> Here's a patch.
This one fixes failure 6 for me, but 7, 8, 11 and 12 still fail.
Doing a
sh t5000-tar-tree.sh -i -v
ends with
* expecting success: (cd b/a && find .) | sort >b.lst &&
diff a.lst b.lst
3,5d2
< ./1.......10........20........30........40......481.......10........20........30........40........50x
< ./1.......10........20........30........40......481.......10........20........30........40........50xx
< ./1.......10........20........30........40......481.......10........20........30........40........50xxx
10d6
< ./l1.......10........20........30........40......481.......10........20........30........40........50
12d7
< ./l101
* FAIL 7: validate filenames (cd b/a && find .) | sort >b.lst &&
diff a.lst b.lst
and you already saw my output from "tar tvf b.tar", so you already know
that this is probably due to not understanding extended headers.
Linus
^ permalink raw reply
* Re: [PATCH] git-tar-tree: add a test case (resent)
From: Linus Torvalds @ 2005-06-03 14:51 UTC (permalink / raw)
To: Rene Scharfe; +Cc: git, Petr Baudis, Junio C Hamano
In-Reply-To: <Pine.LNX.4.58.0506030737050.1876@ppc970.osdl.org>
On Fri, 3 Jun 2005, Linus Torvalds wrote:
>
> and you already saw my output from "tar tvf b.tar", so you already know
> that this is probably due to not understanding extended headers.
My other ppc64 box (running Fedora core 3.92) has no problems, so this is
apparently something that has been changed between tar 1.13.25 and 1.15.1
(YDL 4.0 vs Fedora Core tar versions).
Linus
^ permalink raw reply
* [PATCH] Anal retentive 'const unsigned char *sha1'
From: Jason McMullan @ 2005-06-03 15:05 UTC (permalink / raw)
To: git
Anal Retentive: make 'sha1' parameters const where possible
Signed-off-by: Jason McMullan <jason.mcmullan@timesys.com>
diff --git a/blob.c b/blob.c
--- a/blob.c
+++ b/blob.c
@@ -4,7 +4,7 @@
const char *blob_type = "blob";
-struct blob *lookup_blob(unsigned char *sha1)
+struct blob *lookup_blob(const unsigned char *sha1)
{
struct object *obj = lookup_object(sha1);
if (!obj) {
diff --git a/blob.h b/blob.h
--- a/blob.h
+++ b/blob.h
@@ -9,7 +9,7 @@ struct blob {
struct object object;
};
-struct blob *lookup_blob(unsigned char *sha1);
+struct blob *lookup_blob(const unsigned char *sha1);
int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -157,7 +157,7 @@ extern void * unpack_sha1_file(void *map
extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
-extern int check_sha1_signature(unsigned char *sha1, void *buf, unsigned long size, const char *type);
+extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
/* Read a tree into the cache */
extern int read_tree(void *buffer, unsigned long size, int stage);
diff --git a/commit.c b/commit.c
--- a/commit.c
+++ b/commit.c
@@ -4,7 +4,7 @@
const char *commit_type = "commit";
-static struct commit *check_commit(struct object *obj, unsigned char *sha1)
+static struct commit *check_commit(struct object *obj, const unsigned char *sha1)
{
if (obj->type != commit_type) {
error("Object %s is a %s, not a commit",
@@ -14,7 +14,7 @@ static struct commit *check_commit(struc
return (struct commit *) obj;
}
-struct commit *lookup_commit_reference(unsigned char *sha1)
+struct commit *lookup_commit_reference(const unsigned char *sha1)
{
struct object *obj = parse_object(sha1);
@@ -25,7 +25,7 @@ struct commit *lookup_commit_reference(u
return check_commit(obj, sha1);
}
-struct commit *lookup_commit(unsigned char *sha1)
+struct commit *lookup_commit(const unsigned char *sha1)
{
struct object *obj = lookup_object(sha1);
if (!obj) {
diff --git a/commit.h b/commit.h
--- a/commit.h
+++ b/commit.h
@@ -19,8 +19,8 @@ struct commit {
extern const char *commit_type;
-struct commit *lookup_commit(unsigned char *sha1);
-struct commit *lookup_commit_reference(unsigned char *sha1);
+struct commit *lookup_commit(const unsigned char *sha1);
+struct commit *lookup_commit_reference(const unsigned char *sha1);
int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size);
diff --git a/delta.c b/delta.c
--- a/delta.c
+++ b/delta.c
@@ -17,7 +17,7 @@ struct delta {
} u;
};
-struct delta *lookup_delta(unsigned char *sha1)
+struct delta *lookup_delta(const unsigned char *sha1)
{
struct object *obj = lookup_object(sha1);
if (!obj) {
diff --git a/delta.h b/delta.h
--- a/delta.h
+++ b/delta.h
@@ -12,7 +12,7 @@ extern void *patch_delta(void *src_buf,
/* handling of delta objects */
struct delta;
struct object_list;
-extern struct delta *lookup_delta(unsigned char *sha1);
+extern struct delta *lookup_delta(const unsigned char *sha1);
extern int parse_delta_buffer(struct delta *item, void *buffer, unsigned long size);
extern int parse_delta(struct delta *item, unsigned char sha1);
extern int process_deltas(void *src, unsigned long src_size,
diff --git a/object.c b/object.c
--- a/object.c
+++ b/object.c
@@ -10,7 +10,7 @@ struct object **objs;
int nr_objs;
static int obj_allocs;
-static int find_object(unsigned char *sha1)
+static int find_object(const unsigned char *sha1)
{
int first = 0, last = nr_objs;
@@ -31,7 +31,7 @@ static int find_object(unsigned char *sh
return -first-1;
}
-struct object *lookup_object(unsigned char *sha1)
+struct object *lookup_object(const unsigned char *sha1)
{
int pos = find_object(sha1);
if (pos >= 0)
@@ -39,7 +39,7 @@ struct object *lookup_object(unsigned ch
return NULL;
}
-void created_object(unsigned char *sha1, struct object *obj)
+void created_object(const unsigned char *sha1, struct object *obj)
{
int pos = find_object(sha1);
@@ -98,7 +98,7 @@ void mark_reachable(struct object *obj,
}
}
-struct object *parse_object(unsigned char *sha1)
+struct object *parse_object(const unsigned char *sha1)
{
unsigned long mapsize;
void *map = map_sha1_file(sha1, &mapsize);
diff --git a/object.h b/object.h
--- a/object.h
+++ b/object.h
@@ -20,12 +20,12 @@ struct object {
extern int nr_objs;
extern struct object **objs;
-struct object *lookup_object(unsigned char *sha1);
+struct object *lookup_object(const unsigned char *sha1);
-void created_object(unsigned char *sha1, struct object *obj);
+void created_object(const unsigned char *sha1, struct object *obj);
/** Returns the object, having parsed it to find out what it is. **/
-struct object *parse_object(unsigned char *sha1);
+struct object *parse_object(const unsigned char *sha1);
void add_ref(struct object *refer, struct object *target);
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -257,7 +257,7 @@ static char *find_sha1_file(const unsign
return NULL;
}
-int check_sha1_signature(unsigned char *sha1, void *map, unsigned long size, const char *type)
+int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
{
char header[100];
unsigned char real_sha1[20];
diff --git a/tag.c b/tag.c
--- a/tag.c
+++ b/tag.c
@@ -3,7 +3,7 @@
const char *tag_type = "tag";
-struct tag *lookup_tag(unsigned char *sha1)
+struct tag *lookup_tag(const unsigned char *sha1)
{
struct object *obj = lookup_object(sha1);
if (!obj) {
diff --git a/tag.h b/tag.h
--- a/tag.h
+++ b/tag.h
@@ -12,7 +12,7 @@ struct tag {
char *signature; /* not actually implemented */
};
-extern struct tag *lookup_tag(unsigned char *sha1);
+extern struct tag *lookup_tag(const unsigned char *sha1);
extern int parse_tag_buffer(struct tag *item, void *data, unsigned long size);
extern int parse_tag(struct tag *item);
diff --git a/tree.c b/tree.c
--- a/tree.c
+++ b/tree.c
@@ -73,7 +73,7 @@ int read_tree(void *buffer, unsigned lon
return read_tree_recursive(buffer, size, "", 0, stage);
}
-struct tree *lookup_tree(unsigned char *sha1)
+struct tree *lookup_tree(const unsigned char *sha1)
{
struct object *obj = lookup_object(sha1);
if (!obj) {
diff --git a/tree.h b/tree.h
--- a/tree.h
+++ b/tree.h
@@ -24,7 +24,7 @@ struct tree {
struct tree_entry_list *entries;
};
-struct tree *lookup_tree(unsigned char *sha1);
+struct tree *lookup_tree(const unsigned char *sha1);
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);
======== end ========
--
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation
^ permalink raw reply
* [PATCH] Expose more sha1_file.c interfaces
From: Jason McMullan @ 2005-06-03 15:08 UTC (permalink / raw)
To: git
Expose more SHA1 file interfaces:
/* Unpack the rest of a SHA1 file, after using unpack_sha1_header()
*/
void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size);
/* Copy SHA1 object file between FDs, and verify that the SHA1 is as
* expected. Useful for pulling from a socket into a temporary file
* before you run object reference dependency checks. (Hint Hint people
* maintaining pull.c!)
*/
int write_sha1_from_fd_to_fd(const unsigned char *sha1, int fd, int fd_local);
Signed-off-by: Jason McMullan <jason.mcmullan@timesys.com>
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -153,6 +153,7 @@ extern char *sha1_file_name(const unsign
extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
+extern void *unpack_sha1_rest(z_stream *stream, void *buffer, unsigned long size);
extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
@@ -162,6 +163,7 @@ extern int check_sha1_signature(const un
/* Read a tree into the cache */
extern int read_tree(void *buffer, unsigned long size, int stage);
+extern int write_sha1_from_fd_to_fd(const unsigned char *sha1, int fd, int fd_local);
extern int write_sha1_from_fd(const unsigned char *sha1, int fd);
extern int has_sha1_file(const unsigned char *sha1);
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -579,23 +579,15 @@ int write_sha1_file(void *buf, unsigned
return 0;
}
-int write_sha1_from_fd(const unsigned char *sha1, int fd)
+int write_sha1_from_fd_to_fd(const unsigned char *sha1, int fd, int local)
{
- char *filename = sha1_file_name(sha1);
-
- int local;
z_stream stream;
unsigned char real_sha1[20];
unsigned char buf[4096];
unsigned char discard[4096];
- int ret;
+ int ret, compressed_size=0;
SHA_CTX c;
- local = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
-
- if (local < 0)
- return error("Couldn't open %s\n", filename);
-
memset(&stream, 0, sizeof(stream));
inflateInit(&stream);
@@ -606,13 +598,12 @@ int write_sha1_from_fd(const unsigned ch
ssize_t size;
size = read(fd, buf, 4096);
if (size <= 0) {
- close(local);
- unlink(filename);
if (!size)
return error("Connection closed?");
perror("Reading from connection");
return -1;
}
+ compressed_size += size;
write(local, buf, size);
stream.avail_in = size;
stream.next_in = buf;
@@ -627,18 +618,35 @@ int write_sha1_from_fd(const unsigned ch
} while (ret == Z_OK);
inflateEnd(&stream);
- close(local);
SHA1_Final(real_sha1, &c);
if (ret != Z_STREAM_END) {
- unlink(filename);
return error("File %s corrupted", sha1_to_hex(sha1));
}
if (memcmp(sha1, real_sha1, 20)) {
- unlink(filename);
return error("File %s has bad hash\n", sha1_to_hex(sha1));
}
- return 0;
+ return compressed_size;
+}
+
+int write_sha1_from_fd(const unsigned char *sha1, int fd)
+{
+ char *filename = sha1_file_name(sha1);
+
+ int local;
+ int ret;
+
+ local = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+
+ if (local < 0)
+ return error("Couldn't open %s\n", filename);
+
+ ret = write_sha1_from_fd_to_fd(sha1, fd, local);
+ close(local);
+ if (ret < 0)
+ unlink(filename);
+
+ return ret;
}
int has_sha1_file(const unsigned char *sha1)
======== end ========
--
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation
^ permalink raw reply
* Re: I want to release a "git-1.0"
From: Daniel Barkalow @ 2005-06-03 15:09 UTC (permalink / raw)
To: Petr Baudis; +Cc: Linus Torvalds, Eric W. Biederman, Git Mailing List
In-Reply-To: <20050603094706.GB24873@pasky.ji.cz>
On Fri, 3 Jun 2005, Petr Baudis wrote:
> Dear diary, on Thu, Jun 02, 2005 at 12:00:55AM CEST, I got a letter
> where Daniel Barkalow <barkalow@iabervon.org> told me that...
> > It shouldn't be hard to do one, except that locking with rsync is going to
> > be a pain. I had a patch to make it work with the rpush/rpull pair, but I
> > didn't get its dependancies in at the time.
>
> Was that the patch I was replying to recently? It didn't seem to have
> any dependencies.
The rpush/rpull changes were at the end of a series that you were replying
to the beginning of.
> > I can dust those patches off again if you want that functionality included.
> >
> > The patches are essentially:
> >
> > - make the transport protocol handle things other than objects
> > - library procedure for locking atomic update of refs files
> > - fetching refs in general
> > - rpull/rpush that updates a specified ref file atomically
> >
> > At least the first would be very nice to get in before 1.0, since it is an
> > incompatible change to the protocol.
>
> I would like to have this a lot too. Pulling tags now is a PITA, and I
> definitively want to go in this way. So it will land at least in git-pb.
> :-) (But that's a little troublesome if you say it's incompatible
> change.)
The ssh-based protocol has to change, because the current version doesn't
have any way of being extended. The first patch in the new set makes the
incompatible change without adding anything new (so as to be as
uncontroversial as possible), and now also adds a version number so that
future additions should be less of a big deal. The rest of the series will
add the transfer of refs to the transfer mechanism and the protocol.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* [PATCH] git-daemon server
From: Jason McMullan @ 2005-06-03 15:22 UTC (permalink / raw)
To: git; +Cc: torvalds
git-daemon - Client/server for exchanging GIT objects
Requires: [PATCH] Expose more sha1_file.c interfaces
Requires: [PATCH] Anal retentive 'const unsigned char *sha1'
Signed-off-by: Jason McMullan <jason.mcmullan@timesys.com>
GIT daemon is a symmetric protocol for exchanging objects
between repositories. It has the following features:
* Can use TCP, Unix domain sockets, or stdin/stdout
* Verifies received SHA1 objects are valid and fully
connected before they are stored in the object database,
including delta objects.
* Fully symmetric protocol
* Only pulls the dependencies of the requested object -
allows you to place *multiple* projects in one GIT database.
* Proper head locking, allows either lazy or cmp-xchg updates
(lazy is just 'head head-id old-sha1 new-sha1', cmp-xchg is
'send new-sha1; head head-id old-sha1 new-sha1' )
TODO:
-----
* Command line 'send' of a SHA1 from the local database
(for the cmd-xchg mechanism. Lazy works out-of-the box)
* Optional auto-deltification of transmitted objects
* More documentation
* Test cases for 'make test'
* Merge verify-before-update logic into pull.c
GIT Daemon Protocol Commands:
-----------------------------
version::
Requests the version string, returned in an error message
Expects: 'error'
head <head-id>::
Requests SHA1 of the <head-id>
Expects: 'sha1' or 'error'
head <head-id> <old-sha1> <new-sha1>::
Requests that <head-id> be updated with <new-sha1>. Use
'--' for <old-sha1> to create a new head.
Expects: 'sha1', 'request', or 'error'
exists <sha1>::
Determine if SHA1 exists in remote
Expects: 'sha1' or 'error'
request <sha1>::
Request SHA1 object.
Expects: 'send' or 'error'
send <sha1>::
Send SHA1 object.
Expects: 'sha1' or 'error'
error <key> <hex-code> <error-message>::
Returned error code
Expects: Nothing
sha1 <key> <hex-sha1>::
Success message for 'head' and 'send' commands.
diff -u b/daemon.c b/daemon.c
--- b/daemon.c
+++ b/daemon.c
@@ -0,0 +1,827 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/un.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)NULL)->sun_path)
+#endif
+
+#include "cache.h"
+#include "delta.h"
+#include "object.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
+#include "tag.h"
+
+#define ERROR_VERSION 0,"GIT Daemon protocol version 0.0"
+#define ERROR_INVALID 1,"Invalid command"
+#define ERROR_REQUEST_INVALID 100,"SHA1 does not exist"
+#define ERROR_HEAD_BAD(hash) 200,"Head is not at hash %s",hash
+#define ERROR_HEAD_INVALID 201,"Head does not exist"
+#define ERROR_HEAD_LOCK 202,"Head can't be locked"
+#define ERROR_HEAD_UPDATE 203,"Head can't be updated"
+#define ERROR_HEAD_SHA1_INVALID(sha1) 204,"SHA1 %s does not exist",sha1
+#define ERROR_SEND_INVALID 300,"Invalid data sent on send"
+
+/* Protocol is symmetric, both client and server
+ * use the same commands.
+ *
+ * version\n -> error -- 0 <Version string>\n
+ *
+ * head <head-id>\n -> sha1 <head-id> <sha1>\n
+ *
+ * head <head-id> <old-sha1> <new-sha1>\n -> sha1 <head-id> <new-sha1>\n
+ *
+ * request <sha1>\n -> send <sha1> <hex-bytes>\n<bytes...>
+ *
+ * send <sha1> <hex-bytes>\n<bytes...> -> sha1 -- <sha1>\n
+ *
+ * exists <sha1>\n -> sha1 -- <sha1>\n
+ *
+ * sha1 <any> <sha1>\n -> no-op
+ *
+ * error <key> <hex-code> <error string>\n -> no-op
+ *
+ */
+
+static int fd_in=0, fd_out=1;
+
+static int process_request();
+static int send_request(const unsigned char *sha1);
+static const char *git_dir;
+
+void *map_file(int fd, size_t size)
+{
+ void *map;
+
+ if (fd < 0) {
+ error("cannot map file on fd %d", fd);
+ return NULL;
+ }
+
+ map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (-1 == (int)(long)map)
+ return NULL;
+ return map;
+}
+
+static int sha1_retrieve(const unsigned char *sha1)
+{
+ int err;
+
+ if (!has_sha1_file(sha1)) {
+ err = send_request(sha1);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int verify_file(int fd, unsigned long mapsize, const unsigned char *sha1, char *type)
+{
+ void *map, *buffer;
+ char hdr[8192];
+ struct object *obj;
+ unsigned long size;
+ z_stream stream;
+ int err;
+
+ map = map_file(fd, mapsize);
+ if (map) {
+ err = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
+ if (err < Z_OK || parse_sha1_header(hdr, type, &size) < 0) {
+ munmap(map, mapsize);
+ return -1;
+ }
+ buffer = unpack_sha1_rest(&stream, hdr, size);
+ munmap(map, size);
+
+ if (buffer == NULL) {
+ return -1;
+ }
+
+ if (buffer && !strcmp(type, "delta")) {
+ void *ref = NULL, *delta = buffer;
+ unsigned long ref_size, delta_size = size;
+ buffer = NULL;
+ if (delta_size <= 20) {
+ free(buffer);
+ return -1;
+ }
+ err = sha1_retrieve(delta);
+ if (err < 0) {
+ free(buffer);
+ return err;
+ }
+ ref = read_sha1_file(delta, type, &ref_size);
+
+ if (ref == NULL) {
+ free(buffer);
+ return err;
+ }
+
+ buffer = patch_delta(ref, ref_size,
+ delta+20, delta_size-20,
+ &size);
+ free(delta);
+ free(ref);
+ }
+
+ if (!strcmp(type, "blob")) {
+ struct blob *blob = lookup_blob(sha1);
+ parse_blob_buffer(blob, buffer, size);
+ obj = &blob->object;
+ } else if (!strcmp(type, "tree")) {
+ struct tree *tree = lookup_tree(sha1);
+ parse_tree_buffer(tree, buffer, size);
+ obj = &tree->object;
+ } else if (!strcmp(type, "commit")) {
+ struct commit *commit = lookup_commit(sha1);
+ parse_commit_buffer(commit, buffer, size);
+ if (!commit->buffer) {
+ commit->buffer = buffer;
+ buffer = NULL;
+ }
+ obj = &commit->object;
+ } else if (!strcmp(type, "tag")) {
+ struct tag *tag = lookup_tag(sha1);
+ parse_tag_buffer(tag, buffer, size);
+ obj = &tag->object;
+ } else {
+ obj = NULL;
+ }
+
+ free(buffer);
+
+ if (obj) {
+ struct object_list *refs;
+
+ for (refs = obj->refs; refs ; refs = refs->next) {
+ err = sha1_retrieve(refs->item->sha1);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+ }
+
+ }
+ return -1;
+}
+
+static int send_command(int argc, char **argv)
+{
+ char buff[1024];
+ int len, size;
+
+ size = snprintf(buff, sizeof(buff), "%s", argv[0]);
+ for ( argc--,argv++; argc > 0 ; argc--, argv++) {
+ len = snprintf(buff + size, sizeof(buff) - size, " %s", argv[0]);
+ size += len;
+ }
+ buff[size++]='\n';
+ return write(fd_out, buff, size);
+}
+
+static int send_error(const char *key,int code,const char *errstr,...)
+{
+ va_list args;
+ static char buff[1024];
+ int len;
+
+ va_start(args, errstr);
+
+ len = snprintf(buff, sizeof(buff), "error %s %x ", key ? key : "--", code);
+ write(fd_out, buff, len);
+ len = vsnprintf(buff, sizeof(buff), errstr, args);
+ write(fd_out, buff, len);
+ write(fd_out, "\n", 1);
+
+ va_end(args);
+
+ return 0;
+}
+
+static int send_sha1(const char *key, const unsigned char *sha1)
+{
+ char buff[2048];
+ int len;
+
+ len = snprintf(buff,sizeof(buff), "sha1 %s %s\n",key ? key : "--", sha1_to_hex(sha1));
+ return write(fd_out, buff, len);
+}
+
+static int send_send(const unsigned char *sha1, int size, void *data)
+{
+ char buff[2048];
+ int len, err;
+
+ len = snprintf(buff,sizeof(buff), "send %s %x\n",sha1_to_hex(sha1),size);
+ err = write(fd_out, buff, len);
+
+ if (err < 0)
+ return err;
+
+ err = write(fd_out, data, size);
+ if (err < 0)
+ return err;
+
+ return process_request();
+}
+
+static int send_request(const unsigned char *sha1)
+{
+ char buff[2048];
+ int len, err;
+
+ len = snprintf(buff,sizeof(buff), "request %s\n",sha1_to_hex(sha1));
+ err = write(fd_out, buff, len);
+ if (err < 0)
+ return err;
+
+ return process_request();
+}
+
+
+static inline int lock_file(const char *path, int is_create)
+{
+ int fd;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0 && is_create) {
+ fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);
+ } else if (is_create) {
+ close(fd);
+ return -1;
+ }
+
+ if (fd < 0)
+ return -1;
+
+ if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
+ close(fd);
+ if (is_create)
+ unlink(path);
+ return -1;
+ }
+
+ return fd;
+}
+
+static inline void unlock_file(int fd)
+{
+ flock(fd, LOCK_UN);
+ close(fd);
+}
+
+static int cmd_version(int argc, char **argv)
+{
+ return send_error("--",ERROR_VERSION);
+}
+
+/* Return < 0 on I/O error
+ */
+static int cmd_head(int argc, char **argv)
+{
+ int len, err;
+
+ if (argc == 2) {
+ unsigned char sha1[20];
+
+ /* Get SHA1 for head */
+ err = get_sha1(argv[1], sha1);
+ if (err < 0)
+ return send_error(argv[1],ERROR_HEAD_INVALID);
+
+ return send_sha1(argv[1],sha1);
+ } else if (argc == 4) {
+ char head_sha1[20], sha1[20], sha1_new[20];
+ int fd, head_fd;
+ static char buff[256];
+ static char hfile[PATH_MAX];
+ static char hfile_new[PATH_MAX];
+ int is_create;
+ const char *head=argv[1], *old_hash=argv[2], *new_hash=argv[3];
+
+ is_create = (strcmp(old_hash,"--")==0);
+
+ /* Is the head name valid? */
+ if (strchr(head,'/') != NULL)
+ return send_error(head,ERROR_HEAD_INVALID);
+
+ /* lock head */
+ len = snprintf(hfile, sizeof(hfile), "%s/refs/heads/%s", git_dir, argv[1]);
+ strcpy(hfile_new, hfile);
+ strcpy(hfile_new + len, ".new");
+ head_fd = lock_file(hfile, is_create);
+ if (head_fd < 0) {
+ return send_error(head,ERROR_HEAD_LOCK);
+ }
+
+ /* Verify that we know what we're doing
+ * to do a cmp-xchg update
+ */
+ if (!is_create) {
+ err = get_sha1(head, head_sha1);
+ if (err < 0) {
+ if (is_create) unlink(hfile);
+ unlock_file(head_fd);
+ return send_error(head, ERROR_HEAD_INVALID);
+ }
+
+ err = get_sha1(old_hash, sha1);
+ if (err < 0) {
+ if (is_create) unlink(hfile);
+ unlock_file(head_fd);
+ return send_error(head, ERROR_HEAD_SHA1_INVALID(old_hash));
+ }
+
+ if (memcmp(head_sha1, sha1, 20) != 0) {
+ if (is_create) unlink(hfile);
+ unlock_file(head_fd);
+ return send_error(head, ERROR_HEAD_BAD(old_hash));
+ }
+ }
+
+
+ /* Is the new head id even a valid string? */
+ err = get_sha1(new_hash, sha1_new);
+ if (err < 0) {
+ if (is_create) unlink(hfile);
+ unlock_file(head_fd);
+ return send_error(head,ERROR_HEAD_SHA1_INVALID(new_hash));
+ }
+
+ /* If new-sha1 == old-sha1, short circuit to end */
+ if (memcmp(sha1_new, sha1, 20) == 0)
+ goto done;
+
+ /* Verify that new-sha1 is in the database */
+ err = sha1_retrieve(sha1_new);
+ if (err < 0) {
+ if (is_create) unlink(hfile);
+ unlock_file(head_fd);
+ return err;
+ }
+
+ /* We now have the SHA1. Update head */
+ fd = open(hfile_new, O_RDWR | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0) {
+ if (is_create) unlink(hfile);
+ unlock_file(head_fd);
+ return send_error(argv[1],ERROR_HEAD_UPDATE);
+ }
+
+ len = snprintf(buff, sizeof(buff), "%s\n", sha1_to_hex(sha1_new));
+ err = write(fd, buff, len);
+ close(fd);
+ if (err != len) {
+ if (is_create) unlink(hfile);
+ unlink(hfile_new);
+ unlock_file(head_fd);
+ return send_error(argv[1],ERROR_HEAD_UPDATE);
+ }
+
+ err = rename(hfile_new, hfile);
+ if (err < 0) {
+ if (is_create) unlink(hfile);
+ unlock_file(head_fd);
+ return send_error(argv[1],ERROR_HEAD_UPDATE);
+ }
+
+done:
+ /* Unlock head */
+ unlock_file(head_fd);
+ return send_sha1(argv[1], sha1_new);
+ write(fd_out, buff, len);
+ } else {
+ return send_error(argv[1],ERROR_INVALID);
+ }
+
+ return 0;
+}
+
+/* Return < 0 on I/O error
+ */
+static int cmd_request(int argc, char **argv)
+{
+ int err;
+
+ if (argc == 2) {
+ char sha1[40];
+ void *data;
+ unsigned long size;
+
+ err = get_sha1(argv[1], sha1);
+
+ /* If sha1 exists, send it. */
+ if (err < 0)
+ return send_error(argv[1],ERROR_REQUEST_INVALID);
+
+ data = map_sha1_file(sha1, &size);
+ if (data == NULL)
+ return send_error(argv[1],ERROR_REQUEST_INVALID);
+
+ err = send_send(sha1, size, data);
+ if (err < 0)
+ return err;
+ err = process_request();
+ munmap(data, size);
+ } else {
+ err = send_error(argv[1],ERROR_INVALID);
+ }
+
+ return err;
+}
+
+static int cmd_send(int argc, char **argv)
+{
+ int err;
+ int tmpfd = -1;
+ char tmpn[]="/tmp/git.daemon.XXXXXX";
+
+ if (argc == 3) {
+ char sha1[20];
+ int size = strtol(argv[2],NULL,16);
+ char type[32];
+ void *buff;
+ const char *fname;
+ int fd;
+ int exists = 0;
+
+ err = get_sha1(argv[1], sha1);
+ /* If sha1 exists, just drop all the bytes on the floor */
+ /* Otherwise, create a temp file, and stuff the bytes there */
+
+ if (err == 0) {
+ tmpfd = mkstemp(tmpn);
+ unlink(tmpn);
+ } else {
+ exists = 1;
+ tmpfd = open("/dev/null", O_RDWR);
+ }
+
+ err = write_sha1_from_fd_to_fd(sha1, fd_in, tmpfd);
+ if (err < 0 || size != err) {
+ close(tmpfd);
+ return send_error(argv[1],ERROR_SEND_INVALID);
+ }
+
+ if (exists)
+ goto done;
+
+ /* Verify that the temp file contains a valid blob/tree
+ * This step also recurses and gets all the 'good stuff'
+ */
+ err = verify_file(tmpfd, size, sha1, type);
+ if (err < 0) {
+ close(tmpfd);
+ return send_error(argv[1],ERROR_SEND_INVALID);
+ }
+
+ /* Write to database if verified */
+ buff = map_file(tmpfd, size);
+ fname = sha1_file_name(sha1);
+ fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
+ err = write(fd, buff, size);
+ close(fd);
+ if (err != size) {
+ unlink(fname);
+ close(tmpfd);
+ return send_error(argv[1],ERROR_SEND_INVALID);
+ }
+
+done:
+ close(tmpfd);
+ return send_sha1(NULL, sha1);
+ } else {
+ err = send_error(argv[1],ERROR_INVALID);
+ }
+
+ return err;
+}
+
+int cmd_exists(int argc, char **argv)
+{
+ int err;
+
+ if (argc == 2) {
+ char sha1[20];
+
+ err = get_sha1(argv[1], sha1);
+
+ /* If sha1 exists, say so. Otherwise say 'send sha1'*/
+ if (err >= 0)
+ return send_sha1(NULL, sha1);
+
+ return send_error(NULL, ERROR_REQUEST_INVALID);
+ } else {
+ err = send_error(argv[1],ERROR_INVALID);
+ }
+
+ return err;
+}
+
+int cmd_sha1(int argc, char **argv)
+{
+ int i;
+
+ fprintf(stderr, "%s",argv[0]);
+ for ( i=1; i < argc; i++)
+ fprintf(stderr, " %s",argv[i]);
+ fprintf(stderr, "\n");
+ return 0;
+}
+
+static int cmd_error(int argc, char **argv)
+{
+ int i;
+
+ fprintf(stderr, "%s",argv[0]);
+ for ( i=1; i < argc; i++)
+ fprintf(stderr, " %s",argv[i]);
+ fprintf(stderr, "\n");
+ return 0;
+}
+
+static int command(int argc, char **argv)
+{
+ int err;
+#if 0
+ int i;
+
+ fprintf(stderr, "%s",argv[0]);
+ for ( i=1; i < argc; i++)
+ fprintf(stderr, " %s",argv[i]);
+ fprintf(stderr, "\n");
+#endif
+
+ if (argc < 1)
+ goto invalid;
+
+ if (strcmp(argv[0],"version")==0) {
+ err = cmd_version(argc,argv);
+ return err;
+ } else if (strcmp(argv[0],"head")==0) {
+ err = cmd_head(argc,argv);
+ return err;
+ } else if (strcmp(argv[0],"send")==0) {
+ err = cmd_send(argc,argv);
+ return err;
+ } else if (strcmp(argv[0],"request")==0) {
+ err = cmd_request(argc,argv);
+ return err;
+ } else if (strcmp(argv[0],"exists")==0) {
+ err = cmd_exists(argc,argv);
+ return err;
+ } else if (strcmp(argv[0],"sha1")==0) {
+ err = cmd_sha1(argc,argv);
+ return err;
+ } else if (strcmp(argv[0],"error")==0) {
+ err = cmd_error(argc,argv);
+ return err;
+ }
+
+invalid:
+ return send_error("--",ERROR_INVALID);
+}
+
+/* This *intentionally* drops requests on the floor that are
+ * larger than sizeof(buffer)
+ */
+static int process_request()
+{
+ char buffer[1024];
+ int offset;
+ char **argv,*cp;
+ int argc,err;
+
+ offset=0;
+
+ while (read(fd_in, &buffer[offset], 1)==1) {
+ if (buffer[offset++]=='\n')
+ break;
+ if (offset == sizeof(buffer))
+ return -1;
+ }
+ offset--;
+
+ if (offset < 0 || buffer[offset]!='\n')
+ return -1;
+
+ buffer[offset]=0;
+ argc=0;
+ argv=xmalloc(sizeof(char *));
+
+ cp = &buffer[0];
+ while (1) {
+ while (*cp && isspace(*cp)) cp++;
+ if (*cp == 0)
+ break;
+ argv[argc++]=cp;
+ argv=xrealloc(argv, (argc+1)*sizeof(char *));
+ while (*cp && !isspace(*cp)) cp++;
+ if (*cp == 0)
+ break;
+ *(cp++) = 0;
+ };
+
+ argv[argc]=NULL;
+ err = command(argc,argv);
+ free(argv);
+
+ return err;
+}
+
+/* Reap children */
+static void reaper(int sig)
+{
+ int status;
+
+ waitpid(-1, &status, WNOHANG);
+}
+
+static int get_ip_addr(const char *ip, struct in_addr *addr)
+{
+ int err;
+ struct hostent *host;
+
+ err = inet_pton(AF_INET, ip, addr);
+ if (err < 0)
+ return 0;
+
+ host = gethostbyname(ip);
+ if (host == NULL)
+ return -1;
+
+ return inet_pton(AF_INET, host->h_addr, addr);
+}
+
+static int get_port(const char *port)
+{
+ struct servent *serv;
+ int p;
+
+ if (sscanf(port,"%d",&p) == 1)
+ return p;
+
+ serv = getservbyname(port,"tcp");
+ if (serv == NULL)
+ return -1;
+
+ return serv->s_port;
+}
+
+int main(int argc, char **argv)
+{
+ enum {
+ MODE_STDIO,
+ MODE_UNIX,
+ MODE_TCP,
+ } mode = MODE_STDIO;
+ const char *port = "/tmp/.gitd",*host="127.0.0.1";
+ union {
+ struct sockaddr generic;
+ struct sockaddr_un un;
+ struct sockaddr_in in;
+ } sock;
+ struct sockaddr_un *s_unix = (void *)&sock.un;
+ struct sockaddr_in *s_inet = (void *)&sock.in;
+ size_t s_size = 0;
+ int max_clients=100, err;
+
+ git_dir = gitenv(GIT_DIR_ENVIRONMENT) ? : DEFAULT_GIT_DIR_ENVIRONMENT;
+
+ argv++;
+ argc--;
+ for (; argc > 0; argv++, argc--) {
+ char *path = argv[0];
+
+ if (path[0] != '-')
+ break;
+
+ if (!strcmp(path,"--")) {
+ argv++;
+ argc--;
+ break;
+ }
+
+ if (!strcmp(path,"--unix")) {
+ mode = MODE_UNIX;
+ continue;
+ }
+
+ if (!strcmp(path,"--tcp")) {
+ mode = MODE_TCP;
+ continue;
+ }
+
+ if (!strcmp(path, "--max-clients")) {
+ if (argc < 2)
+ die("git-daemon: --max-clients <number>");
+ max_clients = strtoul(argv[1],NULL,0);
+ argv++;
+ argc--;
+ continue;
+ }
+
+ if (!strcmp(path, "--host")) {
+ if (argc < 2)
+ die("git-daemon: --host <host>");
+ host = argv[1];
+ argv++;
+ argc--;
+ continue;
+ }
+
+ if (!strcmp(path, "--port")) {
+ if (argc < 2)
+ die("git-daemon: --port <port>");
+ port = argv[1];
+ argv++;
+ argc--;
+ continue;
+ }
+
+ if (!strcmp(path, "--db")) {
+ if (argc < 2)
+ die("git-daemon: --db <path/.git>");
+ git_dir = argv[2];
+ argv++;
+ argc--;
+ continue;
+ }
+ }
+
+ switch (mode) {
+ case MODE_STDIO: fd_in = 0; fd_out = 1; break;
+ case MODE_UNIX:
+ fd_in = fd_out = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd_in < 0)
+ die("git-daemon: Can't create local domain socket");
+ strncpy(s_unix->sun_path, port, UNIX_PATH_MAX);
+ s_unix->sun_path[UNIX_PATH_MAX-1]=0;
+ s_unix->sun_family = AF_UNIX;
+ s_size = sizeof(*s_unix);
+ break;
+ case MODE_TCP:
+ fd_in = fd_out = socket(PF_INET, SOCK_STREAM, 0);
+ if (fd_in < 0)
+ die("git-daemon: Can't create TCP/IP socket");
+ s_inet->sin_family = AF_INET;
+ err = get_ip_addr(host, &s_inet->sin_addr);
+ s_inet->sin_port = htons(get_port(port));
+ s_size = sizeof(*s_inet);
+ break;
+ }
+
+
+ if (argc > 0) {
+ if (s_size != 0) {
+ err = connect(fd_in, &sock.generic, s_size);
+ if (err < 0)
+ die("git-daemon: Can't connect to socket \"%s\"",port);
+ }
+
+ err = send_command(argc, argv);
+ if (err < 0)
+ return err;
+ return process_request();
+ }
+
+ if (s_size != 0) {
+ int one = 1;
+ err = setsockopt(fd_in, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+ err = bind(fd_in, &sock.generic, s_size);
+ listen(fd_in, max_clients);
+ do {
+ signal(SIGCHLD, reaper);
+ fd_out = accept(fd_in, NULL, NULL);
+ if (fd_out < 0)
+ die("git-daemon: Failed to start listening");
+ if (fork()==0)
+ break;
+ close(fd_out);
+ } while (1);
+
+ fd_in = fd_out;
+ }
+
+ while (process_request() >= 0);
+
+ return 0;
+}
only in patch2:
unchanged:
--- /dev/null
+++ b/Documentation/git-daemon.txt
@@ -0,0 +1,92 @@
+git-daemon(1)
+=============
+v0.1, May 2005
+
+NAME
+----
+git-daemon - Client/server for exchanging GIT objects
+
+
+SYNOPSIS
+--------
+'git-daemon' [--db <git-db-path>] [--stdio | --tcp | --udp]
+ [--port <port>] [--host <host>] [-- command...]
+
+DESCRIPTION
+-----------
+
+OPTIONS
+-------
+--db::
+ Set the GIT object database path to use
+
+--stdio::
+ Use stdin/stdout as the transport (default)
+
+--tcp::
+ Use TCP as the transport
+
+--unix::
+ Use Unix domain sockets as the transport
+
+--host::
+ Specify IPv4 host for --tcp transport
+
+--port::
+ Specify IPv4 port for --tcp transport, or the
+ filesystem socket path for the --unix transport
+
+--::
+ Stop argument processing
+
+<command>::
+ GIT Daemon protocol command
+
+GIT Daemon Protocol Commands:
+-----------------------------
+
+version::
+ Requests the version string, returned in an error message
+ Expects: 'error'
+
+head <head-id>::
+ Requests SHA1 of the <head-id>
+ Expects: 'sha1' or 'error'
+
+head <head-id> <old-sha1> <new-sha1>::
+ Requests that <head-id> be updated with <new-sha1>. Use
+ '--' for <old-sha1> to create a new head.
+ Expects: 'sha1', 'request', or 'error'
+
+exists <sha1>::
+ Determine if SHA1 exists in remote
+ Expects: 'sha1' or 'error'
+
+request <sha1>::
+ Request SHA1 object.
+ Expects: 'send' or 'error'
+
+send <sha1>::
+ Send SHA1 object.
+ Expects: 'sha1' or 'error'
+
+error <key> <hex-code> <error-message>::
+ Returned error code
+ Expects: Nothing
+
+sha1 <key> <hex-sha1>::
+ Success message for 'head' and 'send' commands.
+ Expects: Nothing
+
+Author
+------
+Written by Jason McMullan <jason.mcmullan@timesys.com>
+
+Documentation
+--------------
+Documentation by Jason McMullan and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the link:git.html[git] suite
+
--
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation
^ permalink raw reply
* Re: qgit-0.3
From: Marco Costalba @ 2005-06-03 15:58 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: git, Stanislav Karchebny, astralstorm, skimo
I'm very sorry for causing you (and possibly other people) waste of your time.
I have surely understimate my ignorance in scons.
Not being an expert, I'am trying to get some help from scons people to find
a fix/solution as soon as possible.
In any case I am sure the fault is mine, not of the tool, that is very good
to keep the build system overhead very low.
Of course, if someone can give my some good advice/patch to fix my Makefile or to document the
prerequisites better it will be very appreciated.
Marco
P.S: I cannot be on-line all day long, so sorry for the delaying of the answers.
I try to answer to all the e-mails as soon as I can.
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: Linus Torvalds @ 2005-06-03 16:02 UTC (permalink / raw)
To: Jason McMullan; +Cc: Git Mailing List
In-Reply-To: <20050603152212.GA4598@jmcmullan.timesys>
On Fri, 3 Jun 2005, Jason McMullan wrote:
>
> git-daemon - Client/server for exchanging GIT objects
Hmm.. I'd prefer not calling it a deamon, since if I understand correctly,
the _normal_ usage would likely be to use it as
.. | ssh .... -e git-deamon
ie it wouldn't be a deamon at all, it would be a foreground server. So I'd
call it just "git-server" or something.
Anyway, technically this looks ok, but I'd hate to apply it until there is
something that actually uses it and an example of that usage.
Linus
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: McMullan, Jason @ 2005-06-03 16:09 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0506030856490.1876@ppc970.osdl.org>
[-- Attachment #1: Type: text/plain, Size: 716 bytes --]
On Fri, 2005-06-03 at 09:02 -0700, Linus Torvalds wrote:
> ie it wouldn't be a deamon at all, it would be a foreground server. So I'd
> call it just "git-server" or something.
Server.. Sounds ok. Will do.
> Anyway, technically this looks ok, but I'd hate to apply it until there is
> something that actually uses it and an example of that usage.
Well, I use it to keep my home and work repos in sync, but yeah,
users == 1 doesn't make a good case for inclusion.
I just want to have this out there, because I find rsync a little too
heavy handed for my taste, and I'm still hesitant about the cg-rpush
locking semantics.
--
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* [PATCH] git-tar-tree: do only basic tests in t/t5000-git-tar-tree.sh
From: Rene Scharfe @ 2005-06-03 16:21 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
git-tar-tree: remove tests of long path handling out of t5000-tar-tree.sh
and make test script cope with tar programs displaying file modification
date as hh:mm (newer variants show it as hh:mm:ss).
This makes the test cover only basic functionality that is expected to
be handled even by older tar programs. Tests for long filenames (which
require pax extended headers) can be added separately.
I ran this test successfully with GNU tar 1.13, 1.14 and 1.15.1.
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -5,17 +5,13 @@
test_description='git-tar-tree and git-get-tar-commit-id test
-This test covers the topics of long paths, file contents, commit date
-handling and commit id embedding:
-
- Paths longer than 100 characters require the use of a pax extended
- header to store them. The test creates files with pathes both longer
- and shorter than 100 chars, and also checks symlinks with long and
- short pathes both as their own name and as target path.
+This test covers the topics of file contents, commit date handling and
+commit id embedding:
The contents of the repository is compared to the extracted tar
archive. The repository contains simple text files, symlinks and a
- binary file (/bin/sh).
+ binary file (/bin/sh). Only pathes shorter than 99 characters are
+ used.
git-tar-tree applies the commit date to every file in the archive it
creates. The test sets the commit date to a specific value and checks
@@ -33,20 +29,10 @@
test_expect_success \
'populate workdir' \
'mkdir a b c &&
- p48=1.......10........20........30........40......48 &&
- p50=1.......10........20........30........40........50 &&
- p98=${p48}${p50} &&
echo simple textfile >a/a &&
- echo 100 chars in path >a/${p98} &&
- echo 101 chars in path >a/${p98}x &&
- echo 102 chars in path >a/${p98}xx &&
- echo 103 chars in path >a/${p98}xxx &&
mkdir a/bin &&
- cp /bin/sh a/bin/sh &&
+ cp /bin/sh a/bin &&
ln -s a a/l1 &&
- ln -s ${p98}xx a/l100 &&
- ln -s ${p98}xxx a/l101 &&
- ln -s ${p98}xxx a/l${p98} &&
(cd a && find .) | sort >a.lst'
test_expect_success \
@@ -64,7 +50,8 @@
test_expect_success \
'validate file modification time' \
- 'tar tvf b.tar a/a | awk \{print\ \$4,\$5\} >b.mtime &&
+ 'tar tvf b.tar a/a |
+ awk \{print\ \$4,\ length\(\$5\)\<7\ ?\ \$5\":00\"\ :\ \$5\} >b.mtime &&
echo "2005-05-27 22:00:00" >expected.mtime &&
diff expected.mtime b.mtime'
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: Linus Torvalds @ 2005-06-03 16:30 UTC (permalink / raw)
To: McMullan, Jason; +Cc: Git Mailing List
In-Reply-To: <1117814982.32257.64.camel@jmcmullan.timesys>
On Fri, 3 Jun 2005, McMullan, Jason wrote:
>
> > Anyway, technically this looks ok, but I'd hate to apply it until there is
> > something that actually uses it and an example of that usage.
>
> Well, I use it to keep my home and work repos in sync, but yeah,
> users == 1 doesn't make a good case for inclusion.
Well, it's fine, but you should at least tell _how_ you use it. What are
the scripts you use to synchronize etc etc..
So when I said "some_thing_ that actually uses it", I didn't mean more
_people_ than you personally, but the scaffolding around it, really.
Linus
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: Junio C Hamano @ 2005-06-03 17:00 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Jason McMullan, Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0506030856490.1876@ppc970.osdl.org>
>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:
LT> ie it wouldn't be a deamon at all, it would be a foreground server. So I'd
LT> call it just "git-server" or something.
That particular name risks conflicting name with other
git-servers offering different service for git; gitweb is a
git-server isn't it? git-sync might be better fit.
LT> Anyway, technically this looks ok,...
I'd address them in a separate message later today.
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: McMullan, Jason @ 2005-06-03 17:18 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0506030929150.1876@ppc970.osdl.org>
[-- Attachment #1: Type: text/plain, Size: 1245 bytes --]
On Fri, 2005-06-03 at 09:30 -0700, Linus Torvalds wrote:
> Well, it's fine, but you should at least tell _how_ you use it. What are
> the scripts you use to synchronize etc etc..
Sorry, here's some use cases (assuming that git-server is running on
192.168.1.1 port 7777)
###### Create a new local git repo
$ GITCONN="--tcp --host 192.168.1.1 --port 7777"
$ git-init-db
$ git-server $GITCONN -- request master
###### Update local repo to remote's head linux-devel
$ git-server $GITCONN -- request linux-devel
###### Create remote head linux-mumble
$ git-server $GITCONN -- head -- linux-mumble
6678abc8d819abc919a018ca89273091bc98a
###### Get remote head's linux-mumble SHA1
$ git-server $GITCONN -- head linux-mumble
sha1 linux-mumble 6678abc8d819abc919a018ca89273091bc98a
###### Set remote head to new SHA1
$ git-server $GITCONN -- head linux-mumble
6678abc8d819abc919a018ca89273091bc98a
8389324a9890218bcd9a0193781abc8a183a9
sha1 linux-mumble 8389324a9890218bcd9a0193781abc8a183a9
(This has the side effect of the server requesting SHA1 objects from the
client if they do not exist on the remote repository)
--
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: Junio C Hamano @ 2005-06-03 17:24 UTC (permalink / raw)
To: Jason McMullan; +Cc: git, torvalds
In-Reply-To: <20050603152212.GA4598@jmcmullan.timesys>
Looks very nice. Some comments.
diff -u b/daemon.c b/daemon.c
--- b/daemon.c
+++ b/daemon.c
------------
+
+/* Protocol is symmetric, both client and server
+ * use the same commands.
+ *
+ * version\n -> error -- 0 <Version string>\n
+ *
+ * head <head-id>\n -> sha1 <head-id> <sha1>\n
+ *
+ * head <head-id> <old-sha1> <new-sha1>\n -> sha1 <head-id> <new-sha1>\n
+ *
+ * request <sha1>\n -> send <sha1> <hex-bytes>\n<bytes...>
+ *
+ * send <sha1> <hex-bytes>\n<bytes...> -> sha1 -- <sha1>\n
+ *
+ * exists <sha1>\n -> sha1 -- <sha1>\n
+ *
+ * sha1 <any> <sha1>\n -> no-op
+ *
+ * error <key> <hex-code> <error string>\n -> no-op
+ *
+ */
This is good for the first cut, but I have a latency concern
about "single request - single send" style of communication.
This being a dedicated GIT specific sync mechanism, you may want
to give more smarts to the server, so that the client can say "I
have these commits as HEADs in my forest, here are their SHA1s,
now sync me up to the head you said you have whose SHA1 is
this", implying he has all their HEADs dependents. Of course
this can come later.
------------
+static int verify_file(int fd, unsigned long mapsize, const unsigned char *sha1, char *type)
+{
+ void *map, *buffer;
~~~
+ if (buffer && !strcmp(type, "delta")) {
+ void *ref = NULL, *delta = buffer;
+ unsigned long ref_size, delta_size = size;
+ buffer = NULL;
~~~
+ buffer = patch_delta(ref, ref_size,
+ delta+20, delta_size-20,
+ &size);
+ free(delta);
+ free(ref);
+ }
A possibility is to chuck the above special case for "delta",
and instead introduce "delta" subclass in struct object family
and make the base object of "delta" simply one object on the
obj->refs list on such a "delta" object. I would imagine that
this would let you reuse the sha1_retrieve() loop that you
already do for "commit", "tree", and "tag".
+ if (!strcmp(type, "blob")) {
+ struct blob *blob = lookup_blob(sha1);
+ parse_blob_buffer(blob, buffer, size);
~~~
+ obj = &tag->object;
+ } else {
+ obj = NULL;
+ }
+
+ free(buffer);
+
+ if (obj) {
+ struct object_list *refs;
+
+ for (refs = obj->refs; refs ; refs = refs->next) {
+ err = sha1_retrieve(refs->item->sha1);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+ }
+
+ }
+ return -1;
+}
------------
+static int send_send(const unsigned char *sha1, int size, void *data)
+{
~~~
+}
~~~
+static int cmd_request(int argc, char **argv)
+{
+ int err;
+
+ if (argc == 2) {
+ char sha1[40];
+ void *data;
+ unsigned long size;
~~~
+ err = send_send(sha1, size, data);
+ if (err < 0)
+ return err;
By definition, size of SHA1 blob is "unsigned long" so
send_send() should take such not "int".
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: Linus Torvalds @ 2005-06-03 17:41 UTC (permalink / raw)
To: McMullan, Jason; +Cc: Git Mailing List
In-Reply-To: <1117819137.32257.75.camel@jmcmullan.timesys>
On Fri, 3 Jun 2005, McMullan, Jason wrote:
>
> ###### Create a new local git repo
>
> $ GITCONN="--tcp --host 192.168.1.1 --port 7777"
> $ git-init-db
> $ git-server $GITCONN -- request master
Ok. Am I to understand that I could do a push to a remote server with ssh
using something like
git-server -- send master |
ssh master.kernel.org git-server --db /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
or what?
Also, how do I send tags?
Linus
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: Linus Torvalds @ 2005-06-03 17:50 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jason McMullan, Git Mailing List
In-Reply-To: <7vr7fjml35.fsf@assigned-by-dhcp.cox.net>
On Fri, 3 Jun 2005, Junio C Hamano wrote:
>
> That particular name risks conflicting name with other
> git-servers offering different service for git; gitweb is a
> git-server isn't it? git-sync might be better fit.
Yeah, you're right.
Linus
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: Junio C Hamano @ 2005-06-03 18:30 UTC (permalink / raw)
To: Jason McMullan; +Cc: git, torvalds
In-Reply-To: <7vk6lbmk01.fsf@assigned-by-dhcp.cox.net>
>>>>> "JCH" == Junio C Hamano <junkio@cox.net> writes:
JCH> Looks very nice. Some comments.
JCH> This being a dedicated GIT specific sync mechanism, you may want
JCH> to give more smarts to the server, so that the client can say "I
JCH> have these commits as HEADs in my forest, here are their SHA1s,
JCH> now sync me up to the head you said you have whose SHA1 is
JCH> this", implying he has all their HEADs dependents. Of course
JCH> this can come later.
About the protocol, here is one change you may want to have even
in the initial version to futureproof yourself, and let you make
a "low hanging fruit" optimization without bumping the protocol
version up.
Make "request" capable to optionally have this format:
request <sha1> <commit-sha1> <ce-path>
Note. You have to make sure you have some way to quote embedded
newlines in ce-path since your protocol is mostly line based.
When this optional form is used, the requestor is telling the
responder the following:
(1) it wants to retrieve <sha1>; this is the same as a
request without the optional two fields.
(2) it wants <sha1> because it is trying to complete a tree
associated with <commit-sha1>; it already has the commit
object itself and knows what the parents of the commit
are.
(3) it already has trees and blobs associated with all the
parents of <commit-sha1>.
(4) it knows that <sha1> resides at <ce-path> in the tree
associated with <commit-sha1>. As a special case, ""
(an empty string) as <ce-path> means "the root level
tree object associated with <commit-sha1>".
The initial implementation of a requestor does not even send
this extended form. The initial implementation of a responder
must be able to parse this extended form, but it does not have
to do anything special about it; just do what your cmd_request()
currently does. However, this extended request lets your later
implementation of the responder create and send delta on the
fly, by:
(0) Look at <sha1> in the local storage. If it is already
deltified, do not do anything special but just send it
out.
(1) Look at <commit-sha1> and its parents. Compare the
object (either a blob or a tree) that corresponds to
<ce-path> in the trees associated with these commits.
Verify <sha1> is indeed what the requestor thinks it is
while you are at it.
(2) Try to synthesize a reasonable delta to create <sha1>
based on the objects you find in step (1). Upon finding
a reasonable delta, send that as a delta object to the
requestor. Optionally you may want to replace the
<sha1> found at the local store in step (0) with this
delta. If you have many parents, this "reasonable"
delta does not necessarily have to be the minimal delta.
Unlike a full-blown "ihave/sendme" protocol extension, this does
not require responder side to keep much client state, and should
give you the ability to create and send a reasonable if not
minimum delta lazily.
Hmm.
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: McMullan, Jason @ 2005-06-03 19:30 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0506031035470.1876@ppc970.osdl.org>
[-- Attachment #1: Type: text/plain, Size: 958 bytes --]
On Fri, 2005-06-03 at 10:41 -0700, Linus Torvalds wrote:
> Ok. Am I to understand that I could do a push to a remote server with ssh
> using something like
>
> git-server -- send master |
> ssh master.kernel.org git-server --db /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
No, but you could do:
$ ssh master.kernel.org -L 7777:localhost:7777 \
git-server --tcp --port 7777 \
--db /pub/scm/linux/kernel/git/torvalds/linux-2.6.git &
$ git-server --tcp --port 7777 send master
You could probably play some games with shell redirection to file
descriptors if you really wanted to use the stdio stuff over ssh,
but that's a little ugly.
> Also, how do I send tags?
Tags are on my 'TODO' list, as are the deltafication and
mulitple-request changes. Also, a verdict on the name
(daemon vs server vs anything else) would be nice.
--
Jason McMullan <jason.mcmullan@timesys.com>
TimeSys Corporation
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] git-daemon server
From: Linus Torvalds @ 2005-06-03 20:25 UTC (permalink / raw)
To: McMullan, Jason; +Cc: Git Mailing List
In-Reply-To: <1117827011.8970.2.camel@jmcmullan.timesys>
On Fri, 3 Jun 2005, McMullan, Jason wrote:
>
> No, but you could do:
That doth suck. Is there any reason for not allowing stdin/stdout as the
transfer protocol?
Making games like having ssh pipe things through is what I already have to
do with mail, and it's ok for long-running servers, but I really think of
a "git pull" as an _event_.
So why doesn't stdin/stdout work with ssh, even though the docs say that
it's even the default?
Linus
^ 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