* [PATCH] This commit implements git-mv
From: Josef Weidendorfer @ 2005-10-23 16:15 UTC (permalink / raw)
To: junkio; +Cc: git
It superceeds git-rename by adding functionality to move
multiple files, directories or symlinks into another directory.
It also provides according documentation.
The implementation renames multiple files, using the arguments
from the command line to produce an array of sources and destinations.
In a first pass, all requested renames are checked for errors, and
overwriting of existing files is only allowed with '-f'.
The actual renaming is done in a second pass.
This ensures that any error condition is checked before anything is
changed.
Signed-off-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
---
The recent request on the list for "mv" in GIT reminded me about
an addition to git-rename I made a week ago. I renamed it to
"git-mv" and added some documentation.
If this works, we can remove git-rename sometimes in the future.
I should complement this command with tests. Also, a nice addition
would be to support an interactive mode like 'mv', by asking if
files should be overwritten.
By the way, it also checks for a request to move a directory into
itself, which of course is an error.
Option "-k" is good for this:
E.g. a "git-mv -k * dir" moves all revision controlled files and
directories (but not "dir"!) into "dir". "-k" makes sure that
the errors (trying to move "dir" into itself, or move files
without revision control around) will not terminate the command
but silently ignored and skipped.
"-k" was taken from "make": Continue even on an error.
Josef
Documentation/git-mv.txt | 51 +++++++++++++
Makefile | 2
git-mv.perl | 185 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 237 insertions(+), 1 deletions(-)
create mode 100644 Documentation/git-mv.txt
create mode 100755 git-mv.perl
applies-to: b9f56dae60decf015079f5feef4544e7177b143a
0baacba7907046796e5a15eb2b191c1e2cb48793
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
new file mode 100644
index 0000000..f2d5882
--- /dev/null
+++ b/Documentation/git-mv.txt
@@ -0,0 +1,51 @@
+git-mv(1)
+=========
+
+NAME
+----
+git-mv - Script used to move or rename a file, directory or symlink.
+
+
+SYNOPSIS
+--------
+'git-mv' [-f] [-n] <source> <destination>
+'git-mv' [-f] [-k] [-n] <source> ... <destination directory>
+
+DESCRIPTION
+-----------
+This script is used to move or rename a file, directory or symlink.
+In the first form, it renames <source>, which must exist and be either
+a file, symlink or directory, to <destination>, which must not exist.
+In the second form, the last argument has to be an existing
+directory; the given sources will be moved into this directory.
+
+The index is updated after successful completion, but the change must still be
+committed.
+
+OPTIONS
+-------
+-f::
+ Force renaming or moving even targets exist
+-k::
+ Skip move or rename actions which would lead to an error
+ condition. An error happens when a source is neither existing nor
+ controlled by GIT, or when it would overwrite an existing
+ file unless '-f' is given.
+-n::
+ Do nothing; only show what would happen
+
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+Rewritten by Ryan Anderson <ryan@michonline.com>
+Move functionality added by Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+Documentation
+--------------
+Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
diff --git a/Makefile b/Makefile
index 5ee72bc..b43c170 100644
--- a/Makefile
+++ b/Makefile
@@ -94,7 +94,7 @@ SCRIPT_SH = \
SCRIPT_PERL = \
git-archimport.perl git-cvsimport.perl git-relink.perl \
git-rename.perl git-shortlog.perl git-fmt-merge-msg.perl \
- git-findtags.perl git-svnimport.perl
+ git-findtags.perl git-svnimport.perl git-mv.perl
SCRIPT_PYTHON = \
git-merge-recursive.py
diff --git a/git-mv.perl b/git-mv.perl
new file mode 100755
index 0000000..28bced9
--- /dev/null
+++ b/git-mv.perl
@@ -0,0 +1,185 @@
+#!/usr/bin/perl
+#
+# Copyright 2005, Ryan Anderson <ryan@michonline.com>
+# Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+#
+# This file is licensed under the GPL v2, or a later version
+# at the discretion of Linus Torvalds.
+
+
+use warnings;
+use strict;
+use Getopt::Std;
+
+sub usage() {
+ print <<EOT;
+$0 [-f] [-n] <source> <dest>
+$0 [-f] [-k] [-n] <source> ... <dest directory>
+
+In the first form, source must exist and be either a file,
+symlink or directory, dest must not exist. It renames source to dest.
+In the second form, the last argument has to be an existing
+directory; the given sources will be moved into this directory.
+
+Updates the git cache to reflect the change.
+Use "git commit" to make the change permanently.
+
+Options:
+ -f Force renaming/moving, even if target exists
+ -k Continue on error by skipping
+ not-existing or not revision-controlled source
+ -n Do nothing; show what would happen
+EOT
+ exit(1);
+}
+
+# Sanity checks:
+my $GIT_DIR = $ENV{'GIT_DIR'} || ".git";
+
+unless ( -d $GIT_DIR && -d $GIT_DIR . "/objects" &&
+ -d $GIT_DIR . "/objects/" && -d $GIT_DIR . "/refs") {
+ print "Git repository not found.";
+ usage();
+}
+
+
+our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v);
+getopts("hnfkv") || usage;
+usage() if $opt_h;
+@ARGV >= 1 or usage;
+
+my (@srcArgs, @dstArgs, @srcs, @dsts);
+my ($src, $dst, $base, $dstDir);
+
+my $argCount = scalar @ARGV;
+if (-d $ARGV[$argCount-1]) {
+ $dstDir = $ARGV[$argCount-1];
+ @srcArgs = @ARGV[0..$argCount-2];
+
+ foreach $src (@srcArgs) {
+ $base = $src;
+ $base =~ s/^.*\///;
+ $dst = "$dstDir/". $base;
+ push @dstArgs, $dst;
+ }
+}
+else {
+ if ($argCount != 2) {
+ print "Error: moving to directory '"
+ . $ARGV[$argCount-1]
+ . "' not possible; not exisiting\n";
+ usage;
+ }
+ @srcArgs = ($ARGV[0]);
+ @dstArgs = ($ARGV[1]);
+ $dstDir = "";
+}
+
+my (@allfiles,@srcfiles,@dstfiles);
+my $safesrc;
+my %overwritten;
+
+$/ = "\0";
+open(F,"-|","git-ls-files","-z")
+ or die "Failed to open pipe from git-ls-files: " . $!;
+
+@allfiles = map { chomp; $_; } <F>;
+close(F);
+
+
+my ($i, $bad);
+while(scalar @srcArgs > 0) {
+ $src = shift @srcArgs;
+ $dst = shift @dstArgs;
+ $bad = "";
+
+ if ($opt_v) {
+ print "Checking rename of '$src' to '$dst'\n";
+ }
+
+ unless (-f $src || -l $src || -d $src) {
+ $bad = "bad source '$src'";
+ }
+
+ $overwritten{$dst} = 0;
+ if (($bad eq "") && -e $dst) {
+ $bad = "destination '$dst' already exists";
+ if (-f $dst && $opt_f) {
+ print "Warning: $bad; will overwrite!\n";
+ $bad = "";
+ $overwritten{$dst} = 1;
+ }
+ }
+
+ if (($bad eq "") && ($src eq $dstDir)) {
+ $bad = "can not move directory '$src' into itself";
+ }
+
+ if ($bad eq "") {
+ $safesrc = quotemeta($src);
+ @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
+ if (scalar @srcfiles == 0) {
+ $bad = "'$src' not under version control";
+ }
+ }
+
+ if ($bad ne "") {
+ if ($opt_k) {
+ print "Warning: $bad; skipping\n";
+ next;
+ }
+ print "Error: $bad\n";
+ usage();
+ }
+ push @srcs, $src;
+ push @dsts, $dst;
+}
+
+# Final pass: rename/move
+my (@deletedfiles,@addedfiles,@changedfiles);
+while(scalar @srcs > 0) {
+ $src = shift @srcs;
+ $dst = shift @dsts;
+
+ if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; }
+ if (!$opt_n) {
+ rename($src,$dst)
+ or die "rename failed: $!";
+ }
+
+ $safesrc = quotemeta($src);
+ @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
+ @dstfiles = @srcfiles;
+ s/^$safesrc(\/|$)/$dst$1/ for @dstfiles;
+
+ push @deletedfiles, @srcfiles;
+ if (scalar @srcfiles == 1) {
+ if ($overwritten{$dst} ==1) {
+ push @changedfiles, $dst;
+ } else {
+ push @addedfiles, $dst;
+ }
+ }
+ else {
+ push @addedfiles, @dstfiles;
+ }
+}
+
+if ($opt_n) {
+ print "Changed : ". join(", ", @changedfiles) ."\n";
+ print "Adding : ". join(", ", @addedfiles) ."\n";
+ print "Deleting : ". join(", ", @deletedfiles) ."\n";
+ exit(1);
+}
+
+my $rc;
+if (scalar @changedfiles >0) {
+ $rc = system("git-update-index","--",@changedfiles);
+ die "git-update-index failed to update changed files with code $?\n" if $rc;
+}
+if (scalar @addedfiles >0) {
+ $rc = system("git-update-index","--add","--",@addedfiles);
+ die "git-update-index failed to add new names with code $?\n" if $rc;
+}
+$rc = system("git-update-index","--remove","--",@deletedfiles);
+die "git-update-index failed to remove old names with code $?\n" if $rc;
---
0.99.8.GIT
^ permalink raw reply related
* [gitweb PATCH] add a 'diff to parent' option in the file history display
From: Brad Roberts @ 2005-10-23 15:25 UTC (permalink / raw)
To: git
I'm not sure how well this plays with multiple parent merges or anything
complicated. It seems to work well on a converted cvs archive.
Pullable from: git://cvs.puremagic.com/git/gitweb.git
---------------------
add a 'diff to parent' option in the file history display
Signed-off-by: Brad Roberts <braddr@puremagic.com>
---
gitweb.cgi | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
2539b424d62cc2ab060c5d2fa9525a6b6f8df7e5
diff --git a/gitweb.cgi b/gitweb.cgi
--- a/gitweb.cgi
+++ b/gitweb.cgi
@@ -2054,6 +2054,9 @@ sub git_history {
print " | " .
$cgi->a({-href => "$my_uri?p=$project;a=blobdiff;h=$blob;hp=$blob_parent;hb=$commit;f=$file_name"},
"diff to current");
+ print " | "
+ $cgi->a({-href => "$my_uri?p=$project;a=blobdiff;h=$blob_parent;hp=$3;hb=$commit;f=$file_name"},
+ "diff to parent");
}
print "</td>\n" .
"</tr>\n";
^ permalink raw reply
* Re: git and gitweb inconsistencies
From: Sven Verdoolaege @ 2005-10-23 11:59 UTC (permalink / raw)
To: Chris Shoemaker; +Cc: git
In-Reply-To: <20051023001412.GA22679@pe.Belkin>
On Sat, Oct 22, 2005 at 08:14:12PM -0400, Chris Shoemaker wrote:
> A few days later, I ran git-cvsimport again, with -i. This imported
> just the recent changes, but the view from gitweb didn't change. :(
Are you sure you didn't just create a new import *inside* the old import ?
Do you have, say, both an 'objects' and a '.git/objects' directory ?
> $ echo `git-rev-list tip --max-count=1` > refs/heads/mytest
> $ git-cat-file -t `cat refs/heads/mytest`
That should be
git-update-ref refs/heads/mytest tip
(the new head will appear in .git/refs/heads/mytest,
unless you've set GIT_DIR)
git-cat-file -t mytest
skimo
^ permalink raw reply
* Re: User-relative paths (was: Server side programs)
From: Andreas Ericsson @ 2005-10-23 9:41 UTC (permalink / raw)
To: git
In-Reply-To: <7vll0l6pn7.fsf@assigned-by-dhcp.cox.net>
[-- Attachment #1: Type: text/plain, Size: 3617 bytes --]
Junio C Hamano wrote:
> Andreas Ericsson <ae@op5.se> writes:
>
>
>>Are git-receive-pack and git-upload-pack the only two binaries that get
>>called directly over a SSH-tunnel?
>
>
> There are git-ssh-fetch and git-ssh-upload which call each other
> (and the older name pairs git-ssh-push and git-sh-pull do so as
> well). However, you do not have to use these commit walkers
> over ssh; fetch-pack/upload-pack pair work quite well.
>
> I think your question is "what is the absolute minimum set of
> binaries you need to allow", so I think the two listed are
> enough. If you want to let your users coming over SSH *create*
> a new repository on your machine, you would need a bit more,
> though (namely, shell access to run mkdir and git-init-db).
>
That's good to know.
>
>>The reason I'm asking is that I'm adding support for userrelative paths
>>(git pull ssh://host:~user/somedir) and removing the possibilities to
>>use a compromised but limited account for finding out what other
>>useraccounts are available.
>
>
> Sorry, it is not clear to me what you are adding. I do this
> regularly:
>
> $ git push kernel.org:git/
> $ git fetch kernel.org:git/
>
> to push into and fetch from $HOME/git/ repository on the other
> end.
>
Looking at the old code I see that that should work. I'll re-work the
patch to take this into account. The help-text was a bit fuzzy however,
and if you tried
$ git fetch ssh://kernel.org:git
it wouldn't work. Here's how I decided it was somehow broken, or at
least non-intuitive:
$ git clone ssh://git.op5.se:git foo
defaulting to local storage area
ssh: ssh: Name or service not known
fatal: unexpected EOF
> Also I can do this already (assuming the other end hangs all
> users under the same directory, presumably /home/$user):
>
> $ git fetch kernel.org:../torvalds/git/
>
> Are you in addition trying to let me do this:
>
> $ git fetch kernel.org:~torvalds/git/
>
> which would work even when ~torvalds == /home/torvalds and
> ~junio == /home2/junio, without having to tell people where
> the user home directories are?
>
Yes. Our servers' home-directories have varying paths and it'd be nice
to be able to pull other team-members code without having to remember
how that particular server is configured.
> At one point, Linus posted an outline of "restricted login shell
> for use with git over ssh". I think you could start from there,
> perhaps extend it so that it checks the binaries *and* pathnames
> the user can specify (e.g. only under your own $HOME is allowed,
> and no /../ in them, or something silly like that).
>
I found this in the archives:
http://article.gmane.org/gmane.comp.version-control.git/5784/match=restricted+login
Is that what you're referring to?
There's no reason why git-upload-pack and git-receive-pack couldn't be
used safely with a perfectly ordinary shell provided we're careful about
giving the same error message for when a directory is missing and when
it isn't a git archive.
Anyways, the attached patch does this. I've tested all the various
syntaxes and they work as expected. rsync, http and local files take the
same syntax as before. I haven't added support for user-relative paths
to the git-daemon (can't see the point, really) although that can be
done easily enough.
This patch works without conflicts alongside Johannes Schindelin's
recent contribution.
Let me know if you want things done differently.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
[-- Attachment #2: git-userrelative-paths.diff --]
[-- Type: text/plain, Size: 7655 bytes --]
diff --git a/Makefile b/Makefile
index 903c57c..87188ea 100644
--- a/Makefile
+++ b/Makefile
@@ -115,15 +115,18 @@ PROGRAMS = \
git-local-fetch$X git-ls-files$X git-ls-tree$X git-merge-base$X \
git-merge-index$X git-mktag$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X git-read-tree$X \
- git-receive-pack$X git-rev-list$X git-rev-parse$X \
+ git-rev-list$X git-rev-parse$X \
git-send-pack$X git-show-branch$X \
git-show-index$X git-ssh-fetch$X \
git-ssh-upload$X git-tar-tree$X git-unpack-file$X \
git-unpack-objects$X git-update-index$X git-update-server-info$X \
- git-upload-pack$X git-verify-pack$X git-write-tree$X \
+ git-verify-pack$X git-write-tree$X \
git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
$(SIMPLE_PROGRAMS)
+# server side programs called (possibly) over an ssh-tunnel
+SERVERSIDE_PROGRAMS = git-receive-pack$X git-upload-pack$X
+
# Backward compatibility -- to be removed after 1.0
PROGRAMS += git-ssh-pull$X git-ssh-push$X
@@ -315,7 +318,7 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)
export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
### Build rules
-all: $(PROGRAMS) $(SCRIPTS)
+all: $(PROGRAMS) $(SCRIPTS) $(SERVERSIDE_PROGRAMS)
all:
$(MAKE) -C templates
@@ -359,6 +362,9 @@ git-cherry-pick: git-revert
%.o: %.S
$(CC) -o $*.o -c $(ALL_CFLAGS) $<
+$(SERVERSIDE_PROGRAMS) : git-%$X : %.o srvside-ssh.o $(LIB_FILE)
+ $(CC) $(ALL_CFLAGS) -o $@ $(filter %o,$^) $(LIBS)
+
git-%$X: %.o $(LIB_FILE)
$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)
@@ -383,6 +389,7 @@ init-db.o: init-db.c
$(LIB_OBJS): $(LIB_H)
$(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H)
+$(patsubst git-%$X,%.o,$(SERVERSIDE_PROGRAMS)): $(LIB_H) srvside-ssh.o
$(DIFF_OBJS): diffcore.h
$(LIB_FILE): $(LIB_OBJS)
@@ -410,9 +417,10 @@ check:
### Installation rules
-install: $(PROGRAMS) $(SCRIPTS)
+install: $(PROGRAMS) $(SCRIPTS) $(SERVERSIDE_PROGRAMS)
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))
- $(INSTALL) $(PROGRAMS) $(SCRIPTS) $(call shellquote,$(DESTDIR)$(bindir))
+ $(INSTALL) $(PROGRAMS) $(SERVERSIDE_PROGRAMS) $(SCRIPTS) \
+ $(call shellquote,$(DESTDIR)$(bindir))
sh ./cmd-rename.sh $(call shellquote,$(DESTDIR)$(bindir))
$(MAKE) -C templates install
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
diff --git a/connect.c b/connect.c
index b171c5d..0d78b3e 100644
--- a/connect.c
+++ b/connect.c
@@ -436,33 +436,44 @@ static int git_tcp_connect(int fd[2], co
int git_connect(int fd[2], char *url, const char *prog)
{
char command[1024];
- char *host, *path;
- char *colon;
+ char *host, *path, *ptr = NULL;
int pipefd[2][2];
pid_t pid;
enum protocol protocol;
+ protocol = PROTO_LOCAL;
host = NULL;
path = url;
- colon = strchr(url, ':');
- protocol = PROTO_LOCAL;
- if (colon) {
- *colon = 0;
- host = url;
- path = colon+1;
- protocol = PROTO_SSH;
- if (!memcmp(path, "//", 2)) {
- char *slash = strchr(path + 2, '/');
- if (slash) {
- int nr = slash - path - 2;
- memmove(path, path+2, nr);
- path[nr] = 0;
- protocol = get_protocol(url);
- host = path;
- path = slash;
- }
+ host = strstr(url, "://");
+ if (host) {
+ *host = '\0';
+ host += 3;
+ protocol = get_protocol(url);
+ }
+ else host = url;
+
+ ptr = strchr(host, ':');
+ path = strchr(host, '/');
+
+ /* leading colon marks relative path for ssh.
+ * Check for host == url and default to PROTO_SSH to allow
+ * $ git fetch kernel.org:git
+ */
+ if(ptr && (!path || ptr < path)) {
+ if(host == url)
+ protocol = PROTO_SSH;
+
+ if(protocol == PROTO_SSH) {
+ *ptr = '\0';
+ path = ptr + 1;
}
}
+ else if(path != url) {
+ /* null-terminate host and copy path if it isn't relative */
+ ptr = strdup(path);
+ *path = '\0';
+ path = ptr;
+ }
if (protocol == PROTO_GIT)
return git_tcp_connect(fd, prog, host, path);
diff --git a/receive-pack.c b/receive-pack.c
index 8f157bc..9a040ff 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -8,6 +8,8 @@ static const char receive_pack_usage[] =
static const char unpacker[] = "git-unpack-objects";
+extern void srvside_chdir(const char *path, int strict);
+
static int show_ref(const char *path, const unsigned char *sha1)
{
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
@@ -265,18 +267,9 @@ int main(int argc, char **argv)
if (!dir)
usage(receive_pack_usage);
- /* chdir to the directory. If that fails, try appending ".git" */
- if (chdir(dir) < 0) {
- if (chdir(mkpath("%s.git", dir)) < 0)
- die("unable to cd to %s", dir);
- }
-
- /* If we have a ".git" directory, chdir to it */
- chdir(".git");
- putenv("GIT_DIR=.");
+ /* Find the right directory */
+ srvside_chdir(dir, 0);
- if (access("objects", X_OK) < 0 || access("refs/heads", X_OK) < 0)
- die("%s doesn't appear to be a git directory", dir);
write_head_info();
/* EOF */
diff --git a/srvside-ssh.c b/srvside-ssh.c
new file mode 100644
index 0000000..0ed5d30
--- /dev/null
+++ b/srvside-ssh.c
@@ -0,0 +1,63 @@
+#include "cache.h"
+#include <unistd.h>
+#include <pwd.h>
+
+extern const char *__progname;
+
+
+/*
+ * Provide support for user-relative paths, but carefully.
+ *
+ * If someone has compromised an account with access limited to a few
+ * commands (git-receive-pack, git-upload-pack) we don't want to let
+ * them find out about other users through git. We prevent that by the
+ * simple expedient of maintaining the 'path' variable as is and always
+ * supplying the same (not entirely) helpful error message.
+ */
+#define DIR_OOPS \
+ die("%s: '%s': unable to chdir or not a git-archive", __progname, path)
+void srvside_chdir(char *path, int strict)
+{
+ char *dir = path;
+ struct passwd *pw;
+
+ if(chdir(path) < 0 && *path == '~') {
+ char *slash;
+ char *user = (char *)path + 1;
+
+ if((slash = strchr(dir, '/')))
+ *slash = '\0';
+
+ if(!(pw = getpwnam(user))) {
+ if(slash)
+ *slash = '/';
+ DIR_OOPS;
+ }
+ if(chdir(pw->pw_dir) < 0) {
+ DIR_OOPS;
+ }
+
+ /* We're in someones homedir so re-insert the slash (for the
+ * error message) and set dir just beyond it. If there was no
+ * spoon we supply the local one */
+ if(slash) {
+ *slash = '/';
+ dir = slash + 1;
+ }
+ else
+ dir = "./";
+ }
+
+ /* chdir to the directory. If that fails, try appending ".git" */
+ if (chdir(dir) < 0) {
+ if (strict || chdir(mkpath("%s.git", dir)) < 0)
+ DIR_OOPS;
+ }
+ if (!strict)
+ chdir(".git");
+
+ if (access("objects", X_OK) || access("refs", X_OK))
+ DIR_OOPS;
+
+ putenv("GIT_DIR=.");
+}
diff --git a/upload-pack.c b/upload-pack.c
index accdba6..356c9b1 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -5,6 +5,7 @@
#include "object.h"
static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>";
+extern void srvside_chdir(const char *path, int strict);
#define MAX_HAS 256
#define MAX_NEEDS 256
@@ -202,7 +203,6 @@ static int upload_pack(void)
int main(int argc, char **argv)
{
- const char *dir;
int i;
int strict = 0;
@@ -227,20 +227,10 @@ int main(int argc, char **argv)
if (i != argc-1)
usage(upload_pack_usage);
- dir = argv[i];
- /* chdir to the directory. If that fails, try appending ".git" */
- if (chdir(dir) < 0) {
- if (strict || chdir(mkpath("%s.git", dir)) < 0)
- die("git-upload-pack unable to chdir to %s", dir);
- }
- if (!strict)
- chdir(".git");
-
- if (access("objects", X_OK) || access("refs", X_OK))
- die("git-upload-pack: %s doesn't seem to be a git archive", dir);
+ /* Find the right directory */
+ srvside_chdir(argv[i], strict);
- putenv("GIT_DIR=.");
upload_pack();
return 0;
}
^ permalink raw reply related
* Re: move directories in work dir
From: Rogelio M. Serrano Jr. @ 2005-10-23 6:53 UTC (permalink / raw)
To: git
In-Reply-To: <7vzmp04uot.fsf@assigned-by-dhcp.cox.net>
On 2005-10-23 14:24:34 +0800 Junio C Hamano <junkio@cox.net> wrote:
> "Rogelio M. Serrano Jr." <rogelio@smsglobal.net> writes:
>
>> ... is there a way to tell git that i moved a directory into
>> another? For example i have.
>
> Before you moved them, you could have done [*1*]:
>
> $ mkdir analyze/import_tools
> $ git rename analyze/import_a analyze/import_tools/import_a
> $ git rename analyze/import_b analyze/import_tools/import_b
>
thanks i can live with that. i have another subtree with about 20
files in it.
[snipped..]
>
> BTW, do you really have a file whose name ends with an ESC
> character?
>
Oh no thats the my mua's editor. its a bug.
[snipped...]
Thanks
^ permalink raw reply
* Re: move directories in work dir
From: Junio C Hamano @ 2005-10-23 6:24 UTC (permalink / raw)
To: Rogelio M. Serrano Jr.; +Cc: git, ryan
In-Reply-To: <6f22540448f7234336a00bce5b6547b6@Splinter>
"Rogelio M. Serrano Jr." <rogelio@smsglobal.net> writes:
> ... is there a way to tell git that i moved a directory into
> another? For example i have.
Before you moved them, you could have done [*1*]:
$ mkdir analyze/import_tools
$ git rename analyze/import_a analyze/import_tools/import_a
$ git rename analyze/import_b analyze/import_tools/import_b
But that may be too late now. Instead you already did:
$ mkdir analyze/import_tools
$ mv analyze/import_a analyze/import_b analyze/import_tools/.
At this point, you can:
$ git-add analyze/import_tools
$ git-ls-files analyze/import_a analyze/import_b |
git-update-index --remove --stdin
> right now i have to do git-update-index --add for everything all over
> again.
"git rename" is just a short-hand of your manual
"git-update-index --add --remove" (and at the same time moving
files in the working tree). There isn't any extra information
you are giving git by using it (IOW "git" does not record
renames).
BTW, do you really have a file whose name ends with an ESC
character?
> analyse/import_a/import_a.c^[
[Footnote]
*1* It strikes me that git rename *could* be friendlier by
emulating how "mv" treats the paths parameters (current
implementation insists two parameters $src and $dst). What do
you think, Ryan?
^ permalink raw reply
* move directories in work dir
From: Rogelio M. Serrano Jr. @ 2005-10-23 5:44 UTC (permalink / raw)
To: git
Hi,
Sorry for asking but is there a way to tell git that i moved a
directory into another? For example i have.
analyse
analyse/import_a
analyse/import_a/Rules.mk
analyse/import_a/import_a.c^[
analyse/import_b
analyse/import_b/Rules.mk
analyse/import_b/import_b.c
i make a new dir
analyse/import_tools
then move import_a and import_b in there and end up with:
analyse
analyse/import_tools/import_a
analyse/import_tools/import_a/Rules.mk
analyse/import_tools/import_a/import_a.c^[
analyse/import_tools/import_b
analyse/import_tools/import_b/Rules.mk
analyse/import_tools/import_b/import_b.c
right now i have to do git-update-index --add for everything all over
again.
^ permalink raw reply
* [PATCH 4/4] git-fetch-pack: Implement client part of the multi_ack extension
From: Johannes Schindelin @ 2005-10-23 1:40 UTC (permalink / raw)
To: git, junkio
This patch concludes the series, which makes
git-fetch-pack/git-upload-pack negotiate a potentially better set of
common revs. It should make a difference when fetching from a repository
with a few branches.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
connect.c | 5 ++++-
fetch-pack.c | 50 +++++++++++++++++++++++++++++++++++++-------------
2 files changed, 41 insertions(+), 14 deletions(-)
applies-to: 6b4b7d9acf60aa99d961b599f37d0c824be79e27
9adb6b3971e7daa79221d7dbe05b66327b266b86
diff --git a/connect.c b/connect.c
index b171c5d..57e25a3 100644
--- a/connect.c
+++ b/connect.c
@@ -59,8 +59,11 @@ int get_ack(int fd, unsigned char *resul
if (!strcmp(line, "NAK"))
return 0;
if (!strncmp(line, "ACK ", 3)) {
- if (!get_sha1_hex(line+4, result_sha1))
+ if (!get_sha1_hex(line+4, result_sha1)) {
+ if (strstr(line+45, "continue"))
+ return 2;
return 1;
+ }
}
die("git-fetch_pack: expected ACK/NAK, got '%s'", line);
}
diff --git a/fetch-pack.c b/fetch-pack.c
index 3a903c4..57602b9 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -125,7 +125,7 @@ static int find_common(int fd[2], unsign
struct ref *refs)
{
int fetching;
- int count = 0, flushes = 0, retval;
+ int count = 0, flushes = 0, multi_ack = 0, retval;
const unsigned char *sha1;
for_each_ref(rev_list_append_sha1);
@@ -156,20 +156,22 @@ static int find_common(int fd[2], unsign
continue;
}
- packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
+ packet_write(fd[1], "want %s multi_ack\n", sha1_to_hex(remote));
fetching++;
}
packet_flush(fd[1]);
if (!fetching)
return 1;
- flushes = 1;
+ flushes = 0;
retval = -1;
while ((sha1 = get_rev())) {
packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
if (verbose)
fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
if (!(31 & ++count)) {
+ int ack;
+
packet_flush(fd[1]);
flushes++;
@@ -179,26 +181,48 @@ static int find_common(int fd[2], unsign
*/
if (count == 32)
continue;
- if (get_ack(fd[0], result_sha1)) {
- flushes = 0;
- retval = 0;
- if (verbose)
- fprintf(stderr, "got ack\n");
- break;
- }
+
+ do {
+ ack = get_ack(fd[0], result_sha1);
+ if (verbose && ack)
+ fprintf(stderr, "got ack %d %s\n", ack,
+ sha1_to_hex(result_sha1));
+ if (ack == 1) {
+ if (!multi_ack)
+ flushes = 0;
+ retval = 0;
+ goto done;
+ } else if (ack == 2) {
+ multi_ack = 1;
+ mark_common((struct commit *)
+ lookup_object(result_sha1));
+ retval = 0;
+ }
+ } while(ack);
flushes--;
}
}
+done:
+ if (multi_ack) {
+ packet_flush(fd[1]);
+ flushes++;
+ }
packet_write(fd[1], "done\n");
if (verbose)
fprintf(stderr, "done\n");
+ if (retval != 0)
+ flushes++;
while (flushes) {
- flushes--;
if (get_ack(fd[0], result_sha1)) {
if (verbose)
- fprintf(stderr, "got ack\n");
- return 0;
+ fprintf(stderr, "got ack %s\n",
+ sha1_to_hex(result_sha1));
+ if (!multi_ack)
+ return 0;
+ retval = 0;
+ continue;
}
+ flushes--;
}
return retval;
}
---
0.99.8.GIT
^ permalink raw reply related
* [PATCH 3/4] git-fetch-pack: Do not use git-rev-list
From: Johannes Schindelin @ 2005-10-23 1:39 UTC (permalink / raw)
To: git, junkio
The code used to call git-rev-list to enumerate the local revisions. A
disadvantage of that method was that git-rev-list, lacking a control apart
from the command line, would happily enumerate ancestors of acknowledged
common commits, which was just taking unnecessary bandwidth.
Therefore, do not use git-rev-list on the fetching side, but rather
construct the list on the go. Send the revisions starting from the local
heads, ignoring the revisions known to be common.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
fetch-pack.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 119 insertions(+), 32 deletions(-)
applies-to: da61ef5f5dbbe9d0f926f47ae0bd594cdff80d64
8078a74c5b771352d9a7d3979c8dd7e7858ccbaa
diff --git a/fetch-pack.c b/fetch-pack.c
index 8566ab1..3a903c4 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -13,18 +13,123 @@ static const char fetch_pack_usage[] =
static const char *exec = "git-upload-pack";
#define COMPLETE (1U << 0)
+#define COMMON (1U << 1)
+#define COMMON_REF (1U << 2 | COMMON)
+#define SEEN (1U << 3)
+#define POPPED (1U << 4)
+
+static struct commit_list *rev_list = NULL;
+static struct commit_list *rev_list_end = NULL;
+static unsigned long non_common_revs = 0;
+
+static void rev_list_append(struct commit *commit, int mark)
+{
+ if (!(commit->object.flags & mark)) {
+ commit->object.flags |= mark;
+
+ if (rev_list == NULL) {
+ commit_list_insert(commit, &rev_list);
+ rev_list_end = rev_list;
+ } else {
+ commit_list_insert(commit, &(rev_list_end->next));
+ rev_list_end = rev_list_end->next;
+ }
+
+ if (!(commit->object.flags & COMMON))
+ non_common_revs++;
+ }
+}
+
+static int rev_list_append_sha1(const char *path, const unsigned char *sha1)
+{
+ struct object *o = deref_tag(parse_object(sha1));
+
+ if (o->type == commit_type)
+ rev_list_append((struct commit *)o, SEEN);
+
+ return 0;
+}
+
+static void mark_common(struct commit *commit)
+{
+ if (commit != NULL && !(commit->object.flags & COMMON)) {
+ struct object *o = (struct object *)commit;
+ o->flags |= COMMON;
+ if (!(o->flags & SEEN))
+ rev_list_append(commit, SEEN);
+ else {
+ struct commit_list *parents;
+
+ if (!(o->flags & POPPED))
+ non_common_revs--;
+ if (!o->parsed)
+ parse_commit(commit);
+ for (parents = commit->parents;
+ parents;
+ parents = parents->next)
+ mark_common(parents->item);
+ }
+ }
+}
+
+/*
+ Get the next rev to send, ignoring the common.
+*/
+
+static const unsigned char* get_rev()
+{
+ struct commit *commit = NULL;
+
+ while (commit == NULL) {
+ unsigned int mark;
+ struct commit_list* parents;
+
+ if (rev_list == NULL || non_common_revs == 0)
+ return NULL;
+
+ commit = rev_list->item;
+ if (!(commit->object.parsed))
+ parse_commit(commit);
+ commit->object.flags |= POPPED;
+ if (!(commit->object.flags & COMMON))
+ non_common_revs--;
+
+ parents = commit->parents;
+
+ if (commit->object.flags & COMMON) {
+ /* do not send "have", and ignore ancestors */
+ commit = NULL;
+ mark = COMMON | SEEN;
+ } else if (commit->object.flags & COMMON_REF)
+ /* send "have", and ignore ancestors */
+ mark = COMMON | SEEN;
+ else
+ /* send "have", also for its ancestors */
+ mark = SEEN;
+
+ while (parents) {
+ if (mark & COMMON)
+ mark_common(parents->item);
+ else
+ rev_list_append(parents->item, mark);
+ parents = parents->next;
+ }
+
+ rev_list = rev_list->next;
+ }
+
+ return commit->object.sha1;
+}
static int find_common(int fd[2], unsigned char *result_sha1,
struct ref *refs)
{
int fetching;
- static char line[1000];
- static char rev_command[1024];
- int count = 0, flushes = 0, retval, rev_command_len;
- FILE *revs;
+ int count = 0, flushes = 0, retval;
+ const unsigned char *sha1;
+
+ for_each_ref(rev_list_append_sha1);
- strcpy(rev_command, "git-rev-list $(git-rev-parse --all)");
- rev_command_len = strlen(rev_command);
fetching = 0;
for ( ; refs ; refs = refs->next) {
unsigned char *remote = refs->old_sha1;
@@ -42,25 +147,15 @@ static int find_common(int fd[2], unsign
*/
if (((o = lookup_object(remote)) != NULL) &&
(o->flags & COMPLETE)) {
- struct commit_list *p;
- struct commit *commit =
- (struct commit *) (o = deref_tag(o));
- if (!o)
- goto repair;
- if (o->type != commit_type)
- continue;
- p = commit->parents;
- while (p &&
- rev_command_len + 44 < sizeof(rev_command)) {
- snprintf(rev_command + rev_command_len, 44,
- " ^%s",
- sha1_to_hex(p->item->object.sha1));
- rev_command_len += 43;
- p = p->next;
- }
+ o = deref_tag(o);
+
+ if (o->type == commit_type)
+ rev_list_append((struct commit *)o,
+ COMMON_REF | SEEN);
+
continue;
}
- repair:
+
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
fetching++;
}
@@ -68,16 +163,9 @@ static int find_common(int fd[2], unsign
if (!fetching)
return 1;
- revs = popen(rev_command, "r");
- if (!revs)
- die("unable to run 'git-rev-list'");
-
flushes = 1;
retval = -1;
- while (fgets(line, sizeof(line), revs) != NULL) {
- unsigned char sha1[20];
- if (get_sha1_hex(line, sha1))
- die("git-fetch-pack: expected object name, got crud");
+ while ((sha1 = get_rev())) {
packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
if (verbose)
fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
@@ -101,7 +189,6 @@ static int find_common(int fd[2], unsign
flushes--;
}
}
- pclose(revs);
packet_write(fd[1], "done\n");
if (verbose)
fprintf(stderr, "done\n");
---
0.99.8.GIT
^ permalink raw reply related
* [PATCH 2/4] git-upload-pack: Support sending multiple ACK messages
From: Johannes Schindelin @ 2005-10-23 1:37 UTC (permalink / raw)
To: git, junkio
The current fetch/upload protocol works like this:
- client sends revs it wants to have via "want" messages
- client sends a flush message (message with len 0)
- client sends revs it has via "have" messages
- after one window (32 revs), a flush is sent
- after each subsequent window, a flush is sent, and an ACK/NAK is received.
(NAK means that server does not have any of the transmitted revs;
ACK sends also the sha1 of the rev server has)
- when the first ACK is received, client sends "done", and does not expect
any further messages
One special case, though:
- if no ACK is received (only NAK's), and client runs out of revs to send,
"done" is sent, and server sends just one more "NAK"
A smarter scheme, which actually has a chance to detect more than one
common rev, would be to send more than just one ACK. This patch implements
the server side of the following extension to the protocol:
- client sends at least one "want" message with "multi_ack" appended, like
"want 1234567890123456789012345678901234567890 multi_ack"
- if the server understands that extension, it will send ACK messages for all
revs it has, not just the first one
- server appends "continue" to the ACK messages like
"ACK 1234567890123456789012345678901234567890 continue"
until it has MAX_HAS-1 revs. In this manner, client knows when to
stop sending revs by checking for the substring "continue" (and
further knows that server understands multi_ack)
In this manner, the protocol stays backwards compatible, since both client
must send "want ... multi_ack" and server must answer with "ACK ...
continue" to enable the extension.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
upload-pack.c | 37 +++++++++++++++----------------------
1 files changed, 15 insertions(+), 22 deletions(-)
applies-to: 95634a3973bbc1eb8cc626fd6fd67bb773caf7ab
89df3fb3bb65e37c33b478b66c76adc46cf22cd7
diff --git a/upload-pack.c b/upload-pack.c
index ab1981c..c3abf7b 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -10,7 +10,7 @@ static const char upload_pack_usage[] =
#define THEY_HAVE (1U << 0)
#define MAX_HAS 256
#define MAX_NEEDS 256
-static int nr_has = 0, nr_needs = 0;
+static int nr_has = 0, nr_needs = 0, multi_ack = 0;
static unsigned char has_sha1[MAX_HAS][20];
static unsigned char needs_sha1[MAX_NEEDS][20];
static unsigned int timeout = 0;
@@ -124,39 +124,28 @@ static int get_common_commits(void)
reset_timeout();
if (!len) {
- packet_write(1, "NAK\n");
+ if (multi_ack || nr_has == 0)
+ packet_write(1, "NAK\n");
continue;
}
len = strip(line, len);
if (!strncmp(line, "have ", 5)) {
- if (got_sha1(line+5, sha1)) {
- packet_write(1, "ACK %s\n", sha1_to_hex(sha1));
- break;
- }
+ if (got_sha1(line+5, sha1) &&
+ (multi_ack || nr_has == 1))
+ packet_write(1, "ACK %s%s\n",
+ sha1_to_hex(sha1),
+ multi_ack && nr_has < MAX_HAS ?
+ " continue" : "");
continue;
}
if (!strcmp(line, "done")) {
+ if (nr_has > 0)
+ return 0;
packet_write(1, "NAK\n");
return -1;
}
die("git-upload-pack: expected SHA1 list, got '%s'", line);
}
-
- for (;;) {
- len = packet_read_line(0, line, sizeof(line));
- reset_timeout();
- if (!len)
- continue;
- len = strip(line, len);
- if (!strncmp(line, "have ", 5)) {
- got_sha1(line+5, sha1);
- continue;
- }
- if (!strcmp(line, "done"))
- break;
- die("git-upload-pack: expected SHA1 list, got '%s'", line);
- }
- return 0;
}
static int receive_needs(void)
@@ -185,6 +174,10 @@ static int receive_needs(void)
if (strncmp("want ", line, 5) || get_sha1_hex(line+5, sha1_buf))
die("git-upload-pack: protocol error, "
"expected to get sha, not '%s'", line);
+
+ if (strstr(line+45, "multi_ack"))
+ multi_ack = 1;
+
needs++;
}
}
---
0.99.8.GIT
^ permalink raw reply related
* [PATCH 1/4] git-upload-pack: More efficient usage of the has_sha1 array
From: Johannes Schindelin @ 2005-10-23 1:36 UTC (permalink / raw)
To: git, junkio
This patch is based on Junio's proposal. It marks parents of common revs
so that they do not clutter up the has_sha1 array.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
upload-pack.c | 25 ++++++++++++++++++++-----
1 files changed, 20 insertions(+), 5 deletions(-)
applies-to: ccef5ac580c68a9714f37dcd8ee433e9691b640a
69e13cda85a74200b25ed48ed81909d848a7b9cb
diff --git a/upload-pack.c b/upload-pack.c
index accdba6..ab1981c 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -3,9 +3,11 @@
#include "pkt-line.h"
#include "tag.h"
#include "object.h"
+#include "commit.h"
static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>";
+#define THEY_HAVE (1U << 0)
#define MAX_HAS 256
#define MAX_NEEDS 256
static int nr_has = 0, nr_needs = 0;
@@ -85,15 +87,25 @@ static void create_pack_file(void)
static int got_sha1(char *hex, unsigned char *sha1)
{
- int nr;
if (get_sha1_hex(hex, sha1))
die("git-upload-pack: expected SHA1 object, got '%s'", hex);
if (!has_sha1_file(sha1))
return 0;
- nr = nr_has;
- if (nr < MAX_HAS) {
- memcpy(has_sha1[nr], sha1, 20);
- nr_has = nr+1;
+ if (nr_has < MAX_HAS) {
+ struct object *o = lookup_object(sha1);
+ if (!o || (!o->parsed && !parse_object(sha1)))
+ die("oops (%s)", sha1_to_hex(sha1));
+ if (o->type == commit_type) {
+ struct commit_list *parents;
+ if (o->flags & THEY_HAVE)
+ return 0;
+ o->flags |= THEY_HAVE;
+ for (parents = ((struct commit*)o)->parents;
+ parents;
+ parents = parents->next)
+ parents->item->object.flags |= THEY_HAVE;
+ }
+ memcpy(has_sha1[nr_has++], sha1, 20);
}
return 1;
}
@@ -104,6 +116,9 @@ static int get_common_commits(void)
unsigned char sha1[20];
int len;
+ track_object_refs = 0;
+ save_commit_buffer = 0;
+
for(;;) {
len = packet_read_line(0, line, sizeof(line));
reset_timeout();
---
0.99.8.GIT
^ permalink raw reply related
* [PATCH 0/4] Spend more effort in git-fetch-pack finding common revisions
From: Johannes Schindelin @ 2005-10-23 1:35 UTC (permalink / raw)
To: git, junkio
This series of 4 patches extends the fetch-pack/upload-pack protocol such
that more than just one common revision is used to find out which objects
are needed by the client.
This means that the client spends more time on enumerating candidates, and
the server just acknowledges those it knows about. That is done until the
client runs out of candidates, or the server got HAS_MAX common revisions.
While it does not make much of a difference when you are tracking one linear
branch on one repository, this change should make it more efficient (and
also ease the burden on the server) to work with several repositories having
several branches, and intertwined development.
Next thing I'll do is write some nasty test cases.
Flame on,
Dscho
^ permalink raw reply
* Re: Server side programs
From: Linus Torvalds @ 2005-10-23 0:42 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: Git Mailing List
In-Reply-To: <435ABB99.5020908@op5.se>
On Sun, 23 Oct 2005, Andreas Ericsson wrote:
>
> Are git-receive-pack and git-upload-pack the only two binaries that get called
> directly over a SSH-tunnel?
With the normal pack thing, yes.
They will exec other programs (mainly git-rev-list and
git-[un]pack-objects), and a client can ask for other programs
(git-send-pack takes an "--exec=" argument, for example), but those two
should be sufficient if you have a server-side special "restricted shell"
that you want to run instead of a real one.
One more issue: you can't create a new archive or delete an old one (or do
administration like repacking, fsck etc) with those interfaces, so if you
want these limited users to be able to do that, then you'd need to add a
few administration commands too.
Linus
^ permalink raw reply
* Re: Server side programs
From: Junio C Hamano @ 2005-10-23 0:30 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: git
In-Reply-To: <435ABB99.5020908@op5.se>
Andreas Ericsson <ae@op5.se> writes:
> Are git-receive-pack and git-upload-pack the only two binaries that get
> called directly over a SSH-tunnel?
There are git-ssh-fetch and git-ssh-upload which call each other
(and the older name pairs git-ssh-push and git-sh-pull do so as
well). However, you do not have to use these commit walkers
over ssh; fetch-pack/upload-pack pair work quite well.
I think your question is "what is the absolute minimum set of
binaries you need to allow", so I think the two listed are
enough. If you want to let your users coming over SSH *create*
a new repository on your machine, you would need a bit more,
though (namely, shell access to run mkdir and git-init-db).
> The reason I'm asking is that I'm adding support for userrelative paths
> (git pull ssh://host:~user/somedir) and removing the possibilities to
> use a compromised but limited account for finding out what other
> useraccounts are available.
Sorry, it is not clear to me what you are adding. I do this
regularly:
$ git push kernel.org:git/
$ git fetch kernel.org:git/
to push into and fetch from $HOME/git/ repository on the other
end.
Also I can do this already (assuming the other end hangs all
users under the same directory, presumably /home/$user):
$ git fetch kernel.org:../torvalds/git/
Are you in addition trying to let me do this:
$ git fetch kernel.org:~torvalds/git/
which would work even when ~torvalds == /home/torvalds and
~junio == /home2/junio, without having to tell people where
the user home directories are?
At one point, Linus posted an outline of "restricted login shell
for use with git over ssh". I think you could start from there,
perhaps extend it so that it checks the binaries *and* pathnames
the user can specify (e.g. only under your own $HOME is allowed,
and no /../ in them, or something silly like that).
^ permalink raw reply
* git and gitweb inconsistencies
From: Chris Shoemaker @ 2005-10-23 0:14 UTC (permalink / raw)
To: git
I've been experimenting with git and gitweb, but I've reached deadend.
Maybe someone can help?
Short Version:
In sub git_get_type in gitweb.cgi, this line:
open my $fd, "-|", "$gitbin/git-cat-file -t $hash" or return;
results in:
error: unable to find e71b869f3333ad10a492251e099ed9176248a420
fatal: git-cat-file e71b869f3333ad10a492251e099ed9176248a420: bad file
BUT, from the shell:
$ git-cat-file -t e71b869f3333ad10a492251e099ed9176248a420
commit
Longer explanation:
Initially I created the git repository using git-cvsimport as
described in the cvs-migration document. I also installed gitweb.cgi
and everything seemed to be fine. In particular the refs/heads/* files
referred to the tips of current branches in cvs. I was quite pleased.
A few days later, I ran git-cvsimport again, with -i. This imported
just the recent changes, but the view from gitweb didn't change. :(
At first, I thought that the git-cvsimport hadn't worked. But,
git-whatchanged clearly showed the new changes. (I later learned that
git-rev-list also returned the tip-of-branch commits.) After reading
gitweb.cgi, I realized that the refs/heads/* files had not been
changed, so they still referred to the tip-of-branch for the initial
import. (I expected the refs/heads/* to point to the last commit on
each branch. Was that wrong?)
Anyway, I tried to make a new head that actually pointed to what I
expected:
$ echo `git-rev-list tip --max-count=1` > refs/heads/mytest
$ git-cat-file -t `cat refs/heads/mytest`
commit
No problem. But, this same task doesn't seem to work from gitweb.cgi:
$ ./gitweb.cgi http://localhost/cgi-bin/gitweb.cgi?p=test\;a=heads > /dev/null
error: unable to find e71b869f3333ad10a492251e099ed9176248a420
fatal: git-cat-file e71b869f3333ad10a492251e099ed9176248a420: bad file
How can this be? Have I messed something up, or am I just totally confused?
-chris
ps. please cc, not subscribed.
^ permalink raw reply
* Server side programs
From: Andreas Ericsson @ 2005-10-22 22:22 UTC (permalink / raw)
To: Git Mailing List
Are git-receive-pack and git-upload-pack the only two binaries that get
called directly over a SSH-tunnel?
The git tutorial explicitly mentions this for git-receive-pack. Several
of the other docs (git-fetch-pack, git-peek-remote and git-clone-pack)
mentions git-upload-pack. No other program from the git suite is
mentioned as an immediate target for ssh connections.
The reason I'm asking is that I'm adding support for userrelative paths
(git pull ssh://host:~user/somedir) and removing the possibilities to
use a compromised but limited account for finding out what other
useraccounts are available.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
* Re: How do I clear the directory cache
From: Petr Baudis @ 2005-10-22 21:09 UTC (permalink / raw)
To: eschvoca; +Cc: git
In-Reply-To: <2b05065b0510221220r5c498c28lcb00d8846f156686@mail.gmail.com>
Dear diary, on Sat, Oct 22, 2005 at 09:20:40PM CEST, I got a letter
where eschvoca <eschvoca@gmail.com> told me that...
> I think it would make a lot of sense to print out an error to stderr
> if the file is
> bad (maybe you already do). From there it should be easy to capture stderr
> and construct .gitignore.
Yes, we already do.
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.
^ permalink raw reply
* Re: git-daemon --inetd
From: Linus Torvalds @ 2005-10-22 21:05 UTC (permalink / raw)
To: Jon Seymour
Cc: martin.langhoff, H. Peter Anvin, Git Mailing List,
Martin Langhoff, Junio C Hamano
In-Reply-To: <2cfc40320510220645r6e8dc735w32b6ec3633b1d1ff@mail.gmail.com>
On Sat, 22 Oct 2005, Jon Seymour wrote:
>
> Is the concern with --merge-order the complexity of the logic (and
> hence size of object), the intrusiveness into rev-list.c or the fact
> that it uses the OPEN_SSL?
Some of all. But mostly just the basic fact being that right now, nobody
can really use --merge-order anyway, because if somebody compiles without
OPEN_SSL, it just won't be there. So it's _practically_ useless.
Linus
^ permalink raw reply
* Re: git-rev-list: add "--dense" flag
From: Linus Torvalds @ 2005-10-22 20:37 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Petr Baudis, Git Mailing List
In-Reply-To: <7voe5iqk82.fsf@assigned-by-dhcp.cox.net>
On Fri, 21 Oct 2005, Junio C Hamano wrote:
>
> If rev-list can optionally be told to detect renames internally
> (it has necessary bits after all), it could adjust the set of
> paths to follow when it sees something got renamed, either by
> replacing the original path given from the command line with its
> previous name, or adding its previous name to the set of path
> limitters (to cover the copy case as well).
The problem with renames isn't the straight-line case.
The problem with renames is the merge case. And quite frankly, I don't
know how to handle that sanely.
If everything was straight-line (CVS), renames would be trivial. But
git-rev-list very fundamentally works on something that isn't. So let's
look at the _fundamental_ problem:
- git-rev-list traverses one commit at a time, and it doesn't even _know_
whether it has seem all the parents of that commit during the first
phase.
The first phase is the "limit_list()" thing, which is when we decide
which commits are reachable, uninteresting, and which merges to follow.
Now, think about this: since we don't even know that we've seen all
parents, that pretty much by definition means that we can't know what
has been renamed if we were to track it.
- in the second phase (which is where I do the densification), we do
actually have the full tree and that makes a lot of things a lot easier
to do. When it comes to dense, for example, it means that I know all
the UNINTERESTING logic has already been done, and that all merges have
been simplified.
But in the second phase, we couldn't do rename detection either, since
by then, we've already fixed the list of names as far as merges are
concerned.
And note that this fundamental issue is true _whether_ we have some
explicit rename information in a commit or not.
Git-rev-list has a few additional issues that make it even more
interesting:
- git-rev-list fundamentally is designed for multiple heads. There is no
one special "origin" head. We might not have _one_ end-point, we might
have twenty-five different heads we're looking at at the same time. Try
gitk --all --dense -d -- git-fetch.c
on the current git archive, and be impressed by how well it works (and
yes, you'll see a funny artifact: "--dense" never removes a line of
development entirely, so you'll see a single dot for the two
"unrelated" lines: "gitk" and "to-do" do not share a root with the rest
of them. You'll get a single dot for that root, even if it
obviously doesn't actually change "git-fetch.c").
You'll also very clearly see the "Big tool rename" which created that
name: it will be the first commit after the root that is visible that
way.
- path limiters are fundamentally designed to take a list of paths and
directories. Personally, I find that to be a lot more important than a
single file. That's very efficient the way we do it, but if you were to
_change_ the list of paths, you'd basically have to track those changes
over history.
(This actually happens even with a single path - imagine a merge, and a
rename down one line of the merge. You'll have to keep track of
different files for the different lines of development, and then when
they join together, and the rename only happened in one of them, you'll
have to make an executive decision, or just continue to track _both_)
So what do I propose? I propose that you realize that "git-rev-list" is
just the _building_ block. It does one thing, and one thing only: it
creates revision list.
A user basically _never_ uses git-rev-list directly: it just doesn't make
sense. It's not what git-rev-list is there for. git-rev-list is meant to
be used as a base for doing the real work. And that's how you can use it
for renaming too.
If you think of "git-rev-list --dense -- name" as a fast way to get a set
of commits that affect "name", suddenly it all makes sense. You suddenly
realize that that's a nice building block for figuring out renames. It's
not _all_ of it, but it's a big portion.
To go back to "gitk", let's see what the path limitation shows us. Right
now, doing a
gitk --all --dense -d -- git-fetch.sh
only shows that particular name, and that's by design. Maybe that's what
the user wants? You have to realize that especially if you remember an
_old_ name that may not even exist any more, that's REALLY what you want.
Something that works more like "annotate" is useless, because something
that works like annotate would just say "I don't have that file, I can't
follow renames" and exit.
So the first lesson to learn is that following just pure path-names is
actually meaningful ON ITS OWN! Sometimes you do NOT want to follow
renames.
For example, let's say that you used to work on git 4 months ago, but gave
up, since it was too rough for you. But you played around with it, and now
you're back, and you have an old patch that you want to re-apply, but it
doesn't talk about "git-fetch.sh", it talks about "git-fetch-script". So
you do
gitk --dense -- git-fetch-script
and voila, it does the right thing, and top of the thing is "Big tool
rename", which tells you _exactly_ what happened to that PATHNAME.
See? Static pathnames are important!
Now, this does show that when you _do_ care about renames, "gitk" right
now doesn't help you very much (no offense to gitk - how could it know
that git-rev-list would give it pathname detection one day?). Let's
go back to the original example, and see what we could do to make gitk
more useful..
gitk --all --dense -d -- git-fetch.sh
Go and select that "Big tool rename" thing, and start looking for the
rename..
You won't find it. Why? You'll see all-new files, no renames. It turns out
that "gitk" follows the "parent" thing a bit _too_ slavishly, which is
correct on one level, but in this case with "--dense" it turns out that
what you want to do is see only what _that_ commit does, not what that
commit did relative to its parent (which was the initial revision).
So while "--dense" made gitk work even without any changes, it's clear
that the new capability means that gitk might want to have a new button:
"show diff against 'fake parent'" and "show diff against 'real parent'".
If you want the global view, the default gitk behaviour is correct (it
will show a "valid" diff - you'll see everything that changed between the
points it shows). But in a rename-centric world, you want the _local_
change to that commit, and right now gitk can't show you that.
So for trackign renames, we probably want that as a helper to gitk.
Also, gitk has a "re-read references" button, but if you track renames,
you probably want to do more than re-read them: you want to re-DO them
with the "Big rename" as the new head (forget the old references
entirely), and with the name list changed. New functionality (possibly
you'd like to havea "New wiew" button, which actually starts a new gitk
so that you can see both of them). Right now you'd have to do it by hand:
gitk --dense 215a7ad1ef790467a4cd3f0dcffbd6e5f04c38f7 -- git-fetch-script
(where 215a.. is the thing you get when you select the "Big tool rename")
You'd also probably like to have some way to limit the names shown for the
git-diff-tree in gitk.
In short, the new "gitk --dense -- filename" doesn't help you nearly as
much as it _could_. But when you squint a bit, I think you'll see how it's
quite possible to do...
Linus
^ permalink raw reply
* Re: How do I clear the directory cache
From: eschvoca @ 2005-10-22 19:20 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
In-Reply-To: <20051021214326.GJ30889@pasky.or.cz>
On 10/21/05, Petr Baudis <pasky@suse.cz> wrote:
> Dear diary, on Fri, Oct 21, 2005 at 10:40:07PM CEST, I got a letter
> where eschvoca <eschvoca@gmail.com> told me that...
> > On 10/21/05, Petr Baudis <pasky@suse.cz> wrote:
> > > Dear diary, on Fri, Oct 21, 2005 at 05:23:28AM CEST, I got a letter
> > > where eschvoca <eschvoca@gmail.com> told me that...
> > > > cg-status -<status_flag> # list files with given status flag (without
> > > > status flag in column 1)
> > > > git-ls-files [--others|--deleted|etc] --exclude-per-directory=/.gitignore
> > >
> > > All right, this might be useful. Implemented as cg-status -s '?' and such,
> > > thanks for the idea.
> >
> > This is great but it would be easier to work with if there was another
> > switch to turn off printing
> > out the status flag. Otherwise you have to 'sed' or 'awk' out the
> > status flag which is a pain, especially when files have spaces in
> > them.
>
> Not such a huge pain, but if we already have -s... I added -n which does
> what you want.
Great.
> > Also, the "cg-add -r" exits when a file is bad. It would have saved
> > me a few hours if it would keep not exit on a failure (and add the bad
> > files to .gitignore ... but that is probably asking for too much).
>
> I don't like the idea of adding the files automagically to .gitignore,
> but it won't abort the whole operation because of them anymore.
>
I think it would make a lot of sense to print out an error to stderr
if the file is
bad (maybe you already do). From there it should be easy to capture stderr
and construct .gitignore.
Thanks for making cogito better for me and exceeding my expectations.
^ permalink raw reply
* Re: 0.99.9 on Saturday next week.
From: H. Peter Anvin @ 2005-10-22 17:54 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vvezpetpv.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano wrote:
>
> Although we had a good proposal for protocol rewrite from HPA
> and discussions that followed, it appeared to me that the change
> might be a bit too backward incompatible while the advantage was
> not obvious enough -- I do not think we have a consensus on it.
> 0.99.9 will not wait for this discussion to conclude.
>
Not the least since it would be quite a bit of work to make it happen.
-hpa
^ permalink raw reply
* git-core rpm requires
From: Andreas Ericsson @ 2005-10-22 17:22 UTC (permalink / raw)
To: git
I tried git on one of our not too updated servers and noticed that
git-update-index requires zlib >= 1.2, which introduced the *Bound
functions.
It took a while to track down due to lazy symbol resolution and the fact
that the problem was hidden by stderr redirection in the first git
version I tried (some months ago).
Here's a cut'n paste solution if you have sed >= 4.0.9 installed and
have some sort of aversion to manual editors. Feels a bit silly to send
a patch for a one-liner.
sed -i 's/^Requires:./&zlib >= 1.2, /' git-core.spec.in
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
* Re: git-daemon --inetd
From: Jon Seymour @ 2005-10-22 13:45 UTC (permalink / raw)
To: martin.langhoff, Linus Torvalds
Cc: H. Peter Anvin, Git Mailing List, Martin Langhoff, Junio C Hamano
In-Reply-To: <46a038f905091514447e13404d@mail.gmail.com>
On 9/16/05, Martin Langhoff <martin.langhoff@gmail.com> wrote:
> On 9/16/05, Linus Torvalds <torvalds@osdl.org> wrote:
> > Btw, I think --merge-order was cool, but its weaker cousin --topo-order is
> > what is actually _used_. Maybe we should deprecate --merge-order? Right
> > now the only real user is git-archimport, and I think that one too really
> > only wants topo-order too. For example, right now I think git-archimport
> > won't actually work if you build without openssl.
> >
> > Jon? Martin?
Sorry for the long delay in replying - I need to fix my mail filter so
that I do see GIT mail that is actually directed to me!
Is the concern with --merge-order the complexity of the logic (and
hence size of object), the intrusiveness into rev-list.c or the fact
that it uses the OPEN_SSL?
I believe I can rework the merge-order algorithm to avoid the need for
bignum support for OPEN_SSL, though I am not going to get a chance to
do that until December at the earliest.
Much as I hate to see my baby being orphaned, how about we deprecate
--merge-order for now and arrange things so that users have to
explicitly enable it if they want it. If enough people complain about
that, then I can produce a bignum-free version in the December
timeframe?
Regards,
jon.
^ permalink raw reply
* 0.99.9 on Saturday next week.
From: Junio C Hamano @ 2005-10-22 10:23 UTC (permalink / raw)
To: git
We have been at version "0.99.8.GIT" for too long, and
maintenance branch is now up to 0.99.8f.
When git-daemon was deployed on kernel.org machines, I wanted to
stabilize things a bit so that we can feature freeze and do a
real 1.0. Recently we have changed things quite a bit, but
having them only in the "master" branch without having an
official release for some time kept Porcelains in limbo. I am
sure both Pasky and Catalin want to start updating Cogito and
StGIT to take advantage of what the new core offers, but they
cannot just randomly use new features only available in the
"master" branch and expect people to use 0.99.8.GIT version of
unknown vintage.
So here is a heads-up to list what to expect in 0.99.9. I am
not promising that 0.99.9 will be followed by 1.0 -- it could
well be 0.99.10.
The "master" branch, not counting barebone Porcelainish scripts
that real Porcelains would not utilize, contains the following
additions and enhancements. Many of them have been forward
ported to 0.99.8 maintenance branch already:
- Cygwin (HPA).
- Configuration files (Linus).
- core.filemode to tell not to trust working tree mode bits.
- git-daemon (HPA).
- git-symbolic-ref for platforms with/without symlinks (Linus).
- sparse .git/object/??/ directory (Linus).
- git-update-ref.
- funny pathnames quoted in C-style.
- sha1^{} and sha1^{type} notation.
- git-ls-remote reports object names tags point to.
- git-apply operates in a sparse tree.
- git-diff records which blob each patch applies to.
- git-format-patch; --stdout and rev ranges.
- git-update-index --index-info.
- git-read-tree -m -u removes empty directories.
- git-http-fetch drives multiple connections (Nick Hengeveld).
- git-http-fetch is safer with funny-characters.
- the name of packfile is more stable.
- clone-pack keeps the pack unpacked.
- git-check-ref-format; ref names are stricter than before.
- git-pack-files --local (Linus).
- fetch-pack git+ssh:// and ssh+git:// (Linus).
- svn import (Matthias).
- ls-tree filename listing bugfix (Robert Fitzsimons).
- git-index-pack (Sergey).
In addition, we have handful things cooking in the proposed
updates branch. I expect these to come to some conclusion by
the end of next week, and 0.99.9 will contain what's ready by
then:
- rev-list --dense (Linus).
- fetch-pack further improvements (Johannes).
- pack-objects using cached results.
Although we had a good proposal for protocol rewrite from HPA
and discussions that followed, it appeared to me that the change
might be a bit too backward incompatible while the advantage was
not obvious enough -- I do not think we have a consensus on it.
0.99.9 will not wait for this discussion to conclude.
One last request. If you have sent bugfixes in the C-part of
the code (i.e. really core) that I have not applied without a
good reason, please remind me. I do not think I have dropped or
postponed-then-forgot anything, but I just want to be sure. I
am really in stabilization mood this week.
^ permalink raw reply
* [PATCH] Allow caching of generated pack for full cloning.
From: Junio C Hamano @ 2005-10-22 9:00 UTC (permalink / raw)
To: git; +Cc: H Peter Anvin
git-pack-objects can reuse pack files stored in $GIT_DIR/pack-cache
directory, when a necessary pack is found. This is hopefully useful
when upload-pack (called from git-daemon) is expected to receive
requests for the same set of objects many times (e.g full cloning
request of any project, or updates from the set of heads previous day
to the latest for a slow moving project).
Currently git-pack-objects does *not* keep pack files it creates for
reusing. It might be useful to implement its --update-cache option,
which would let it store pack files it created in the pack-cache
directory, and prune rarely used ones from it.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
Right now, this is not very useful except perhaps preparing
for many clone requests by statically creating and storing a
full pack in pack-cache directory. I am expecting that
enabling the unimplemented --update-cache option of
git-pack-objects would let the server keep recently generated
packs, hoping that fetch requests close together would be for
the same "master" head, relative to the same previous heads
(multiple people making a habit of pulling every day, or every
week, or whatever). These cached packs need to be purged from
the pack-cache directory quite often. They would become
useless once you update a popular ref in the repository.
Even if this caching would help git-daemon by reusing
generated packs, I see one potential problem; --update-cache
option would require the process to be able to write into the
pack-cache directory, but I expect git-daemon would run as a
user that does not have any write privilege to the filesystem.
Makefile | 2 +
cache.h | 1 +
copy.c | 37 +++++++++++++++++++++++
pack-objects.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++-------
upload-pack.c | 12 ++++++-
5 files changed, 126 insertions(+), 16 deletions(-)
create mode 100644 copy.c
applies-to: a0d57ba5b9245eb3a4cc15fb029af51a40eb8136
dd42e422104f43b369929c4f900362d401d2e962
diff --git a/Makefile b/Makefile
index 903c57c..3d8503d 100644
--- a/Makefile
+++ b/Makefile
@@ -159,7 +159,7 @@ LIB_OBJS = \
object.o pack-check.o patch-delta.o path.o pkt-line.o \
quote.o read-cache.o refs.o run-command.o \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
- tag.o tree.o usage.o config.o environment.o ctype.o \
+ tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
$(DIFF_OBJS)
LIBS = $(LIB_FILE)
diff --git a/cache.h b/cache.h
index d776016..2e36cc5 100644
--- a/cache.h
+++ b/cache.h
@@ -413,4 +413,5 @@ static inline int sane_case(int x, int h
return x;
}
+extern int copy_fd(int ifd, int ofd);
#endif /* CACHE_H */
diff --git a/copy.c b/copy.c
new file mode 100644
index 0000000..2009275
--- /dev/null
+++ b/copy.c
@@ -0,0 +1,37 @@
+#include "cache.h"
+
+int copy_fd(int ifd, int ofd)
+{
+ while (1) {
+ int len;
+ char buffer[8192];
+ char *buf = buffer;
+ len = read(ifd, buffer, sizeof(buffer));
+ if (!len)
+ break;
+ if (len < 0) {
+ if (errno == EAGAIN)
+ continue;
+ return error("copy-fd: read returned %s",
+ strerror(errno));
+ }
+ while (1) {
+ int written = write(ofd, buf, len);
+ if (written > 0) {
+ buf += written;
+ len -= written;
+ if (!len)
+ break;
+ }
+ if (!written)
+ return error("copy-fd: write returned 0");
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ return error("copy-fd: write returned %s",
+ strerror(errno));
+ }
+ }
+ close(ifd);
+ return 0;
+}
+
diff --git a/pack-objects.c b/pack-objects.c
index b3e6152..915469e 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -4,7 +4,7 @@
#include "pack.h"
#include "csum-file.h"
-static const char pack_usage[] = "git-pack-objects [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
+static const char pack_usage[] = "git-pack-objects [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} [--update-cache] < object-list";
struct object_entry {
unsigned char sha1[20];
@@ -400,6 +400,71 @@ static void find_deltas(struct object_en
free(array);
}
+static void prepare_pack(int window, int depth)
+{
+ get_object_details();
+
+ fprintf(stderr, "Packing %d objects\n", nr_objects);
+
+ sorted_by_type = create_sorted_list(type_size_sort);
+ if (window && depth)
+ find_deltas(sorted_by_type, window+1, depth);
+ write_pack_file();
+}
+
+static int reuse_cached_pack(unsigned char *sha1, int pack_to_stdout)
+{
+ static const char cache[] = "pack-cache/pack-%s.%s";
+ char *cached_pack, *cached_idx;
+ int ifd, ofd, ifd_ix = -1;
+
+ cached_pack = git_path(cache, sha1_to_hex(sha1), "pack");
+ ifd = open(cached_pack, O_RDONLY);
+ if (ifd < 0)
+ return 0;
+
+ if (!pack_to_stdout) {
+ cached_idx = git_path(cache, sha1_to_hex(sha1), "idx");
+ ifd_ix = open(cached_idx, O_RDONLY);
+ if (ifd_ix < 0) {
+ close(ifd);
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "Reusing %d objects pack %s\n", nr_objects,
+ sha1_to_hex(sha1));
+
+ if (pack_to_stdout) {
+ if (copy_fd(ifd, 1))
+ exit(1);
+ close(ifd);
+ }
+ else {
+ char name[PATH_MAX];
+ snprintf(name, sizeof(name),
+ "%s-%s.%s", base_name, sha1_to_hex(sha1), "pack");
+ ofd = open(name, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ if (ofd < 0)
+ die("unable to open %s (%s)", name, strerror(errno));
+ if (copy_fd(ifd, ofd))
+ exit(1);
+ close(ifd);
+
+ snprintf(name, sizeof(name),
+ "%s-%s.%s", base_name, sha1_to_hex(sha1), "idx");
+ ofd = open(name, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ if (ofd < 0)
+ die("unable to open %s (%s)", name, strerror(errno));
+ if (copy_fd(ifd_ix, ofd))
+ exit(1);
+ close(ifd_ix);
+ puts(sha1_to_hex(sha1));
+ }
+
+ return 1;
+}
+
int main(int argc, char **argv)
{
SHA_CTX ctx;
@@ -424,6 +489,10 @@ int main(int argc, char **argv)
incremental = 1;
continue;
}
+ if (!strcmp("--update-cache", arg)) {
+ /* Not implemented */
+ continue;
+ }
if (!strncmp("--window=", arg, 9)) {
char *end;
window = strtoul(arg+9, &end, 0);
@@ -472,9 +541,6 @@ int main(int argc, char **argv)
}
if (non_empty && !nr_objects)
return 0;
- get_object_details();
-
- fprintf(stderr, "Packing %d objects\n", nr_objects);
sorted_by_sha = create_sorted_list(sha1_sort);
SHA1_Init(&ctx);
@@ -485,14 +551,14 @@ int main(int argc, char **argv)
}
SHA1_Final(object_list_sha1, &ctx);
- sorted_by_type = create_sorted_list(type_size_sort);
- if (window && depth)
- find_deltas(sorted_by_type, window+1, depth);
-
- write_pack_file();
- if (!pack_to_stdout) {
- write_index_file();
- puts(sha1_to_hex(object_list_sha1));
+ if (reuse_cached_pack(object_list_sha1, pack_to_stdout))
+ ;
+ else {
+ prepare_pack(window, depth);
+ if (!pack_to_stdout) {
+ write_index_file();
+ puts(sha1_to_hex(object_list_sha1));
+ }
}
return 0;
}
diff --git a/upload-pack.c b/upload-pack.c
index 8a41caf..6fb8eb7 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -29,6 +29,7 @@ static void create_pack_file(void)
{
int fd[2];
pid_t pid;
+ int create_full_pack = (MAX_NEEDS <= nr_needs);
if (pipe(fd) < 0)
die("git-upload-pack: unable to create pipe");
@@ -43,7 +44,7 @@ static void create_pack_file(void)
char *buf;
char **p;
- if (MAX_NEEDS <= nr_needs)
+ if (create_full_pack)
args = nr_has + 10;
else
args = nr_has + nr_needs + 5;
@@ -57,7 +58,7 @@ static void create_pack_file(void)
close(fd[1]);
*p++ = "git-rev-list";
*p++ = "--objects";
- if (MAX_NEEDS <= nr_needs)
+ if (create_full_pack)
*p++ = "--all";
else {
for (i = 0; i < nr_needs; i++) {
@@ -79,7 +80,12 @@ static void create_pack_file(void)
dup2(fd[0], 0);
close(fd[0]);
close(fd[1]);
- execlp("git-pack-objects", "git-pack-objects", "--stdout", NULL);
+ if (create_full_pack)
+ execlp("git-pack-objects", "git-pack-objects",
+ "--stdout", NULL);
+ else
+ execlp("git-pack-objects", "git-pack-objects",
+ "--stdout", "--update-cache", NULL);
die("git-upload-pack: unable to exec git-pack-objects");
}
---
0.99.8.GIT
^ permalink raw reply related
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