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>maint v0.99.9k
commit
93dcab2937
|
@ -75,6 +75,7 @@ git-rebase
|
||||||
git-receive-pack
|
git-receive-pack
|
||||||
git-relink
|
git-relink
|
||||||
git-repack
|
git-repack
|
||||||
|
git-repo-config
|
||||||
git-request-pull
|
git-request-pull
|
||||||
git-reset
|
git-reset
|
||||||
git-resolve
|
git-resolve
|
||||||
|
|
|
@ -8,7 +8,7 @@ git-daemon - A really simple server for git repositories.
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
|
'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
|
||||||
[--timeout=n] [--init-timeout=n] [directory...]
|
[--timeout=n] [--init-timeout=n] [--strict-paths] [directory...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
@ -29,9 +29,15 @@ This is ideally suited for read-only updates, ie pulling from git repositories.
|
||||||
|
|
||||||
OPTIONS
|
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::
|
--export-all::
|
||||||
Allow pulling from all directories that look like GIT repositories
|
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.
|
do not have the 'git-daemon-export-ok' file.
|
||||||
|
|
||||||
--inetd::
|
--inetd::
|
||||||
|
@ -57,9 +63,15 @@ OPTIONS
|
||||||
--verbose::
|
--verbose::
|
||||||
Log details about the incoming connections and requested files.
|
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
|
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
|
Documentation
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -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
|
Sets the current head to the specified commit and optionally resets the
|
||||||
index and working tree to match.
|
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
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
--mixed::
|
--mixed::
|
||||||
Like --soft but reports what has not been updated. This is the
|
Resets the index but not the working tree (ie, the changed files
|
||||||
default action.
|
are preserved but not marked for commit) and reports what has not
|
||||||
|
been updated. This is the default action.
|
||||||
|
|
||||||
--soft::
|
--soft::
|
||||||
Does not touch the index file nor the working tree at all, but
|
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::
|
--hard::
|
||||||
Matches the working tree and index to that of the tree being
|
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-ish>::
|
||||||
Commit to make the current HEAD.
|
Commit to make the current HEAD.
|
||||||
|
|
|
@ -108,6 +108,9 @@ gitlink:git-prune-packed[1]::
|
||||||
gitlink:git-read-tree[1]::
|
gitlink:git-read-tree[1]::
|
||||||
Reads tree information into the directory index
|
Reads tree information into the directory index
|
||||||
|
|
||||||
|
gitlink:git-repo-config[1]::
|
||||||
|
Get and set options in .git/config.
|
||||||
|
|
||||||
gitlink:git-unpack-objects[1]::
|
gitlink:git-unpack-objects[1]::
|
||||||
Unpacks objects out of a packed archive.
|
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
|
$ git checkout master
|
||||||
$ cd Documentation; ed git.txt ...
|
$ cd Documentation; ed git.txt ...
|
||||||
$ cd ..; git add Documentation/*.txt
|
$ cd ..; git add Documentation/*.txt
|
||||||
$ git commit -s -v
|
$ git commit -s
|
||||||
|
|
||||||
NOTE. The -v flag to commit is a handy way to make sure that
|
|
||||||
your additions are not introducing bogusly formatted lines.
|
|
||||||
|
|
||||||
After the commit, the ancestry graph would look like this:
|
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.
|
Let's go back to the earlier picture, with different labels.
|
||||||
|
|
||||||
You, as an individual developer, cloned upstream repository and
|
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
|
*your "master" head
|
||||||
upstream --> #1 --> #2 --> #3
|
upstream --> #1 --> #2 --> #3
|
||||||
|
|
|
@ -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:
|
to name the remote repository:
|
||||||
+
|
+
|
||||||
===============================================================
|
===============================================================
|
||||||
- Rsync URL: rsync://remote.machine/path/to/repo.git/
|
- rsync://host.xz/path/to/repo.git/
|
||||||
- HTTP(s) URL: http://remote.machine/path/to/repo.git/
|
- http://host.xz/path/to/repo.git/
|
||||||
- git URL: git://remote.machine/path/to/repo.git/
|
- https://host.xz/path/to/repo.git/
|
||||||
- ssh URL: remote.machine:/path/to/repo.git/
|
- git://host.xz/path/to/repo.git/
|
||||||
- Local directory: /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
|
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.
|
the "project lead" person does.
|
||||||
|
|
||||||
3. Copy over the packed files from "project lead" public
|
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
|
4. Push into the public repository from your primary
|
||||||
repository. Run `git repack`, and possibly `git prune` if the
|
repository. Run `git repack`, and possibly `git prune` if the
|
||||||
|
|
61
Makefile
61
Makefile
|
@ -50,7 +50,7 @@
|
||||||
# Define USE_STDEV below if you want git to care about the underlying device
|
# 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.
|
# 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.
|
# CFLAGS and LDFLAGS are for the users to override from the command line.
|
||||||
|
|
||||||
|
@ -102,6 +102,11 @@ SCRIPT_PERL = \
|
||||||
SCRIPT_PYTHON = \
|
SCRIPT_PYTHON = \
|
||||||
git-merge-recursive.py
|
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.
|
# The ones that do not have to link with lcrypto nor lz.
|
||||||
SIMPLE_PROGRAMS = \
|
SIMPLE_PROGRAMS = \
|
||||||
git-get-tar-commit-id$X git-mailinfo$X git-mailsplit$X \
|
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-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-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-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
|
# Backward compatibility -- to be removed after 1.0
|
||||||
PROGRAMS += git-ssh-pull$X git-ssh-push$X
|
PROGRAMS += git-ssh-pull$X git-ssh-push$X
|
||||||
|
|
||||||
GIT_LIST_TWEAK =
|
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 = \
|
PYMODULES = \
|
||||||
gitMergeCommon.py
|
gitMergeCommon.py
|
||||||
|
|
||||||
ifdef WITH_OWN_SUBPROCESS_PY
|
ifdef WITH_OWN_SUBPROCESS_PY
|
||||||
PYMODULES += compat/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
|
endif
|
||||||
|
|
||||||
ifdef WITH_SEND_EMAIL
|
ifdef WITH_SEND_EMAIL
|
||||||
|
@ -242,20 +265,13 @@ ifndef NO_CURL
|
||||||
CURL_LIBCURL = -lcurl
|
CURL_LIBCURL = -lcurl
|
||||||
endif
|
endif
|
||||||
PROGRAMS += git-http-fetch$X
|
PROGRAMS += git-http-fetch$X
|
||||||
|
curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p)
|
||||||
|
ifeq "$(curl_check)" "070908"
|
||||||
ifndef NO_EXPAT
|
ifndef NO_EXPAT
|
||||||
EXPAT_LIBEXPAT = -lexpat
|
EXPAT_LIBEXPAT = -lexpat
|
||||||
PROGRAMS += git-http-push$X
|
PROGRAMS += git-http-push$X
|
||||||
endif
|
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
|
endif
|
||||||
|
|
||||||
ifndef NO_OPENSSL
|
ifndef NO_OPENSSL
|
||||||
|
@ -330,25 +346,20 @@ endif
|
||||||
|
|
||||||
ALL_CFLAGS += -DSHA1_HEADER=$(call shellquote,$(SHA1_HEADER))
|
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
|
export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
|
||||||
### Build rules
|
### Build rules
|
||||||
|
|
||||||
all: $(PROGRAMS) $(SCRIPTS) git
|
all: $(ALL_PROGRAMS)
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(MAKE) -C templates
|
$(MAKE) -C templates
|
||||||
|
|
||||||
# Only use $(CFLAGS). We don't need anything else.
|
# 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)"' \
|
$(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 $@
|
rm -f $@
|
||||||
sed -e '1s|#!.*/sh|#!$(call shq,$(SHELL_PATH))|' \
|
sed -e '1s|#!.*/sh|#!$(call shq,$(SHELL_PATH))|' \
|
||||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||||
|
@ -387,7 +398,8 @@ $(SIMPLE_PROGRAMS) : git-%$X : %.o
|
||||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||||
$(LIB_FILE) $(SIMPLE_LIB)
|
$(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-local-fetch$X: fetch.o
|
||||||
git-ssh-fetch$X: rsh.o fetch.o
|
git-ssh-fetch$X: rsh.o fetch.o
|
||||||
git-ssh-upload$X: rsh.o
|
git-ssh-upload$X: rsh.o
|
||||||
|
@ -431,9 +443,9 @@ check:
|
||||||
|
|
||||||
### Installation rules
|
### Installation rules
|
||||||
|
|
||||||
install: $(PROGRAMS) $(SCRIPTS) git
|
install: all
|
||||||
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))
|
$(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
|
$(MAKE) -C templates install
|
||||||
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
|
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
|
||||||
$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
|
$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
|
||||||
|
@ -470,7 +482,8 @@ deb: dist
|
||||||
### Cleaning rules
|
### Cleaning rules
|
||||||
|
|
||||||
clean:
|
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 $(filter-out gitk,$(SCRIPTS))
|
||||||
rm -f *.spec *.pyc *.pyo
|
rm -f *.spec *.pyc *.pyo
|
||||||
rm -rf $(GIT_TARNAME)
|
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);
|
int safe_create_leading_directories(char *path);
|
||||||
char *safe_strncpy(char *, const char *, size_t);
|
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 */
|
/* 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);
|
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 *);
|
unsigned long approxidate(const char *);
|
||||||
|
|
||||||
extern int setup_ident(void);
|
extern int setup_ident(void);
|
||||||
extern char *get_ident(const char *name, const char *email, const char *date_str);
|
extern const char *git_author_info(void);
|
||||||
extern char *git_author_info(void);
|
extern const char *git_committer_info(void);
|
||||||
extern char *git_committer_info(void);
|
|
||||||
|
|
||||||
static inline void *xmalloc(size_t size)
|
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(config_fn_t fn);
|
||||||
extern int git_config_int(const char *, const char *);
|
extern int git_config_int(const char *, const char *);
|
||||||
extern int git_config_bool(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)
|
#define MAX_GITNAME (1000)
|
||||||
extern char git_default_email[MAX_GITNAME];
|
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 "cache.h"
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#define MAXNAME (256)
|
#define MAXNAME (256)
|
||||||
|
|
||||||
|
@ -136,7 +143,7 @@ static int get_base_var(char *name)
|
||||||
return -1;
|
return -1;
|
||||||
if (c == ']')
|
if (c == ']')
|
||||||
return baselen;
|
return baselen;
|
||||||
if (!isalnum(c))
|
if (!isalnum(c) && c != '.')
|
||||||
return -1;
|
return -1;
|
||||||
if (baselen > MAXNAME / 2)
|
if (baselen > MAXNAME / 2)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -229,11 +236,6 @@ int git_default_config(const char *var, const char *value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(var, "diff.renamelimit")) {
|
|
||||||
diff_rename_limit_default = git_config_int(var, value);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add other config variables here.. */
|
/* Add other config variables here.. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -252,3 +254,327 @@ int git_config(config_fn_t fn)
|
||||||
}
|
}
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
164
connect.c
164
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);
|
memset(&sa, 0, sizeof sa);
|
||||||
sa.sin_family = he->h_addrtype;
|
sa.sin_family = he->h_addrtype;
|
||||||
sa.sin_port = htons(nport);
|
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) {
|
if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
|
@ -448,42 +448,162 @@ static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path)
|
||||||
|
|
||||||
#endif /* NO_IPV6 */
|
#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.
|
* Yeah, yeah, fixme. Need to pass in the heads etc.
|
||||||
*/
|
*/
|
||||||
int git_connect(int fd[2], char *url, const char *prog)
|
int git_connect(int fd[2], char *url, const char *prog)
|
||||||
{
|
{
|
||||||
char command[1024];
|
char command[1024];
|
||||||
char *host, *path;
|
char *host, *path = url;
|
||||||
char *colon;
|
char *colon = NULL;
|
||||||
int pipefd[2][2];
|
int pipefd[2][2];
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
enum protocol protocol;
|
enum protocol protocol = PROTO_LOCAL;
|
||||||
|
|
||||||
host = NULL;
|
host = strstr(url, "://");
|
||||||
path = url;
|
if(host) {
|
||||||
colon = strchr(url, ':');
|
*host = '\0';
|
||||||
protocol = PROTO_LOCAL;
|
|
||||||
if (colon) {
|
|
||||||
*colon = 0;
|
|
||||||
host = url;
|
|
||||||
path = colon+1;
|
|
||||||
protocol = PROTO_SSH;
|
|
||||||
if (!memcmp(path, "//", 2)) {
|
|
||||||
char *slash = strchr(path + 2, '/');
|
|
||||||
if (slash) {
|
|
||||||
int nr = slash - path - 2;
|
|
||||||
memmove(path, path+2, nr);
|
|
||||||
path[nr] = 0;
|
|
||||||
protocol = get_protocol(url);
|
protocol = get_protocol(url);
|
||||||
host = path;
|
host += 3;
|
||||||
path = slash;
|
path = strchr(host, '/');
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
host = url;
|
||||||
|
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);
|
return git_tcp_connect(fd, prog, host, path);
|
||||||
|
}
|
||||||
|
|
||||||
if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
|
if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
|
||||||
die("unable to create pipe pair for communication");
|
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[] =
|
static const char daemon_usage[] =
|
||||||
"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
|
"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 */
|
/* List of acceptable pathname prefixes */
|
||||||
static char **ok_paths = NULL;
|
static char **ok_paths = NULL;
|
||||||
|
static int strict_paths = 0;
|
||||||
|
|
||||||
/* If this is set, git-daemon-export-ok is not required */
|
/* If this is set, git-daemon-export-ok is not required */
|
||||||
static int export_all_trees = 0;
|
static int export_all_trees = 0;
|
||||||
|
@ -81,69 +82,52 @@ static void loginfo(const char *err, ...)
|
||||||
va_end(params);
|
va_end(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int path_ok(const char *dir)
|
static char *path_ok(char *dir)
|
||||||
{
|
{
|
||||||
const char *p = dir;
|
char *path = enter_repo(dir, strict_paths);
|
||||||
char **pp;
|
|
||||||
int sl, ndot;
|
|
||||||
|
|
||||||
/* The pathname here should be an absolute path. */
|
if (!path) {
|
||||||
if ( *p++ != '/' )
|
logerror("'%s': unable to chdir or not a git archive", dir);
|
||||||
return 0;
|
return NULL;
|
||||||
|
|
||||||
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 ( ok_paths && *ok_paths ) {
|
if ( ok_paths && *ok_paths ) {
|
||||||
int ok = 0;
|
char **pp;
|
||||||
int dirlen = strlen(dir);
|
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++ ) {
|
for ( pp = ok_paths ; *pp ; pp++ ) {
|
||||||
int len = strlen(*pp);
|
int len = strlen(*pp);
|
||||||
if ( len <= dirlen &&
|
if (len <= pathlen &&
|
||||||
!strncmp(*pp, dir, len) &&
|
!memcmp(*pp, path, len) &&
|
||||||
(dir[len] == '/' || dir[len] == '\0') ) {
|
(path[len] == '\0' ||
|
||||||
ok = 1;
|
(!strict_paths && path[len] == '/')))
|
||||||
break;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
/* be backwards compatible */
|
||||||
|
if (!strict_paths)
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
if ( !ok )
|
logerror("'%s': not in whitelist", path);
|
||||||
return 0; /* Path not in whitelist */
|
return NULL; /* Fallthrough. Deny by default */
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1; /* Path acceptable */
|
static int upload(char *dir)
|
||||||
}
|
|
||||||
|
|
||||||
static int set_dir(const char *dir)
|
|
||||||
{
|
{
|
||||||
if (!path_ok(dir)) {
|
/* Timeout as string */
|
||||||
errno = EACCES;
|
char timeout_buf[64];
|
||||||
return -1;
|
const char *path;
|
||||||
}
|
|
||||||
|
|
||||||
if ( chdir(dir) )
|
loginfo("Request for '%s'", dir);
|
||||||
|
|
||||||
|
if (!(path = path_ok(dir)))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -152,45 +136,17 @@ static int set_dir(const char *dir)
|
||||||
* We want a readable HEAD, usable "objects" directory, and
|
* We want a readable HEAD, usable "objects" directory, and
|
||||||
* a "git-daemon-export-ok" flag that says that the other side
|
* a "git-daemon-export-ok" flag that says that the other side
|
||||||
* is ok with us doing this.
|
* 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)) {
|
if (!export_all_trees && access("git-daemon-export-ok", F_OK)) {
|
||||||
|
logerror("'%s': repository not exported.", path);
|
||||||
errno = EACCES;
|
errno = EACCES;
|
||||||
return -1;
|
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
|
* We'll ignore SIGTERM from now on, we have a
|
||||||
* good client.
|
* good client.
|
||||||
|
@ -216,7 +172,7 @@ static int execute(void)
|
||||||
if (len && line[len-1] == '\n')
|
if (len && line[len-1] == '\n')
|
||||||
line[--len] = 0;
|
line[--len] = 0;
|
||||||
|
|
||||||
if (!strncmp("git-upload-pack /", line, 17))
|
if (!strncmp("git-upload-pack ", line, 16))
|
||||||
return upload(line+16);
|
return upload(line+16);
|
||||||
|
|
||||||
logerror("Protocol error: '%s'", line);
|
logerror("Protocol error: '%s'", line);
|
||||||
|
@ -510,8 +466,14 @@ static int socksetup(int port, int **socklist_p)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (listen(sockfd, 5) < 0) {
|
||||||
|
close(sockfd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
*socklist_p = xmalloc(sizeof(int));
|
*socklist_p = xmalloc(sizeof(int));
|
||||||
**socklist_p = sockfd;
|
**socklist_p = sockfd;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -617,6 +579,10 @@ int main(int argc, char **argv)
|
||||||
init_timeout = atoi(arg+15);
|
init_timeout = atoi(arg+15);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(arg, "--strict-paths")) {
|
||||||
|
strict_paths = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!strcmp(arg, "--")) {
|
if (!strcmp(arg, "--")) {
|
||||||
ok_paths = &argv[i+1];
|
ok_paths = &argv[i+1];
|
||||||
break;
|
break;
|
||||||
|
@ -631,6 +597,14 @@ int main(int argc, char **argv)
|
||||||
if (log_syslog)
|
if (log_syslog)
|
||||||
openlog("git-daemon", 0, LOG_DAEMON);
|
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) {
|
if (inetd_mode) {
|
||||||
fclose(stderr); //FIXME: workaround
|
fclose(stderr); //FIXME: workaround
|
||||||
return execute();
|
return execute();
|
||||||
|
|
|
@ -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-core (0.99.9j-0) unstable; urgency=low
|
||||||
|
|
||||||
* GIT 0.99.9j aka 1.0rc3
|
* GIT 0.99.9j aka 1.0rc3
|
||||||
|
|
|
@ -38,7 +38,7 @@ int main(int argc, const char **argv)
|
||||||
const char *prefix = setup_git_directory();
|
const char *prefix = setup_git_directory();
|
||||||
int entries, i;
|
int entries, i;
|
||||||
|
|
||||||
git_config(git_default_config);
|
git_config(git_diff_config);
|
||||||
diff_setup(&diff_options);
|
diff_setup(&diff_options);
|
||||||
while (1 < argc && argv[1][0] == '-') {
|
while (1 < argc && argv[1][0] == '-') {
|
||||||
if (!strcmp(argv[1], "--")) {
|
if (!strcmp(argv[1], "--")) {
|
||||||
|
|
|
@ -180,7 +180,7 @@ int main(int argc, const char **argv)
|
||||||
int allow_options = 1;
|
int allow_options = 1;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
git_config(git_default_config);
|
git_config(git_diff_config);
|
||||||
diff_setup(&diff_options);
|
diff_setup(&diff_options);
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
const char *arg = argv[i];
|
const char *arg = argv[i];
|
||||||
|
|
|
@ -55,6 +55,9 @@ int main(int ac, const char **av)
|
||||||
{
|
{
|
||||||
int stage1, stage2;
|
int stage1, stage2;
|
||||||
|
|
||||||
|
setup_git_directory();
|
||||||
|
|
||||||
|
git_config(git_diff_config);
|
||||||
read_cache();
|
read_cache();
|
||||||
diff_setup(&diff_options);
|
diff_setup(&diff_options);
|
||||||
while (1 < ac && av[1][0] == '-') {
|
while (1 < ac && av[1][0] == '-') {
|
||||||
|
|
54
diff-tree.c
54
diff-tree.c
|
@ -69,52 +69,50 @@ static int diff_root_tree(const unsigned char *new, const char *base)
|
||||||
return retval;
|
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];
|
static char this_header[16384];
|
||||||
int offset;
|
int offset;
|
||||||
|
unsigned long len;
|
||||||
|
|
||||||
if (!verbose_header)
|
if (!verbose_header)
|
||||||
return commit;
|
return commit;
|
||||||
|
|
||||||
|
len = strlen(msg);
|
||||||
offset = sprintf(this_header, "%s%s (from %s)\n", header_prefix, commit, parent);
|
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);
|
offset += pretty_print_commit(commit_format, msg, len, this_header + offset, sizeof(this_header) - offset);
|
||||||
return this_header;
|
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;
|
struct commit *commit;
|
||||||
char *buf = read_object_with_reference(commit, "commit", &size, NULL);
|
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;
|
return -1;
|
||||||
|
name[40] = 0;
|
||||||
if (!name) {
|
commit = lookup_commit(sha1);
|
||||||
static char commit_name[60];
|
|
||||||
strcpy(commit_name, sha1_to_hex(commit));
|
|
||||||
name = commit_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Root commit? */
|
/* Root commit? */
|
||||||
if (show_root_diff && memcmp(buf + 46, "parent ", 7)) {
|
if (show_root_diff && !commit->parents) {
|
||||||
header = generate_header(name, "root", buf, size);
|
header = generate_header(name, "root", commit->buffer);
|
||||||
diff_root_tree(commit, "");
|
diff_root_tree(commit_sha1, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* More than one parent? */
|
/* More than one parent? */
|
||||||
if (ignore_merges) {
|
if (ignore_merges && commit->parents && commit->parents->next)
|
||||||
if (!memcmp(buf + 46 + 48, "parent ", 7))
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
offset = 46;
|
for (parents = commit->parents; parents; parents = parents->next) {
|
||||||
while (offset + 48 < size && !memcmp(buf + offset, "parent ", 7)) {
|
struct commit *parent = parents->item;
|
||||||
unsigned char parent[20];
|
header = generate_header(name,
|
||||||
if (get_sha1_hex(buf + offset + 7, parent))
|
sha1_to_hex(parent->object.sha1),
|
||||||
return -1;
|
commit->buffer);
|
||||||
header = generate_header(name, sha1_to_hex(parent), buf, size);
|
diff_tree_sha1_top(parent->object.sha1, commit_sha1, "");
|
||||||
diff_tree_sha1_top(parent, commit, "");
|
|
||||||
if (!header && verbose_header) {
|
if (!header && verbose_header) {
|
||||||
header_prefix = "\ndiff-tree ";
|
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.
|
* don't print the diffs.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
offset += 48;
|
|
||||||
}
|
}
|
||||||
free(buf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +143,7 @@ static int diff_tree_stdin(char *line)
|
||||||
return diff_tree_sha1_top(parent, commit, "");
|
return diff_tree_sha1_top(parent, commit, "");
|
||||||
}
|
}
|
||||||
line[40] = 0;
|
line[40] = 0;
|
||||||
return diff_tree_commit(commit, line);
|
return diff_tree_commit(commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char diff_tree_usage[] =
|
static const char diff_tree_usage[] =
|
||||||
|
@ -164,7 +160,7 @@ int main(int argc, const char **argv)
|
||||||
unsigned char sha1[2][20];
|
unsigned char sha1[2][20];
|
||||||
const char *prefix = setup_git_directory();
|
const char *prefix = setup_git_directory();
|
||||||
|
|
||||||
git_config(git_default_config);
|
git_config(git_diff_config);
|
||||||
nr_sha1 = 0;
|
nr_sha1 = 0;
|
||||||
diff_setup(&diff_options);
|
diff_setup(&diff_options);
|
||||||
|
|
||||||
|
@ -250,7 +246,7 @@ int main(int argc, const char **argv)
|
||||||
usage(diff_tree_usage);
|
usage(diff_tree_usage);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
diff_tree_commit(sha1[0], NULL);
|
diff_tree_commit(sha1[0]);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
diff_tree_sha1_top(sha1[0], sha1[1], "");
|
diff_tree_sha1_top(sha1[0], sha1[1], "");
|
||||||
|
|
37
diff.c
37
diff.c
|
@ -15,6 +15,16 @@ static int use_size_cache;
|
||||||
|
|
||||||
int diff_rename_limit_default = -1;
|
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)
|
static char *quote_one(const char *str)
|
||||||
{
|
{
|
||||||
int needlen;
|
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)
|
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;
|
const char *cp = *cp_p;
|
||||||
|
|
||||||
cnt = num = 0;
|
num = 0;
|
||||||
scale = 1;
|
scale = 1;
|
||||||
while ('0' <= (ch = *cp) && ch <= '9') {
|
dot = 0;
|
||||||
if (cnt++ < 5) {
|
for(;;) {
|
||||||
/* We simply ignore more than 5 digits precision. */
|
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;
|
scale *= 10;
|
||||||
num = num * 10 + ch - '0';
|
num = (num*10) + (ch-'0');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
cp++;
|
cp++;
|
||||||
}
|
}
|
||||||
|
@ -856,7 +879,7 @@ static int parse_num(const char **cp_p)
|
||||||
/* user says num divided by scale and we say internally that
|
/* user says num divided by scale and we say internally that
|
||||||
* is MAX_SCORE * num / scale.
|
* 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)
|
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_CACHE 2
|
||||||
#define DIFF_SETUP_USE_SIZE_CACHE 4
|
#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 void diff_setup(struct diff_options *);
|
||||||
extern int diff_opt_parse(struct diff_options *, const char **, int);
|
extern int diff_opt_parse(struct diff_options *, const char **, int);
|
||||||
extern int diff_setup_done(struct diff_options *);
|
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)
|
if (rename_count == rename_dst_nr)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
if (minimum_score == MAX_SCORE)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
num_create = (rename_dst_nr - rename_count);
|
num_create = (rename_dst_nr - rename_count);
|
||||||
num_src = rename_src_nr;
|
num_src = rename_src_nr;
|
||||||
mx = xmalloc(sizeof(*mx) * num_create * num_src);
|
mx = xmalloc(sizeof(*mx) * num_create * num_src);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
echo >&2 "usage: $0 [--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] <mbox>"
|
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-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 () {
|
usage () {
|
||||||
echo >&2 "applymbox [-u] [-k] [-q] [-m] (-c .dotest/<num> | mbox) [signoff]"
|
echo >&2 "applymbox [-u] [-k] [-q] [-m] (-c .dotest/<num> | mbox) [signoff]"
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
## $3 - "info" file with Author, email and subject
|
## $3 - "info" file with Author, email and subject
|
||||||
## $4 - optional file containing signoff to add
|
## $4 - optional file containing signoff to add
|
||||||
##
|
##
|
||||||
. git-sh-setup || die "Not a git archive."
|
. git-sh-setup
|
||||||
|
|
||||||
final=.dotest/final-commit
|
final=.dotest/final-commit
|
||||||
##
|
##
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. git-sh-setup || dir "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo >&2 'usage: git bisect [start|bad|good|next|reset|visualize]
|
echo >&2 'usage: git bisect [start|bad|good|next|reset|visualize]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
echo >&2 "usage: $(basename $0)"' [-d <branch>] | [[-f] <branch> [start-point]]
|
echo >&2 "usage: $(basename $0)"' [-d <branch>] | [[-f] <branch> [start-point]]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
die "usage: git checkout [-f] [-b <new_branch>] [<branch>] [<paths>...]"
|
die "usage: git checkout [-f] [-b <new_branch>] [<branch>] [<paths>...]"
|
||||||
|
@ -82,7 +82,6 @@ then
|
||||||
# rescuing paths and is never meant to remove what
|
# rescuing paths and is never meant to remove what
|
||||||
# is not in the named tree-ish.
|
# is not in the named tree-ish.
|
||||||
git-ls-tree -r "$new" "$@" |
|
git-ls-tree -r "$new" "$@" |
|
||||||
sed -ne 's/^\([0-7]*\) blob \(.*\)$/\1 \2/p' |
|
|
||||||
git-update-index --index-info || exit $?
|
git-update-index --index-info || exit $?
|
||||||
fi
|
fi
|
||||||
git-checkout-index -f -u -- "$@"
|
git-checkout-index -f -u -- "$@"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Copyright (c) 2005 Junio C Hamano.
|
# Copyright (c) 2005 Junio C Hamano.
|
||||||
#
|
#
|
||||||
|
|
||||||
. git-sh-setup || die "Not a git archive."
|
. git-sh-setup
|
||||||
|
|
||||||
usage="usage: $0 "'[-v] <upstream> [<head>]
|
usage="usage: $0 "'[-v] <upstream> [<head>]
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Copyright (c) 2005 Linus Torvalds
|
# Copyright (c) 2005 Linus Torvalds
|
||||||
#
|
#
|
||||||
|
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
die 'git commit [-a] [-s] [-v | --no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit>] [-e] [<path>...]'
|
die 'git commit [-a] [-s] [-v | --no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit>] [-e] [<path>...]'
|
||||||
|
@ -92,10 +92,13 @@ tt*)
|
||||||
esac
|
esac
|
||||||
|
|
||||||
case "$all,$#" in
|
case "$all,$#" in
|
||||||
t,*)
|
t,0)
|
||||||
git-diff-files --name-only -z |
|
git-diff-files --name-only -z |
|
||||||
git-update-index --remove -z --stdin
|
git-update-index --remove -z --stdin
|
||||||
;;
|
;;
|
||||||
|
t,*)
|
||||||
|
die "Cannot use -a and explicit files at the same time."
|
||||||
|
;;
|
||||||
,0)
|
,0)
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
|
|
@ -1,7 +1,25 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2005 Junio C Hamano
|
||||||
|
#
|
||||||
|
|
||||||
. git-sh-setup
|
. 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 $(find "$GIT_DIR/objects"/?? -type f -print 2>/dev/null | wc -l) objects, \
|
||||||
$({
|
$({
|
||||||
echo 0
|
echo 0
|
||||||
|
|
|
@ -502,7 +502,7 @@ unless($pid) {
|
||||||
if ($opt_P) {
|
if ($opt_P) {
|
||||||
exec("cat", $opt_P);
|
exec("cat", $opt_P);
|
||||||
} else {
|
} 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";
|
die "Could not start cvsps: $!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
. git-parse-remote
|
. git-parse-remote
|
||||||
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
|
_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"
|
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Copyright (c) 2005 Junio C Hamano
|
# Copyright (c) 2005 Junio C Hamano
|
||||||
#
|
#
|
||||||
|
|
||||||
. git-sh-setup || die "Not a git archive."
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
|
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
|
# Also, "rev1.." should mean "rev1..HEAD"; git-diff users are
|
||||||
# familiar with that syntax.
|
# familiar with that syntax.
|
||||||
|
|
||||||
case "$#,$1" in
|
case "$#,$1$2" in
|
||||||
1,?*..?*)
|
1,?*..?*)
|
||||||
# single "rev1..rev2"
|
# single "rev1..rev2"
|
||||||
;;
|
;;
|
||||||
|
@ -131,7 +131,8 @@ do
|
||||||
rev2=`expr "$revpair" : '.*\.\.\(.*\)'`
|
rev2=`expr "$revpair" : '.*\.\.\(.*\)'`
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
usage
|
rev1="$revpair^"
|
||||||
|
rev2="$revpair"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
git-rev-parse --verify "$rev1^0" >/dev/null 2>&1 ||
|
git-rev-parse --verify "$rev1^0" >/dev/null 2>&1 ||
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
. git-sh-setup || die "Not a git archive."
|
. git-sh-setup
|
||||||
|
|
||||||
laf="$GIT_DIR/lost-found"
|
laf="$GIT_DIR/lost-found"
|
||||||
rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit
|
rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
. git-sh-setup
|
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
echo >&2 "usage: $0 [--heads] [--tags] <repository> <refs>..."
|
echo >&2 "usage: $0 [--heads] [--tags] <repository> <refs>..."
|
||||||
|
|
|
@ -25,7 +25,8 @@ case "${1:-.}${2:-.}${3:-.}" in
|
||||||
echo "Removing $4"
|
echo "Removing $4"
|
||||||
fi
|
fi
|
||||||
if test -f "$4"; then
|
if test -f "$4"; then
|
||||||
rm -f -- "$4"
|
rm -f -- "$4" &&
|
||||||
|
rmdir -p "$(expr "$4" : '\(.*\)/')" 2>/dev/null
|
||||||
fi &&
|
fi &&
|
||||||
exec git-update-index --remove -- "$4"
|
exec git-update-index --remove -- "$4"
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -245,7 +245,7 @@ def updateFileExt(sha, mode, path, updateCache, updateWd):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
createDir = not stat.S_ISDIR(os.lstat(p).st_mode)
|
createDir = not stat.S_ISDIR(os.lstat(p).st_mode)
|
||||||
except:
|
except OSError:
|
||||||
createDir = True
|
createDir = True
|
||||||
|
|
||||||
if createDir:
|
if createDir:
|
||||||
|
@ -293,6 +293,10 @@ def removeFile(clean, path):
|
||||||
except OSError, e:
|
except OSError, e:
|
||||||
if e.errno != errno.ENOENT and e.errno != errno.EISDIR:
|
if e.errno != errno.ENOENT and e.errno != errno.EISDIR:
|
||||||
raise
|
raise
|
||||||
|
try:
|
||||||
|
os.removedirs(os.path.dirname(path))
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
def uniquePath(path, branch):
|
def uniquePath(path, branch):
|
||||||
def fileExists(path):
|
def fileExists(path):
|
||||||
|
|
22
git-merge.sh
22
git-merge.sh
|
@ -3,7 +3,7 @@
|
||||||
# Copyright (c) 2005 Junio C Hamano
|
# Copyright (c) 2005 Junio C Hamano
|
||||||
#
|
#
|
||||||
|
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
LF='
|
LF='
|
||||||
'
|
'
|
||||||
|
@ -12,10 +12,8 @@ usage () {
|
||||||
die "git-merge [-n] [--no-commit] [-s <strategy>]... <merge-message> <head> <remote>+"
|
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'
|
all_strategies='recursive octopus resolve stupid ours'
|
||||||
default_strategies='resolve octopus'
|
default_strategies='recursive'
|
||||||
use_strategies=
|
use_strategies=
|
||||||
|
|
||||||
dropsave() {
|
dropsave() {
|
||||||
|
@ -90,11 +88,6 @@ do
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
case "$use_strategies" in
|
|
||||||
'')
|
|
||||||
use_strategies=$default_strategies
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
test "$#" -le 2 && usage ;# we need at least two heads.
|
test "$#" -le 2 && usage ;# we need at least two heads.
|
||||||
|
|
||||||
merge_msg="$1"
|
merge_msg="$1"
|
||||||
|
@ -185,6 +178,17 @@ case "$#,$common,$no_commit" in
|
||||||
;;
|
;;
|
||||||
esac
|
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
|
# At this point, we need a real merge. No matter what strategy
|
||||||
# we use, it would operate on the index, possibly affecting the
|
# we use, it would operate on the index, possibly affecting the
|
||||||
# working tree, and when resolved cleanly, have the desired tree
|
# working tree, and when resolved cleanly, have the desired tree
|
||||||
|
|
19
git-mv.perl
19
git-mv.perl
|
@ -103,14 +103,23 @@ while(scalar @srcArgs > 0) {
|
||||||
$bad = "bad source '$src'";
|
$bad = "bad source '$src'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$safesrc = quotemeta($src);
|
||||||
|
@srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
|
||||||
|
|
||||||
$overwritten{$dst} = 0;
|
$overwritten{$dst} = 0;
|
||||||
if (($bad eq "") && -e $dst) {
|
if (($bad eq "") && -e $dst) {
|
||||||
$bad = "destination '$dst' already exists";
|
$bad = "destination '$dst' already exists";
|
||||||
if (-f $dst && $opt_f) {
|
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";
|
print "Warning: $bad; will overwrite!\n";
|
||||||
$bad = "";
|
$bad = "";
|
||||||
$overwritten{$dst} = 1;
|
$overwritten{$dst} = 1;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$bad = "Can not overwrite '$src' with '$dst'";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($bad eq "") && ($src eq $dstDir)) {
|
if (($bad eq "") && ($src eq $dstDir)) {
|
||||||
|
@ -118,8 +127,6 @@ while(scalar @srcArgs > 0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($bad eq "") {
|
if ($bad eq "") {
|
||||||
$safesrc = quotemeta($src);
|
|
||||||
@srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
|
|
||||||
if (scalar @srcfiles == 0) {
|
if (scalar @srcfiles == 0) {
|
||||||
$bad = "'$src' not under version control";
|
$bad = "'$src' not under version control";
|
||||||
}
|
}
|
||||||
|
@ -166,10 +173,12 @@ while(scalar @srcs > 0) {
|
||||||
|
|
||||||
push @deletedfiles, @srcfiles;
|
push @deletedfiles, @srcfiles;
|
||||||
if (scalar @srcfiles == 1) {
|
if (scalar @srcfiles == 1) {
|
||||||
|
# $dst can be a directory with 1 file inside
|
||||||
if ($overwritten{$dst} ==1) {
|
if ($overwritten{$dst} ==1) {
|
||||||
push @changedfiles, $dst;
|
push @changedfiles, $dstfiles[0];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
push @addedfiles, $dst;
|
push @addedfiles, $dstfiles[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#
|
#
|
||||||
# Resolve two or more trees recorded in $GIT_DIR/FETCH_HEAD.
|
# Resolve two or more trees recorded in $GIT_DIR/FETCH_HEAD.
|
||||||
#
|
#
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
die "usage: git octopus"
|
die "usage: git octopus"
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#!/bin/sh
|
#!/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 () {
|
get_data_source () {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
dryrun=
|
dryrun=
|
||||||
echo=
|
echo=
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#
|
#
|
||||||
# Fetch one or more remote refs and merge it/them into the current HEAD.
|
# 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 () {
|
usage () {
|
||||||
echo >&2 "usage: $0"' [-n] [--no-commit] [--no-summary] [--help]
|
echo >&2 "usage: $0"' [-n] [--no-commit] [--no-summary] [--help]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
die "Usage: git push [--all] [--force] <repository> [<refspec>]"
|
die "Usage: git push [--all] [--force] <repository> [<refspec>]"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Copyright (c) 2005 Junio C Hamano.
|
# Copyright (c) 2005 Junio C Hamano.
|
||||||
#
|
#
|
||||||
|
|
||||||
. git-sh-setup || die "Not a git archive."
|
. git-sh-setup
|
||||||
|
|
||||||
# The other head is given
|
# The other head is given
|
||||||
other=$(git-rev-parse --verify "$1^0") || exit
|
other=$(git-rev-parse --verify "$1^0") || exit
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Copyright (c) 2005 Linus Torvalds
|
# 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=
|
no_update_info= all_into_one= remove_redundant= local=
|
||||||
while case "$#" in 0) break ;; esac
|
while case "$#" in 0) break ;; esac
|
||||||
|
@ -32,24 +32,20 @@ case ",$all_into_one," in
|
||||||
rev_list=
|
rev_list=
|
||||||
rev_parse='--all'
|
rev_parse='--all'
|
||||||
pack_objects=
|
pack_objects=
|
||||||
|
|
||||||
|
# Redundancy check in all-into-one case is trivial.
|
||||||
|
existing=`cd "$PACKDIR" && \
|
||||||
|
find . -type f \( -name '*.pack' -o -name '*.idx' \) -print`
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
if [ "$local" ]; then
|
if [ "$local" ]; then
|
||||||
pack_objects="$pack_objects --local"
|
pack_objects="$pack_objects --local"
|
||||||
fi
|
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) ||
|
git-pack-objects --non-empty $pack_objects .tmp-pack) ||
|
||||||
exit 1
|
exit 1
|
||||||
if [ -z "$name" ]; then
|
if [ -z "$name" ]; then
|
||||||
echo Nothing new to pack.
|
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
|
exit 0
|
||||||
fi
|
fi
|
||||||
echo "Pack pack-$name created."
|
echo "Pack pack-$name created."
|
||||||
|
@ -62,11 +58,12 @@ exit
|
||||||
|
|
||||||
if test "$remove_redundant" = t
|
if test "$remove_redundant" = t
|
||||||
then
|
then
|
||||||
sync
|
# We know $existing are all redundant only when
|
||||||
if test "$all_into_one" = t
|
# all-into-one is used.
|
||||||
|
if test "$all_into_one" != '' && test "$existing" != ''
|
||||||
then
|
then
|
||||||
cd "$PACKDIR"
|
sync
|
||||||
existing=`find . -type f \( -name '*.pack' -o -name '*.idx' \) -print`
|
( cd "$PACKDIR" &&
|
||||||
for e in $existing
|
for e in $existing
|
||||||
do
|
do
|
||||||
case "$e" in
|
case "$e" in
|
||||||
|
@ -74,11 +71,7 @@ then
|
||||||
*) rm -f $e ;;
|
*) rm -f $e ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
else
|
)
|
||||||
redundant=$(git-pack-redundant --all)
|
|
||||||
if test "$redundant" != "" ; then
|
|
||||||
echo $redundant | xargs rm
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
die 'Usage: git reset [--mixed | --soft | --hard] [<commit-ish>]'
|
die 'Usage: git reset [--mixed | --soft | --hard] [<commit-ish>]'
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#
|
#
|
||||||
# Resolve two trees.
|
# Resolve two trees.
|
||||||
#
|
#
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
die "git-resolve <head> <remote> <merge-message>"
|
die "git-resolve <head> <remote> <merge-message>"
|
||||||
|
|
|
@ -3,15 +3,17 @@
|
||||||
# Copyright (c) 2005 Linus Torvalds
|
# Copyright (c) 2005 Linus Torvalds
|
||||||
# Copyright (c) 2005 Junio C Hamano
|
# Copyright (c) 2005 Junio C Hamano
|
||||||
#
|
#
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
case "$0" in
|
case "$0" in
|
||||||
*-revert* )
|
*-revert* )
|
||||||
|
test -t 0 && edit=-e
|
||||||
me=revert ;;
|
me=revert ;;
|
||||||
*-cherry-pick* )
|
*-cherry-pick* )
|
||||||
|
edit=
|
||||||
me=cherry-pick ;;
|
me=cherry-pick ;;
|
||||||
* )
|
* )
|
||||||
die "What are ou talking about?" ;;
|
die "What are you talking about?" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
|
@ -33,6 +35,12 @@ do
|
||||||
--no-commi|--no-commit)
|
--no-commi|--no-commit)
|
||||||
no_commit=t
|
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)
|
-r|--r|--re|--rep|--repl|--repla|--replay)
|
||||||
replay=t
|
replay=t
|
||||||
;;
|
;;
|
||||||
|
@ -163,7 +171,7 @@ echo >&2 "Finished one $me."
|
||||||
|
|
||||||
case "$no_commit" in
|
case "$no_commit" in
|
||||||
'')
|
'')
|
||||||
git-commit -n -F .msg
|
git-commit -n -F .msg $edit
|
||||||
rm -f .msg
|
rm -f .msg
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# Set up GIT_DIR and GIT_OBJECT_DIRECTORY
|
# This is included in commands that either have to be run from the toplevel
|
||||||
# and return true if everything looks ok
|
# of the repository, or with GIT_DIR environment variable properly.
|
||||||
#
|
# If the GIT_DIR does not look like the right correct git-repository,
|
||||||
: ${GIT_DIR=.git}
|
# it dies.
|
||||||
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
|
|
||||||
|
|
||||||
# Having this variable in your environment would break scripts because
|
# Having this variable in your environment would break scripts because
|
||||||
# you would cause "cd" to be be taken to unexpected places. If you
|
# you would cause "cd" to be be taken to unexpected places. If you
|
||||||
|
@ -12,14 +11,13 @@
|
||||||
# exporting it.
|
# exporting it.
|
||||||
unset CDPATH
|
unset CDPATH
|
||||||
|
|
||||||
|
: ${GIT_DIR=.git}
|
||||||
|
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
echo >&2 "$@"
|
echo >&2 "$@"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD 2>/dev/null)" in
|
# Make sure we are in a valid repository of a vintage we understand.
|
||||||
refs/*) : ;;
|
GIT_DIR="$GIT_DIR" git-var GIT_AUTHOR_IDENT >/dev/null || exit
|
||||||
*) false ;;
|
|
||||||
esac &&
|
|
||||||
[ -d "$GIT_DIR/refs" ] &&
|
|
||||||
[ -d "$GIT_OBJECT_DIRECTORY/" ]
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2005 Linus Torvalds
|
# Copyright (c) 2005 Linus Torvalds
|
||||||
#
|
#
|
||||||
. git-sh-setup || die "Not a git archive"
|
GIT_DIR=$(git-rev-parse --git-dir) || exit
|
||||||
|
|
||||||
report () {
|
report () {
|
||||||
header="#
|
header="#
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Copyright (c) 2005 Linus Torvalds
|
# Copyright (c) 2005 Linus Torvalds
|
||||||
|
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
echo >&2 "Usage: git-tag [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <tagname> [<head>]"
|
echo >&2 "Usage: git-tag [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <tagname> [<head>]"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. git-sh-setup || die "Not a git archive"
|
. git-sh-setup
|
||||||
|
|
||||||
type="$(git-cat-file -t "$1" 2>/dev/null)" ||
|
type="$(git-cat-file -t "$1" 2>/dev/null)" ||
|
||||||
die "$1: no such object."
|
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)) {
|
while (!strncmp(exec_path, "./", 2)) {
|
||||||
exec_path += 2;
|
exec_path += 2;
|
||||||
while (*exec_path == '/')
|
while (*exec_path == '/')
|
||||||
*exec_path++;
|
exec_path++;
|
||||||
}
|
}
|
||||||
snprintf(git_command + len, sizeof(git_command) - len,
|
snprintf(git_command + len, sizeof(git_command) - len,
|
||||||
"/%s", exec_path);
|
"/%s", exec_path);
|
||||||
|
|
207
gitk
207
gitk
|
@ -60,7 +60,7 @@ proc getcommits {rargs} {
|
||||||
|
|
||||||
proc getcommitlines {commfd} {
|
proc getcommitlines {commfd} {
|
||||||
global commits parents cdate children
|
global commits parents cdate children
|
||||||
global commitlisted phase commitinfo nextupdate
|
global commitlisted phase nextupdate
|
||||||
global stopped redisplaying leftover
|
global stopped redisplaying leftover
|
||||||
|
|
||||||
set stuff [read $commfd]
|
set stuff [read $commfd]
|
||||||
|
@ -196,42 +196,44 @@ proc parsecommit {id contents listed olds} {
|
||||||
incr ncleft($p)
|
incr ncleft($p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach line [split $contents "\n"] {
|
set hdrend [string first "\n\n" $contents]
|
||||||
if {$inhdr} {
|
if {$hdrend < 0} {
|
||||||
if {$line == {}} {
|
# should never happen...
|
||||||
set inhdr 0
|
set hdrend [string length $contents]
|
||||||
} else {
|
}
|
||||||
|
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]
|
set tag [lindex $line 0]
|
||||||
if {$tag == "author"} {
|
if {$tag == "author"} {
|
||||||
set x [expr {[llength $line] - 2}]
|
set audate [lindex $line end-1]
|
||||||
set audate [lindex $line $x]
|
set auname [lrange $line 1 end-2]
|
||||||
set auname [lrange $line 1 [expr {$x - 1}]]
|
|
||||||
} elseif {$tag == "committer"} {
|
} elseif {$tag == "committer"} {
|
||||||
set x [expr {[llength $line] - 2}]
|
set comdate [lindex $line end-1]
|
||||||
set comdate [lindex $line $x]
|
set comname [lrange $line 1 end-2]
|
||||||
set comname [lrange $line 1 [expr {$x - 1}]]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 {
|
} else {
|
||||||
if {$comment == {}} {
|
set headline $comment
|
||||||
set headline [string trim $line]
|
|
||||||
} else {
|
|
||||||
append comment "\n"
|
|
||||||
}
|
}
|
||||||
if {!$listed} {
|
if {!$listed} {
|
||||||
# git-rev-list indents the comment by 4 spaces;
|
# git-rev-list indents the comment by 4 spaces;
|
||||||
# if we got this via git-cat-file, add the indentation
|
# if we got this via git-cat-file, add the indentation
|
||||||
append comment " "
|
set newcomment {}
|
||||||
|
foreach line [split $comment "\n"] {
|
||||||
|
append newcomment " "
|
||||||
|
append newcomment $line
|
||||||
|
append newcomment "\n"
|
||||||
}
|
}
|
||||||
append comment $line
|
set comment $newcomment
|
||||||
}
|
|
||||||
}
|
|
||||||
if {$audate != {}} {
|
|
||||||
set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"]
|
|
||||||
}
|
}
|
||||||
if {$comdate != {}} {
|
if {$comdate != {}} {
|
||||||
set cdate($id) $comdate
|
set cdate($id) $comdate
|
||||||
set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"]
|
|
||||||
}
|
}
|
||||||
set commitinfo($id) [list $headline $auname $audate \
|
set commitinfo($id) [list $headline $auname $audate \
|
||||||
$comname $comdate $comment]
|
$comname $comdate $comment]
|
||||||
|
@ -239,77 +241,43 @@ proc parsecommit {id contents listed olds} {
|
||||||
|
|
||||||
proc readrefs {} {
|
proc readrefs {} {
|
||||||
global tagids idtags headids idheads tagcontents
|
global tagids idtags headids idheads tagcontents
|
||||||
|
global otherrefids idotherrefs
|
||||||
|
|
||||||
set tags [glob -nocomplain -types f [gitdir]/refs/tags/*]
|
set refd [open [list | git-ls-remote [gitdir]] r]
|
||||||
foreach f $tags {
|
while {0 <= [set n [gets $refd line]]} {
|
||||||
catch {
|
if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \
|
||||||
set fd [open $f r]
|
match id path]} {
|
||||||
set line [read $fd]
|
continue
|
||||||
if {[regexp {^[0-9a-f]{40}} $line id]} {
|
}
|
||||||
set direct [file tail $f]
|
if {![regexp {^(tags|heads)/(.*)$} $path match type name]} {
|
||||||
set tagids($direct) $id
|
set type others
|
||||||
lappend idtags($id) $direct
|
set name $path
|
||||||
set tagblob [exec git-cat-file tag $id]
|
}
|
||||||
set contents [split $tagblob "\n"]
|
if {$type == "tags"} {
|
||||||
|
set tagids($name) $id
|
||||||
|
lappend idtags($id) $name
|
||||||
set obj {}
|
set obj {}
|
||||||
set type {}
|
set type {}
|
||||||
set tag {}
|
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 {
|
catch {
|
||||||
set fd [open $f r]
|
set commit [exec git-rev-parse "$id^0"]
|
||||||
set line [read $fd 40]
|
if {"$commit" != "$id"} {
|
||||||
if {[regexp {^[0-9a-f]{40}} $line id]} {
|
set tagids($name) $commit
|
||||||
set head [file tail $f]
|
lappend idtags($commit) $name
|
||||||
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 {
|
catch {
|
||||||
set fd [open $f r]
|
set tagcontents($name) [exec git-cat-file tag "$id"]
|
||||||
set line [read $fd 40]
|
}
|
||||||
if {[regexp {^[0-9a-f]{40}} $line id]} {
|
} elseif { $type == "heads" } {
|
||||||
set name "$dname[file tail $f]"
|
set headids($name) $id
|
||||||
|
lappend idheads($id) $name
|
||||||
|
} else {
|
||||||
set otherrefids($name) $id
|
set otherrefids($name) $id
|
||||||
lappend idotherrefs($id) $name
|
lappend idotherrefs($id) $name
|
||||||
}
|
}
|
||||||
close $fd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
proc error_popup msg {
|
||||||
|
@ -683,7 +651,7 @@ Use and redistribute under the terms of the GNU General Public License} \
|
||||||
}
|
}
|
||||||
|
|
||||||
proc assigncolor {id} {
|
proc assigncolor {id} {
|
||||||
global commitinfo colormap commcolors colors nextcolor
|
global colormap commcolors colors nextcolor
|
||||||
global parents nparents children nchildren
|
global parents nparents children nchildren
|
||||||
global cornercrossings crossings
|
global cornercrossings crossings
|
||||||
|
|
||||||
|
@ -783,10 +751,12 @@ proc bindline {t id} {
|
||||||
$canv bind $t <Button-1> "lineclick %x %y $id 1"
|
$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
|
global mainline mainlinearrow sidelines lthickness colormap canv
|
||||||
|
|
||||||
|
if {$delold} {
|
||||||
$canv delete lines.$id
|
$canv delete lines.$id
|
||||||
|
}
|
||||||
if {[info exists mainline($id)]} {
|
if {[info exists mainline($id)]} {
|
||||||
set t [$canv create line $mainline($id) \
|
set t [$canv create line $mainline($id) \
|
||||||
-width [expr {($xtra + 1) * $lthickness}] \
|
-width [expr {($xtra + 1) * $lthickness}] \
|
||||||
|
@ -858,7 +828,7 @@ proc drawcommitline {level} {
|
||||||
set mainline($id) [trimdiagstart $mainline($id)]
|
set mainline($id) [trimdiagstart $mainline($id)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawlines $id 0
|
drawlines $id 0 0
|
||||||
set orad [expr {$linespc / 3}]
|
set orad [expr {$linespc / 3}]
|
||||||
set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
|
set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
|
||||||
[expr $x + $orad - 1] [expr $y1 + $orad - 1] \
|
[expr $x + $orad - 1] [expr $y1 + $orad - 1] \
|
||||||
|
@ -878,6 +848,7 @@ proc drawcommitline {level} {
|
||||||
set headline [lindex $commitinfo($id) 0]
|
set headline [lindex $commitinfo($id) 0]
|
||||||
set name [lindex $commitinfo($id) 1]
|
set name [lindex $commitinfo($id) 1]
|
||||||
set date [lindex $commitinfo($id) 2]
|
set date [lindex $commitinfo($id) 2]
|
||||||
|
set date [formatdate $date]
|
||||||
set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
|
set linehtag($lineno) [$canv create text $xt $y1 -anchor w \
|
||||||
-text $headline -font $mainfont ]
|
-text $headline -font $mainfont ]
|
||||||
$canv bind $linehtag($lineno) <Button-3> "rowmenu %X %Y $id"
|
$canv bind $linehtag($lineno) <Button-3> "rowmenu %X %Y $id"
|
||||||
|
@ -1446,8 +1417,8 @@ proc decidenext {{noread 0}} {
|
||||||
}
|
}
|
||||||
|
|
||||||
proc drawcommit {id} {
|
proc drawcommit {id} {
|
||||||
global phase todo nchildren datemode nextupdate
|
global phase todo nchildren datemode nextupdate revlistorder
|
||||||
global numcommits ncmupdate displayorder todo onscreen
|
global numcommits ncmupdate displayorder todo onscreen parents
|
||||||
|
|
||||||
if {$phase != "incrdraw"} {
|
if {$phase != "incrdraw"} {
|
||||||
set phase incrdraw
|
set phase incrdraw
|
||||||
|
@ -1459,6 +1430,15 @@ proc drawcommit {id} {
|
||||||
lappend todo $id
|
lappend todo $id
|
||||||
set onscreen($id) 0
|
set onscreen($id) 0
|
||||||
}
|
}
|
||||||
|
if {$revlistorder} {
|
||||||
|
set level [lsearch -exact $todo $id]
|
||||||
|
if {$level < 0} {
|
||||||
|
error_popup "oops, $id isn't in todo"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lappend displayorder $id
|
||||||
|
updatetodo $level 0
|
||||||
|
} else {
|
||||||
set level [decidenext 1]
|
set level [decidenext 1]
|
||||||
if {$level == {} || $id != [lindex $todo $level]} {
|
if {$level == {} || $id != [lindex $todo $level]} {
|
||||||
return
|
return
|
||||||
|
@ -1474,6 +1454,7 @@ proc drawcommit {id} {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
drawmore 1
|
drawmore 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1523,7 +1504,7 @@ proc drawrest {} {
|
||||||
global phase stopped redisplaying selectedline
|
global phase stopped redisplaying selectedline
|
||||||
global datemode todo displayorder
|
global datemode todo displayorder
|
||||||
global numcommits ncmupdate
|
global numcommits ncmupdate
|
||||||
global nextupdate startmsecs
|
global nextupdate startmsecs revlistorder
|
||||||
|
|
||||||
set level [decidenext]
|
set level [decidenext]
|
||||||
if {$level >= 0} {
|
if {$level >= 0} {
|
||||||
|
@ -1536,8 +1517,8 @@ proc drawrest {} {
|
||||||
if {$level < 0} break
|
if {$level < 0} break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawmore 0
|
|
||||||
}
|
}
|
||||||
|
drawmore 0
|
||||||
set phase {}
|
set phase {}
|
||||||
set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs]
|
set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs]
|
||||||
#puts "overall $drawmsecs ms for $numcommits commits"
|
#puts "overall $drawmsecs ms for $numcommits commits"
|
||||||
|
@ -2146,8 +2127,10 @@ proc selectline {l isnew} {
|
||||||
$ctext mark set fmark.0 0.0
|
$ctext mark set fmark.0 0.0
|
||||||
$ctext mark gravity fmark.0 left
|
$ctext mark gravity fmark.0 left
|
||||||
set info $commitinfo($id)
|
set info $commitinfo($id)
|
||||||
$ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n"
|
set date [formatdate [lindex $info 2]]
|
||||||
$ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n"
|
$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)]} {
|
if {[info exists idtags($id)]} {
|
||||||
$ctext insert end "Tags:"
|
$ctext insert end "Tags:"
|
||||||
foreach tag $idtags($id) {
|
foreach tag $idtags($id) {
|
||||||
|
@ -2805,8 +2788,7 @@ proc gettreediffs {ids} {
|
||||||
set treepending $ids
|
set treepending $ids
|
||||||
set treediff {}
|
set treediff {}
|
||||||
set id [lindex $ids 0]
|
set id [lindex $ids 0]
|
||||||
set p [lindex $ids 1]
|
if [catch {set gdtf [open "|git-diff-tree --no-commit-id -r $id" r]}] return
|
||||||
if [catch {set gdtf [open "|git-diff-tree -r $id" r]}] return
|
|
||||||
fconfigure $gdtf -blocking 0
|
fconfigure $gdtf -blocking 0
|
||||||
fileevent $gdtf readable [list gettreediffline $gdtf $ids]
|
fileevent $gdtf readable [list gettreediffline $gdtf $ids]
|
||||||
}
|
}
|
||||||
|
@ -2840,9 +2822,8 @@ proc getblobdiffs {ids} {
|
||||||
global difffilestart nextupdate diffinhdr treediffs
|
global difffilestart nextupdate diffinhdr treediffs
|
||||||
|
|
||||||
set id [lindex $ids 0]
|
set id [lindex $ids 0]
|
||||||
set p [lindex $ids 1]
|
|
||||||
set env(GIT_DIFF_OPTS) $diffopts
|
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]} {
|
if {[catch {set bdf [open $cmd r]} err]} {
|
||||||
puts "error getting diffs: $err"
|
puts "error getting diffs: $err"
|
||||||
return
|
return
|
||||||
|
@ -3143,7 +3124,7 @@ proc linehover {} {
|
||||||
set t [$canv create rectangle $x0 $y0 $x1 $y1 \
|
set t [$canv create rectangle $x0 $y0 $x1 $y1 \
|
||||||
-fill \#ffff80 -outline black -width 1 -tags hover]
|
-fill \#ffff80 -outline black -width 1 -tags hover]
|
||||||
$canv raise $t
|
$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
|
$canv raise $t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3178,7 +3159,7 @@ proc clickisonarrow {id y} {
|
||||||
}
|
}
|
||||||
|
|
||||||
proc arrowjump {id dirn y} {
|
proc arrowjump {id dirn y} {
|
||||||
global mainline sidelines canv
|
global mainline sidelines canv canv2 canv3
|
||||||
|
|
||||||
set yt {}
|
set yt {}
|
||||||
if {$dirn eq "down"} {
|
if {$dirn eq "down"} {
|
||||||
|
@ -3216,6 +3197,8 @@ proc arrowjump {id dirn y} {
|
||||||
set yfrac 0
|
set yfrac 0
|
||||||
}
|
}
|
||||||
$canv yview moveto $yfrac
|
$canv yview moveto $yfrac
|
||||||
|
$canv2 yview moveto $yfrac
|
||||||
|
$canv3 yview moveto $yfrac
|
||||||
}
|
}
|
||||||
|
|
||||||
proc lineclick {x y id isnew} {
|
proc lineclick {x y id isnew} {
|
||||||
|
@ -3226,7 +3209,7 @@ proc lineclick {x y id isnew} {
|
||||||
normalline
|
normalline
|
||||||
$canv delete hover
|
$canv delete hover
|
||||||
# draw this line thicker than normal
|
# draw this line thicker than normal
|
||||||
drawlines $id 1
|
drawlines $id 1 1
|
||||||
set thickerline $id
|
set thickerline $id
|
||||||
if {$isnew} {
|
if {$isnew} {
|
||||||
set ymax [lindex [$canv cget -scrollregion] 3]
|
set ymax [lindex [$canv cget -scrollregion] 3]
|
||||||
|
@ -3255,7 +3238,8 @@ proc lineclick {x y id isnew} {
|
||||||
set info $commitinfo($id)
|
set info $commitinfo($id)
|
||||||
$ctext insert end "\n\t[lindex $info 0]\n"
|
$ctext insert end "\n\t[lindex $info 0]\n"
|
||||||
$ctext insert end "\tAuthor:\t[lindex $info 1]\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)]} {
|
if {[info exists children($id)]} {
|
||||||
$ctext insert end "\nChildren:"
|
$ctext insert end "\nChildren:"
|
||||||
set i 0
|
set i 0
|
||||||
|
@ -3267,7 +3251,8 @@ proc lineclick {x y id isnew} {
|
||||||
$ctext tag bind link$i <1> [list selbyid $child]
|
$ctext tag bind link$i <1> [list selbyid $child]
|
||||||
$ctext insert end "\n\t[lindex $info 0]"
|
$ctext insert end "\n\t[lindex $info 0]"
|
||||||
$ctext insert end "\n\tAuthor:\t[lindex $info 1]"
|
$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
|
$ctext conf -state disabled
|
||||||
|
@ -3278,7 +3263,7 @@ proc lineclick {x y id isnew} {
|
||||||
proc normalline {} {
|
proc normalline {} {
|
||||||
global thickerline
|
global thickerline
|
||||||
if {[info exists thickerline]} {
|
if {[info exists thickerline]} {
|
||||||
drawlines $thickerline 0
|
drawlines $thickerline 0 1
|
||||||
unset thickerline
|
unset thickerline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3650,6 +3635,23 @@ proc doquit {} {
|
||||||
destroy .
|
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...
|
# defaults...
|
||||||
set datemode 0
|
set datemode 0
|
||||||
set boldnames 0
|
set boldnames 0
|
||||||
|
@ -3662,6 +3664,8 @@ set findmergefiles 0
|
||||||
set gaudydiff 0
|
set gaudydiff 0
|
||||||
set maxgraphpct 50
|
set maxgraphpct 50
|
||||||
set maxwidth 16
|
set maxwidth 16
|
||||||
|
set revlistorder 0
|
||||||
|
set fastdate 0
|
||||||
|
|
||||||
set colors {green red blue magenta darkgrey brown orange}
|
set colors {green red blue magenta darkgrey brown orange}
|
||||||
|
|
||||||
|
@ -3678,6 +3682,7 @@ foreach arg $argv {
|
||||||
"^$" { }
|
"^$" { }
|
||||||
"^-b" { set boldnames 1 }
|
"^-b" { set boldnames 1 }
|
||||||
"^-d" { set datemode 1 }
|
"^-d" { set datemode 1 }
|
||||||
|
"^-r" { set revlistorder 1 }
|
||||||
default {
|
default {
|
||||||
lappend revtreeargs $arg
|
lappend revtreeargs $arg
|
||||||
}
|
}
|
||||||
|
|
821
http-fetch.c
821
http-fetch.c
File diff suppressed because it is too large
Load Diff
799
http-push.c
799
http-push.c
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
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];
|
static char buffer[1000];
|
||||||
char date[50];
|
char date[50];
|
||||||
|
@ -181,12 +182,16 @@ char *get_ident(const char *name, const char *email, const char *date_str)
|
||||||
return buffer;
|
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);
|
fwrite(p_start, p - p_start, 1, stdout);
|
||||||
}
|
}
|
||||||
} else if (all) {
|
} else if (all) {
|
||||||
extern struct object **objs;
|
|
||||||
extern int nr_objs;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < nr_objs; i++)
|
for (i = 0; i < nr_objs; i++)
|
||||||
|
|
|
@ -524,7 +524,7 @@ int main(int argc, char **argv)
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
|
||||||
if (get_sha1_hex(line, sha1))
|
if (get_sha1_hex(line, sha1))
|
||||||
die("expected sha1, got garbage");
|
die("expected sha1, got garbage:\n %s", line);
|
||||||
hash = 0;
|
hash = 0;
|
||||||
p = line+40;
|
p = line+40;
|
||||||
while (*p) {
|
while (*p) {
|
||||||
|
|
128
pack-redundant.c
128
pack-redundant.c
|
@ -11,19 +11,19 @@
|
||||||
static const char pack_redundant_usage[] =
|
static const char pack_redundant_usage[] =
|
||||||
"git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
|
"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 {
|
||||||
struct llist_item *next;
|
struct llist_item *next;
|
||||||
char *sha1;
|
unsigned char *sha1;
|
||||||
};
|
};
|
||||||
struct llist {
|
static struct llist {
|
||||||
struct llist_item *front;
|
struct llist_item *front;
|
||||||
struct llist_item *back;
|
struct llist_item *back;
|
||||||
size_t size;
|
size_t size;
|
||||||
} *all_objects; /* all objects which must be present in local packfiles */
|
} *all_objects; /* all objects which must be present in local packfiles */
|
||||||
|
|
||||||
struct pack_list {
|
static struct pack_list {
|
||||||
struct pack_list *next;
|
struct pack_list *next;
|
||||||
struct packed_git *pack;
|
struct packed_git *pack;
|
||||||
struct llist *unique_objects;
|
struct llist *unique_objects;
|
||||||
|
@ -36,23 +36,43 @@ struct pll {
|
||||||
size_t pl_size;
|
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)) {
|
while((list->back = list->front)) {
|
||||||
list->front = list->front->next;
|
list->front = list->front->next;
|
||||||
free(list->back);
|
llist_item_put(list->back);
|
||||||
}
|
}
|
||||||
free(list);
|
free(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void llist_init(struct llist **list)
|
static inline void llist_init(struct llist **list)
|
||||||
{
|
{
|
||||||
*list = xmalloc(sizeof(struct llist));
|
*list = xmalloc(sizeof(struct llist));
|
||||||
(*list)->front = (*list)->back = NULL;
|
(*list)->front = (*list)->back = NULL;
|
||||||
(*list)->size = 0;
|
(*list)->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct llist * llist_copy(struct llist *list)
|
static struct llist * llist_copy(struct llist *list)
|
||||||
{
|
{
|
||||||
struct llist *ret;
|
struct llist *ret;
|
||||||
struct llist_item *new, *old, *prev;
|
struct llist_item *new, *old, *prev;
|
||||||
|
@ -62,13 +82,13 @@ struct llist * llist_copy(struct llist *list)
|
||||||
if ((ret->size = list->size) == 0)
|
if ((ret->size = list->size) == 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
new = ret->front = xmalloc(sizeof(struct llist_item));
|
new = ret->front = llist_item_get();
|
||||||
new->sha1 = list->front->sha1;
|
new->sha1 = list->front->sha1;
|
||||||
|
|
||||||
old = list->front->next;
|
old = list->front->next;
|
||||||
while (old) {
|
while (old) {
|
||||||
prev = new;
|
prev = new;
|
||||||
new = xmalloc(sizeof(struct llist_item));
|
new = llist_item_get();
|
||||||
prev->next = new;
|
prev->next = new;
|
||||||
new->sha1 = old->sha1;
|
new->sha1 = old->sha1;
|
||||||
old = old->next;
|
old = old->next;
|
||||||
|
@ -79,10 +99,11 @@ struct llist * llist_copy(struct llist *list)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline struct llist_item * llist_insert(struct llist *list,
|
static inline struct llist_item * llist_insert(struct llist *list,
|
||||||
struct llist_item *after, char *sha1)
|
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->sha1 = sha1;
|
||||||
new->next = NULL;
|
new->next = NULL;
|
||||||
|
|
||||||
|
@ -102,13 +123,12 @@ inline struct llist_item * llist_insert(struct llist *list,
|
||||||
return new;
|
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);
|
return llist_insert(list, list->back, sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline struct llist_item * llist_insert_sorted_unique(struct llist *list,
|
static inline struct llist_item *llist_insert_sorted_unique(struct llist *list, unsigned char *sha1, struct llist_item *hint)
|
||||||
char *sha1, struct llist_item *hint)
|
|
||||||
{
|
{
|
||||||
struct llist_item *prev = NULL, *l;
|
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 */
|
/* returns a pointer to an item in front of sha1 */
|
||||||
inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
|
static inline struct llist_item * llist_sorted_remove(struct llist *list, const unsigned char *sha1, struct llist_item *hint)
|
||||||
struct llist_item *hint)
|
|
||||||
{
|
{
|
||||||
struct llist_item *prev, *l;
|
struct llist_item *prev, *l;
|
||||||
|
|
||||||
|
@ -153,7 +172,7 @@ redo_from_start:
|
||||||
prev->next = l->next;
|
prev->next = l->next;
|
||||||
if (l == list->back)
|
if (l == list->back)
|
||||||
list->back = prev;
|
list->back = prev;
|
||||||
free(l);
|
llist_item_put(l);
|
||||||
list->size--;
|
list->size--;
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
@ -164,7 +183,7 @@ redo_from_start:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* computes A\B */
|
/* 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 *B)
|
||||||
{
|
{
|
||||||
struct llist_item *hint, *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 *entry)
|
||||||
{
|
{
|
||||||
struct pack_list *p = xmalloc(sizeof(struct pack_list));
|
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;
|
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;
|
size_t ret = 0;
|
||||||
while(pl) {
|
while(pl) {
|
||||||
|
@ -198,10 +217,11 @@ inline size_t pack_list_size(struct pack_list *pl)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pack_list * pack_list_difference(struct pack_list *A,
|
static struct pack_list * pack_list_difference(const struct pack_list *A,
|
||||||
struct pack_list *B)
|
const struct pack_list *B)
|
||||||
{
|
{
|
||||||
struct pack_list *ret, *pl;
|
struct pack_list *ret;
|
||||||
|
const struct pack_list *pl;
|
||||||
|
|
||||||
if (A == NULL)
|
if (A == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -218,7 +238,7 @@ struct pack_list * pack_list_difference(struct pack_list *A,
|
||||||
return ret;
|
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;
|
int p1_off, p2_off;
|
||||||
void *p1_base, *p2_base;
|
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;
|
struct pll *prev;
|
||||||
int i = (*pll)->pl_size - 1;
|
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,
|
/* all the permutations have to be free()d at the same time,
|
||||||
* since they refer to each other
|
* 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*/
|
struct pll *subset, *pll, *new_pll = NULL; /*silence warning*/
|
||||||
static struct pll **hint = NULL;
|
static struct pll **hint = NULL;
|
||||||
|
@ -323,15 +343,14 @@ struct pll * get_all_permutations(struct pack_list *list)
|
||||||
return hint[0];
|
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;
|
struct llist *diff;
|
||||||
|
|
||||||
diff = llist_copy(list);
|
diff = llist_copy(list);
|
||||||
|
|
||||||
while (pl) {
|
while (pl) {
|
||||||
llist_sorted_difference_inplace(diff,
|
llist_sorted_difference_inplace(diff, pl->all_objects);
|
||||||
pl->all_objects);
|
|
||||||
if (diff->size == 0) { /* we're done */
|
if (diff->size == 0) { /* we're done */
|
||||||
llist_free(diff);
|
llist_free(diff);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -342,7 +361,7 @@ int is_superset(struct pack_list *pl, struct llist *list)
|
||||||
return 0;
|
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;
|
size_t ret = 0;
|
||||||
int p1_off, p2_off;
|
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 ... */
|
/* 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;
|
struct pack_list *subset;
|
||||||
|
size_t ret = 0;
|
||||||
|
|
||||||
if (pl == NULL)
|
if (pl == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
size_t ret = 0;
|
|
||||||
while ((subset = pl->next)) {
|
while ((subset = pl->next)) {
|
||||||
while(subset) {
|
while(subset) {
|
||||||
ret += sizeof_union(pl->pack, subset->pack);
|
ret += sizeof_union(pl->pack, subset->pack);
|
||||||
|
@ -391,7 +410,7 @@ size_t get_pack_redundancy(struct pack_list *pl)
|
||||||
return ret;
|
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;
|
size_t ret = 0;
|
||||||
while (pl) {
|
while (pl) {
|
||||||
|
@ -402,7 +421,7 @@ inline size_t pack_set_bytecount(struct pack_list *pl)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void minimize(struct pack_list **min)
|
static void minimize(struct pack_list **min)
|
||||||
{
|
{
|
||||||
struct pack_list *pl, *unique = NULL,
|
struct pack_list *pl, *unique = NULL,
|
||||||
*non_unique = NULL, *min_perm = 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 pack_list *pl = local_packs;
|
||||||
struct llist_item *hint, *l;
|
struct llist_item *hint, *l;
|
||||||
int i;
|
|
||||||
|
|
||||||
llist_init(&all_objects);
|
llist_init(&all_objects);
|
||||||
|
|
||||||
while (pl) {
|
while (pl) {
|
||||||
i = 0;
|
|
||||||
hint = NULL;
|
hint = NULL;
|
||||||
l = pl->all_objects->front;
|
l = pl->all_objects->front;
|
||||||
while (l) {
|
while (l) {
|
||||||
|
@ -497,7 +514,7 @@ void load_all_objects()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this scales like O(n^2) */
|
/* this scales like O(n^2) */
|
||||||
void cmp_local_packs()
|
static void cmp_local_packs(void)
|
||||||
{
|
{
|
||||||
struct pack_list *subset, *pl = local_packs;
|
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;
|
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;
|
struct pack_list l;
|
||||||
size_t off;
|
size_t off;
|
||||||
|
@ -550,7 +567,7 @@ struct pack_list * add_pack(struct packed_git *p)
|
||||||
return pack_list_insert(&altodb_packs, &l);
|
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;
|
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);
|
die("Filename %s not found in packed_git\n", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_all()
|
static void load_all(void)
|
||||||
{
|
{
|
||||||
struct packed_git *p = packed_git;
|
struct packed_git *p = packed_git;
|
||||||
|
|
||||||
|
@ -579,6 +596,9 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct pack_list *min, *red, *pl;
|
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++) {
|
for (i = 1; i < argc; i++) {
|
||||||
const char *arg = argv[i];
|
const char *arg = argv[i];
|
||||||
|
@ -621,6 +641,23 @@ int main(int argc, char **argv)
|
||||||
if (alt_odb)
|
if (alt_odb)
|
||||||
scan_alt_odb_packs();
|
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);
|
minimize(&min);
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
@ -647,6 +684,9 @@ int main(int argc, char **argv)
|
||||||
pl->pack->pack_name);
|
pl->pack->pack_name);
|
||||||
pl = pl->next;
|
pl = pl->next;
|
||||||
}
|
}
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stderr, "%luMB of redundant packs in total.\n",
|
||||||
|
(unsigned long)pack_set_bytecount(red)/(1024*1024));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
115
path.c
115
path.c
|
@ -11,6 +11,7 @@
|
||||||
* which is what it's designed for.
|
* which is what it's designed for.
|
||||||
*/
|
*/
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
static char pathname[PATH_MAX];
|
static char pathname[PATH_MAX];
|
||||||
static char bad_path[] = "/bad-path/";
|
static char bad_path[] = "/bad-path/";
|
||||||
|
@ -89,3 +90,117 @@ char *safe_strncpy(char *dest, const char *src, size_t n)
|
||||||
|
|
||||||
return dest;
|
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 main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
const char *dir = NULL;
|
char *dir = NULL;
|
||||||
|
|
||||||
argv++;
|
argv++;
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
const char *arg = *argv++;
|
char *arg = *argv++;
|
||||||
|
|
||||||
if (*arg == '-') {
|
if (*arg == '-') {
|
||||||
/* Do flag handling here */
|
/* Do flag handling here */
|
||||||
|
@ -265,18 +265,9 @@ int main(int argc, char **argv)
|
||||||
if (!dir)
|
if (!dir)
|
||||||
usage(receive_pack_usage);
|
usage(receive_pack_usage);
|
||||||
|
|
||||||
/* chdir to the directory. If that fails, try appending ".git" */
|
if(!enter_repo(dir, 0))
|
||||||
if (chdir(dir) < 0) {
|
die("'%s': unable to chdir or not a git archive", dir);
|
||||||
if (chdir(mkpath("%s.git", dir)) < 0)
|
|
||||||
die("unable to cd to %s", dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we have a ".git" directory, chdir to it */
|
|
||||||
chdir(".git");
|
|
||||||
putenv("GIT_DIR=.");
|
|
||||||
|
|
||||||
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();
|
write_head_info();
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
40
refs.c
40
refs.c
|
@ -10,46 +10,6 @@
|
||||||
#define USE_SYMLINK_HEAD 1
|
#define USE_SYMLINK_HEAD 1
|
||||||
#endif
|
#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)
|
const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
||||||
{
|
{
|
||||||
int depth = MAXDEPTH, len;
|
int depth = MAXDEPTH, len;
|
||||||
|
|
|
@ -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;
|
stop_traversal=1;
|
||||||
return CONTINUE;
|
return CONTINUE;
|
||||||
}
|
}
|
||||||
if (max_count != -1 && !max_count--)
|
|
||||||
return STOP;
|
|
||||||
if (no_merges && (commit->parents && commit->parents->next))
|
if (no_merges && (commit->parents && commit->parents->next))
|
||||||
return CONTINUE;
|
return CONTINUE;
|
||||||
if (paths && dense) {
|
if (paths && dense) {
|
||||||
|
@ -148,6 +146,9 @@ static int process_commit(struct commit * commit)
|
||||||
return CONTINUE;
|
return CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (max_count != -1 && !max_count--)
|
||||||
|
return STOP;
|
||||||
|
|
||||||
show_commit(commit);
|
show_commit(commit);
|
||||||
|
|
||||||
return CONTINUE;
|
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
|
* Test if it looks like we're at the top level git directory.
|
||||||
* level git directory. We want to see a
|
* We want to see:
|
||||||
*
|
*
|
||||||
* - either a .git/objects/ directory _or_ the proper
|
* - either a .git/objects/ directory _or_ the proper
|
||||||
* GIT_OBJECT_DIRECTORY environment variable
|
* GIT_OBJECT_DIRECTORY environment variable
|
||||||
|
@ -92,17 +92,43 @@ static int is_toplevel_directory(void)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *setup_git_directory(void)
|
static const char *setup_git_directory_1(void)
|
||||||
{
|
{
|
||||||
static char cwd[PATH_MAX+1];
|
static char cwd[PATH_MAX+1];
|
||||||
int len, offset;
|
int len, offset;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If GIT_DIR is set explicitly, we're not going
|
* 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;
|
return NULL;
|
||||||
|
bad_dir_environ:
|
||||||
|
path[len] = 0;
|
||||||
|
die("Not a git repository: '%s'", path);
|
||||||
|
}
|
||||||
|
|
||||||
if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
|
if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
|
||||||
die("Unable to read current working directory");
|
die("Unable to read current working directory");
|
||||||
|
@ -127,3 +153,9 @@ const char *setup_git_directory(void)
|
||||||
cwd[len] = 0;
|
cwd[len] = 0;
|
||||||
return cwd + offset;
|
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
|
NULL
|
||||||
};
|
};
|
||||||
const char **p;
|
const char **p;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
if (len == 40 && !get_sha1_hex(str, sha1))
|
if (len == 40 && !get_sha1_hex(str, sha1))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -246,10 +247,20 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
||||||
|
|
||||||
for (p = prefix; *p; p++) {
|
for (p = prefix; *p; p++) {
|
||||||
char *pathname = git_path("%s/%.*s", *p, len, str);
|
char *pathname = git_path("%s/%.*s", *p, len, str);
|
||||||
if (!read_ref(pathname, sha1))
|
if (!read_ref(pathname, sha1)) {
|
||||||
return 0;
|
/* 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;
|
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)
|
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 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)
|
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)
|
if (MAX_REVS <= num_rev)
|
||||||
die("cannot handle more than %d revs.", MAX_REVS);
|
die("cannot handle more than %d revs.", MAX_REVS);
|
||||||
if (get_sha1(ref_name[num_rev], revkey))
|
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);
|
commit = lookup_commit_reference(revkey);
|
||||||
if (!commit)
|
if (!commit)
|
||||||
die("cannot find commit %s (%s)",
|
die("cannot find commit %s (%s)",
|
||||||
|
|
|
@ -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".
|
# (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
|
if expr "$2" : '0*$' >/dev/null
|
||||||
then
|
then
|
||||||
echo "Created a new ref, with the following commits:"
|
echo "Created a new ref, with the following commits:"
|
||||||
git-rev-list --pretty "$3"
|
git-rev-list --pretty "$3"
|
||||||
else
|
else
|
||||||
$base=$(git-merge-base "$2" "$3")
|
base=$(git-merge-base "$2" "$3")
|
||||||
case "$base" in
|
case "$base" in
|
||||||
"$2")
|
"$2")
|
||||||
echo "New commits:"
|
echo "New commits:"
|
||||||
|
@ -24,7 +24,6 @@ else
|
||||||
echo "Rebased ref, commits from common ancestor:"
|
echo "Rebased ref, commits from common ancestor:"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
|
||||||
git-rev-list --pretty "$3" "^$base"
|
git-rev-list --pretty "$3" "^$base"
|
||||||
fi |
|
fi |
|
||||||
mail -s "Changes to ref $1" "$recipient"
|
mail -s "Changes to ref $1" "$recipient"
|
||||||
|
|
|
@ -338,7 +338,7 @@ static void read_index_info(int line_termination)
|
||||||
struct strbuf buf;
|
struct strbuf buf;
|
||||||
strbuf_init(&buf);
|
strbuf_init(&buf);
|
||||||
while (1) {
|
while (1) {
|
||||||
char *ptr;
|
char *ptr, *tab;
|
||||||
char *path_name;
|
char *path_name;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
unsigned int mode;
|
unsigned int mode;
|
||||||
|
@ -348,12 +348,15 @@ static void read_index_info(int line_termination)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
mode = strtoul(buf.buf, &ptr, 8);
|
mode = strtoul(buf.buf, &ptr, 8);
|
||||||
if (ptr == buf.buf || *ptr != ' ' ||
|
if (ptr == buf.buf || *ptr != ' ')
|
||||||
get_sha1_hex(ptr + 1, sha1) ||
|
|
||||||
ptr[41] != '\t')
|
|
||||||
goto bad_line;
|
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] == '"')
|
if (line_termination && ptr[0] == '"')
|
||||||
path_name = unquote_c_style(ptr, NULL);
|
path_name = unquote_c_style(ptr, NULL);
|
||||||
|
|
|
@ -248,7 +248,7 @@ static int upload_pack(void)
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
const char *dir;
|
char *dir;
|
||||||
int i;
|
int i;
|
||||||
int strict = 0;
|
int strict = 0;
|
||||||
|
|
||||||
|
@ -275,18 +275,9 @@ int main(int argc, char **argv)
|
||||||
usage(upload_pack_usage);
|
usage(upload_pack_usage);
|
||||||
dir = argv[i];
|
dir = argv[i];
|
||||||
|
|
||||||
/* chdir to the directory. If that fails, try appending ".git" */
|
if (!enter_repo(dir, strict))
|
||||||
if (chdir(dir) < 0) {
|
die("'%s': unable to chdir or not a git archive", dir);
|
||||||
if (strict || chdir(mkpath("%s.git", dir)) < 0)
|
|
||||||
die("git-upload-pack unable to chdir to %s", dir);
|
|
||||||
}
|
|
||||||
if (!strict)
|
|
||||||
chdir(".git");
|
|
||||||
|
|
||||||
if (access("objects", X_OK) || access("refs", X_OK))
|
|
||||||
die("git-upload-pack: %s doesn't seem to be a git archive", dir);
|
|
||||||
|
|
||||||
putenv("GIT_DIR=.");
|
|
||||||
upload_pack();
|
upload_pack();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
4
var.c
4
var.c
|
@ -12,7 +12,7 @@ static const char var_usage[] = "git-var [-l | <variable>]";
|
||||||
|
|
||||||
struct git_var {
|
struct git_var {
|
||||||
const char *name;
|
const char *name;
|
||||||
char *(*read)(void);
|
const char *(*read)(void);
|
||||||
};
|
};
|
||||||
static struct git_var git_vars[] = {
|
static struct git_var git_vars[] = {
|
||||||
{ "GIT_COMMITTER_IDENT", git_committer_info },
|
{ "GIT_COMMITTER_IDENT", git_committer_info },
|
||||||
|
@ -57,6 +57,8 @@ int main(int argc, char **argv)
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
usage(var_usage);
|
usage(var_usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_git_directory();
|
||||||
setup_ident();
|
setup_ident();
|
||||||
val = NULL;
|
val = NULL;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue