GIT 0.99.9k

This is not 1.0rc4 yet, but to push the recent fixes out.

Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Junio C Hamano 2005-11-25 16:35:20 -08:00
commit 93dcab2937
77 changed files with 2854 additions and 1802 deletions

1
.gitignore vendored
View File

@ -75,6 +75,7 @@ git-rebase
git-receive-pack
git-relink
git-repack
git-repo-config
git-request-pull
git-reset
git-resolve

View File

@ -8,7 +8,7 @@ git-daemon - A really simple server for git repositories.
SYNOPSIS
--------
'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
[--timeout=n] [--init-timeout=n] [directory...]
[--timeout=n] [--init-timeout=n] [--strict-paths] [directory...]
DESCRIPTION
-----------
@ -29,9 +29,15 @@ This is ideally suited for read-only updates, ie pulling from git repositories.
OPTIONS
-------
--strict-paths::
Match paths exactly (i.e. don't allow "/foo/repo" when the real path is
"/foo/repo.git" or "/foo/repo/.git") and don't do user-relative paths.
git-daemon will refuse to start when this option is enabled and no
whitelist is specified.
--export-all::
Allow pulling from all directories that look like GIT repositories
(have the 'objects' subdirectory and a 'HEAD' file), even if they
(have the 'objects' and 'refs' subdirectories), even if they
do not have the 'git-daemon-export-ok' file.
--inetd::
@ -57,9 +63,15 @@ OPTIONS
--verbose::
Log details about the incoming connections and requested files.
<directory>::
A directory to add to the whitelist of allowed directories. Unless
--strict-paths is specified this will also include subdirectories
of each named directory.
Author
------
Written by Linus Torvalds <torvalds@osdl.org> and YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Written by Linus Torvalds <torvalds@osdl.org>, YOSHIFUJI Hideaki
<yoshfuji@linux-ipv6.org> and the git-list <git@vger.kernel.org>
Documentation
--------------

View File

@ -0,0 +1,170 @@
git-repo-config(1)
==================
NAME
----
git-repo-config - Get and set options in .git/config.
SYNOPSIS
--------
'git-repo-config' name [value [value_regex]]
'git-repo-config' --replace-all name [value [value_regex]]
'git-repo-config' --get name [value_regex]
'git-repo-config' --get-all name [value_regex]
'git-repo-config' --unset name [value_regex]
'git-repo-config' --unset-all name [value_regex]
DESCRIPTION
-----------
You can query/set/replace/unset options with this command. The name is
actually the section and the key separated by a dot, and the value will be
escaped.
If you want to set/unset an option which can occor on multiple lines, you
should provide a POSIX regex for the value. If you want to handle the lines
*not* matching the regex, just prepend a single exlamation mark in front
(see EXAMPLES).
This command will fail if
. .git/config is invalid,
. .git/config can not be written to,
. no section was provided,
. the section or key is invalid,
. you try to unset an option which does not exist, or
. you try to unset/set an option for which multiple lines match.
OPTIONS
-------
--replace-all::
Default behaviour is to replace at most one line. This replaces
all lines matching the key (and optionally the value_regex)
--get::
Get the value for a given key (optionally filtered by a regex
matching the value).
--get-all::
Like get, but does not fail if the number of values for the key
is not exactly one.
--unset::
Remove the line matching the key from .git/config.
--unset-all::
Remove all matching lines from .git/config.
EXAMPLE
-------
Given a .git/config like this:
#
# This is the config file, and
# a '#' or ';' character indicates
# a comment
#
; core variables
[core]
; Don't trust file modes
filemode = false
; Our diff algorithm
[diff]
external = "/usr/local/bin/gnu-diff -u"
renames = true
; Proxy settings
[proxy]
command="ssh" for "ssh://kernel.org/"
command="proxy-command" for kernel.org
command="myprotocol-command" for "my://"
command=default-proxy ; for all the rest
you can set the filemode to true with
------------
% git repo-config core.filemode true
------------
The hypothetic proxy command entries actually have a postfix to discern
to what URL they apply. Here is how to change the entry for kernel.org
to "ssh".
------------
% git repo-config proxy.command '"ssh" for kernel.org' 'for kernel.org$'
------------
This makes sure that only the key/value pair for kernel.org is replaced.
To delete the entry for renames, do
------------
% git repo-config --unset diff.renames
------------
If you want to delete an entry for a multivar (like proxy.command above),
you have to provide a regex matching the value of exactly one line.
To query the value for a given key, do
------------
% git repo-config --get core.filemode
------------
or
------------
% git repo-config core.filemode
------------
or, to query a multivar:
------------
% git repo-config --get proxy.command "for kernel.org$"
------------
If you want to know all the values for a multivar, do:
------------
% git repo-config --get-all proxy.command
------------
If you like to live dangerous, you can replace *all* proxy.commands by a
new one with
------------
% git repo-config --replace-all proxy.command ssh
------------
However, if you really only want to replace the line for the default proxy,
i.e. the one without a "for ..." postfix, do something like this:
------------
% git repo-config proxy.command ssh '! for '
------------
To actually match only values with an exclamation mark, you have to
------------
% git repo-config section.key value '[!]'
------------
Author
------
Written by Johannes Schindelin <Johannes.Schindelin@gmx.de>
Documentation
--------------
Documentation by Johannes Schindelin.
GIT
---
Part of the gitlink:git[7] suite

View File

@ -14,19 +14,30 @@ DESCRIPTION
Sets the current head to the specified commit and optionally resets the
index and working tree to match.
This command is useful if you notice some small error in a recent
commit (or set of commits) and want to redo that part without showing
the undo in the history.
If you want to undo a commit other than the latest on a branch,
gitlink:git-revert[1] is your friend.
OPTIONS
-------
--mixed::
Like --soft but reports what has not been updated. This is the
default action.
Resets the index but not the working tree (ie, the changed files
are preserved but not marked for commit) and reports what has not
been updated. This is the default action.
--soft::
Does not touch the index file nor the working tree at all, but
requires them in a good order.
requires them to be in a good order. This leaves all your changed
files "Updated but not checked in", as gitlink:git-status[1] would
put it.
--hard::
Matches the working tree and index to that of the tree being
switched to.
switched to. Any changes to tracked files in the working tree
since <commit-ish> are lost.
<commit-ish>::
Commit to make the current HEAD.

View File

@ -108,6 +108,9 @@ gitlink:git-prune-packed[1]::
gitlink:git-read-tree[1]::
Reads tree information into the directory index
gitlink:git-repo-config[1]::
Get and set options in .git/config.
gitlink:git-unpack-objects[1]::
Unpacks objects out of a packed archive.

View File

@ -40,10 +40,7 @@ So I started from master, made a bunch of edits, and committed:
$ git checkout master
$ cd Documentation; ed git.txt ...
$ cd ..; git add Documentation/*.txt
$ git commit -s -v
NOTE. The -v flag to commit is a handy way to make sure that
your additions are not introducing bogusly formatted lines.
$ git commit -s
After the commit, the ancestry graph would look like this:
@ -98,7 +95,7 @@ to do cherrypicking using only the core GIT tools.
Let's go back to the earlier picture, with different labels.
You, as an individual developer, cloned upstream repository and
amde a couple of commits on top of it.
made a couple of commits on top of it.
*your "master" head
upstream --> #1 --> #2 --> #3

View File

@ -0,0 +1,105 @@
From: Junio C Hamano <junkio@cox.net>
Subject: control access to branches.
Date: Thu, 17 Nov 2005 23:55:32 -0800
Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net>
Abstract: An example hooks/update script is presented to
implement repository maintenance policies, such as who can push
into which branch and who can make a tag.
When your developer runs git-push into the repository,
git-receive-pack is run (either locally or over ssh) as that
developer, so is hooks/update script. Quoting from the relevant
section of the documentation:
Before each ref is updated, if $GIT_DIR/hooks/update file exists
and executable, it is called with three parameters:
$GIT_DIR/hooks/update refname sha1-old sha1-new
The refname parameter is relative to $GIT_DIR; e.g. for the
master head this is "refs/heads/master". Two sha1 are the
object names for the refname before and after the update. Note
that the hook is called before the refname is updated, so either
sha1-old is 0{40} (meaning there is no such ref yet), or it
should match what is recorded in refname.
So if your policy is (1) always require fast-forward push
(i.e. never allow "git-push repo +branch:branch"), (2) you
have a list of users allowed to update each branch, and (3) you
do not let tags to be overwritten, then:
#!/bin/sh
# This is a sample hooks/update script, written by JC
# in his e-mail buffer, so naturally it is not tested
# but hopefully would convey the idea.
umask 002
case "$1" in
refs/tags/*)
# No overwriting an existing tag
if test -f "$GIT_DIR/$1"
then
exit 1
fi
;;
refs/heads/*)
# No rebasing or rewinding
if expr "$2" : '0*$' >/dev/null
then
# creating a new branch
;
else
# updating -- make sure it is a fast forward
mb=`git-merge-base "$2" "$3"`
case "$mb,$2" in
"$2,$mb")
;; # fast forward -- happy
*)
exit 1 ;; # unhappy
esac
fi
;;
*)
# No funny refs allowed
exit 1
;;
esac
# Is the user allowed to update it?
me=`id -u -n` ;# e.g. "junio"
while read head_pattern users
do
if expr "$1" : "$head_pattern" >/dev/null
then
case " $users " in
*" $me "*)
exit 0 ;; # happy
' * ')
exit 0 ;; # anybody
esac
fi
done
exit 1
For the sake of simplicity, I assumed that you keep something
like this in $GIT_DIR/info/allowed-pushers file:
refs/heads/master junio
refs/heads/cogito$ pasky
refs/heads/bw/ linus
refs/heads/tmp/ *
refs/tags/v[0-9]* junio
With this, Linus can push or create "bw/penguin" or "bw/zebra"
or "bw/panda" branches, Pasky can do only "cogito", and I can do
master branch and make versioned tags. And anybody can do
tmp/blah branches. This assumes all the users are in a single
group that can write into $GIT_DIR/ and underneath.

View File

@ -5,11 +5,31 @@
to name the remote repository:
+
===============================================================
- Rsync URL: rsync://remote.machine/path/to/repo.git/
- HTTP(s) URL: http://remote.machine/path/to/repo.git/
- git URL: git://remote.machine/path/to/repo.git/
- ssh URL: remote.machine:/path/to/repo.git/
- Local directory: /path/to/repo.git/
- rsync://host.xz/path/to/repo.git/
- http://host.xz/path/to/repo.git/
- https://host.xz/path/to/repo.git/
- git://host.xz/path/to/repo.git/
- git://host.xz/~user/path/to/repo.git/
- ssh://host.xz/path/to/repo.git/
- ssh://host.xz/~user/path/to/repo.git/
- ssh://host.xz/~/path/to/repo.git
===============================================================
+
SSH Is the default transport protocol and also supports an
scp-like syntax. Both syntaxes support username expansion,
as does the native git protocol. The following three are
identical to the last three above, respectively:
+
===============================================================
- host.xz:/path/to/repo.git/
- host.xz:~user/path/to/repo.git/
- host.xz:path/to/repo.git
===============================================================
+
To sync with a local directory, use:
===============================================================
- /path/to/repo.git/
===============================================================
+
In addition to the above, as a short-hand, the name of a

View File

@ -1534,7 +1534,10 @@ on that project and has an own "public repository" goes like this:
the "project lead" person does.
3. Copy over the packed files from "project lead" public
repository to your public repository.
repository to your public repository, unless the "project
lead" repository lives on the same machine as yours. In the
latter case, you can use `objects/info/alternates` file to
point at the repository you are borrowing from.
4. Push into the public repository from your primary
repository. Run `git repack`, and possibly `git prune` if the

View File

@ -50,7 +50,7 @@
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-cache perspective.
GIT_VERSION = 0.99.9j
GIT_VERSION = 0.99.9k
# CFLAGS and LDFLAGS are for the users to override from the command line.
@ -102,6 +102,11 @@ SCRIPT_PERL = \
SCRIPT_PYTHON = \
git-merge-recursive.py
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
gitk git-cherry-pick
# The ones that do not have to link with lcrypto nor lz.
SIMPLE_PROGRAMS = \
git-get-tar-commit-id$X git-mailinfo$X git-mailsplit$X \
@ -125,18 +130,36 @@ PROGRAMS = \
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-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
git-name-rev$X git-pack-redundant$X git-var$X $(SIMPLE_PROGRAMS)
git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X
# what 'all' will build and 'install' will install.
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) git$X
# Backward compatibility -- to be removed after 1.0
PROGRAMS += git-ssh-pull$X git-ssh-push$X
GIT_LIST_TWEAK =
# Set paths to tools early so that they can be used for version tests.
ifndef SHELL_PATH
SHELL_PATH = /bin/sh
endif
ifndef PERL_PATH
PERL_PATH = /usr/bin/perl
endif
ifndef PYTHON_PATH
PYTHON_PATH = /usr/bin/python
endif
PYMODULES = \
gitMergeCommon.py
ifdef WITH_OWN_SUBPROCESS_PY
PYMODULES += compat/subprocess.py
else
ifneq ($(shell $(PYTHON_PATH) -c 'import subprocess;print"OK"' 2>/dev/null),OK)
PYMODULES += compat/subprocess.py
endif
endif
ifdef WITH_SEND_EMAIL
@ -242,22 +265,15 @@ ifndef NO_CURL
CURL_LIBCURL = -lcurl
endif
PROGRAMS += git-http-fetch$X
ifndef NO_EXPAT
EXPAT_LIBEXPAT = -lexpat
PROGRAMS += git-http-push$X
curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p)
ifeq "$(curl_check)" "070908"
ifndef NO_EXPAT
EXPAT_LIBEXPAT = -lexpat
PROGRAMS += git-http-push$X
endif
endif
endif
ifndef SHELL_PATH
SHELL_PATH = /bin/sh
endif
ifndef PERL_PATH
PERL_PATH = /usr/bin/perl
endif
ifndef PYTHON_PATH
PYTHON_PATH = /usr/bin/python
endif
ifndef NO_OPENSSL
LIB_OBJS += epoch.o
OPENSSL_LIBSSL = -lssl
@ -330,25 +346,20 @@ endif
ALL_CFLAGS += -DSHA1_HEADER=$(call shellquote,$(SHA1_HEADER))
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
gitk git-cherry-pick
export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
### Build rules
all: $(PROGRAMS) $(SCRIPTS) git
all: $(ALL_PROGRAMS)
all:
$(MAKE) -C templates
# Only use $(CFLAGS). We don't need anything else.
git: git.c Makefile
git$(X): git.c Makefile
$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
$(CFLAGS) $@.c -o $@
$(CFLAGS) $< -o $@
$(filter-out git,$(patsubst %.sh,%,$(SCRIPT_SH))) : % : %.sh
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
rm -f $@
sed -e '1s|#!.*/sh|#!$(call shq,$(SHELL_PATH))|' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
@ -387,7 +398,8 @@ $(SIMPLE_PROGRAMS) : git-%$X : %.o
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIB_FILE) $(SIMPLE_LIB)
git-http-fetch$X: fetch.o
git-http-fetch$X: fetch.o http.o
git-http-push$X: http.o
git-local-fetch$X: fetch.o
git-ssh-fetch$X: rsh.o fetch.o
git-ssh-upload$X: rsh.o
@ -431,9 +443,9 @@ check:
### Installation rules
install: $(PROGRAMS) $(SCRIPTS) git
install: all
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))
$(INSTALL) git $(PROGRAMS) $(SCRIPTS) $(call shellquote,$(DESTDIR)$(bindir))
$(INSTALL) $(ALL_PROGRAMS) $(call shellquote,$(DESTDIR)$(bindir))
$(MAKE) -C templates install
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
@ -470,7 +482,8 @@ deb: dist
### Cleaning rules
clean:
rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o git $(PROGRAMS) $(LIB_FILE)
rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o $(LIB_FILE)
rm -f $(PROGRAMS) $(SIMPLE_PROGRAMS) git$X
rm -f $(filter-out gitk,$(SCRIPTS))
rm -f *.spec *.pyc *.pyo
rm -rf $(GIT_TARNAME)

