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:
commit
93dcab2937
1
.gitignore
vendored
1
.gitignore
vendored
@ -75,6 +75,7 @@ git-rebase
|
||||
git-receive-pack
|
||||
git-relink
|
||||
git-repack
|
||||
git-repo-config
|
||||
git-request-pull
|
||||
git-reset
|
||||
git-resolve
|
||||
|
@ -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
|
||||
--------------
|
||||
|
170
Documentation/git-repo-config.txt
Normal file
170
Documentation/git-repo-config.txt
Normal 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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
105
Documentation/howto/update-hook-example.txt
Normal file
105
Documentation/howto/update-hook-example.txt
Normal 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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
69
Makefile
69
Makefile
@ -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)
|
||||
|
8
cache.h
8
cache.h
@ -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
340
config.c
@ -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
166
connect.c
@ -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
140
daemon.c
@ -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
6
debian/changelog
vendored
@ -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
|
||||
|
@ -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], "--")) {
|
||||
|
@ -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];
|
||||
|
@ -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] == '-') {
|
||||
|
56
diff-tree.c
56
diff-tree.c
@ -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
39
diff.c
@ -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
1
diff.h
@ -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 *);
|
||||
|
@ -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);
|
||||
|
@ -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>"
|
||||
|
@ -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]"
|
||||
|
@ -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
|
||||
##
|
||||
|
@ -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]
|
||||
|
@ -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]]
|
||||
|
@ -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 -- "$@"
|
||||
|
@ -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>]
|
||||
|
||||
|
@ -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)
|
||||
;;
|
||||
*)
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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 ||
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,5 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
. git-sh-setup
|
||||
|
||||
usage () {
|
||||
echo >&2 "usage: $0 [--heads] [--tags] <repository> <refs>..."
|
||||
|
@ -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"
|
||||
;;
|
||||
|
@ -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):
|
||||
|
22
git-merge.sh
22
git-merge.sh
@ -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
|
||||
|
25
git-mv.perl
25
git-mv.perl
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
. git-sh-setup || die "Not a git archive"
|
||||
. git-sh-setup
|
||||
|
||||
dryrun=
|
||||
echo=
|
||||
|
@ -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]
|
||||
|
@ -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>]"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>]'
|
||||
|
@ -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>"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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="#
|
||||
|
@ -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>]"
|
||||
|
@ -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
2
git.c
@ -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
265
gitk
@ -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
|
||||
}
|
||||
|
825
http-fetch.c
825
http-fetch.c
File diff suppressed because it is too large
Load Diff
805
http-push.c
805
http-push.c
File diff suppressed because it is too large
Load Diff
442
http.c
Normal file
442
http.c
Normal 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
95
http.h
Normal 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
15
ident.c
@ -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"));
|
||||
}
|
||||
|
@ -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++)
|
||||
|
@ -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) {
|
||||
|
128
pack-redundant.c
128
pack-redundant.c
@ -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
115
path.c
@ -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;
|
||||
}
|
||||
|
@ -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
40
refs.c
@ -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
116
repo-config.c
Normal 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;
|
||||
}
|
@ -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
42
setup.c
@ -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;
|
||||
}
|
||||
|
17
sha1_name.c
17
sha1_name.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
271
t/t1300-repo-config.sh
Normal 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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
4
var.c
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user