View File

@ -203,6 +203,7 @@ int git_mkstemp(char *path, size_t n, const char *template);
int safe_create_leading_directories(char *path);
char *safe_strncpy(char *, const char *, size_t);
char *enter_repo(char *path, int strict);
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
@ -262,9 +263,8 @@ void datestamp(char *buf, int bufsize);
unsigned long approxidate(const char *);
extern int setup_ident(void);
extern char *get_ident(const char *name, const char *email, const char *date_str);
extern char *git_author_info(void);
extern char *git_committer_info(void);
extern const char *git_author_info(void);
extern const char *git_committer_info(void);
static inline void *xmalloc(size_t size)
{
@ -386,6 +386,8 @@ extern int git_default_config(const char *, const char *);
extern int git_config(config_fn_t fn);
extern int git_config_int(const char *, const char *);
extern int git_config_bool(const char *, const char *);
extern int git_config_set(const char *, const char *);
extern int git_config_set_multivar(const char *, const char *, const char *, int);
#define MAX_GITNAME (1000)
extern char git_default_email[MAX_GITNAME];

340
config.c
View File

@ -1,5 +1,12 @@
/*
* GIT - The information manager from hell
*
* Copyright (C) Linus Torvalds, 2005
* Copyright (C) Johannes Schindelin, 2005
*
*/
#include "cache.h"
#include <regex.h>
#define MAXNAME (256)
@ -136,7 +143,7 @@ static int get_base_var(char *name)
return -1;
if (c == ']')
return baselen;
if (!isalnum(c))
if (!isalnum(c) && c != '.')
return -1;
if (baselen > MAXNAME / 2)
return -1;
@ -229,11 +236,6 @@ int git_default_config(const char *var, const char *value)
return 0;
}
if (!strcmp(var, "diff.renamelimit")) {
diff_rename_limit_default = git_config_int(var, value);
return 0;
}
/* Add other config variables here.. */
return 0;
}
@ -252,3 +254,327 @@ int git_config(config_fn_t fn)
}
return ret;
}
/*
* Find all the stuff for git_config_set() below.
*/
#define MAX_MATCHES 512
static struct {
int baselen;
char* key;
int do_not_match;
regex_t* value_regex;
int multi_replace;
off_t offset[MAX_MATCHES];
enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
int seen;
} store;
static int matches(const char* key, const char* value)
{
return !strcmp(key, store.key) &&
(store.value_regex == NULL ||
(store.do_not_match ^
!regexec(store.value_regex, value, 0, NULL, 0)));
}
static int store_aux(const char* key, const char* value)
{
switch (store.state) {
case KEY_SEEN:
if (matches(key, value)) {
if (store.seen == 1 && store.multi_replace == 0) {
fprintf(stderr,
"Warning: %s has multiple values\n",
key);
} else if (store.seen >= MAX_MATCHES) {
fprintf(stderr, "Too many matches\n");
return 1;
}
store.offset[store.seen] = ftell(config_file);
store.seen++;
}
break;
case SECTION_SEEN:
if (strncmp(key, store.key, store.baselen+1)) {
store.state = SECTION_END_SEEN;
break;
} else
/* do not increment matches: this is no match */
store.offset[store.seen] = ftell(config_file);
/* fallthru */
case SECTION_END_SEEN:
case START:
if (matches(key, value)) {
store.offset[store.seen] = ftell(config_file);
store.state = KEY_SEEN;
store.seen++;
} else if(!strncmp(key, store.key, store.baselen))
store.state = SECTION_SEEN;
}
return 0;
}
static void store_write_section(int fd, const char* key)
{
write(fd, "[", 1);
write(fd, key, store.baselen);
write(fd, "]\n", 2);
}
static void store_write_pair(int fd, const char* key, const char* value)
{
int i;
write(fd, "\t", 1);
write(fd, key+store.baselen+1,
strlen(key+store.baselen+1));
write(fd, " = ", 3);
for (i = 0; value[i]; i++)
switch (value[i]) {
case '\n': write(fd, "\\n", 2); break;
case '\t': write(fd, "\\t", 2); break;
case '"': case '\\': write(fd, "\\", 1);
default: write(fd, value+i, 1);
}
write(fd, "\n", 1);
}
static int find_beginning_of_line(const char* contents, int size,
int offset_, int* found_bracket)
{
int equal_offset = size, bracket_offset = size;
int offset;
for (offset = offset_-2; offset > 0
&& contents[offset] != '\n'; offset--)
switch (contents[offset]) {
case '=': equal_offset = offset; break;
case ']': bracket_offset = offset; break;
}
if (bracket_offset < equal_offset) {
*found_bracket = 1;
offset = bracket_offset+1;
} else
offset++;
return offset;
}
int git_config_set(const char* key, const char* value)
{
return git_config_set_multivar(key, value, NULL, 0);
}
/*
* If value==NULL, unset in (remove from) config,
* if value_regex!=NULL, disregard key/value pairs where value does not match.
* if multi_replace==0, nothing, or only one matching key/value is replaced,
* else all matching key/values (regardless how many) are removed,
* before the new pair is written.
*
* Returns 0 on success.
*
* This function does this:
*
* - it locks the config file by creating ".git/config.lock"
*
* - it then parses the config using store_aux() as validator to find
* the position on the key/value pair to replace. If it is to be unset,
* it must be found exactly once.
*
* - the config file is mmap()ed and the part before the match (if any) is
* written to the lock file, then the changed part and the rest.
*
* - the config file is removed and the lock file rename()d to it.
*
*/
int git_config_set_multivar(const char* key, const char* value,
const char* value_regex, int multi_replace)
{
int i;
struct stat st;
int fd;
char* config_filename = strdup(git_path("config"));
char* lock_file = strdup(git_path("config.lock"));
const char* last_dot = strrchr(key, '.');
/*
* Since "key" actually contains the section name and the real
* key name separated by a dot, we have to know where the dot is.
*/
if (last_dot == NULL) {
fprintf(stderr, "key does not contain a section: %s\n", key);
return 2;
}
store.baselen = last_dot - key;
store.multi_replace = multi_replace;
/*
* Validate the key and while at it, lower case it for matching.
*/
store.key = (char*)malloc(strlen(key)+1);
for (i = 0; key[i]; i++)
if (i != store.baselen &&
((!isalnum(key[i]) && key[i] != '.') ||
(i == store.baselen+1 && !isalpha(key[i])))) {
fprintf(stderr, "invalid key: %s\n", key);
free(store.key);
return 1;
} else
store.key[i] = tolower(key[i]);
store.key[i] = 0;
/*
* The lock_file serves a purpose in addition to locking: the new
* contents of .git/config will be written into it.
*/
fd = open(lock_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd < 0) {
fprintf(stderr, "could not lock config file\n");
free(store.key);
return -1;
}
/*
* If .git/config does not exist yet, write a minimal version.
*/
if (stat(config_filename, &st)) {
static const char contents[] =
"#\n"
"# This is the config file\n"
"#\n"
"\n";
free(store.key);
/* if nothing to unset, error out */
if (value == NULL) {
close(fd);
unlink(lock_file);
return 5;
}
store.key = (char*)key;
write(fd, contents, sizeof(contents)-1);
store_write_section(fd, key);
store_write_pair(fd, key, value);
} else{
int in_fd;
char* contents;
int i, copy_begin, copy_end, new_line = 0;
if (value_regex == NULL)
store.value_regex = NULL;
else {
if (value_regex[0] == '!') {
store.do_not_match = 1;
value_regex++;
} else
store.do_not_match = 0;
store.value_regex = (regex_t*)malloc(sizeof(regex_t));
if (regcomp(store.value_regex, value_regex,
REG_EXTENDED)) {
fprintf(stderr, "Invalid pattern: %s",
value_regex);
free(store.value_regex);
return 6;
}
}
store.offset[0] = 0;
store.state = START;
store.seen = 0;
/*
* After this, store.offset will contain the *end* offset
* of the last match, or remain at 0 if no match was found.
* As a side effect, we make sure to transform only a valid
* existing config file.
*/
if (git_config(store_aux)) {
fprintf(stderr, "invalid config file\n");
free(store.key);
if (store.value_regex != NULL) {
regfree(store.value_regex);
free(store.value_regex);
}
return 3;
}
free(store.key);
if (store.value_regex != NULL) {
regfree(store.value_regex);
free(store.value_regex);
}
/* if nothing to unset, or too many matches, error out */
if ((store.seen == 0 && value == NULL) ||
(store.seen > 1 && multi_replace == 0)) {
close(fd);
unlink(lock_file);
return 5;
}
in_fd = open(config_filename, O_RDONLY, 0666);
contents = mmap(NULL, st.st_size, PROT_READ,
MAP_PRIVATE, in_fd, 0);
close(in_fd);
if (store.seen == 0)
store.seen = 1;
for (i = 0, copy_begin = 0; i < store.seen; i++) {
if (store.offset[i] == 0) {
store.offset[i] = copy_end = st.st_size;
} else if (store.state != KEY_SEEN) {
copy_end = store.offset[i];
} else
copy_end = find_beginning_of_line(
contents, st.st_size,
store.offset[i]-2, &new_line);
/* write the first part of the config */
if (copy_end > copy_begin) {
write(fd, contents + copy_begin,
copy_end - copy_begin);
if (new_line)
write(fd, "\n", 1);
}
copy_begin = store.offset[i];
}
/* write the pair (value == NULL means unset) */
if (value != NULL) {
if (store.state == START)
store_write_section(fd, key);
store_write_pair(fd, key, value);
}
/* write the rest of the config */
if (copy_begin < st.st_size)
write(fd, contents + copy_begin,
st.st_size - copy_begin);
munmap(contents, st.st_size);
unlink(config_filename);
}
close(fd);
if (rename(lock_file, config_filename) < 0) {
fprintf(stderr, "Could not rename the lock file?\n");
return 4;
}
return 0;
}

166
connect.c
View File

@ -427,7 +427,7 @@ static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path)
memset(&sa, 0, sizeof sa);
sa.sin_family = he->h_addrtype;
sa.sin_port = htons(nport);
memcpy(&sa.sin_addr, ap, he->h_length);
memcpy(&sa.sin_addr, *ap, he->h_length);
if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
close(sockfd);
@ -448,42 +448,162 @@ static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path)
#endif /* NO_IPV6 */
static char *git_proxy_command = NULL;
static const char *rhost_name = NULL;
static int rhost_len;
static int git_proxy_command_options(const char *var, const char *value)
{
if (!strcmp(var, "core.gitproxy")) {
const char *for_pos;
int matchlen = -1;
int hostlen;
if (git_proxy_command)
return 0;
/* [core]
* ;# matches www.kernel.org as well
* gitproxy = netcatter-1 for kernel.org
* gitproxy = netcatter-2 for sample.xz
* gitproxy = netcatter-default
*/
for_pos = strstr(value, " for ");
if (!for_pos)
/* matches everybody */
matchlen = strlen(value);
else {
hostlen = strlen(for_pos + 5);
if (rhost_len < hostlen)
matchlen = -1;
else if (!strncmp(for_pos + 5,
rhost_name + rhost_len - hostlen,
hostlen) &&
((rhost_len == hostlen) ||
rhost_name[rhost_len - hostlen -1] == '.'))
matchlen = for_pos - value;
else
matchlen = -1;
}
if (0 <= matchlen) {
/* core.gitproxy = none for kernel.org */
if (matchlen == 4 &&
!memcmp(value, "none", 4))
matchlen = 0;
git_proxy_command = xmalloc(matchlen + 1);
memcpy(git_proxy_command, value, matchlen);
git_proxy_command[matchlen] = 0;
}
return 0;
}
return git_default_config(var, value);
}
static int git_use_proxy(const char *host)
{
rhost_name = host;
rhost_len = strlen(host);
git_proxy_command = getenv("GIT_PROXY_COMMAND");
git_config(git_proxy_command_options);
rhost_name = NULL;
return (git_proxy_command && *git_proxy_command);
}
static int git_proxy_connect(int fd[2], const char *prog, char *host, char *path)
{
char *port = STR(DEFAULT_GIT_PORT);
char *colon, *end;
int pipefd[2][2];
pid_t pid;
if (host[0] == '[') {
end = strchr(host + 1, ']');
if (end) {
*end = 0;
end++;
host++;
} else
end = host;
} else
end = host;
colon = strchr(end, ':');
if (colon) {
*colon = 0;
port = colon + 1;
}
if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
die("unable to create pipe pair for communication");
pid = fork();
if (!pid) {
dup2(pipefd[1][0], 0);
dup2(pipefd[0][1], 1);
close(pipefd[0][0]);
close(pipefd[0][1]);
close(pipefd[1][0]);
close(pipefd[1][1]);
execlp(git_proxy_command, git_proxy_command, host, port, NULL);
die("exec failed");
}
fd[0] = pipefd[0][0];
fd[1] = pipefd[1][1];
close(pipefd[0][1]);
close(pipefd[1][0]);
packet_write(fd[1], "%s %s\n", prog, path);
return pid;
}
/*
* Yeah, yeah, fixme. Need to pass in the heads etc.
*/
int git_connect(int fd[2], char *url, const char *prog)
{
char command[1024];
char *host, *path;
char *colon;
char *host, *path = url;
char *colon = NULL;
int pipefd[2][2];
pid_t pid;
enum protocol protocol;
enum protocol protocol = PROTO_LOCAL;
host = NULL;
path = url;
colon = strchr(url, ':');
protocol = PROTO_LOCAL;
if (colon) {
*colon = 0;
host = strstr(url, "://");
if(host) {
*host = '\0';
protocol = get_protocol(url);
host += 3;
path = strchr(host, '/');
}
else {
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;
}
if ((colon = strchr(host, ':'))) {
protocol = PROTO_SSH;
*colon = '\0';
path = colon + 1;
}
}
if (protocol == PROTO_GIT)
if (!path || !*path)
die("No path specified. See 'man git-pull' for valid url syntax");
/*
* null-terminate hostname and point path to ~ for URL's like this:
* ssh://host.xz/~user/repo
*/
if (protocol != PROTO_LOCAL && host != url) {
char *ptr = path;
if (path[1] == '~')
path++;
else
path = strdup(ptr);
*ptr = '\0';
}
if (protocol == PROTO_GIT) {
if (git_use_proxy(host))
return git_proxy_connect(fd, prog, host, path);
return git_tcp_connect(fd, prog, host, path);
}
if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
die("unable to create pipe pair for communication");

140
daemon.c
View File

@ -15,10 +15,11 @@ static int verbose;
static const char daemon_usage[] =
"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
" [--timeout=n] [--init-timeout=n] [directory...]";
" [--timeout=n] [--init-timeout=n] [--strict-paths] [directory...]";
/* List of acceptable pathname prefixes */
static char **ok_paths = NULL;
static int strict_paths = 0;
/* If this is set, git-daemon-export-ok is not required */
static int export_all_trees = 0;
@ -81,69 +82,52 @@ static void loginfo(const char *err, ...)
va_end(params);
}
static int path_ok(const char *dir)
static char *path_ok(char *dir)
{
const char *p = dir;
char **pp;
int sl, ndot;
char *path = enter_repo(dir, strict_paths);
/* The pathname here should be an absolute path. */
if ( *p++ != '/' )
return 0;
sl = 1; ndot = 0;
for (;;) {
if ( *p == '.' ) {
ndot++;
} else if ( *p == '\0' ) {
/* Reject "." and ".." at the end of the path */
if ( sl && ndot > 0 && ndot < 3 )
return 0;
/* Otherwise OK */
break;
} else if ( *p == '/' ) {
/* Refuse "", "." or ".." */
if ( sl && ndot < 3 )
return 0;
sl = 1;
ndot = 0;
} else {
sl = ndot = 0;
}
p++;
if (!path) {
logerror("'%s': unable to chdir or not a git archive", dir);
return NULL;
}
if ( ok_paths && *ok_paths ) {
int ok = 0;
int dirlen = strlen(dir);
char **pp;
int pathlen = strlen(path);
/* The validation is done on the paths after enter_repo
* canonicalization, so whitelist should be written in
* terms of real pathnames (i.e. after ~user is expanded
* and symlinks resolved).
*/
for ( pp = ok_paths ; *pp ; pp++ ) {
int len = strlen(*pp);
if ( len <= dirlen &&
!strncmp(*pp, dir, len) &&
(dir[len] == '/' || dir[len] == '\0') ) {
ok = 1;
break;
}
if (len <= pathlen &&
!memcmp(*pp, path, len) &&
(path[len] == '\0' ||
(!strict_paths && path[len] == '/')))
return path;
}
if ( !ok )
return 0; /* Path not in whitelist */
}
else {
/* be backwards compatible */
if (!strict_paths)
return path;
}
return 1; /* Path acceptable */
logerror("'%s': not in whitelist", path);
return NULL; /* Fallthrough. Deny by default */
}
static int set_dir(const char *dir)
static int upload(char *dir)
{
if (!path_ok(dir)) {
errno = EACCES;
return -1;
}
/* Timeout as string */
char timeout_buf[64];
const char *path;
if ( chdir(dir) )
loginfo("Request for '%s'", dir);
if (!(path = path_ok(dir)))
return -1;
/*
@ -152,45 +136,17 @@ static int set_dir(const char *dir)
* We want a readable HEAD, usable "objects" directory, and
* a "git-daemon-export-ok" flag that says that the other side
* is ok with us doing this.
*
* path_ok() uses enter_repo() and does whitelist checking.
* We only need to make sure the repository is exported.
*/
if (!export_all_trees && access("git-daemon-export-ok", F_OK)) {
logerror("'%s': repository not exported.", path);
errno = EACCES;
return -1;
}
if (access("objects/", X_OK) || access("HEAD", R_OK)) {
errno = EINVAL;
return -1;
}
/* If all this passed, we're OK */
return 0;
}
static int upload(char *dir)
{
/* Try paths in this order */
static const char *paths[] = { "%s", "%s/.git", "%s.git", "%s.git/.git", NULL };
const char **pp;
/* Enough for the longest path above including final null */
int buflen = strlen(dir)+10;
char *dirbuf = xmalloc(buflen);
/* Timeout as string */
char timeout_buf[64];
loginfo("Request for '%s'", dir);
for ( pp = paths ; *pp ; pp++ ) {
snprintf(dirbuf, buflen, *pp, dir);
if ( !set_dir(dirbuf) )
break;
}
if ( !*pp ) {
logerror("Cannot set directory '%s': %s", dir, strerror(errno));
return -1;
}
/*
* We'll ignore SIGTERM from now on, we have a
* good client.
@ -216,7 +172,7 @@ static int execute(void)
if (len && line[len-1] == '\n')
line[--len] = 0;
if (!strncmp("git-upload-pack /", line, 17))
if (!strncmp("git-upload-pack ", line, 16))
return upload(line+16);
logerror("Protocol error: '%s'", line);
@ -510,8 +466,14 @@ static int socksetup(int port, int **socklist_p)
return 0;
}
if (listen(sockfd, 5) < 0) {
close(sockfd);
return 0;
}
*socklist_p = xmalloc(sizeof(int));
**socklist_p = sockfd;
return 1;
}
#endif
@ -617,6 +579,10 @@ int main(int argc, char **argv)
init_timeout = atoi(arg+15);
continue;
}
if (!strcmp(arg, "--strict-paths")) {
strict_paths = 1;
continue;
}
if (!strcmp(arg, "--")) {
ok_paths = &argv[i+1];
break;
@ -631,6 +597,14 @@ int main(int argc, char **argv)
if (log_syslog)
openlog("git-daemon", 0, LOG_DAEMON);
if (strict_paths && (!ok_paths || !*ok_paths)) {
if (!inetd_mode)
die("git-daemon: option --strict-paths requires a whitelist");
logerror("option --strict-paths requires a whitelist");
exit (1);
}
if (inetd_mode) {
fclose(stderr); //FIXME: workaround
return execute();

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
git-core (0.99.9k-0) unstable; urgency=low
* GIT 0.99.9k but not 1.0rc yet.
-- Junio C Hamano <junkio@cox.net> Fri, 25 Nov 2005 16:33:11 -0800
git-core (0.99.9j-0) unstable; urgency=low
* GIT 0.99.9j aka 1.0rc3

View File

@ -38,7 +38,7 @@ int main(int argc, const char **argv)
const char *prefix = setup_git_directory();
int entries, i;
git_config(git_default_config);
git_config(git_diff_config);
diff_setup(&diff_options);
while (1 < argc && argv[1][0] == '-') {
if (!strcmp(argv[1], "--")) {

View File

@ -180,7 +180,7 @@ int main(int argc, const char **argv)
int allow_options = 1;
int i;
git_config(git_default_config);
git_config(git_diff_config);
diff_setup(&diff_options);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];

View File

@ -55,6 +55,9 @@ int main(int ac, const char **av)
{
int stage1, stage2;
setup_git_directory();
git_config(git_diff_config);
read_cache();
diff_setup(&diff_options);
while (1 < ac && av[1][0] == '-') {

View File

@ -69,52 +69,50 @@ static int diff_root_tree(const unsigned char *new, const char *base)
return retval;
}
static const char *generate_header(const char *commit, const char *parent, const char *msg, unsigned long len)
static const char *generate_header(const char *commit, const char *parent, const char *msg)
{
static char this_header[16384];
int offset;
unsigned long len;
if (!verbose_header)
return commit;
len = strlen(msg);
offset = sprintf(this_header, "%s%s (from %s)\n", header_prefix, commit, parent);
offset += pretty_print_commit(commit_format, msg, len, this_header + offset, sizeof(this_header) - offset);
return this_header;
}
static int diff_tree_commit(const unsigned char *commit, const char *name)
static int diff_tree_commit(const unsigned char *commit_sha1)
{
unsigned long size, offset;
char *buf = read_object_with_reference(commit, "commit", &size, NULL);
struct commit *commit;
struct commit_list *parents;
char name[50];
unsigned char sha1[20];
if (!buf)
sprintf(name, "%s^0", sha1_to_hex(commit_sha1));
if (get_sha1(name, sha1))
return -1;
if (!name) {
static char commit_name[60];
strcpy(commit_name, sha1_to_hex(commit));
name = commit_name;
}
name[40] = 0;
commit = lookup_commit(sha1);
/* Root commit? */
if (show_root_diff && memcmp(buf + 46, "parent ", 7)) {
header = generate_header(name, "root", buf, size);
diff_root_tree(commit, "");
if (show_root_diff && !commit->parents) {
header = generate_header(name, "root", commit->buffer);
diff_root_tree(commit_sha1, "");
}
/* More than one parent? */
if (ignore_merges) {
if (!memcmp(buf + 46 + 48, "parent ", 7))
if (ignore_merges && commit->parents && commit->parents->next)
return 0;
}
offset = 46;
while (offset + 48 < size && !memcmp(buf + offset, "parent ", 7)) {
unsigned char parent[20];
if (get_sha1_hex(buf + offset + 7, parent))
return -1;
header = generate_header(name, sha1_to_hex(parent), buf, size);
diff_tree_sha1_top(parent, commit, "");
for (parents = commit->parents; parents; parents = parents->next) {
struct commit *parent = parents->item;
header = generate_header(name,
sha1_to_hex(parent->object.sha1),
commit->buffer);
diff_tree_sha1_top(parent->object.sha1, commit_sha1, "");
if (!header && verbose_header) {
header_prefix = "\ndiff-tree ";
/*
@ -122,9 +120,7 @@ static int diff_tree_commit(const unsigned char *commit, const char *name)
* don't print the diffs.
*/
}
offset += 48;
}
free(buf);
return 0;
}
@ -147,7 +143,7 @@ static int diff_tree_stdin(char *line)
return diff_tree_sha1_top(parent, commit, "");
}
line[40] = 0;
return diff_tree_commit(commit, line);
return diff_tree_commit(commit);
}
static const char diff_tree_usage[] =
@ -164,7 +160,7 @@ int main(int argc, const char **argv)
unsigned char sha1[2][20];
const char *prefix = setup_git_directory();
git_config(git_default_config);
git_config(git_diff_config);
nr_sha1 = 0;
diff_setup(&diff_options);
@ -250,7 +246,7 @@ int main(int argc, const char **argv)
usage(diff_tree_usage);
break;
case 1:
diff_tree_commit(sha1[0], NULL);
diff_tree_commit(sha1[0]);
break;
case 2:
diff_tree_sha1_top(sha1[0], sha1[1], "");

39
diff.c
View File

@ -15,6 +15,16 @@ static int use_size_cache;
int diff_rename_limit_default = -1;
int git_diff_config(const char *var, const char *value)
{
if (!strcmp(var, "diff.renamelimit")) {
diff_rename_limit_default = git_config_int(var, value);
return 0;
}
return git_default_config(var, value);
}
static char *quote_one(const char *str)
{
int needlen;
@ -838,16 +848,29 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
static int parse_num(const char **cp_p)
{
int num, scale, ch, cnt;
unsigned long num, scale;
int ch, dot;
const char *cp = *cp_p;
cnt = num = 0;
num = 0;
scale = 1;
while ('0' <= (ch = *cp) && ch <= '9') {
if (cnt++ < 5) {
/* We simply ignore more than 5 digits precision. */
scale *= 10;
num = num * 10 + ch - '0';
dot = 0;
for(;;) {
ch = *cp;
if ( !dot && ch == '.' ) {
scale = 1;
dot = 1;
} else if ( ch == '%' ) {
scale = dot ? scale*100 : 100;
cp++; /* % is always at the end */
break;
} else if ( ch >= '0' && ch <= '9' ) {
if ( scale < 100000 ) {
scale *= 10;
num = (num*10) + (ch-'0');
}
} else {
break;
}
cp++;
}
@ -856,7 +879,7 @@ static int parse_num(const char **cp_p)
/* user says num divided by scale and we say internally that
* is MAX_SCORE * num / scale.
*/
return (MAX_SCORE * num / scale);
return (num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale);
}
int diff_scoreopt_parse(const char *opt)

1
diff.h
View File

@ -77,6 +77,7 @@ extern int diff_scoreopt_parse(const char *opt);
#define DIFF_SETUP_USE_CACHE 2
#define DIFF_SETUP_USE_SIZE_CACHE 4
extern int git_diff_config(const char *var, const char *value);
extern void diff_setup(struct diff_options *);
extern int diff_opt_parse(struct diff_options *, const char **, int);
extern int diff_setup_done(struct diff_options *);

View File

@ -307,6 +307,9 @@ void diffcore_rename(struct diff_options *options)
if (rename_count == rename_dst_nr)
goto cleanup;
if (minimum_score == MAX_SCORE)
goto cleanup;
num_create = (rename_dst_nr - rename_count);
num_src = rename_src_nr;
mx = xmalloc(sizeof(*mx) * num_create * num_src);

View File

@ -1,7 +1,7 @@
#!/bin/sh
#
#
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
echo >&2 "usage: $0 [--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] <mbox>"

View File

@ -18,7 +18,7 @@
##
## git-am is supposed to be the newer and better tool for this job.
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
echo >&2 "applymbox [-u] [-k] [-q] [-m] (-c .dotest/<num> | mbox) [signoff]"

View File

@ -10,7 +10,7 @@
## $3 - "info" file with Author, email and subject
## $4 - optional file containing signoff to add
##
. git-sh-setup || die "Not a git archive."
. git-sh-setup
final=.dotest/final-commit
##

View File

@ -1,5 +1,5 @@
#!/bin/sh
. git-sh-setup || dir "Not a git archive"
. git-sh-setup
usage() {
echo >&2 'usage: git bisect [start|bad|good|next|reset|visualize]

View File

@ -1,6 +1,6 @@
#!/bin/sh
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
echo >&2 "usage: $(basename $0)"' [-d <branch>] | [[-f] <branch> [start-point]]

View File

@ -1,5 +1,5 @@
#!/bin/sh
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
die "usage: git checkout [-f] [-b <new_branch>] [<branch>] [<paths>...]"
@ -82,7 +82,6 @@ then
# rescuing paths and is never meant to remove what
# is not in the named tree-ish.
git-ls-tree -r "$new" "$@" |
sed -ne 's/^\([0-7]*\) blob \(.*\)$/\1 \2/p' |
git-update-index --index-info || exit $?
fi
git-checkout-index -f -u -- "$@"

View File

@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano.
#
. git-sh-setup || die "Not a git archive."
. git-sh-setup
usage="usage: $0 "'[-v] <upstream> [<head>]

View File

@ -3,7 +3,7 @@
# Copyright (c) 2005 Linus Torvalds
#
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
die 'git commit [-a] [-s] [-v | --no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit>] [-e] [<path>...]'
@ -92,10 +92,13 @@ tt*)
esac
case "$all,$#" in
t,*)
t,0)
git-diff-files --name-only -z |
git-update-index --remove -z --stdin
;;
t,*)
die "Cannot use -a and explicit files at the same time."
;;
,0)
;;
*)

View File

@ -1,7 +1,25 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
. git-sh-setup
dc </dev/null 2>/dev/null || {
# This is not a real DC at all -- it just knows how
# this script feeds DC and does the computation itself.
dc () {
while read a b
do
case $a,$b in
0,) acc=0 ;;
*,+) acc=$(($acc + $a)) ;;
p,) echo "$acc" ;;
esac
done
}
}
echo $(find "$GIT_DIR/objects"/?? -type f -print 2>/dev/null | wc -l) objects, \
$({
echo 0

View File

@ -502,7 +502,7 @@ unless($pid) {
if ($opt_P) {
exec("cat", $opt_P);
} else {
exec("cvsps",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
die "Could not start cvsps: $!\n";
}
}

View File

@ -1,6 +1,6 @@
#!/bin/sh
#
. git-sh-setup || die "Not a git archive"
. git-sh-setup
. git-parse-remote
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"

View File

@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano
#
. git-sh-setup || die "Not a git archive."
. git-sh-setup
usage () {
echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
@ -99,7 +99,7 @@ filelist=$tmp-files
# Also, "rev1.." should mean "rev1..HEAD"; git-diff users are
# familiar with that syntax.
case "$#,$1" in
case "$#,$1$2" in
1,?*..?*)
# single "rev1..rev2"
;;
@ -131,7 +131,8 @@ do
rev2=`expr "$revpair" : '.*\.\.\(.*\)'`
;;
*)
usage
rev1="$revpair^"
rev2="$revpair"
;;
esac
git-rev-parse --verify "$rev1^0" >/dev/null 2>&1 ||

View File

@ -1,6 +1,6 @@
#!/bin/sh
. git-sh-setup || die "Not a git archive."
. git-sh-setup
laf="$GIT_DIR/lost-found"
rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit

View File

@ -1,6 +1,5 @@
#!/bin/sh
#
. git-sh-setup
usage () {
echo >&2 "usage: $0 [--heads] [--tags] <repository> <refs>..."

View File

@ -25,7 +25,8 @@ case "${1:-.}${2:-.}${3:-.}" in
echo "Removing $4"
fi
if test -f "$4"; then
rm -f -- "$4"
rm -f -- "$4" &&
rmdir -p "$(expr "$4" : '\(.*\)/')" 2>/dev/null
fi &&
exec git-update-index --remove -- "$4"
;;

View File

@ -245,7 +245,7 @@ def updateFileExt(sha, mode, path, updateCache, updateWd):
try:
createDir = not stat.S_ISDIR(os.lstat(p).st_mode)
except:
except OSError:
createDir = True
if createDir:
@ -293,6 +293,10 @@ def removeFile(clean, path):
except OSError, e:
if e.errno != errno.ENOENT and e.errno != errno.EISDIR:
raise
try:
os.removedirs(os.path.dirname(path))
except OSError:
pass
def uniquePath(path, branch):
def fileExists(path):

View File

@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano
#
. git-sh-setup || die "Not a git archive"
. git-sh-setup
LF='
'
@ -12,10 +12,8 @@ usage () {
die "git-merge [-n] [--no-commit] [-s <strategy>]... <merge-message> <head> <remote>+"
}
# all_strategies='resolve recursive stupid octopus'
all_strategies='recursive octopus resolve stupid ours'
default_strategies='resolve octopus'
default_strategies='recursive'
use_strategies=
dropsave() {
@ -90,11 +88,6 @@ do
shift
done
case "$use_strategies" in
'')
use_strategies=$default_strategies
;;
esac
test "$#" -le 2 && usage ;# we need at least two heads.
merge_msg="$1"
@ -185,6 +178,17 @@ case "$#,$common,$no_commit" in
;;
esac
case "$use_strategies" in
'')
case "$#" in
1)
use_strategies="$default_strategies" ;;
*)
use_strategies=octopus ;;
esac
;;
esac
# At this point, we need a real merge. No matter what strategy
# we use, it would operate on the index, possibly affecting the
# working tree, and when resolved cleanly, have the desired tree

View File

@ -103,13 +103,22 @@ while(scalar @srcArgs > 0) {
$bad = "bad source '$src'";
}
$safesrc = quotemeta($src);
@srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
$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 ($opt_f) {
# only files can overwrite each other: check both source and destination
if (-f $dst && (scalar @srcfiles == 1)) {
print "Warning: $bad; will overwrite!\n";
$bad = "";
$overwritten{$dst} = 1;
}
else {
$bad = "Can not overwrite '$src' with '$dst'";
}
}
}
@ -118,8 +127,6 @@ while(scalar @srcArgs > 0) {
}
if ($bad eq "") {
$safesrc = quotemeta($src);
@srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
if (scalar @srcfiles == 0) {
$bad = "'$src' not under version control";
}
@ -166,10 +173,12 @@ while(scalar @srcs > 0) {
push @deletedfiles, @srcfiles;
if (scalar @srcfiles == 1) {
# $dst can be a directory with 1 file inside
if ($overwritten{$dst} ==1) {
push @changedfiles, $dst;
push @changedfiles, $dstfiles[0];
} else {
push @addedfiles, $dst;
push @addedfiles, $dstfiles[0];
}
}
else {

View File

@ -4,7 +4,7 @@
#
# Resolve two or more trees recorded in $GIT_DIR/FETCH_HEAD.
#
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
die "usage: git octopus"

View File

@ -1,6 +1,8 @@
#!/bin/sh
. git-sh-setup
# git-ls-remote could be called from outside a git managed repository;
# this would fail in that case and would issue an error message.
GIT_DIR=$(git-rev-parse --git-dir 2>/dev/null) || :;
get_data_source () {
case "$1" in

View File

@ -1,6 +1,6 @@
#!/bin/sh
. git-sh-setup || die "Not a git archive"
. git-sh-setup
dryrun=
echo=

View File

@ -4,7 +4,7 @@
#
# Fetch one or more remote refs and merge it/them into the current HEAD.
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
echo >&2 "usage: $0"' [-n] [--no-commit] [--no-summary] [--help]

View File

@ -1,5 +1,5 @@
#!/bin/sh
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
die "Usage: git push [--all] [--force] <repository> [<refspec>]"

View File

@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano.
#
. git-sh-setup || die "Not a git archive."
. git-sh-setup
# The other head is given
other=$(git-rev-parse --verify "$1^0") || exit

View File

@ -3,7 +3,7 @@
# Copyright (c) 2005 Linus Torvalds
#
. git-sh-setup || die "Not a git archive"
. git-sh-setup
no_update_info= all_into_one= remove_redundant= local=
while case "$#" in 0) break ;; esac
@ -32,24 +32,20 @@ case ",$all_into_one," in
rev_list=
rev_parse='--all'
pack_objects=
# Redundancy check in all-into-one case is trivial.
existing=`cd "$PACKDIR" && \
find . -type f \( -name '*.pack' -o -name '*.idx' \) -print`
;;
esac
if [ "$local" ]; then
pack_objects="$pack_objects --local"
fi
name=$(git-rev-list --objects $rev_list $(git-rev-parse $rev_parse) |
name=$(git-rev-list --objects $rev_list $(git-rev-parse $rev_parse) 2>&1 |
git-pack-objects --non-empty $pack_objects .tmp-pack) ||
exit 1
if [ -z "$name" ]; then
echo Nothing new to pack.
if test "$remove_redundant" = t ; then
echo "Removing redundant packs."
sync
redundant=$(git-pack-redundant --all)
if test "$redundant" != "" ; then
echo $redundant | xargs rm
fi
fi
exit 0
fi
echo "Pack pack-$name created."
@ -62,23 +58,20 @@ exit
if test "$remove_redundant" = t
then
sync
if test "$all_into_one" = t
# We know $existing are all redundant only when
# all-into-one is used.
if test "$all_into_one" != '' && test "$existing" != ''
then
cd "$PACKDIR"
existing=`find . -type f \( -name '*.pack' -o -name '*.idx' \) -print`
for e in $existing
do
sync
( cd "$PACKDIR" &&
for e in $existing
do
case "$e" in
./pack-$name.pack | ./pack-$name.idx) ;;
*) rm -f $e ;;
*) rm -f $e ;;
esac
done
else
redundant=$(git-pack-redundant --all)
if test "$redundant" != "" ; then
echo $redundant | xargs rm
fi
done
)
fi
fi

View File

@ -1,5 +1,5 @@
#!/bin/sh
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
die 'Usage: git reset [--mixed | --soft | --hard] [<commit-ish>]'

View File

@ -4,7 +4,7 @@
#
# Resolve two trees.
#
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
die "git-resolve <head> <remote> <merge-message>"

View File

@ -3,15 +3,17 @@
# Copyright (c) 2005 Linus Torvalds
# Copyright (c) 2005 Junio C Hamano
#
. git-sh-setup || die "Not a git archive"
. git-sh-setup
case "$0" in
*-revert* )
test -t 0 && edit=-e
me=revert ;;
*-cherry-pick* )
edit=
me=cherry-pick ;;
* )
die "What are ou talking about?" ;;
die "What are you talking about?" ;;
esac
usage () {
@ -33,6 +35,12 @@ do
--no-commi|--no-commit)
no_commit=t
;;
-e|--e|--ed|--edi|--edit)
edit=-e
;;
-n|--n|--no|--no-|--no-e|--no-ed|--no-edi|--no-edit)
edit=
;;
-r|--r|--re|--rep|--repl|--repla|--replay)
replay=t
;;
@ -163,7 +171,7 @@ echo >&2 "Finished one $me."
case "$no_commit" in
'')
git-commit -n -F .msg
git-commit -n -F .msg $edit
rm -f .msg
;;
esac

View File

@ -1,10 +1,9 @@
#!/bin/sh
#
# Set up GIT_DIR and GIT_OBJECT_DIRECTORY
# and return true if everything looks ok
#
: ${GIT_DIR=.git}
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
# This is included in commands that either have to be run from the toplevel
# of the repository, or with GIT_DIR environment variable properly.
# If the GIT_DIR does not look like the right correct git-repository,
# it dies.
# Having this variable in your environment would break scripts because
# you would cause "cd" to be be taken to unexpected places. If you
@ -12,14 +11,13 @@
# exporting it.
unset CDPATH
: ${GIT_DIR=.git}
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
die() {
echo >&2 "$@"
exit 1
}
case "$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD 2>/dev/null)" in
refs/*) : ;;
*) false ;;
esac &&
[ -d "$GIT_DIR/refs" ] &&
[ -d "$GIT_OBJECT_DIRECTORY/" ]
# Make sure we are in a valid repository of a vintage we understand.
GIT_DIR="$GIT_DIR" git-var GIT_AUTHOR_IDENT >/dev/null || exit

View File

@ -2,7 +2,7 @@
#
# Copyright (c) 2005 Linus Torvalds
#
. git-sh-setup || die "Not a git archive"
GIT_DIR=$(git-rev-parse --git-dir) || exit
report () {
header="#

View File

@ -1,7 +1,7 @@
#!/bin/sh
# Copyright (c) 2005 Linus Torvalds
. git-sh-setup || die "Not a git archive"
. git-sh-setup
usage () {
echo >&2 "Usage: git-tag [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <tagname> [<head>]"

View File

@ -1,5 +1,5 @@
#!/bin/sh
. git-sh-setup || die "Not a git archive"
. git-sh-setup
type="$(git-cat-file -t "$1" 2>/dev/null)" ||
die "$1: no such object."

2
git.c
View File

@ -273,7 +273,7 @@ int main(int argc, char **argv, char **envp)
while (!strncmp(exec_path, "./", 2)) {
exec_path += 2;
while (*exec_path == '/')
*exec_path++;
exec_path++;
}
snprintf(git_command + len, sizeof(git_command) - len,
"/%s", exec_path);

265
gitk
View File

@ -60,7 +60,7 @@ proc getcommits {rargs} {
proc getcommitlines {commfd} {
global commits parents cdate children
global commitlisted phase commitinfo nextupdate
global commitlisted phase nextupdate
global stopped redisplaying leftover
set stuff [read $commfd]
@ -196,42 +196,44 @@ proc parsecommit {id contents listed olds} {
incr ncleft($p)
}
}
foreach line [split $contents "\n"] {
if {$inhdr} {
if {$line == {}} {
set inhdr 0
} else {
set tag [lindex $line 0]
if {$tag == "author"} {
set x [expr {[llength $line] - 2}]
set audate [lindex $line $x]
set auname [lrange $line 1 [expr {$x - 1}]]
} elseif {$tag == "committer"} {
set x [expr {[llength $line] - 2}]
set comdate [lindex $line $x]
set comname [lrange $line 1 [expr {$x - 1}]]
}
}
} else {
if {$comment == {}} {
set headline [string trim $line]
} else {
append comment "\n"
}
if {!$listed} {
# git-rev-list indents the comment by 4 spaces;
# if we got this via git-cat-file, add the indentation
append comment " "
}
append comment $line
set hdrend [string first "\n\n" $contents]
if {$hdrend < 0} {
# should never happen...
set hdrend [string length $contents]
}
set header [string range $contents 0 [expr {$hdrend - 1}]]
set comment [string range $contents [expr {$hdrend + 2}] end]
foreach line [split $header "\n"] {
set tag [lindex $line 0]
if {$tag == "author"} {
set audate [lindex $line end-1]
set auname [lrange $line 1 end-2]
} elseif {$tag == "committer"} {
set comdate [lindex $line end-1]
set comname [lrange $line 1 end-2]
}
}
if {$audate != {}} {
set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"]
set headline {}
# take the first line of the comment as the headline
set i [string first "\n" $comment]
if {$i >= 0} {
set headline [string trim [string range $comment 0 $i]]
} else {
set headline $comment
}
if {!$listed} {
# git-rev-list indents the comment by 4 spaces;
# if we got this via git-cat-file, add the indentation
set newcomment {}
foreach line [split $comment "\n"] {
append newcomment " "
append newcomment $line
append newcomment "\n"
}
set comment $newcomment
}
if {$comdate != {}} {
set cdate($id) $comdate
set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"]
}
set commitinfo($id) [list $headline $auname $audate \
$comname $comdate $comment]
@ -239,77 +241,43 @@ proc parsecommit {id contents listed olds} {
proc readrefs {} {
global tagids idtags headids idheads tagcontents
set tags [glob -nocomplain -types f [gitdir]/refs/tags/*]
foreach f $tags {
catch {
set fd [open $f r]
set line [read $fd]
if {[regexp {^[0-9a-f]{40}} $line id]} {
set direct [file tail $f]
set tagids($direct) $id
lappend idtags($id) $direct
set tagblob [exec git-cat-file tag $id]
set contents [split $tagblob "\n"]
set obj {}
set type {}
set tag {}
foreach l $contents {
if {$l == {}} break
switch -- [lindex $l 0] {
"object" {set obj [lindex $l 1]}
"type" {set type [lindex $l 1]}
"tag" {set tag [string range $l 4 end]}
}
}
if {$obj != {} && $type == "commit" && $tag != {}} {
set tagids($tag) $obj
lappend idtags($obj) $tag
set tagcontents($tag) $tagblob
}
}
close $fd
}
}
set heads [glob -nocomplain -types f [gitdir]/refs/heads/*]
foreach f $heads {
catch {
set fd [open $f r]
set line [read $fd 40]
if {[regexp {^[0-9a-f]{40}} $line id]} {
set head [file tail $f]
set headids($head) $line
lappend idheads($line) $head
}
close $fd
}
}
readotherrefs refs {} {tags heads}
}
proc readotherrefs {base dname excl} {
global otherrefids idotherrefs
set git [gitdir]
set files [glob -nocomplain -types f [file join $git $base *]]
foreach f $files {
catch {
set fd [open $f r]
set line [read $fd 40]
if {[regexp {^[0-9a-f]{40}} $line id]} {
set name "$dname[file tail $f]"
set otherrefids($name) $id
lappend idotherrefs($id) $name
set refd [open [list | git-ls-remote [gitdir]] r]
while {0 <= [set n [gets $refd line]]} {
if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \
match id path]} {
continue
}
if {![regexp {^(tags|heads)/(.*)$} $path match type name]} {
set type others
set name $path
}
if {$type == "tags"} {
set tagids($name) $id
lappend idtags($id) $name
set obj {}
set type {}
set tag {}
catch {
set commit [exec git-rev-parse "$id^0"]
if {"$commit" != "$id"} {
set tagids($name) $commit
lappend idtags($commit) $name
}
}
catch {
set tagcontents($name) [exec git-cat-file tag "$id"]
}
close $fd
} elseif { $type == "heads" } {
set headids($name) $id
lappend idheads($id) $name
} else {
set otherrefids($name) $id
lappend idotherrefs($id) $name
}
}
set dirs [glob -nocomplain -types d [file join $git $base *]]
foreach d $dirs {
set dir [file tail $d]
if {[lsearch -exact $excl $dir] >= 0} continue
readotherrefs [file join $base $dir] "$dname$dir/" {}
}
close $refd
}
proc error_popup msg {
@ -683,7 +651,7 @@ Use and redistribute under the terms of the GNU General Public License} \
}
proc assigncolor {id} {
global commitinfo colormap commcolors colors nextcolor
global colormap commcolors colors nextcolor
global parents nparents children nchildren
global cornercrossings crossings
@ -783,10 +751,12 @@ proc bindline {t id} {
$canv bind $t <Button-1> "lineclick %x %y $id 1"
}
proc drawlines {id xtra} {
proc drawlines {id xtra delold} {
global mainline mainlinearrow sidelines lthickness colormap canv
$canv delete lines.$id
if {$delold} {
$canv delete lines.$id
}
if {[info exists mainline($id)]} {
set t [$canv create line $mainline($id) \
-width [expr {($xtra + 1) * $lthickness}] \
@ -858,7 +828,7 @@ proc drawcommitline {level} {
set mainline($id) [trimdiagstart $mainline($id)]
}
}
drawlines $id 0
drawlines $id 0 0
set orad [expr {$linespc / 3}]
set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
[expr $x + $orad - 1] [expr $y1 + $orad - 1] \
@ -878,6 +848,7 @@ proc drawcommitline {level} {
set headline [lindex $commitinfo($id) 0]
set name [lindex $commitinfo($id) 1]
set date [lindex $commitinfo($id) 2]
set date [formatdate $date]
set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
-text $headline -font $mainfont ]
$canv bind $linehtag($lineno) <Button-3> "rowmenu %X %Y $id"
@ -1446,8 +1417,8 @@ proc decidenext {{noread 0}} {
}
proc drawcommit {id} {
global phase todo nchildren datemode nextupdate
global numcommits ncmupdate displayorder todo onscreen
global phase todo nchildren datemode nextupdate revlistorder
global numcommits ncmupdate displayorder todo onscreen parents
if {$phase != "incrdraw"} {
set phase incrdraw
@ -1459,19 +1430,29 @@ proc drawcommit {id} {
lappend todo $id
set onscreen($id) 0
}
set level [decidenext 1]
if {$level == {} || $id != [lindex $todo $level]} {
return
}
while 1 {
lappend displayorder [lindex $todo $level]
if {[updatetodo $level $datemode]} {
set level [decidenext 1]
if {$level == {}} break
if {$revlistorder} {
set level [lsearch -exact $todo $id]
if {$level < 0} {
error_popup "oops, $id isn't in todo"
return
}
set id [lindex $todo $level]
if {![info exists commitlisted($id)]} {
break
lappend displayorder $id
updatetodo $level 0
} else {
set level [decidenext 1]
if {$level == {} || $id != [lindex $todo $level]} {
return
}
while 1 {
lappend displayorder [lindex $todo $level]
if {[updatetodo $level $datemode]} {
set level [decidenext 1]
if {$level == {}} break
}
set id [lindex $todo $level]
if {![info exists commitlisted($id)]} {
break
}
}
}
drawmore 1
@ -1523,7 +1504,7 @@ proc drawrest {} {
global phase stopped redisplaying selectedline
global datemode todo displayorder
global numcommits ncmupdate
global nextupdate startmsecs
global nextupdate startmsecs revlistorder
set level [decidenext]
if {$level >= 0} {
@ -1536,8 +1517,8 @@ proc drawrest {} {
if {$level < 0} break
}
}
drawmore 0
}
drawmore 0
set phase {}
set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs]
#puts "overall $drawmsecs ms for $numcommits commits"
@ -2146,8 +2127,10 @@ proc selectline {l isnew} {
$ctext mark set fmark.0 0.0
$ctext mark gravity fmark.0 left
set info $commitinfo($id)
$ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n"
$ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n"
set date [formatdate [lindex $info 2]]
$ctext insert end "Author: [lindex $info 1] $date\n"
set date [formatdate [lindex $info 4]]
$ctext insert end "Committer: [lindex $info 3] $date\n"
if {[info exists idtags($id)]} {
$ctext insert end "Tags:"
foreach tag $idtags($id) {
@ -2805,8 +2788,7 @@ proc gettreediffs {ids} {
set treepending $ids
set treediff {}
set id [lindex $ids 0]
set p [lindex $ids 1]
if [catch {set gdtf [open "|git-diff-tree -r $id" r]}] return
if [catch {set gdtf [open "|git-diff-tree --no-commit-id -r $id" r]}] return
fconfigure $gdtf -blocking 0
fileevent $gdtf readable [list gettreediffline $gdtf $ids]
}
@ -2840,9 +2822,8 @@ proc getblobdiffs {ids} {
global difffilestart nextupdate diffinhdr treediffs
set id [lindex $ids 0]
set p [lindex $ids 1]
set env(GIT_DIFF_OPTS) $diffopts
set cmd [list | git-diff-tree -r -p -C $id]
set cmd [list | git-diff-tree --no-commit-id -r -p -C $id]
if {[catch {set bdf [open $cmd r]} err]} {
puts "error getting diffs: $err"
return
@ -3143,7 +3124,7 @@ proc linehover {} {
set t [$canv create rectangle $x0 $y0 $x1 $y1 \
-fill \#ffff80 -outline black -width 1 -tags hover]
$canv raise $t
set t [$canv create text $x $y -anchor nw -text $text -tags hover]
set t [$canv create text $x $y -anchor nw -text $text -tags hover -font $mainfont]
$canv raise $t
}
@ -3178,7 +3159,7 @@ proc clickisonarrow {id y} {
}
proc arrowjump {id dirn y} {
global mainline sidelines canv
global mainline sidelines canv canv2 canv3
set yt {}
if {$dirn eq "down"} {
@ -3216,6 +3197,8 @@ proc arrowjump {id dirn y} {
set yfrac 0
}
$canv yview moveto $yfrac
$canv2 yview moveto $yfrac
$canv3 yview moveto $yfrac
}
proc lineclick {x y id isnew} {
@ -3226,7 +3209,7 @@ proc lineclick {x y id isnew} {
normalline
$canv delete hover
# draw this line thicker than normal
drawlines $id 1
drawlines $id 1 1
set thickerline $id
if {$isnew} {
set ymax [lindex [$canv cget -scrollregion] 3]
@ -3255,7 +3238,8 @@ proc lineclick {x y id isnew} {
set info $commitinfo($id)
$ctext insert end "\n\t[lindex $info 0]\n"
$ctext insert end "\tAuthor:\t[lindex $info 1]\n"
$ctext insert end "\tDate:\t[lindex $info 2]\n"
set date [formatdate [lindex $info 2]]
$ctext insert end "\tDate:\t$date\n"
if {[info exists children($id)]} {
$ctext insert end "\nChildren:"
set i 0
@ -3267,7 +3251,8 @@ proc lineclick {x y id isnew} {
$ctext tag bind link$i <1> [list selbyid $child]
$ctext insert end "\n\t[lindex $info 0]"
$ctext insert end "\n\tAuthor:\t[lindex $info 1]"
$ctext insert end "\n\tDate:\t[lindex $info 2]\n"
set date [formatdate [lindex $info 2]]
$ctext insert end "\n\tDate:\t$date\n"
}
}
$ctext conf -state disabled
@ -3278,7 +3263,7 @@ proc lineclick {x y id isnew} {
proc normalline {} {
global thickerline
if {[info exists thickerline]} {
drawlines $thickerline 0
drawlines $thickerline 0 1
unset thickerline
}
}
@ -3650,6 +3635,23 @@ proc doquit {} {
destroy .
}
proc formatdate {d} {
global hours nhours tfd fastdate
if {!$fastdate} {
return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
}
set hr [expr {$d / 3600}]
set ms [expr {$d % 3600}]
if {![info exists hours($hr)]} {
set hours($hr) [clock format $d -format "%Y-%m-%d %H"]
set nhours($hr) 0
}
incr nhours($hr)
set minsec [format "%.2d:%.2d" [expr {$ms/60}] [expr {$ms%60}]]
return "$hours($hr):$minsec"
}
# defaults...
set datemode 0
set boldnames 0
@ -3662,6 +3664,8 @@ set findmergefiles 0
set gaudydiff 0
set maxgraphpct 50
set maxwidth 16
set revlistorder 0
set fastdate 0
set colors {green red blue magenta darkgrey brown orange}
@ -3678,6 +3682,7 @@ foreach arg $argv {
"^$" { }
"^-b" { set boldnames 1 }
"^-d" { set datemode 1 }
"^-r" { set revlistorder 1 }
default {
lappend revtreeargs $arg
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

442
http.c Normal file
View File

@ -0,0 +1,442 @@
#include "http.h"
int data_received;
int active_requests = 0;
#ifdef USE_CURL_MULTI
int max_requests = -1;
CURLM *curlm;
#endif
#ifndef NO_CURL_EASY_DUPHANDLE
CURL *curl_default;
#endif
char curl_errorstr[CURL_ERROR_SIZE];
int curl_ssl_verify = -1;
char *ssl_cert = NULL;
#if LIBCURL_VERSION_NUM >= 0x070902
char *ssl_key = NULL;
#endif
#if LIBCURL_VERSION_NUM >= 0x070908
char *ssl_capath = NULL;
#endif
char *ssl_cainfo = NULL;
long curl_low_speed_limit = -1;
long curl_low_speed_time = -1;
struct curl_slist *pragma_header;
struct curl_slist *no_range_header;
struct active_request_slot *active_queue_head = NULL;
size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
struct buffer *buffer)
{
size_t size = eltsize * nmemb;
if (size > buffer->size - buffer->posn)
size = buffer->size - buffer->posn;
memcpy(ptr, buffer->buffer + buffer->posn, size);
buffer->posn += size;
return size;
}
size_t fwrite_buffer(const void *ptr, size_t eltsize,
size_t nmemb, struct buffer *buffer)
{
size_t size = eltsize * nmemb;
if (size > buffer->size - buffer->posn) {
buffer->size = buffer->size * 3 / 2;
if (buffer->size < buffer->posn + size)
buffer->size = buffer->posn + size;
buffer->buffer = xrealloc(buffer->buffer, buffer->size);
}
memcpy(buffer->buffer + buffer->posn, ptr, size);
buffer->posn += size;
data_received++;
return size;
}
size_t fwrite_null(const void *ptr, size_t eltsize,
size_t nmemb, struct buffer *buffer)
{
data_received++;
return eltsize * nmemb;
}
static void finish_active_slot(struct active_request_slot *slot);
#ifdef USE_CURL_MULTI
static void process_curl_messages(void)
{
int num_messages;
struct active_request_slot *slot;
CURLMsg *curl_message = curl_multi_info_read(curlm, &num_messages);
while (curl_message != NULL) {
if (curl_message->msg == CURLMSG_DONE) {
int curl_result = curl_message->data.result;
slot = active_queue_head;
while (slot != NULL &&
slot->curl != curl_message->easy_handle)
slot = slot->next;
if (slot != NULL) {
curl_multi_remove_handle(curlm, slot->curl);
slot->curl_result = curl_result;
finish_active_slot(slot);
} else {
fprintf(stderr, "Received DONE message for unknown request!\n");
}
} else {
fprintf(stderr, "Unknown CURL message received: %d\n",
(int)curl_message->msg);
}
curl_message = curl_multi_info_read(curlm, &num_messages);
}
}
#endif
static int http_options(const char *var, const char *value)
{
if (!strcmp("http.sslverify", var)) {
if (curl_ssl_verify == -1) {
curl_ssl_verify = git_config_bool(var, value);
}
return 0;
}
if (!strcmp("http.sslcert", var)) {
if (ssl_cert == NULL) {
ssl_cert = xmalloc(strlen(value)+1);
strcpy(ssl_cert, value);
}
return 0;
}
#if LIBCURL_VERSION_NUM >= 0x070902
if (!strcmp("http.sslkey", var)) {
if (ssl_key == NULL) {
ssl_key = xmalloc(strlen(value)+1);
strcpy(ssl_key, value);
}
return 0;
}
#endif
#if LIBCURL_VERSION_NUM >= 0x070908
if (!strcmp("http.sslcapath", var)) {
if (ssl_capath == NULL) {
ssl_capath = xmalloc(strlen(value)+1);
strcpy(ssl_capath, value);
}
return 0;
}
#endif
if (!strcmp("http.sslcainfo", var)) {
if (ssl_cainfo == NULL) {
ssl_cainfo = xmalloc(strlen(value)+1);
strcpy(ssl_cainfo, value);
}
return 0;
}
#ifdef USE_CURL_MULTI
if (!strcmp("http.maxrequests", var)) {
if (max_requests == -1)
max_requests = git_config_int(var, value);
return 0;
}
#endif
if (!strcmp("http.lowspeedlimit", var)) {
if (curl_low_speed_limit == -1)
curl_low_speed_limit = (long)git_config_int(var, value);
return 0;
}
if (!strcmp("http.lowspeedtime", var)) {
if (curl_low_speed_time == -1)
curl_low_speed_time = (long)git_config_int(var, value);
return 0;
}
/* Fall back on the default ones */
return git_default_config(var, value);
}
static CURL* get_curl_handle(void)
{
CURL* result = curl_easy_init();
curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify);
#if LIBCURL_VERSION_NUM >= 0x070907
curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
#endif
if (ssl_cert != NULL)
curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
#if LIBCURL_VERSION_NUM >= 0x070902
if (ssl_key != NULL)
curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
#endif
#if LIBCURL_VERSION_NUM >= 0x070908
if (ssl_capath != NULL)
curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath);
#endif
if (ssl_cainfo != NULL)
curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
curl_easy_setopt(result, CURLOPT_FAILONERROR, 1);
if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT,
curl_low_speed_limit);
curl_easy_setopt(result, CURLOPT_LOW_SPEED_TIME,
curl_low_speed_time);
}
curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
return result;
}
void http_init(void)
{
char *low_speed_limit;
char *low_speed_time;
curl_global_init(CURL_GLOBAL_ALL);
pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache");
no_range_header = curl_slist_append(no_range_header, "Range:");
#ifdef USE_CURL_MULTI
{
char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
if (http_max_requests != NULL)
max_requests = atoi(http_max_requests);
}
curlm = curl_multi_init();
if (curlm == NULL) {
fprintf(stderr, "Error creating curl multi handle.\n");
exit(1);
}
#endif
if (getenv("GIT_SSL_NO_VERIFY"))
curl_ssl_verify = 0;
ssl_cert = getenv("GIT_SSL_CERT");
#if LIBCURL_VERSION_NUM >= 0x070902
ssl_key = getenv("GIT_SSL_KEY");
#endif
#if LIBCURL_VERSION_NUM >= 0x070908
ssl_capath = getenv("GIT_SSL_CAPATH");
#endif
ssl_cainfo = getenv("GIT_SSL_CAINFO");
low_speed_limit = getenv("GIT_HTTP_LOW_SPEED_LIMIT");
if (low_speed_limit != NULL)
curl_low_speed_limit = strtol(low_speed_limit, NULL, 10);
low_speed_time = getenv("GIT_HTTP_LOW_SPEED_TIME");
if (low_speed_time != NULL)
curl_low_speed_time = strtol(low_speed_time, NULL, 10);
git_config(http_options);
if (curl_ssl_verify == -1)
curl_ssl_verify = 1;
#ifdef USE_CURL_MULTI
if (max_requests < 1)
max_requests = DEFAULT_MAX_REQUESTS;
#endif
#ifndef NO_CURL_EASY_DUPHANDLE
curl_default = get_curl_handle();
#endif
}
void http_cleanup(void)
{
struct active_request_slot *slot = active_queue_head;
#ifdef USE_CURL_MULTI
char *wait_url;
#endif
while (slot != NULL) {
#ifdef USE_CURL_MULTI
if (slot->in_use) {
curl_easy_getinfo(slot->curl,
CURLINFO_EFFECTIVE_URL,
&wait_url);
fprintf(stderr, "Waiting for %s\n", wait_url);
run_active_slot(slot);
}
#endif
if (slot->curl != NULL)
curl_easy_cleanup(slot->curl);
slot = slot->next;
}
#ifndef NO_CURL_EASY_DUPHANDLE
curl_easy_cleanup(curl_default);
#endif
#ifdef USE_CURL_MULTI
curl_multi_cleanup(curlm);
#endif
curl_global_cleanup();
}
struct active_request_slot *get_active_slot(void)
{
struct active_request_slot *slot = active_queue_head;
struct active_request_slot *newslot;
#ifdef USE_CURL_MULTI
int num_transfers;
/* Wait for a slot to open up if the queue is full */
while (active_requests >= max_requests) {
curl_multi_perform(curlm, &num_transfers);
if (num_transfers < active_requests) {
process_curl_messages();
}
}
#endif
while (slot != NULL && slot->in_use) {
slot = slot->next;
}
if (slot == NULL) {
newslot = xmalloc(sizeof(*newslot));
newslot->curl = NULL;
newslot->in_use = 0;
newslot->next = NULL;
slot = active_queue_head;
if (slot == NULL) {
active_queue_head = newslot;
} else {
while (slot->next != NULL) {
slot = slot->next;
}
slot->next = newslot;
}
slot = newslot;
}
if (slot->curl == NULL) {
#ifdef NO_CURL_EASY_DUPHANDLE
slot->curl = get_curl_handle();
#else
slot->curl = curl_easy_duphandle(curl_default);
#endif
}
active_requests++;
slot->in_use = 1;
slot->local = NULL;
slot->callback_data = NULL;
slot->callback_func = NULL;
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_range_header);
curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
return slot;
}
int start_active_slot(struct active_request_slot *slot)
{
#ifdef USE_CURL_MULTI
CURLMcode curlm_result = curl_multi_add_handle(curlm, slot->curl);
if (curlm_result != CURLM_OK &&
curlm_result != CURLM_CALL_MULTI_PERFORM) {
active_requests--;
slot->in_use = 0;
return 0;
}
#endif
return 1;
}
#ifdef USE_CURL_MULTI
void step_active_slots(void)
{
int num_transfers;
CURLMcode curlm_result;
do {
curlm_result = curl_multi_perform(curlm, &num_transfers);
} while (curlm_result == CURLM_CALL_MULTI_PERFORM);
if (num_transfers < active_requests) {
process_curl_messages();
fill_active_slots();
}
}
#endif
void run_active_slot(struct active_request_slot *slot)
{
#ifdef USE_CURL_MULTI
long last_pos = 0;
long current_pos;
fd_set readfds;
fd_set writefds;
fd_set excfds;
int max_fd;
struct timeval select_timeout;
while (slot->in_use) {
data_received = 0;
step_active_slots();
if (!data_received && slot->local != NULL) {
current_pos = ftell(slot->local);
if (current_pos > last_pos)
data_received++;
last_pos = current_pos;
}
if (slot->in_use && !data_received) {
max_fd = 0;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&excfds);
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 50000;
select(max_fd, &readfds, &writefds,
&excfds, &select_timeout);
}
}
#else
while (slot->in_use) {
slot->curl_result = curl_easy_perform(slot->curl);
finish_active_slot(slot);
}
#endif
}
static void finish_active_slot(struct active_request_slot *slot)
{
active_requests--;
slot->in_use = 0;
curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
/* Run callback if appropriate */
if (slot->callback_func != NULL) {
slot->callback_func(slot->callback_data);
}
}
void finish_all_active_slots(void)
{
struct active_request_slot *slot = active_queue_head;
while (slot != NULL)
if (slot->in_use) {
run_active_slot(slot);
slot = active_queue_head;
} else {
slot = slot->next;
}
}

95
http.h Normal file
View File

@ -0,0 +1,95 @@
#ifndef HTTP_H
#define HTTP_H
#include "cache.h"
#include <curl/curl.h>
#include <curl/easy.h>
#if LIBCURL_VERSION_NUM >= 0x070908
#define USE_CURL_MULTI
#define DEFAULT_MAX_REQUESTS 5
#endif
#if LIBCURL_VERSION_NUM < 0x070704
#define curl_global_cleanup() do { /* nothing */ } while(0)
#endif
#if LIBCURL_VERSION_NUM < 0x070800
#define curl_global_init(a) do { /* nothing */ } while(0)
#endif
#if LIBCURL_VERSION_NUM < 0x070c04
#define NO_CURL_EASY_DUPHANDLE
#endif
struct active_request_slot
{
CURL *curl;
FILE *local;
int in_use;
CURLcode curl_result;
long http_code;
void *callback_data;
void (*callback_func)(void *data);
struct active_request_slot *next;
};
struct buffer
{
size_t posn;
size_t size;
void *buffer;
};
/* Curl request read/write callbacks */
extern size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
struct buffer *buffer);
extern size_t fwrite_buffer(const void *ptr, size_t eltsize,
size_t nmemb, struct buffer *buffer);
extern size_t fwrite_null(const void *ptr, size_t eltsize,
size_t nmemb, struct buffer *buffer);
/* Slot lifecycle functions */
extern struct active_request_slot *get_active_slot(void);
extern int start_active_slot(struct active_request_slot *slot);
extern void run_active_slot(struct active_request_slot *slot);
extern void finish_all_active_slots(void);
#ifdef USE_CURL_MULTI
extern void fill_active_slots(void);
extern void step_active_slots(void);
#endif
extern void http_init(void);
extern void http_cleanup(void);
extern int data_received;
extern int active_requests;
#ifdef USE_CURL_MULTI
extern int max_requests;
extern CURLM *curlm;
#endif
#ifndef NO_CURL_EASY_DUPHANDLE
extern CURL *curl_default;
#endif
extern char curl_errorstr[CURL_ERROR_SIZE];
extern int curl_ssl_verify;
extern char *ssl_cert;
#if LIBCURL_VERSION_NUM >= 0x070902
extern char *ssl_key;
#endif
#if LIBCURL_VERSION_NUM >= 0x070908
extern char *ssl_capath;
#endif
extern char *ssl_cainfo;
extern long curl_low_speed_limit;
extern long curl_low_speed_time;
extern struct curl_slist *pragma_header;
extern struct curl_slist *no_range_header;
extern struct active_request_slot *active_queue_head;
#endif /* HTTP_H */

15
ident.c
View File

@ -156,7 +156,8 @@ static int copy(char *buf, int size, int offset, const char *src)
return offset;
}
char *get_ident(const char *name, const char *email, const char *date_str)
static const char *get_ident(const char *name, const char *email,
const char *date_str)
{
static char buffer[1000];
char date[50];
@ -181,12 +182,16 @@ char *get_ident(const char *name, const char *email, const char *date_str)
return buffer;
}
char *git_author_info(void)
const char *git_author_info(void)
{
return get_ident(getenv("GIT_AUTHOR_NAME"), getenv("GIT_AUTHOR_EMAIL"), getenv("GIT_AUTHOR_DATE"));
return get_ident(getenv("GIT_AUTHOR_NAME"),
getenv("GIT_AUTHOR_EMAIL"),
getenv("GIT_AUTHOR_DATE"));
}
char *git_committer_info(void)
const char *git_committer_info(void)
{
return get_ident(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"), getenv("GIT_COMMITTER_DATE"));
return get_ident(getenv("GIT_COMMITTER_NAME"),
getenv("GIT_COMMITTER_EMAIL"),
getenv("GIT_COMMITTER_DATE"));
}

View File

@ -230,8 +230,6 @@ int main(int argc, char **argv)
fwrite(p_start, p - p_start, 1, stdout);
}
} else if (all) {
extern struct object **objs;
extern int nr_objs;
int i;
for (i = 0; i < nr_objs; i++)

View File

@ -524,7 +524,7 @@ int main(int argc, char **argv)
unsigned char sha1[20];
if (get_sha1_hex(line, sha1))
die("expected sha1, got garbage");
die("expected sha1, got garbage:\n %s", line);
hash = 0;
p = line+40;
while (*p) {

View File

@ -11,19 +11,19 @@
static const char pack_redundant_usage[] =
"git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
int load_all_packs = 0, verbose = 0, alt_odb = 0;
static int load_all_packs = 0, verbose = 0, alt_odb = 0;
struct llist_item {
struct llist_item *next;
char *sha1;
unsigned char *sha1;
};
struct llist {
static struct llist {
struct llist_item *front;
struct llist_item *back;
size_t size;
} *all_objects; /* all objects which must be present in local packfiles */
struct pack_list {
static struct pack_list {
struct pack_list *next;
struct packed_git *pack;
struct llist *unique_objects;
@ -36,23 +36,43 @@ struct pll {
size_t pl_size;
};
inline void llist_free(struct llist *list)
static struct llist_item *free_nodes = NULL;
static inline struct llist_item *llist_item_get()
{
struct llist_item *new;
if ( free_nodes ) {
new = free_nodes;
free_nodes = free_nodes->next;
} else
new = xmalloc(sizeof(struct llist_item));
return new;
}
static inline void llist_item_put(struct llist_item *item)
{
item->next = free_nodes;
free_nodes = item;
}
static void llist_free(struct llist *list)
{
while((list->back = list->front)) {
list->front = list->front->next;
free(list->back);
llist_item_put(list->back);
}
free(list);
}
inline void llist_init(struct llist **list)
static inline void llist_init(struct llist **list)
{
*list = xmalloc(sizeof(struct llist));
(*list)->front = (*list)->back = NULL;
(*list)->size = 0;
}
struct llist * llist_copy(struct llist *list)
static struct llist * llist_copy(struct llist *list)
{
struct llist *ret;
struct llist_item *new, *old, *prev;
@ -62,13 +82,13 @@ struct llist * llist_copy(struct llist *list)
if ((ret->size = list->size) == 0)
return ret;
new = ret->front = xmalloc(sizeof(struct llist_item));
new = ret->front = llist_item_get();
new->sha1 = list->front->sha1;
old = list->front->next;
while (old) {
prev = new;
new = xmalloc(sizeof(struct llist_item));
new = llist_item_get();
prev->next = new;
new->sha1 = old->sha1;
old = old->next;
@ -79,10 +99,11 @@ struct llist * llist_copy(struct llist *list)
return ret;
}
inline struct llist_item * llist_insert(struct llist *list,
struct llist_item *after, char *sha1)
static inline struct llist_item * llist_insert(struct llist *list,
struct llist_item *after,
unsigned char *sha1)
{
struct llist_item *new = xmalloc(sizeof(struct llist_item));
struct llist_item *new = llist_item_get();
new->sha1 = sha1;
new->next = NULL;
@ -102,13 +123,12 @@ inline struct llist_item * llist_insert(struct llist *list,
return new;
}
inline struct llist_item * llist_insert_back(struct llist *list, char *sha1)
static inline struct llist_item *llist_insert_back(struct llist *list, unsigned char *sha1)
{
return llist_insert(list, list->back, sha1);
}
inline struct llist_item * llist_insert_sorted_unique(struct llist *list,
char *sha1, struct llist_item *hint)
static inline struct llist_item *llist_insert_sorted_unique(struct llist *list, unsigned char *sha1, struct llist_item *hint)
{
struct llist_item *prev = NULL, *l;
@ -129,8 +149,7 @@ inline struct llist_item * llist_insert_sorted_unique(struct llist *list,
}
/* returns a pointer to an item in front of sha1 */
inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
struct llist_item *hint)
static inline struct llist_item * llist_sorted_remove(struct llist *list, const unsigned char *sha1, struct llist_item *hint)
{
struct llist_item *prev, *l;
@ -153,7 +172,7 @@ redo_from_start:
prev->next = l->next;
if (l == list->back)
list->back = prev;
free(l);
llist_item_put(l);
list->size--;
return prev;
}
@ -164,7 +183,7 @@ redo_from_start:
}
/* computes A\B */
void llist_sorted_difference_inplace(struct llist *A,
static void llist_sorted_difference_inplace(struct llist *A,
struct llist *B)
{
struct llist_item *hint, *b;
@ -178,7 +197,7 @@ void llist_sorted_difference_inplace(struct llist *A,
}
}
inline struct pack_list * pack_list_insert(struct pack_list **pl,
static inline struct pack_list * pack_list_insert(struct pack_list **pl,
struct pack_list *entry)
{
struct pack_list *p = xmalloc(sizeof(struct pack_list));
@ -188,7 +207,7 @@ inline struct pack_list * pack_list_insert(struct pack_list **pl,
return p;
}
inline size_t pack_list_size(struct pack_list *pl)
static inline size_t pack_list_size(struct pack_list *pl)
{
size_t ret = 0;
while(pl) {
@ -198,10 +217,11 @@ inline size_t pack_list_size(struct pack_list *pl)
return ret;
}
struct pack_list * pack_list_difference(struct pack_list *A,
struct pack_list *B)
static struct pack_list * pack_list_difference(const struct pack_list *A,
const struct pack_list *B)
{
struct pack_list *ret, *pl;
struct pack_list *ret;
const struct pack_list *pl;
if (A == NULL)
return NULL;
@ -218,7 +238,7 @@ struct pack_list * pack_list_difference(struct pack_list *A,
return ret;
}
void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
{
int p1_off, p2_off;
void *p1_base, *p2_base;
@ -250,7 +270,7 @@ void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
}
}
void pll_insert(struct pll **pll, struct pll **hint_table)
static void pll_insert(struct pll **pll, struct pll **hint_table)
{
struct pll *prev;
int i = (*pll)->pl_size - 1;
@ -276,7 +296,7 @@ void pll_insert(struct pll **pll, struct pll **hint_table)
/* all the permutations have to be free()d at the same time,
* since they refer to each other
*/
struct pll * get_all_permutations(struct pack_list *list)
static struct pll * get_all_permutations(struct pack_list *list)
{
struct pll *subset, *pll, *new_pll = NULL; /*silence warning*/
static struct pll **hint = NULL;
@ -323,15 +343,14 @@ struct pll * get_all_permutations(struct pack_list *list)
return hint[0];
}
int is_superset(struct pack_list *pl, struct llist *list)
static int is_superset(struct pack_list *pl, struct llist *list)
{
struct llist *diff;
diff = llist_copy(list);
while (pl) {
llist_sorted_difference_inplace(diff,
pl->all_objects);
llist_sorted_difference_inplace(diff, pl->all_objects);
if (diff->size == 0) { /* we're done */
llist_free(diff);
return 1;
@ -342,7 +361,7 @@ int is_superset(struct pack_list *pl, struct llist *list)
return 0;
}
size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
{
size_t ret = 0;
int p1_off, p2_off;
@ -373,14 +392,14 @@ size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
}
/* another O(n^2) function ... */
size_t get_pack_redundancy(struct pack_list *pl)
static size_t get_pack_redundancy(struct pack_list *pl)
{
struct pack_list *subset;
size_t ret = 0;
if (pl == NULL)
return 0;
size_t ret = 0;
while ((subset = pl->next)) {
while(subset) {
ret += sizeof_union(pl->pack, subset->pack);
@ -391,7 +410,7 @@ size_t get_pack_redundancy(struct pack_list *pl)
return ret;
}
inline size_t pack_set_bytecount(struct pack_list *pl)
static inline size_t pack_set_bytecount(struct pack_list *pl)
{
size_t ret = 0;
while (pl) {
@ -402,7 +421,7 @@ inline size_t pack_set_bytecount(struct pack_list *pl)
return ret;
}
void minimize(struct pack_list **min)
static void minimize(struct pack_list **min)
{
struct pack_list *pl, *unique = NULL,
*non_unique = NULL, *min_perm = NULL;
@ -469,16 +488,14 @@ void minimize(struct pack_list **min)
}
}
void load_all_objects()
static void load_all_objects(void)
{
struct pack_list *pl = local_packs;
struct llist_item *hint, *l;
int i;
llist_init(&all_objects);
while (pl) {
i = 0;
hint = NULL;
l = pl->all_objects->front;
while (l) {
@ -497,7 +514,7 @@ void load_all_objects()
}
/* this scales like O(n^2) */
void cmp_local_packs()
static void cmp_local_packs(void)
{
struct pack_list *subset, *pl = local_packs;
@ -508,7 +525,7 @@ void cmp_local_packs()
}
}
void scan_alt_odb_packs()
static void scan_alt_odb_packs(void)
{
struct pack_list *local, *alt;
@ -524,7 +541,7 @@ void scan_alt_odb_packs()
}
}
struct pack_list * add_pack(struct packed_git *p)
static struct pack_list * add_pack(struct packed_git *p)
{
struct pack_list l;
size_t off;
@ -550,7 +567,7 @@ struct pack_list * add_pack(struct packed_git *p)
return pack_list_insert(&altodb_packs, &l);
}
struct pack_list * add_pack_file(char *filename)
static struct pack_list * add_pack_file(char *filename)
{
struct packed_git *p = packed_git;
@ -565,7 +582,7 @@ struct pack_list * add_pack_file(char *filename)
die("Filename %s not found in packed_git\n", filename);
}
void load_all()
static void load_all(void)
{
struct packed_git *p = packed_git;
@ -579,6 +596,9 @@ int main(int argc, char **argv)
{
int i;
struct pack_list *min, *red, *pl;
struct llist *ignore;
unsigned char *sha1;
char buf[42]; /* 40 byte sha1 + \n + \0 */
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
@ -621,6 +641,23 @@ int main(int argc, char **argv)
if (alt_odb)
scan_alt_odb_packs();
/* ignore objects given on stdin */
llist_init(&ignore);
if (!isatty(0)) {
while (fgets(buf, sizeof(buf), stdin)) {
sha1 = xmalloc(20);
if (get_sha1_hex(buf, sha1))
die("Bad sha1 on stdin: %s", buf);
llist_insert_sorted_unique(ignore, sha1, NULL);
}
}
llist_sorted_difference_inplace(all_objects, ignore);
pl = local_packs;
while (pl) {
llist_sorted_difference_inplace(pl->unique_objects, ignore);
pl = pl->next;
}
minimize(&min);
if (verbose) {
@ -647,6 +684,9 @@ int main(int argc, char **argv)
pl->pack->pack_name);
pl = pl->next;
}
if (verbose)
fprintf(stderr, "%luMB of redundant packs in total.\n",
(unsigned long)pack_set_bytecount(red)/(1024*1024));
return 0;
}

115
path.c
View File

@ -11,6 +11,7 @@
* which is what it's designed for.
*/
#include "cache.h"
#include <pwd.h>
static char pathname[PATH_MAX];
static char bad_path[] = "/bad-path/";
@ -89,3 +90,117 @@ char *safe_strncpy(char *dest, const char *src, size_t n)
return dest;
}
int validate_symref(const char *path)
{
struct stat st;
char *buf, buffer[256];
int len, fd;
if (lstat(path, &st) < 0)
return -1;
/* Make sure it is a "refs/.." symlink */
if (S_ISLNK(st.st_mode)) {
len = readlink(path, buffer, sizeof(buffer)-1);
if (len >= 5 && !memcmp("refs/", buffer, 5))
return 0;
return -1;
}
/*
* Anything else, just open it and try to see if it is a symbolic ref.
*/
fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
len = read(fd, buffer, sizeof(buffer)-1);
close(fd);
/*
* Is it a symbolic ref?
*/
if (len < 4 || memcmp("ref:", buffer, 4))
return -1;
buf = buffer + 4;
len -= 4;
while (len && isspace(*buf))
buf++, len--;
if (len >= 5 && !memcmp("refs/", buf, 5))
return 0;
return -1;
}
static char *current_dir(void)
{
return getcwd(pathname, sizeof(pathname));
}
static int user_chdir(char *path)
{
char *dir = path;
if(*dir == '~') { /* user-relative path */
struct passwd *pw;
char *slash = strchr(dir, '/');
dir++;
/* '~/' and '~' (no slash) means users own home-dir */
if(!*dir || *dir == '/')
pw = getpwuid(getuid());
else {
if (slash) {
*slash = '\0';
pw = getpwnam(dir);
*slash = '/';
}
else
pw = getpwnam(dir);
}
/* make sure we got something back that we can chdir() to */
if(!pw || chdir(pw->pw_dir) < 0)
return -1;
if(!slash || !slash[1]) /* no path following username */
return 0;
dir = slash + 1;
}
/* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */
if(chdir(dir) < 0)
return -1;
return 0;
}
char *enter_repo(char *path, int strict)
{
if(!path)
return NULL;
if (strict) {
if (chdir(path) < 0)
return NULL;
}
else {
if (!*path)
; /* happy -- no chdir */
else if (!user_chdir(path))
; /* happy -- as given */
else if (!user_chdir(mkpath("%s.git", path)))
; /* happy -- uemacs --> uemacs.git */
else
return NULL;
(void)chdir(".git");
}
if(access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
validate_symref("HEAD") == 0) {
putenv("GIT_DIR=.");
return current_dir();
}
return NULL;
}

View File

@ -248,11 +248,11 @@ static void unpack(void)
int main(int argc, char **argv)
{
int i;
const char *dir = NULL;
char *dir = NULL;
argv++;
for (i = 1; i < argc; i++) {
const char *arg = *argv++;
char *arg = *argv++;
if (*arg == '-') {
/* Do flag handling here */
@ -265,18 +265,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(!enter_repo(dir, 0))
die("'%s': unable to chdir or not a git archive", dir);
/* If we have a ".git" directory, chdir to it */
chdir(".git");
putenv("GIT_DIR=.");
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 */

40
refs.c
View File

@ -10,46 +10,6 @@
#define USE_SYMLINK_HEAD 1
#endif
int validate_symref(const char *path)
{
struct stat st;
char *buf, buffer[256];
int len, fd;
if (lstat(path, &st) < 0)
return -1;
/* Make sure it is a "refs/.." symlink */
if (S_ISLNK(st.st_mode)) {
len = readlink(path, buffer, sizeof(buffer)-1);
if (len >= 5 && !memcmp("refs/", buffer, 5))
return 0;
return -1;
}
/*
* Anything else, just open it and try to see if it is a symbolic ref.
*/
fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
len = read(fd, buffer, sizeof(buffer)-1);
close(fd);
/*
* Is it a symbolic ref?
*/
if (len < 4 || memcmp("ref:", buffer, 4))
return -1;
buf = buffer + 4;
len -= 4;
while (len && isspace(*buf))
buf++, len--;
if (len >= 5 && !memcmp("refs/", buf, 5))
return 0;
return -1;
}
const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
{
int depth = MAXDEPTH, len;

116
repo-config.c Normal file
View File

@ -0,0 +1,116 @@
#include "cache.h"
#include <regex.h>
static const char git_config_set_usage[] =
"git-repo-config [--get | --get-all | --replace-all | --unset | --unset-all] name [value [value_regex]]";
static char* key = NULL;
static char* value = NULL;
static regex_t* regex = NULL;
static int do_all = 0;
static int do_not_match = 0;
static int seen = 0;
static int show_config(const char* key_, const char* value_)
{
if (!strcmp(key_, key) &&
(regex == NULL ||
(do_not_match ^
!regexec(regex, value_, 0, NULL, 0)))) {
if (do_all) {
printf("%s\n", value_);
return 0;
}
if (seen > 0) {
fprintf(stderr, "More than one value: %s\n", value);
free(value);
}
value = strdup(value_);
seen++;
}
return 0;
}
static int get_value(const char* key_, const char* regex_)
{
int i;
key = malloc(strlen(key_)+1);
for (i = 0; key_[i]; i++)
key[i] = tolower(key_[i]);
key[i] = 0;
if (regex_) {
if (regex_[0] == '!') {
do_not_match = 1;
regex_++;
}
regex = (regex_t*)malloc(sizeof(regex_t));
if (regcomp(regex, regex_, REG_EXTENDED)) {
fprintf(stderr, "Invalid pattern: %s\n", regex_);
return -1;
}
}
i = git_config(show_config);
if (value) {
printf("%s\n", value);
free(value);
}
free(key);
if (regex) {
regfree(regex);
free(regex);
}
if (do_all)
return 0;
return seen == 1 ? 0 : 1;
}
int main(int argc, const char **argv)
{
setup_git_directory();
switch (argc) {
case 2:
return get_value(argv[1], NULL);
case 3:
if (!strcmp(argv[1], "--unset"))
return git_config_set(argv[2], NULL);
else if (!strcmp(argv[1], "--unset-all"))
return git_config_set_multivar(argv[2], NULL, NULL, 1);
else if (!strcmp(argv[1], "--get"))
return get_value(argv[2], NULL);
else if (!strcmp(argv[1], "--get-all")) {
do_all = 1;
return get_value(argv[2], NULL);
} else
return git_config_set(argv[1], argv[2]);
case 4:
if (!strcmp(argv[1], "--unset"))
return git_config_set_multivar(argv[2], NULL, argv[3], 0);
else if (!strcmp(argv[1], "--unset-all"))
return git_config_set_multivar(argv[2], NULL, argv[3], 1);
else if (!strcmp(argv[1], "--get"))
return get_value(argv[2], argv[3]);
else if (!strcmp(argv[1], "--get-all")) {
do_all = 1;
return get_value(argv[2], argv[3]);
} else if (!strcmp(argv[1], "--replace-all"))
return git_config_set_multivar(argv[2], argv[3], NULL, 1);
else
return git_config_set_multivar(argv[1], argv[2], argv[3], 0);
case 5:
if (!strcmp(argv[1], "--replace-all"))
return git_config_set_multivar(argv[2], argv[3], argv[4], 1);
case 1:
default:
usage(git_config_set_usage);
}
return 0;
}

View File

@ -124,8 +124,6 @@ static int filter_commit(struct commit * commit)
stop_traversal=1;
return CONTINUE;
}
if (max_count != -1 && !max_count--)
return STOP;
if (no_merges && (commit->parents && commit->parents->next))
return CONTINUE;
if (paths && dense) {
@ -148,6 +146,9 @@ static int process_commit(struct commit * commit)
return CONTINUE;
}
if (max_count != -1 && !max_count--)
return STOP;
show_commit(commit);
return CONTINUE;

42
setup.c
View File

@ -73,8 +73,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
}
/*
* Test it it looks like we're at the top
* level git directory. We want to see a
* Test if it looks like we're at the top level git directory.
* We want to see:
*
* - either a .git/objects/ directory _or_ the proper
* GIT_OBJECT_DIRECTORY environment variable
@ -92,17 +92,43 @@ static int is_toplevel_directory(void)
return 1;
}
const char *setup_git_directory(void)
static const char *setup_git_directory_1(void)
{
static char cwd[PATH_MAX+1];
int len, offset;
/*
* If GIT_DIR is set explicitly, we're not going
* to do any discovery
* to do any discovery, but we still do repository
* validation.
*/
if (getenv(GIT_DIR_ENVIRONMENT))
if (getenv(GIT_DIR_ENVIRONMENT)) {
char path[PATH_MAX];
int len = strlen(getenv(GIT_DIR_ENVIRONMENT));
if (sizeof(path) - 40 < len)
die("'$%s' too big", GIT_DIR_ENVIRONMENT);
memcpy(path, getenv(GIT_DIR_ENVIRONMENT), len);
strcpy(path + len, "/refs");
if (access(path, X_OK))
goto bad_dir_environ;
strcpy(path + len, "/HEAD");
if (validate_symref(path))
goto bad_dir_environ;
if (getenv(DB_ENVIRONMENT)) {
if (access(DB_ENVIRONMENT, X_OK))
goto bad_dir_environ;
}
else {
strcpy(path + len, "/objects");
if (access(path, X_OK))
goto bad_dir_environ;
}
return NULL;
bad_dir_environ:
path[len] = 0;
die("Not a git repository: '%s'", path);
}
if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
die("Unable to read current working directory");
@ -127,3 +153,9 @@ const char *setup_git_directory(void)
cwd[len] = 0;
return cwd + offset;
}
const char *setup_git_directory(void)
{
const char *retval = setup_git_directory_1();
return retval;
}

View File

@ -236,6 +236,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
NULL
};
const char **p;
int found = 0;
if (len == 40 && !get_sha1_hex(str, sha1))
return 0;
@ -246,10 +247,20 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
for (p = prefix; *p; p++) {
char *pathname = git_path("%s/%.*s", *p, len, str);
if (!read_ref(pathname, sha1))
return 0;
if (!read_ref(pathname, sha1)) {
/* Must be unique; i.e. when heads/foo and
* tags/foo are both present, reject "foo".
* Note that read_ref() eventually calls
* get_sha1_hex() which can smudge initial
* part of the buffer even if what is read
* is found to be invalid halfway.
*/
if (1 < found++)
return -1;
}
}
if (found == 1)
return 0;
return -1;
}

View File

@ -313,9 +313,16 @@ static int append_ref(const char *refname, const unsigned char *sha1)
static int append_head_ref(const char *refname, const unsigned char *sha1)
{
if (strncmp(refname, "refs/heads/", 11))
unsigned char tmp[20];
int ofs = 11;
if (strncmp(refname, "refs/heads/", ofs))
return 0;
return append_ref(refname + 11, sha1);
/* If both heads/foo and tags/foo exists, get_sha1 would
* get confused.
*/
if (get_sha1(refname + ofs, tmp) || memcmp(tmp, sha1, 20))
ofs = 5;
return append_ref(refname + ofs, sha1);
}
static int append_tag_ref(const char *refname, const unsigned char *sha1)
@ -470,7 +477,7 @@ int main(int ac, char **av)
if (MAX_REVS <= num_rev)
die("cannot handle more than %d revs.", MAX_REVS);
if (get_sha1(ref_name[num_rev], revkey))
usage(show_branch_usage);
die("'%s' is not a valid ref.\n", ref_name[num_rev]);
commit = lookup_commit_reference(revkey);
if (!commit)
die("cannot find commit %s (%s)",

271
t/t1300-repo-config.sh Normal file
View File

@ -0,0 +1,271 @@
#!/bin/sh
#
# Copyright (c) 2005 Johannes Schindelin
#
test_description='Test git-repo-config in different settings'
. ./test-lib.sh
test -f .git/config && rm .git/config
git-repo-config core.penguin "little blue"
cat > expect << EOF
#
# This is the config file
#
[core]
penguin = little blue
EOF
test_expect_success 'initial' 'cmp .git/config expect'
git-repo-config Core.Movie BadPhysics
cat > expect << EOF
#
# This is the config file
#
[core]
penguin = little blue
Movie = BadPhysics
EOF
test_expect_success 'mixed case' 'cmp .git/config expect'
git-repo-config Cores.WhatEver Second
cat > expect << EOF
#
# This is the config file
#
[core]
penguin = little blue
Movie = BadPhysics
[Cores]
WhatEver = Second
EOF
test_expect_success 'similar section' 'cmp .git/config expect'
git-repo-config CORE.UPPERCASE true
cat > expect << EOF
#
# This is the config file
#
[core]
penguin = little blue
Movie = BadPhysics
UPPERCASE = true
[Cores]
WhatEver = Second
EOF
test_expect_success 'similar section' 'cmp .git/config expect'
test_expect_success 'replace with non-match' \
'git-repo-config core.penguin kingpin !blue'
test_expect_success 'replace with non-match (actually matching)' \
'git-repo-config core.penguin "very blue" !kingpin'
cat > expect << EOF
#
# This is the config file
#
[core]
penguin = very blue
Movie = BadPhysics
UPPERCASE = true
penguin = kingpin
[Cores]
WhatEver = Second
EOF
test_expect_success 'non-match result' 'cmp .git/config expect'
cat > .git/config << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
haha ="beta" # last silly comment
haha = hello
haha = bello
[nextSection] noNewline = ouch
EOF
cp .git/config .git/config2
test_expect_success 'multiple unset' \
'git-repo-config --unset-all beta.haha'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection] noNewline = ouch
EOF
test_expect_success 'multiple unset is correct' 'cmp .git/config expect'
mv .git/config2 .git/config
test_expect_success '--replace-all' \
'git-repo-config --replace-all beta.haha gamma'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
haha = gamma
[nextSection] noNewline = ouch
EOF
test_expect_success 'all replaced' 'cmp .git/config expect'
git-repo-config beta.haha alpha
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
haha = alpha
[nextSection] noNewline = ouch
EOF
test_expect_success 'really mean test' 'cmp .git/config expect'
git-repo-config nextsection.nonewline wow
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
haha = alpha
[nextSection]
nonewline = wow
EOF
test_expect_success 'really really mean test' 'cmp .git/config expect'
test_expect_success 'get value' 'test alpha = $(git-repo-config beta.haha)'
git-repo-config --unset beta.haha
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection]
nonewline = wow
EOF
test_expect_success 'unset' 'cmp .git/config expect'
git-repo-config nextsection.NoNewLine "wow2 for me" "for me$"
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection]
nonewline = wow
NoNewLine = wow2 for me
EOF
test_expect_success 'multivar' 'cmp .git/config expect'
test_expect_success 'non-match' \
'git-repo-config --get nextsection.nonewline !for'
test_expect_success 'non-match value' \
'test wow = $(git-repo-config --get nextsection.nonewline !for)'
test_expect_failure 'ambiguous get' \
'git-repo-config --get nextsection.nonewline'
test_expect_success 'get multivar' \
'git-repo-config --get-all nextsection.nonewline'
git-repo-config nextsection.nonewline "wow3" "wow$"
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection]
nonewline = wow3
NoNewLine = wow2 for me
EOF
test_expect_success 'multivar replace' 'cmp .git/config expect'
test_expect_failure 'ambiguous value' 'git-repo-config nextsection.nonewline'
test_expect_failure 'ambiguous unset' \
'git-repo-config --unset nextsection.nonewline'
test_expect_failure 'invalid unset' \
'git-repo-config --unset somesection.nonewline'
git-repo-config --unset nextsection.nonewline "wow3$"
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection]
NoNewLine = wow2 for me
EOF
test_expect_success 'multivar unset' 'cmp .git/config expect'
test_expect_failure 'invalid key' 'git-repo-config inval.2key blabla'
test_expect_success 'correct key' 'git-repo-config 123456.a123 987'
test_expect_success 'hierarchical section' \
'git-repo-config 1.2.3.alpha beta'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection]
NoNewLine = wow2 for me
[123456]
a123 = 987
[1.2.3]
alpha = beta
EOF
test_expect_success 'hierarchical section value' 'cmp .git/config expect'
test_done

View File

@ -8,14 +8,14 @@
# (2) make this file executable by "chmod +x update".
#
recipient="commit-list@mydomain.xz"
recipient="commit-list@example.com"
if expr "$2" : '0*$' >/dev/null
then
echo "Created a new ref, with the following commits:"
git-rev-list --pretty "$3"
else
$base=$(git-merge-base "$2" "$3")
base=$(git-merge-base "$2" "$3")
case "$base" in
"$2")
echo "New commits:"
@ -24,8 +24,7 @@ else
echo "Rebased ref, commits from common ancestor:"
;;
esac
fi
git-rev-list --pretty "$3" "^$base"
git-rev-list --pretty "$3" "^$base"
fi |
mail -s "Changes to ref $1" "$recipient"
exit 0

View File

@ -338,7 +338,7 @@ static void read_index_info(int line_termination)
struct strbuf buf;
strbuf_init(&buf);
while (1) {
char *ptr;
char *ptr, *tab;
char *path_name;
unsigned char sha1[20];
unsigned int mode;
@ -348,12 +348,15 @@ static void read_index_info(int line_termination)
break;
mode = strtoul(buf.buf, &ptr, 8);
if (ptr == buf.buf || *ptr != ' ' ||
get_sha1_hex(ptr + 1, sha1) ||
ptr[41] != '\t')
if (ptr == buf.buf || *ptr != ' ')
goto bad_line;
ptr += 42;
tab = strchr(ptr, '\t');
if (!tab || tab - ptr < 41)
goto bad_line;
if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
goto bad_line;
ptr = tab + 1;
if (line_termination && ptr[0] == '"')
path_name = unquote_c_style(ptr, NULL);

View File

@ -248,7 +248,7 @@ static int upload_pack(void)
int main(int argc, char **argv)
{
const char *dir;
char *dir;
int i;
int strict = 0;
@ -275,18 +275,9 @@ int main(int argc, char **argv)
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 (!enter_repo(dir, strict))
die("'%s': unable to chdir or not a git archive", dir);
if (access("objects", X_OK) || access("refs", X_OK))
die("git-upload-pack: %s doesn't seem to be a git archive", dir);
putenv("GIT_DIR=.");
upload_pack();
return 0;
}

4
var.c
View File

@ -12,7 +12,7 @@ static const char var_usage[] = "git-var [-l | <variable>]";
struct git_var {
const char *name;
char *(*read)(void);
const char *(*read)(void);
};
static struct git_var git_vars[] = {
{ "GIT_COMMITTER_IDENT", git_committer_info },
@ -57,6 +57,8 @@ int main(int argc, char **argv)
if (argc != 2) {
usage(var_usage);
}
setup_git_directory();
setup_ident();
val = NULL;