This commit is contained in:
Junio C Hamano 2005-12-03 23:46:02 -08:00
Родитель 93dcab2937 d79374c7b5
Коммит 423325a2d2
90 изменённых файлов: 1519 добавлений и 761 удалений

Просмотреть файл

@ -4,6 +4,11 @@
option old data in `.git/FETCH_HEAD` will be overwritten.
-f, \--force::
When `git-fetch` is used with `<rbranch>:<lbranch>`
refspec, it refuses to update the local branch
`<lbranch>` unless the remote branch `<rbranch>` it
fetches is a descendant of `<lbranch>`. This option
overrides that check.
-t, \--tags::
By default, the git core utilities will not fetch and store

Просмотреть файл

@ -8,13 +8,13 @@ git-bisect - Find the change that introduced a bug
SYNOPSIS
--------
'git bisect' start
'git bisect' bad <rev>
'git bisect' good <rev>
'git bisect' reset [<branch>]
'git bisect' visualize
'git bisect' replay <logfile>
'git bisect' log
'git bisect' start
'git bisect' bad <rev>
'git bisect' good <rev>
'git bisect' reset [<branch>]
'git bisect' visualize
'git bisect' replay <logfile>
'git bisect' log
DESCRIPTION
-----------

Просмотреть файл

@ -8,7 +8,7 @@ git-cat-file - Provide content or type information for repository objects
SYNOPSIS
--------
'git-cat-file' (-t | -s | <type>) <object>
'git-cat-file' (-t | -s | -e | <type>) <object>
DESCRIPTION
-----------
@ -29,6 +29,10 @@ OPTIONS
Instead of the content, show the object size identified by
<object>.
-e::
Suppress all output; instead exit with zero status if <object>
exists and is a valid object.
<type>::
Typically this matches the real type of <object> but asking
for a type that can trivially be dereferenced from the given
@ -39,8 +43,11 @@ OPTIONS
OUTPUT
------
If '-t' is specified, one of the <type>. If '-s' is specified,
the size of the <object> in bytes.
If '-t' is specified, one of the <type>.
If '-s' is specified, the size of the <object> in bytes.
If '-e' is specified, no output.
Otherwise the raw (though uncompressed) contents of the <object> will
be returned.

Просмотреть файл

@ -21,6 +21,15 @@ OPTIONS
-------
include::diff-options.txt[]
-1 -2 -3 or --base --ours --theirs, and -0::
Diff against the "base" version, "our branch" or "their
branch" respectively. With these options, diffs for
merged entries are not shown.
+
The default is to diff against our branch (-2) and the
cleanly resolved paths. The option -0 can be given to
omit diff output for unmerged entries and just show "Unmerged".
-q::
Remain silent even on nonexisting files

Просмотреть файл

@ -8,7 +8,7 @@ git-mailinfo - Extracts patch from a single e-mail message.
SYNOPSIS
--------
'git-mailinfo' [-k] [-u] <msg> <patch>
'git-mailinfo' [-k] [-u | --encoding=<encoding>] <msg> <patch>
DESCRIPTION
@ -37,10 +37,17 @@ OPTIONS
author email are taken from the e-mail without any
charset conversion, after minimally decoding MIME
transfer encoding. This flag causes the resulting
commit to be encoded in utf-8 by transliterating them.
commit to be encoded in the encoding specified by
i18n.commitencoding configuration (defaults to utf-8) by
transliterating them.
Note that the patch is always used as is without charset
conversion, even with this flag.
--encoding=<encoding>::
Similar to -u but if the local convention is different
from what is specified by i18n.commitencoding, this flag
can be used to override it.
<msg>::
The commit log message extracted from e-mail, usually
except the title line which comes from e-mail Subject.

Просмотреть файл

@ -37,6 +37,103 @@ include::merge-options.txt[]
include::merge-strategies.txt[]
HOW MERGE WORKS
---------------
A merge is always between the current `HEAD` and one or more
remote branch heads, and the index file must exactly match the
tree of `HEAD` commit (i.e. the contents of the last commit) when
it happens. In other words, `git-diff --cached HEAD` must
report no changes.
[NOTE]
This is a bit of lie. In certain special cases, your index are
allowed to be different from the tree of `HEAD` commit. The most
notable case is when your `HEAD` commit is already ahead of what
is being merged, in which case your index can have arbitrary
difference from your `HEAD` commit. Otherwise, your index entries
are allowed have differences from your `HEAD` commit that match
the result of trivial merge (e.g. you received the same patch
from external source to produce the same result as what you are
merging). For example, if a path did not exist in the common
ancestor and your head commit but exists in the tree you are
merging into your repository, and if you already happen to have
that path exactly in your index, the merge does not have to
fail.
Otherwise, merge will refuse to do any harm to your repository
(that is, it may fetch the objects from remote, and it may even
update the local branch used to keep track of the remote branch
with `git pull remote rbranch:lbranch`, but your working tree,
`.git/HEAD` pointer and index file are left intact).
You may have local modifications in the working tree files. In
other words, `git-diff` is allowed to report changes.
However, the merge uses your working tree as the working area,
and in order to prevent the merge operation from losing such
changes, it makes sure that they do not interfere with the
merge. Those complex tables in read-tree documentation define
what it means for a path to "interfere with the merge". And if
your local modifications interfere with the merge, again, it
stops before touching anything.
So in the above two "failed merge" case, you do not have to
worry about lossage of data --- you simply were not ready to do
a merge, so no merge happened at all. You may want to finish
whatever you were in the middle of doing, and retry the same
pull after you are done and ready.
When things cleanly merge, these things happen:
1. the results are updated both in the index file and in your
working tree,
2. index file is written out as a tree,
3. the tree gets committed, and
4. the `HEAD` pointer gets advanced.
Because of 2., we require that the original state of the index
file to match exactly the current `HEAD` commit; otherwise we
will write out your local changes already registered in your
index file along with the merge result, which is not good.
Because 1. involves only the paths different between your
branch and the remote branch you are pulling from during the
merge (which is typically a fraction of the whole tree), you can
have local modifications in your working tree as long as they do
not overlap with what the merge updates.
When there are conflicts, these things happen:
1. `HEAD` stays the same.
2. Cleanly merged paths are updated both in the index file and
in your working tree.
3. For conflicting paths, the index file records up to three
versions; stage1 stores the version from the common ancestor,
stage2 from `HEAD`, and stage3 from the remote branch (you
can inspect the stages with `git-ls-files -u`). The working
tree files have the result of "merge" program; i.e. 3-way
merge result with familiar conflict markers `<<< === >>>`.
4. No other changes are done. In particular, the local
modifications you had before you started merge will stay the
same and the index entries for them stay as they were,
i.e. matching `HEAD`.
After seeing a conflict, you can do two things:
* Decide not to merge. The only clean-up you need are to reset
the index file to the `HEAD` commit to reverse 2. and to clean
up working tree changes made by 2. and 3.; `git-reset` can
be used for this.
* Resolve the conflicts. `git-diff` would report only the
conflicting paths because of the above 2. and 3.. Edit the
working tree files into a desirable shape, `git-update-index`
them, to make the index file contain what the merge result
should be, and run `git-commit` to commit the result.
SEE ALSO
--------
gitlink:git-fmt-merge-msg[1], gitlink:git-pull[1]

Просмотреть файл

@ -8,14 +8,14 @@ git-mv - Script used to move or rename a file, directory or symlink.
SYNOPSIS
--------
'git-mv' [-f] [-n] <source> <destination>
'git-mv' [-f] [-k] [-n] <source> ... <destination directory>
'git-mv' [-f] [-n] <source> <destination>
'git-mv' [-f] [-n] [-k] <source> ... <destination directory>
DESCRIPTION
-----------
This script is used to move or rename a file, directory or symlink.
In the first form, it renames <source>, which must exist and be either
a file, symlink or directory, to <destination>, which must not exist.
a file, symlink or directory, to <destination>.
In the second form, the last argument has to be an existing
directory; the given sources will be moved into this directory.
@ -25,7 +25,7 @@ committed.
OPTIONS
-------
-f::
Force renaming or moving even targets exist
Force renaming or moving of a file even if the target exists
-k::
Skip move or rename actions which would lead to an error
condition. An error happens when a source is neither existing nor

Просмотреть файл

@ -28,11 +28,14 @@ will be in unmerged state when "git-read-tree" returns.
OPTIONS
-------
-m::
Perform a merge, not just a read.
Perform a merge, not just a read. The command will
refuse to run if your index file has unmerged entries,
indicating that you have not finished previous merge you
started.
--reset::
Same as -m except that unmerged entries will be silently ignored.
Same as -m, except that unmerged entries are discarded
instead of failing.
-u::
After a successful merge, update the files in the work
@ -47,7 +50,6 @@ OPTIONS
trees that are not directly related to the current
working tree status into a temporary index file.
<tree-ish#>::
The id of the tree object(s) to be read/merged.

Просмотреть файл

@ -10,7 +10,7 @@ git-svnimport - Import a SVN repository into git
SYNOPSIS
--------
'git-svnimport' [ -o <branch-for-HEAD> ] [ -h ] [ -v ] [ -d | -D ]
[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_nr_changes]
[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev]
[ -b branch_subdir ] [ -t trunk_subdir ] [ -T tag_subdir ]
[ -s start_chg ] [ -m ] [ -M regex ]
<SVN_repository_URL> [ <path> ]
@ -71,14 +71,11 @@ When importing incementally, you might need to edit the .git/svn2git file.
regex. It can be used with -m to also see the default regexes.
You must escape forward slashes.
-l <max_num_changes>::
Limit the number of SVN changesets we pull before quitting.
This option is necessary because the SVN library has serious memory
leaks; the recommended value for nontrivial imports is 100.
-l <max_rev>::
Specify a maximum revision number to pull.
git-svnimport will still exit with a zero exit code. You can check
the size of the file ".git/svn2git" to determine whether to call
the importer again.
Formerly, this option controlled how many revisions to pull, due to
SVN memory leaks. (These have been worked around.)
-v::
Verbosity: let 'svnimport' report what it is doing.

Просмотреть файл

@ -10,6 +10,26 @@ SYNOPSIS
--------
'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <name> [<head>]
OPTIONS
-------
-a::
Make an unsigned, annotated tag object
-s::
Make a GPG-signed tag, using the default e-mail address's key
-u <key-id>::
Make a GPG-signed tag, using the given key
-f::
Replace an existing tag with the given name (instead of failing)
-d::
Delete an existing tag with the given name
-m <msg>::
Use the given tag message (instead of prompting)
DESCRIPTION
-----------
Adds a 'tag' reference in .git/refs/tags/
@ -23,7 +43,7 @@ creates a 'tag' object, and requires the tag message. Unless
in the tag message.
Otherwise just the SHA1 object name of the commit object is
written (i.e. an lightweight tag).
written (i.e. a lightweight tag).
A GnuPG signed tag object will be created when `-s` or `-u
<key-id>` is used. When `-u <key-id>` is not used, the

Просмотреть файл

@ -15,10 +15,10 @@
- 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:
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/
@ -26,8 +26,8 @@
- host.xz:path/to/repo.git
===============================================================
+
To sync with a local directory, use:
To sync with a local directory, use:
+
===============================================================
- /path/to/repo.git/
===============================================================
@ -113,7 +113,7 @@ on the remote branch, merge it into your development branch with
`git pull . remote-B`, while you are on `my-B` branch.
The common `Pull: master:origin` mapping of a remote `master`
branch to a local `origin` branch, which is then merged to a
ocal development branch, again typically named `master`, is made
local development branch, again typically named `master`, is made
when you run `git clone` for you to follow this pattern.
+
[NOTE]

Просмотреть файл

@ -898,9 +898,8 @@ file, which had no differences in the `mybranch` branch), and say:
fatal: Merge requires file-level merging
Nope.
...
merge: warning: conflicts during merge
ERROR: Merge conflict in hello.
fatal: merge program failed
Auto-merging hello
CONFLICT (content): Merge conflict in hello
Automatic merge failed/prevented; fix up by hand
----------------
@ -942,10 +941,10 @@ environment, is `git show-branch`.
------------------------------------------------
$ git show-branch master mybranch
* [master] Merged "mybranch" changes.
* [master] Merge work in mybranch
! [mybranch] Some work.
--
+ [master] Merged "mybranch" changes.
+ [master] Merge work in mybranch
++ [mybranch] Some work.
------------------------------------------------
@ -998,10 +997,10 @@ looks like, or run `show-branch`, which tells you this.
------------------------------------------------
$ git show-branch master mybranch
! [master] Merged "mybranch" changes.
* [mybranch] Merged "mybranch" changes.
! [master] Merge work in mybranch
* [mybranch] Merge work in mybranch
--
++ [master] Merged "mybranch" changes.
++ [master] Merge work in mybranch
------------------------------------------------

Просмотреть файл

@ -1,3 +1,6 @@
# The default target of this Makefile is...
all:
# Define MOZILLA_SHA1 environment variable when running make to make use of
# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
@ -18,6 +21,8 @@
#
# Define NO_STRCASESTR if you don't have strcasestr.
#
# Define NO_SETENV if you don't have setenv in the C library.
#
# Define PPC_SHA1 environment variable when running make to make use of
# a bundled SHA1 routine optimized for PowerPC.
#
@ -50,7 +55,7 @@
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-cache perspective.
GIT_VERSION = 0.99.9k
GIT_VERSION = 0.99.9l
# CFLAGS and LDFLAGS are for the users to override from the command line.
@ -138,8 +143,6 @@ ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) git$X
# Backward compatibility -- to be removed after 1.0
PROGRAMS += git-ssh-pull$X git-ssh-push$X
GIT_LIST_TWEAK =
# Set paths to tools early so that they can be used for version tests.
ifndef SHELL_PATH
SHELL_PATH = /bin/sh
@ -154,20 +157,6 @@ endif
PYMODULES = \
gitMergeCommon.py
ifdef WITH_OWN_SUBPROCESS_PY
PYMODULES += compat/subprocess.py
else
ifneq ($(shell $(PYTHON_PATH) -c 'import subprocess;print"OK"' 2>/dev/null),OK)
PYMODULES += compat/subprocess.py
endif
endif
ifdef WITH_SEND_EMAIL
SCRIPT_PERL += git-send-email.perl
else
GIT_LIST_TWEAK += -e '/^send-email$$/d'
endif
LIB_FILE=libgit.a
LIB_H = \
@ -207,6 +196,7 @@ shellquote = '$(call shq,$(1))'
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
ifeq ($(uname_S),Darwin)
NEEDS_SSL_WITH_CRYPTO = YesPlease
@ -224,6 +214,9 @@ ifeq ($(uname_S),SunOS)
NEEDS_LIBICONV = YesPlease
SHELL_PATH = /bin/bash
NO_STRCASESTR = YesPlease
ifeq ($(uname_R),5.8)
NO_SETENV = YesPlease
endif
INSTALL = ginstall
TAR = gtar
ALL_CFLAGS += -D__EXTENSIONS__
@ -256,6 +249,18 @@ endif
-include config.mak
ifdef WITH_OWN_SUBPROCESS_PY
PYMODULES += compat/subprocess.py
else
ifneq ($(shell $(PYTHON_PATH) -c 'import subprocess;print"OK"' 2>/dev/null),OK)
PYMODULES += compat/subprocess.py
endif
endif
ifdef WITH_SEND_EMAIL
SCRIPT_PERL += git-send-email.perl
endif
ifndef NO_CURL
ifdef CURLDIR
# This is still problematic -- gcc does not always want -R.
@ -315,12 +320,16 @@ ifdef NEEDS_NSL
SIMPLE_LIB += -lnsl
endif
ifdef NO_STRCASESTR
ALL_CFLAGS += -Dstrcasestr=gitstrcasestr -DNO_STRCASESTR=1
LIB_OBJS += compat/strcasestr.o
COMPAT_CFLAGS += -Dstrcasestr=gitstrcasestr -DNO_STRCASESTR=1
COMPAT_OBJS += compat/strcasestr.o
endif
ifdef NO_SETENV
COMPAT_CFLAGS += -Dsetenv=gitsetenv -DNO_SETENV=1
COMPAT_OBJS += compat/setenv.o
endif
ifdef NO_MMAP
ALL_CFLAGS += -Dmmap=gitfakemmap -Dmunmap=gitfakemunmap -DNO_MMAP
LIB_OBJS += compat/mmap.o
COMPAT_CFLAGS += -Dmmap=gitfakemmap -Dmunmap=gitfakemunmap -DNO_MMAP
COMPAT_OBJS += compat/mmap.o
endif
ifdef NO_IPV6
ALL_CFLAGS += -DNO_IPV6 -Dsockaddr_storage=sockaddr_in
@ -344,8 +353,8 @@ endif
endif
endif
ALL_CFLAGS += -DSHA1_HEADER=$(call shellquote,$(SHA1_HEADER))
ALL_CFLAGS += -DSHA1_HEADER=$(call shellquote,$(SHA1_HEADER)) $(COMPAT_CFLAGS)
LIB_OBJS += $(COMPAT_OBJS)
export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
### Build rules
@ -354,10 +363,9 @@ all: $(ALL_PROGRAMS)
all:
$(MAKE) -C templates
# Only use $(CFLAGS). We don't need anything else.
git$(X): git.c Makefile
git$(X): git.c $(COMPAT_OBJS) Makefile
$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
$(CFLAGS) $< -o $@
$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(filter %.o,$^)
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
rm -f $@

18
apply.c
Просмотреть файл

@ -16,6 +16,9 @@
// --numstat does numeric diffstat, and doesn't actually apply
// --index-info shows the old and new index info for paths if available.
//
static const char *prefix;
static int prefix_length = -1;
static int allow_binary_replacement = 0;
static int check_index = 0;
static int write_index = 0;
@ -1706,6 +1709,12 @@ static int use_patch(struct patch *p)
return 0;
x = x->next;
}
if (0 < prefix_length) {
int pathlen = strlen(pathname);
if (pathlen <= prefix_length ||
memcmp(prefix, pathname, prefix_length))
return 0;
}
return 1;
}
@ -1845,6 +1854,15 @@ int main(int argc, char **argv)
line_termination = 0;
continue;
}
if (check_index && prefix_length < 0) {
prefix = setup_git_directory();
prefix_length = prefix ? strlen(prefix) : 0;
git_config(git_default_config);
}
if (0 < prefix_length)
arg = prefix_filename(prefix, prefix_length, arg);
fd = open(arg, O_RDONLY);
if (fd < 0)
usage(apply_usage);

11
cache.h
Просмотреть файл

@ -147,8 +147,10 @@ extern char *get_graft_file(void);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
extern const char **get_pathspec(const char *prefix, const char **pathspec);
extern const char *setup_git_directory_gently(int *);
extern const char *setup_git_directory(void);
extern const char *prefix_path(const char *prefix, int len, const char *path);
extern const char *prefix_filename(const char *prefix, int len, const char *path);
#define alloc_nr(x) (((x)+16)*3/2)
@ -182,6 +184,10 @@ extern int trust_executable_bit;
extern int only_use_symrefs;
extern int diff_rename_limit_default;
#define GIT_REPO_VERSION 0
extern int repository_format_version;
extern int check_repository_format(void);
#define MTIME_CHANGED 0x0001
#define CTIME_CHANGED 0x0002
#define OWNER_CHANGED 0x0004
@ -383,16 +389,21 @@ extern int gitfakemunmap(void *start, size_t length);
typedef int (*config_fn_t)(const char *, const char *);
extern int git_default_config(const char *, const char *);
extern int git_config_from_file(config_fn_t fn, const char *);
extern int git_config(config_fn_t fn);
extern int git_config_int(const char *, const char *);
extern int git_config_bool(const char *, const char *);
extern int git_config_set(const char *, const char *);
extern int git_config_set_multivar(const char *, const char *, const char *, int);
extern int check_repository_format_version(const char *var, const char *value);
#define MAX_GITNAME (1000)
extern char git_default_email[MAX_GITNAME];
extern char git_default_name[MAX_GITNAME];
#define MAX_ENCODING_LENGTH 64
extern char git_commit_encoding[MAX_ENCODING_LENGTH];
/* Sane ctype - no locale, and works with signed chars */
#undef isspace
#undef isdigit

Просмотреть файл

@ -11,27 +11,44 @@ int main(int argc, char **argv)
char type[20];
void *buf;
unsigned long size;
int opt;
setup_git_directory();
if (argc != 3 || get_sha1(argv[2], sha1))
usage("git-cat-file [-t | -s | <type>] <sha1>");
usage("git-cat-file [-t|-s|-e|<type>] <sha1>");
if (!strcmp("-t", argv[1]) || !strcmp("-s", argv[1])) {
if (!sha1_object_info(sha1, type,
argv[1][1] == 's' ? &size : NULL)) {
switch (argv[1][1]) {
case 't':
printf("%s\n", type);
break;
case 's':
printf("%lu\n", size);
break;
}
opt = 0;
if ( argv[1][0] == '-' ) {
opt = argv[1][1];
if ( !opt || argv[1][2] )
opt = -1; /* Not a single character option */
}
buf = NULL;
switch (opt) {
case 't':
if (!sha1_object_info(sha1, type, NULL)) {
printf("%s\n", type);
return 0;
}
buf = NULL;
} else {
break;
case 's':
if (!sha1_object_info(sha1, type, &size)) {
printf("%lu\n", size);
return 0;
}
break;
case 'e':
return !has_sha1_file(sha1);
case 0:
buf = read_object_with_reference(sha1, argv[1], &size, NULL);
break;
default:
die("git-cat-file: unknown option: %s\n", argv[1]);
}
if (!buf)

Просмотреть файл

@ -34,6 +34,9 @@
*/
#include "cache.h"
static const char *prefix;
static int prefix_length;
static struct checkout state = {
.base_dir = "",
.base_dir_len = 0,
@ -69,6 +72,10 @@ static int checkout_all(void)
struct cache_entry *ce = active_cache[i];
if (ce_stage(ce))
continue;
if (prefix && *prefix &&
( ce_namelen(ce) <= prefix_length ||
memcmp(prefix, ce->name, prefix_length) ))
continue;
if (checkout_entry(ce, &state) < 0)
errs++;
}
@ -91,6 +98,9 @@ int main(int argc, char **argv)
int newfd = -1;
int all = 0;
prefix = setup_git_directory();
prefix_length = prefix ? strlen(prefix) : 0;
if (read_cache() < 0) {
die("invalid cache");
}
@ -155,7 +165,7 @@ int main(int argc, char **argv)
if (all)
die("git-checkout-index: don't mix '--all' and explicit filenames");
checkout_file(arg);
checkout_file(prefix_path(prefix, prefix_length, arg));
}
if (all)

Просмотреть файл

@ -271,6 +271,8 @@ int main(int argc, char **argv)
int fd[2];
pid_t pid;
setup_git_directory();
nr_heads = 0;
heads = NULL;
for (i = 1; i < argc; i++) {

Просмотреть файл

@ -91,6 +91,8 @@ int main(int argc, char **argv)
if (argc < 2 || get_sha1_hex(argv[1], tree_sha1) < 0)
usage(commit_tree_usage);
setup_git_directory();
check_valid(tree_sha1, "tree");
for (i = 2; i < argc; i += 2) {
char *a, *b;

31
compat/setenv.c Normal file
Просмотреть файл

@ -0,0 +1,31 @@
#include <stdlib.h>
#include <string.h>
int gitsetenv(const char *name, const char *value, int replace)
{
int out;
size_t namelen, valuelen;
char *envstr;
if (!name || !value) return -1;
if (!replace) {
char *oldval = NULL;
oldval = getenv(name);
if (oldval) return 0;
}
namelen = strlen(name);
valuelen = strlen(value);
envstr = malloc((namelen + valuelen + 2) * sizeof(char));
if (!envstr) return -1;
memcpy(envstr, name, namelen);
envstr[namelen] = '=';
memcpy(envstr + namelen + 1, value, valuelen);
envstr[namelen + valuelen + 1] = 0;
out = putenv(envstr);
free(envstr);
return out;
}

Просмотреть файл

@ -11,6 +11,7 @@
#define MAXNAME (256)
static FILE *config_file;
static const char *config_file_name;
static int config_linenr;
static int get_next_char(void)
{
@ -186,7 +187,7 @@ static int git_parse_file(config_fn_t fn)
if (get_value(fn, var, baselen+1) < 0)
break;
}
die("bad config file line %d", config_linenr);
die("bad config file line %d in %s", config_linenr, config_file_name);
}
int git_config_int(const char *name, const char *value)
@ -197,7 +198,7 @@ int git_config_int(const char *name, const char *value)
if (!*end)
return val;
}
die("bad config value for '%s'", name);
die("bad config value for '%s' in %s", name, config_file_name);
}
int git_config_bool(const char *name, const char *value)
@ -236,25 +237,37 @@ int git_default_config(const char *var, const char *value)
return 0;
}
if (!strcmp(var, "i18n.commitencoding")) {
strncpy(git_commit_encoding, value, sizeof(git_commit_encoding));
return 0;
}
/* Add other config variables here.. */
return 0;
}
int git_config(config_fn_t fn)
int git_config_from_file(config_fn_t fn, const char *filename)
{
int ret;
FILE *f = fopen(git_path("config"), "r");
FILE *f = fopen(filename, "r");
ret = -1;
if (f) {
config_file = f;
config_file_name = filename;
config_linenr = 1;
ret = git_parse_file(fn);
fclose(f);
config_file_name = NULL;
}
return ret;
}
int git_config(config_fn_t fn)
{
return git_config_from_file(fn, git_path("config"));
}
/*
* Find all the stuff for git_config_set() below.
*/

Просмотреть файл

@ -316,6 +316,8 @@ int main(int argc, char **argv)
unsigned char sha1[20];
struct entry *entry;
setup_git_directory();
if (argc != 2 || get_sha1(argv[1], sha1))
usage("git-convert-objects <sha1>");

Просмотреть файл

@ -82,9 +82,63 @@ static void loginfo(const char *err, ...)
va_end(params);
}
static int avoid_alias(char *p)
{
int sl, ndot;
/*
* This resurrects the belts and suspenders paranoia check by HPA
* done in <435560F7.4080006@zytor.com> thread, now enter_repo()
* does not do getcwd() based path canonicalizations.
*
* sl becomes true immediately after seeing '/' and continues to
* be true as long as dots continue after that without intervening
* non-dot character.
*/
if (!p || (*p != '/' && *p != '~'))
return -1;
sl = 1; ndot = 0;
p++;
while (1) {
char ch = *p++;
if (sl) {
if (ch == '.')
ndot++;
else if (ch == '/') {
if (ndot < 3)
/* reject //, /./ and /../ */
return -1;
ndot = 0;
}
else if (ch == 0) {
if (0 < ndot && ndot < 3)
/* reject /.$ and /..$ */
return -1;
return 0;
}
else
sl = ndot = 0;
}
else if (ch == 0)
return 0;
else if (ch == '/') {
sl = 1;
ndot = 0;
}
}
}
static char *path_ok(char *dir)
{
char *path = enter_repo(dir, strict_paths);
char *path;
if (avoid_alias(dir)) {
logerror("'%s': aliased", dir);
return NULL;
}
path = enter_repo(dir, strict_paths);
if (!path) {
logerror("'%s': unable to chdir or not a git archive", dir);
@ -96,9 +150,11 @@ static char *path_ok(char *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).
* appends optional {.git,.git/.git} and friends, but
* it does not use getcwd(). So if your /pub is
* a symlink to /mnt/pub, you can whitelist /pub and
* do not have to say /mnt/pub.
* Do not say /pub/.
*/
for ( pp = ok_paths ; *pp ; pp++ ) {
int len = strlen(*pp);

6
debian/changelog поставляемый
Просмотреть файл

@ -1,3 +1,9 @@
git-core (0.99.9l-0) unstable; urgency=low
* GIT 0.99.9l aka 1.0rc4
-- Junio C Hamano <junkio@cox.net> Sat, 3 Dec 2005 23:45:23 -0800
git-core (0.99.9k-0) unstable; urgency=low
* GIT 0.99.9k but not 1.0rc yet.

Просмотреть файл

@ -7,12 +7,12 @@
#include "diff.h"
static const char diff_files_usage[] =
"git-diff-files [-q] "
"[<common diff options>] [<path>...]"
"git-diff-files [-q] [-0/-1/2/3] [<common diff options>] [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
static struct diff_options diff_options;
static int silent = 0;
static int diff_unmerged_stage = 2;
static void show_unmerge(const char *path)
{
@ -46,7 +46,21 @@ int main(int argc, const char **argv)
argc--;
break;
}
if (!strcmp(argv[1], "-q"))
if (!strcmp(argv[1], "-0"))
diff_unmerged_stage = 0;
else if (!strcmp(argv[1], "-1"))
diff_unmerged_stage = 1;
else if (!strcmp(argv[1], "-2"))
diff_unmerged_stage = 2;
else if (!strcmp(argv[1], "-3"))
diff_unmerged_stage = 3;
else if (!strcmp(argv[1], "--base"))
diff_unmerged_stage = 1;
else if (!strcmp(argv[1], "--ours"))
diff_unmerged_stage = 2;
else if (!strcmp(argv[1], "--theirs"))
diff_unmerged_stage = 3;
else if (!strcmp(argv[1], "-q"))
silent = 1;
else if (!strcmp(argv[1], "-r"))
; /* no-op */
@ -95,11 +109,26 @@ int main(int argc, const char **argv)
if (ce_stage(ce)) {
show_unmerge(ce->name);
while (i < entries &&
!strcmp(ce->name, active_cache[i]->name))
while (i < entries) {
struct cache_entry *nce = active_cache[i];
if (strcmp(ce->name, nce->name))
break;
/* diff against the proper unmerged stage */
if (ce_stage(nce) == diff_unmerged_stage)
ce = nce;
i++;
i--; /* compensate for loop control increments */
continue;
}
/*
* Compensate for loop update
*/
i--;
/*
* Show the diff for the 'ce' if we found the one
* from the desired stage.
*/
if (ce_stage(ce) != diff_unmerged_stage)
continue;
}
if (lstat(ce->name, &st) < 0) {

Просмотреть файл

@ -13,6 +13,8 @@ char git_default_email[MAX_GITNAME];
char git_default_name[MAX_GITNAME];
int trust_executable_bit = 1;
int only_use_symrefs = 0;
int repository_format_version = 0;
char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
*git_graft_file;

Просмотреть файл

@ -424,6 +424,8 @@ int main(int argc, char **argv)
int fd[2];
pid_t pid;
setup_git_directory();
nr_heads = 0;
heads = NULL;
for (i = 1; i < argc; i++) {

Просмотреть файл

@ -431,6 +431,8 @@ int main(int argc, char **argv)
{
int i, heads;
setup_git_directory();
for (i = 1; i < argc; i++) {
const char *arg = argv[i];

Просмотреть файл

@ -1,5 +1,10 @@
#!/bin/sh
die () {
echo >&2 "$*"
exit 1
}
usage() {
die "usage: git add [-n] [-v] <file>..."
}

Просмотреть файл

@ -33,7 +33,7 @@ do
-k) keep_subject=-k ;;
-q) query_apply=t ;;
-c) continue="$2"; resume=f; shift ;;
-m) fallback_3way=t ;;
-m) fall_back_3way=t ;;
-*) usage ;;
*) break ;;
esac

Просмотреть файл

@ -120,26 +120,36 @@ git-apply --index "$PATCHFILE" || {
O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
rm -fr .patch-merge-*
if git-apply -z --index-info "$PATCHFILE" \
>.patch-merge-index-info 2>/dev/null &&
GIT_INDEX_FILE=.patch-merge-tmp-index \
git-update-index -z --index-info <.patch-merge-index-info &&
GIT_INDEX_FILE=.patch-merge-tmp-index \
git-write-tree >.patch-merge-tmp-base &&
(
mkdir .patch-merge-tmp-dir &&
cd .patch-merge-tmp-dir &&
GIT_INDEX_FILE="../.patch-merge-tmp-index" \
GIT_OBJECT_DIRECTORY="$O_OBJECT" \
git-apply $binary --index
) <"$PATCHFILE"
then
echo Using index info to reconstruct a base tree...
mv .patch-merge-tmp-base .patch-merge-base
mv .patch-merge-tmp-index .patch-merge-index
else
(
N=10
# if the patch records the base tree...
sed -ne '
/^diff /q
/^applies-to: \([0-9a-f]*\)$/{
s//\1/p
q
}
' "$PATCHFILE"
# or hoping the patch is against our recent commits...
# Otherwise, try nearby trees that can be used to apply the
# patch.
git-rev-list --max-count=$N HEAD
# or hoping the patch is against known tags...
git-ls-remote --tags .
) |
while read base junk
do
while read base junk
do
# Try it if we have it as a tree.
git-cat-file tree "$base" >/dev/null 2>&1 || continue
@ -155,7 +165,8 @@ git-apply --index "$PATCHFILE" || {
mv ../.patch-merge-tmp-index ../.patch-merge-index &&
echo "$base" >../.patch-merge-base
) <"$PATCHFILE" 2>/dev/null && break
done
done
fi
test -f .patch-merge-index &&
his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) &&

Просмотреть файл

@ -1,9 +1,19 @@
#!/bin/sh
. git-sh-setup
sq() {
perl -e '
for (@ARGV) {
s/'\''/'\'\\\\\'\''/g;
print " '\''$_'\''";
}
print "\n";
' "$@"
}
usage() {
echo >&2 'usage: git bisect [start|bad|good|next|reset|visualize]
git bisect start reset bisect state and start bisection.
git bisect start [<pathspec>] reset bisect state and start bisection.
git bisect bad [<rev>] mark <rev> a known-bad revision.
git bisect good [<rev>...] mark <rev>... known-good revisions.
git bisect next find next bisection to test and check it out.
@ -33,7 +43,6 @@ bisect_autostart() {
}
bisect_start() {
case "$#" in 0) ;; *) usage ;; esac
#
# Verify HEAD. If we were bisecting before this, reset to the
# top-of-line master first!
@ -57,7 +66,11 @@ bisect_start() {
rm -f "$GIT_DIR/refs/heads/bisect"
rm -rf "$GIT_DIR/refs/bisect/"
mkdir "$GIT_DIR/refs/bisect"
echo "git-bisect start" >"$GIT_DIR/BISECT_LOG"
{
echo -n "git-bisect start"
sq "$@"
} >"$GIT_DIR/BISECT_LOG"
sq "$@" >"$GIT_DIR/BISECT_NAMES"
}
bisect_bad() {
@ -121,7 +134,7 @@ bisect_next() {
bad=$(git-rev-parse --verify refs/bisect/bad) &&
good=$(git-rev-parse --sq --revs-only --not \
$(cd "$GIT_DIR" && ls refs/bisect/good-*)) &&
rev=$(eval "git-rev-list --bisect $good $bad") || exit
rev=$(eval "git-rev-list --bisect $good $bad -- $(cat $GIT_DIR/BISECT_NAMES)") || exit
if [ -z "$rev" ]; then
echo "$bad was both good and bad"
exit 1
@ -131,7 +144,7 @@ bisect_next() {
git-diff-tree --pretty $rev
exit 0
fi
nr=$(eval "git-rev-list $rev $good" | wc -l) || exit
nr=$(eval "git-rev-list $rev $good -- $(cat $GIT_DIR/BISECT_NAMES)" | wc -l) || exit
echo "Bisecting: $nr revisions left to test after this"
echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
git checkout new-bisect || exit
@ -142,7 +155,8 @@ bisect_next() {
bisect_visualize() {
bisect_next_check fail
gitk bisect/bad --not `cd "$GIT_DIR/refs" && echo bisect/good-*`
not=`cd "$GIT_DIR/refs" && echo bisect/good-*`
eval gitk bisect/bad --not $not -- $(cat "$GIT_DIR/BISECT_NAMES")
}
bisect_reset() {
@ -173,7 +187,8 @@ bisect_replay () {
test "$bisect" = "git-bisect" || continue
case "$command" in
start)
bisect_start
cmd="bisect_start $rev"
eval "$cmd"
;;
good)
echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"

Просмотреть файл

@ -1,6 +1,11 @@
#!/bin/sh
. git-sh-setup
GIT_DIR=`git-rev-parse --git-dir` || exit $?
die () {
echo >&2 "$*"
exit 1
}
usage () {
echo >&2 "usage: $(basename $0)"' [-d <branch>] | [[-f] <branch> [start-point]]
@ -12,8 +17,7 @@ If two arguments, create a new branch <branchname> based off of <start-point>.
exit 1
}
headref=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD |
sed -e 's|^refs/heads/||')
headref=$(git-symbolic-ref HEAD | sed -e 's|^refs/heads/||')
delete_branch () {
option="$1"
@ -114,4 +118,3 @@ then
fi
fi
git update-ref "refs/heads/$branchname" $rev

Просмотреть файл

@ -73,7 +73,7 @@ while
*,-n) no_checkout=yes ;;
*,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) use_local=yes ;;
*,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
local_shared=yes ;;
local_shared=yes; use_local=yes ;;
*,-q|*,--quiet) quiet=-q ;;
1,-u|1,--upload-pack) usage ;;
*,-u|*,--upload-pack)

Просмотреть файл

@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano
#
. git-sh-setup
GIT_DIR=`git-rev-parse --git-dir` || exit $?
dc </dev/null 2>/dev/null || {
# This is not a real DC at all -- it just knows how

Просмотреть файл

@ -7,7 +7,10 @@ rev=$(git-rev-parse --revs-only --no-flags --sq "$@") || exit
flags=$(git-rev-parse --no-revs --flags --sq "$@")
files=$(git-rev-parse --no-revs --no-flags --sq "$@")
: ${flags:="'-M' '-p'"}
die () {
echo >&2 "$*"
exit 1
}
# I often say 'git diff --cached -p' and get scolded by git-diff-files, but
# obviously I mean 'git diff --cached -p HEAD' in that case.
@ -20,6 +23,21 @@ case "$rev" in
esac
esac
# If we do not have --name-status, --name-only nor -r, default to -p.
# If we do not have -B nor -C, default to -M.
case " $flags " in
*" '--name-status' "* | *" '--name-only' "* | *" '-r' "* )
;;
*)
flags="$flags'-p' " ;;
esac
case " $flags " in
*" '-"[BCM]* | *" '--find-copies-harder' "*)
;; # something like -M50.
*)
flags="$flags'-M' " ;;
esac
case "$rev" in
?*' '?*' '?*)
echo >&2 "I don't understand"

Просмотреть файл

@ -5,6 +5,10 @@
. git-sh-setup
# Force diff to run in C locale.
LANG=C LC_ALL=C
export LANG LC_ALL
usage () {
echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
[--check] [--signoff] [-<diff options>...]
@ -202,7 +206,7 @@ process_one () {
;;
esac
eval "$(LANG=C LC_ALL=C sed -ne "$whosepatchScript" $commsg)"
eval "$(sed -ne "$whosepatchScript" $commsg)"
test "$author,$au" = ",$me" || {
mailScript="$mailScript"'
a\
@ -238,9 +242,8 @@ Date: '"$ad"
echo
git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
echo
git-cat-file commit "$commit^" | sed -e 's/^tree /applies-to: /' -e q
git-diff-tree -p $diff_opts "$commit"
echo "---"
echo "-- "
echo "@@GIT_VERSION@@"
case "$mbox" in
@ -268,7 +271,7 @@ do
file=`printf '%04d-%stxt' $i "$title"`
if test '' = "$stdout"
then
echo "* $file"
echo "$file"
process_one >"$outdir$file"
if test t = "$check"
then
@ -279,7 +282,7 @@ do
:
fi
else
echo >&2 "* $file"
echo >&2 "$file"
process_one
fi
i=`expr "$i" + 1`

Просмотреть файл

@ -1,7 +1,6 @@
#!/bin/sh
. git-sh-setup
GIT_DIR=`git-rev-parse --git-dir` || exit $?
laf="$GIT_DIR/lost-found"
rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit

Просмотреть файл

@ -6,6 +6,11 @@ usage () {
exit 1;
}
die () {
echo >&2 "$*"
exit 1
}
while case "$#" in 0) break;; esac
do
case "$1" in

Просмотреть файл

@ -8,6 +8,11 @@
LF='
'
die () {
echo >&2 "$*"
exit 1
}
# The first parameters up to -- are merge bases; the rest are heads.
bases= head= remotes= sep_seen=
for arg

Просмотреть файл

@ -26,7 +26,7 @@ case "${1:-.}${2:-.}${3:-.}" in
fi
if test -f "$4"; then
rm -f -- "$4" &&
rmdir -p "$(expr "$4" : '\(.*\)/')" 2>/dev/null
rmdir -p "$(expr "$4" : '\(.*\)/')" 2>/dev/null || :
fi &&
exec git-update-index --remove -- "$4"
;;
@ -58,6 +58,14 @@ case "${1:-.}${2:-.}${3:-.}" in
# Modified in both, but differently.
#
"$1$2$3" | ".$2$3")
case ",$6,$7," in
*,120000,*)
echo "ERROR: $4: Not merging symbolic link changes."
exit 1
;;
esac
src2=`git-unpack-file $3`
case "$1" in
'')
@ -79,10 +87,12 @@ case "${1:-.}${2:-.}${3:-.}" in
;;
esac
# We reset the index to the first branch, making
# git-diff-file useful
git-update-index --add --cacheinfo "$6" "$2" "$4"
git-checkout-index -u -f -- "$4" &&
# Create the working tree file, with the correct permission bits.
# we can not rely on the fact that our tree has the path, because
# we allow the merge to be done in an unchecked-out working tree.
rm -f "$4" &&
git-cat-file blob "$2" >"$4" &&
case "$6" in *7??) chmod +x "$4" ;; esac &&
merge "$4" "$orig" "$src2"
ret=$?
rm -f -- "$orig" "$src2"

Просмотреть файл

@ -98,7 +98,7 @@ getFilesRE = re.compile(r'^([0-7]+) (\S+) ([0-9a-f]{40})\t(.*)$', re.S)
def getFilesAndDirs(tree):
files = Set()
dirs = Set()
out = runProgram(['git-ls-tree', '-r', '-z', tree])
out = runProgram(['git-ls-tree', '-r', '-z', '-t', tree])
for l in out.split('\0'):
m = getFilesRE.match(l)
if m:
@ -828,8 +828,6 @@ def processEntry(entry, branch1Name, branch2Name):
if cacheOnly:
updateFile(False, sha, mode, path)
else:
updateFileExt(aSha, aMode, path,
updateCache=True, updateWd=False)
updateFileExt(sha, mode, path, updateCache=False, updateWd=True)
else:
die("ERROR: Fatal merge failure, shouldn't happen.")

Просмотреть файл

@ -273,7 +273,8 @@ fi
case "$best_strategy" in
'')
restorestate
die "No merge strategy handled the merge."
echo >&2 "No merge strategy handled the merge."
exit 2
;;
"$wt_strategy")
# We already have its result in the working tree.

Просмотреть файл

@ -13,35 +13,15 @@ use Getopt::Std;
sub usage() {
print <<EOT;
$0 [-f] [-n] <source> <dest>
$0 [-f] [-k] [-n] <source> ... <dest directory>
In the first form, source must exist and be either a file,
symlink or directory, dest must not exist. It renames source to dest.
In the second form, the last argument has to be an existing
directory; the given sources will be moved into this directory.
Updates the git cache to reflect the change.
Use "git commit" to make the change permanently.
Options:
-f Force renaming/moving, even if target exists
-k Continue on error by skipping
not-existing or not revision-controlled source
-n Do nothing; show what would happen
$0 [-f] [-n] <source> <destination>
$0 [-f] [-n] [-k] <source> ... <destination directory>
EOT
exit(1);
}
# Sanity checks:
my $GIT_DIR = $ENV{'GIT_DIR'} || ".git";
unless ( -d $GIT_DIR && -d $GIT_DIR . "/objects" &&
-d $GIT_DIR . "/objects/" && -d $GIT_DIR . "/refs") {
print "Git repository not found.";
usage();
}
my $GIT_DIR = `git rev-parse --git-dir`;
exit 1 if $?; # rev-parse would have given "not a git dir" message.
chomp($GIT_DIR);
our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v);
getopts("hnfkv") || usage;
@ -70,7 +50,7 @@ else {
print "Error: moving to directory '"
. $ARGV[$argCount-1]
. "' not possible; not exisiting\n";
usage;
exit(1);
}
@srcArgs = ($ARGV[0]);
@dstArgs = ($ARGV[1]);
@ -122,7 +102,7 @@ while(scalar @srcArgs > 0) {
}
}
if (($bad eq "") && ($src eq $dstDir)) {
if (($bad eq "") && ($dst =~ /^$safesrc\//)) {
$bad = "can not move directory '$src' into itself";
}
@ -148,7 +128,7 @@ while(scalar @srcArgs > 0) {
next;
}
print "Error: $bad\n";
usage();
exit(1);
}
push @srcs, $src;
push @dsts, $dst;
@ -156,14 +136,22 @@ while(scalar @srcArgs > 0) {
# Final pass: rename/move
my (@deletedfiles,@addedfiles,@changedfiles);
$bad = "";
while(scalar @srcs > 0) {
$src = shift @srcs;
$dst = shift @dsts;
if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; }
if (!$opt_n) {
rename($src,$dst)
or die "rename failed: $!";
if (!rename($src,$dst)) {
$bad = "renaming '$src' failed: $!";
if ($opt_k) {
print "Warning: skipped: $bad\n";
$bad = "";
next;
}
last;
}
}
$safesrc = quotemeta($src);
@ -187,20 +175,44 @@ while(scalar @srcs > 0) {
}
if ($opt_n) {
if (@changedfiles) {
print "Changed : ". join(", ", @changedfiles) ."\n";
}
if (@addedfiles) {
print "Adding : ". join(", ", @addedfiles) ."\n";
}
if (@deletedfiles) {
print "Deleting : ". join(", ", @deletedfiles) ."\n";
exit(1);
}
}
my $rc;
if (scalar @changedfiles >0) {
$rc = system("git-update-index","--",@changedfiles);
die "git-update-index failed to update changed files with code $?\n" if $rc;
else {
if (@changedfiles) {
open(H, "| git-update-index -z --stdin")
or die "git-update-index failed to update changed files with code $!\n";
foreach my $fileName (@changedfiles) {
print H "$fileName\0";
}
close(H);
}
if (@addedfiles) {
open(H, "| git-update-index --add -z --stdin")
or die "git-update-index failed to add new names with code $!\n";
foreach my $fileName (@addedfiles) {
print H "$fileName\0";
}
close(H);
}
if (@deletedfiles) {
open(H, "| git-update-index --remove -z --stdin")
or die "git-update-index failed to remove old names with code $!\n";
foreach my $fileName (@deletedfiles) {
print H "$fileName\0";
}
close(H);
}
}
if (scalar @addedfiles >0) {
$rc = system("git-update-index","--add","--",@addedfiles);
die "git-update-index failed to add new names with code $?\n" if $rc;
if ($bad ne "") {
print "Error: $bad\n";
exit(1);
}
$rc = system("git-update-index","--remove","--",@deletedfiles);
die "git-update-index failed to remove old names with code $?\n" if $rc;

Просмотреть файл

@ -5,9 +5,25 @@
. git-sh-setup
# The other head is given
# Make sure we do not have .dotest
if mkdir .dotest
then
rmdir .dotest
else
echo >&2 '
It seems that I cannot create a .dotest directory, and I wonder if you
are in the middle of patch application or another rebase. If that is not
the case, please rm -fr .dotest and run me again. I am stopping in case
you still have something valuable there.'
exit 1
fi
# The other head is given. Make sure it is valid.
other=$(git-rev-parse --verify "$1^0") || exit
# Make sure we have HEAD that is valid.
head=$(git-rev-parse --verify "HEAD^0") || exit
# The tree must be really really clean.
git-update-index --refresh || exit
diff=$(git-diff-index --cached --name-status -r HEAD)
@ -23,6 +39,16 @@ case "$#" in
git-checkout "$2" || exit
esac
# If the HEAD is a proper descendant of $other, we do not even need
# to rebase. Make sure we do not do needless rebase. In such a
# case, merge-base should be the same as "$other".
mb=$(git-merge-base "$other" "$head")
if test "$mb" = "$other"
then
echo >&2 "Current branch `git-symbolic-ref HEAD` is up to date."
exit 0
fi
# Rewind the head to "$other"
git-reset --hard "$other"
git-format-patch -k --stdout --full-index "$other" ORIG_HEAD |

Просмотреть файл

@ -35,7 +35,7 @@ our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b
sub usage() {
print STDERR <<END;
Usage: ${\basename $0} # fetch/update GIT from SVN
[-o branch-for-HEAD] [-h] [-v] [-l max_num_changes]
[-o branch-for-HEAD] [-h] [-v] [-l max_rev]
[-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
[-d|-D] [-i] [-u] [-s start_chg] [-m] [-M regex] [SVN_URL]
END
@ -126,8 +126,9 @@ sub file {
package main;
use URI;
my $svn = $svn_url;
our $svn = $svn_url;
$svn .= "/$svn_dir" if defined $svn_dir;
my $svn2 = SVNconn->new($svn);
$svn = SVNconn->new($svn);
my $lwp_ua;
@ -198,7 +199,7 @@ $ENV{GIT_INDEX_FILE} = $git_index;
my $maxnum = 0;
my $last_rev = "";
my $last_branch;
my $current_rev = $opt_s-1;
my $current_rev = $opt_s || 1;
unless(-d $git_dir) {
system("git-init-db");
die "Cannot init the GIT db at $git_tree: $?\n" if $?;
@ -254,7 +255,7 @@ EOM
my($num,$branch,$ref) = split;
$branches{$branch}{$num} = $ref;
$branches{$branch}{"LAST"} = $ref;
$current_rev = $num if $current_rev < $num;
$current_rev = $num+1 if $current_rev <= $num;
}
close($B);
}
@ -708,17 +709,17 @@ sub commit {
print "DONE: $revision $dest $cid\n" if $opt_v;
}
my ($changed_paths, $revision, $author, $date, $message, $pool) = @_;
sub _commit_all {
($changed_paths, $revision, $author, $date, $message, $pool) = @_;
sub commit_all {
# Recursive use of the SVN connection does not work
local $svn = $svn2;
my ($changed_paths, $revision, $author, $date, $message, $pool) = @_;
my %p;
while(my($path,$action) = each %$changed_paths) {
$p{$path} = [ $action->action,$action->copyfrom_path, $action->copyfrom_rev, $path ];
}
$changed_paths = \%p;
}
sub commit_all {
my %done;
my @col;
my $pref;
@ -734,18 +735,12 @@ sub commit_all {
}
}
while(++$current_rev <= $svn->{'maxrev'}) {
if (defined $opt_l) {
$opt_l--;
if ($opt_l < 0) {
last;
}
}
my $pool=SVN::Pool->new;
$svn->{'svn'}->get_log("/",$current_rev,$current_rev,1,1,1,\&_commit_all,$pool);
$pool->clear;
commit_all();
}
$opt_l = $svn->{'maxrev'} if not defined $opt_l or $opt_l > $svn->{'maxrev'};
print "Fetching from $current_rev to $opt_l ...\n" if $opt_v;
my $pool=SVN::Pool->new;
$svn->{'svn'}->get_log("/",$current_rev,$opt_l,0,1,1,\&commit_all,$pool);
$pool->clear;
unlink($git_index);

Просмотреть файл

@ -1,13 +1,18 @@
#!/bin/sh
# Copyright (c) 2005 Linus Torvalds
. git-sh-setup
GIT_DIR=`git-rev-parse --git-dir` || exit $?
usage () {
echo >&2 "Usage: git-tag [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <tagname> [<head>]"
exit 1
}
die () {
echo >&2 "$*"
exit 1
}
annotate=
signed=
force=

Просмотреть файл

@ -1,5 +1,11 @@
#!/bin/sh
. git-sh-setup
GIT_DIR=`git-rev-parse --git-dir` || exit $?
die () {
echo >&2 "$*"
exit 1
}
type="$(git-cat-file -t "$1" 2>/dev/null)" ||
die "$1: no such object."
@ -7,6 +13,9 @@ type="$(git-cat-file -t "$1" 2>/dev/null)" ||
test "$type" = tag ||
die "$1: cannot verify a non-tag object of type $type."
git-cat-file tag "$1" > .tmp-vtag || exit 1
cat .tmp-vtag | sed '/-----BEGIN PGP/Q' | gpg --verify .tmp-vtag - || exit 1
rm -f .tmp-vtag
git-cat-file tag "$1" >"$GIT_DIR/.tmp-vtag" || exit 1
cat "$GIT_DIR/.tmp-vtag" |
sed '/-----BEGIN PGP/Q' |
gpg --verify "$GIT_DIR/.tmp-vtag" - || exit 1
rm -f "$GIT_DIR/.tmp-vtag"

23
git.c
Просмотреть файл

@ -13,6 +13,10 @@
# define PATH_MAX 4096
#endif
#ifdef NO_SETENV
extern int gitsetenv(char *name, char *value, int overwrite);
#endif
static const char git_usage[] =
"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
@ -283,16 +287,21 @@ int main(int argc, char **argv, char **envp)
len = strlen(git_command);
prepend_to_path(git_command, len);
strncat(&git_command[len], "/git-", sizeof(git_command) - len);
len += 5;
strncat(&git_command[len], argv[i], sizeof(git_command) - len);
if (access(git_command, X_OK))
usage(exec_path, "'%s' is not a git-command", argv[i]);
len += snprintf(git_command + len, sizeof(git_command) - len,
"/git-%s", argv[i]);
if (sizeof(git_command) <= len) {
fprintf(stderr, "git: command name given is too long (%d)\n", len);
exit(1);
}
/* execve() can only ever return if it fails */
execve(git_command, &argv[i], envp);
printf("Failed to run command '%s': %s\n", git_command, strerror(errno));
if (errno == ENOENT)
usage(exec_path, "'%s' is not a git-command", argv[i]);
fprintf(stderr, "Failed to run command '%s': %s\n",
git_command, strerror(errno));
return 1;
}

259
gitk
Просмотреть файл

@ -19,7 +19,7 @@ proc gitdir {} {
proc getcommits {rargs} {
global commits commfd phase canv mainfont env
global startmsecs nextupdate ncmupdate
global ctext maincursor textcursor leftover
global ctext maincursor textcursor leftover gitencoding
# check that we can find a .git directory somewhere...
set gitdir [gitdir]
@ -30,7 +30,7 @@ proc getcommits {rargs} {
set commits {}
set phase getcommits
set startmsecs [clock clicks -milliseconds]
set nextupdate [expr $startmsecs + 100]
set nextupdate [expr {$startmsecs + 100}]
set ncmupdate 1
if [catch {
set parse_args [concat --default HEAD $rargs]
@ -49,7 +49,7 @@ proc getcommits {rargs} {
exit 1
}
set leftover {}
fconfigure $commfd -blocking 0 -translation lf
fconfigure $commfd -blocking 0 -translation lf -encoding $gitencoding
fileevent $commfd readable [list getcommitlines $commfd]
$canv delete all
$canv create text 3 3 -anchor nw -text "Reading commits..." \
@ -74,9 +74,9 @@ proc getcommitlines {commfd} {
}
if {[string range $err 0 4] == "usage"} {
set err \
{Gitk: error reading commits: bad arguments to git-rev-list.
(Note: arguments to gitk are passed to git-rev-list
to allow selection of commits to be displayed.)}
"Gitk: error reading commits: bad arguments to git-rev-list.\
(Note: arguments to gitk are passed to git-rev-list\
to allow selection of commits to be displayed.)"
} else {
set err "Error reading commits: $err"
}
@ -297,23 +297,26 @@ proc makewindow {} {
global findtype findtypemenu findloc findstring fstring geometry
global entries sha1entry sha1string sha1but
global maincursor textcursor curtextcursor
global rowctxmenu gaudydiff mergemax
global rowctxmenu mergemax
menu .bar
.bar add cascade -label "File" -menu .bar.file
menu .bar.file
.bar.file add command -label "Reread references" -command rereadrefs
.bar.file add command -label "Quit" -command doquit
menu .bar.edit
.bar add cascade -label "Edit" -menu .bar.edit
.bar.edit add command -label "Preferences" -command doprefs
menu .bar.help
.bar add cascade -label "Help" -menu .bar.help
.bar.help add command -label "About gitk" -command about
. configure -menu .bar
if {![info exists geometry(canv1)]} {
set geometry(canv1) [expr 45 * $charspc]
set geometry(canv2) [expr 30 * $charspc]
set geometry(canv3) [expr 15 * $charspc]
set geometry(canvh) [expr 25 * $linespc + 4]
set geometry(canv1) [expr {45 * $charspc}]
set geometry(canv2) [expr {30 * $charspc}]
set geometry(canv3) [expr {15 * $charspc}]
set geometry(canvh) [expr {25 * $linespc + 4}]
set geometry(ctextw) 80
set geometry(ctexth) 30
set geometry(cflistw) 30
@ -414,25 +417,19 @@ proc makewindow {} {
.ctop.cdet add .ctop.cdet.left
$ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
if {$gaudydiff} {
$ctext tag conf hunksep -back blue -fore white
$ctext tag conf d0 -back "#ff8080"
$ctext tag conf d1 -back green
} else {
$ctext tag conf hunksep -fore blue
$ctext tag conf d0 -fore red
$ctext tag conf d1 -fore "#00a000"
$ctext tag conf m0 -fore red
$ctext tag conf m1 -fore blue
$ctext tag conf m2 -fore green
$ctext tag conf m3 -fore purple
$ctext tag conf m4 -fore brown
$ctext tag conf mmax -fore darkgrey
set mergemax 5
$ctext tag conf mresult -font [concat $textfont bold]
$ctext tag conf msep -font [concat $textfont bold]
$ctext tag conf found -back yellow
}
$ctext tag conf hunksep -fore blue
$ctext tag conf d0 -fore red
$ctext tag conf d1 -fore "#00a000"
$ctext tag conf m0 -fore red
$ctext tag conf m1 -fore blue
$ctext tag conf m2 -fore green
$ctext tag conf m3 -fore purple
$ctext tag conf m4 -fore brown
$ctext tag conf mmax -fore darkgrey
set mergemax 5
$ctext tag conf mresult -font [concat $textfont bold]
$ctext tag conf msep -font [concat $textfont bold]
$ctext tag conf found -back yellow
frame .ctop.cdet.right
set cflist .ctop.cdet.right.cfiles
@ -533,7 +530,7 @@ proc click {w} {
proc savestuff {w} {
global canv canv2 canv3 ctext cflist mainfont textfont
global stuffsaved findmergefiles gaudydiff maxgraphpct
global stuffsaved findmergefiles maxgraphpct
global maxwidth
if {$stuffsaved} return
@ -543,15 +540,14 @@ proc savestuff {w} {
puts $f [list set mainfont $mainfont]
puts $f [list set textfont $textfont]
puts $f [list set findmergefiles $findmergefiles]
puts $f [list set gaudydiff $gaudydiff]
puts $f [list set maxgraphpct $maxgraphpct]
puts $f [list set maxwidth $maxwidth]
puts $f "set geometry(width) [winfo width .ctop]"
puts $f "set geometry(height) [winfo height .ctop]"
puts $f "set geometry(canv1) [expr [winfo width $canv]-2]"
puts $f "set geometry(canv2) [expr [winfo width $canv2]-2]"
puts $f "set geometry(canv3) [expr [winfo width $canv3]-2]"
puts $f "set geometry(canvh) [expr [winfo height $canv]-2]"
puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]"
puts $f "set geometry(canv2) [expr {[winfo width $canv2]-2}]"
puts $f "set geometry(canv3) [expr {[winfo width $canv3]-2}]"
puts $f "set geometry(canvh) [expr {[winfo height $canv]-2}]"
set wid [expr {([winfo width $ctext] - 8) \
/ [font measure $textfont "0"]}]
puts $f "set geometry(ctextw) $wid"
@ -580,12 +576,12 @@ proc resizeclistpanes {win w} {
set sash0 30
}
if {$sash1 < $sash0 + 20} {
set sash1 [expr $sash0 + 20]
set sash1 [expr {$sash0 + 20}]
}
if {$sash1 > $w - 10} {
set sash1 [expr $w - 10]
set sash1 [expr {$w - 10}]
if {$sash0 > $sash1 - 20} {
set sash0 [expr $sash1 - 20]
set sash0 [expr {$sash1 - 20}]
}
}
}
@ -608,7 +604,7 @@ proc resizecdetpanes {win w} {
set sash0 45
}
if {$sash0 > $w - 15} {
set sash0 [expr $w - 15]
set sash0 [expr {$w - 15}]
}
}
$win sash place 0 $sash0 [lindex $s0 1]
@ -819,9 +815,9 @@ proc drawcommitline {level} {
}
set x [xcoord $level $level $lineno]
set y1 $canvy
set canvy [expr $canvy + $linespc]
set canvy [expr {$canvy + $linespc}]
allcanvs conf -scrollregion \
[list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]]
[list 0 0 0 [expr {$y1 + 0.5 * $linespc + 2}]]
if {[info exists mainline($id)]} {
lappend mainline($id) $x $y1
if {$mainlinearrow($id) ne "none"} {
@ -830,8 +826,8 @@ proc drawcommitline {level} {
}
drawlines $id 0 0
set orad [expr {$linespc / 3}]
set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \
[expr $x + $orad - 1] [expr $y1 + $orad - 1] \
set t [$canv create oval [expr {$x - $orad}] [expr {$y1 - $orad}] \
[expr {$x + $orad - 1}] [expr {$y1 + $orad - 1}] \
-fill $ofill -outline black -width 1]
$canv raise $t
$canv bind $t <1> {selcanvline {} %x %y}
@ -886,8 +882,8 @@ proc drawtags {id x xt y1} {
}
set delta [expr {int(0.5 * ($linespc - $lthickness))}]
set yt [expr $y1 - 0.5 * $linespc]
set yb [expr $yt + $linespc - 1]
set yt [expr {$y1 - 0.5 * $linespc}]
set yb [expr {$yt + $linespc - 1}]
set xvals {}
set wvals {}
foreach tag $marks {
@ -900,12 +896,12 @@ proc drawtags {id x xt y1} {
-width $lthickness -fill black -tags tag.$id]
$canv lower $t
foreach tag $marks x $xvals wid $wvals {
set xl [expr $x + $delta]
set xr [expr $x + $delta + $wid + $lthickness]
set xl [expr {$x + $delta}]
set xr [expr {$x + $delta + $wid + $lthickness}]
if {[incr ntags -1] >= 0} {
# draw a tag
set t [$canv create polygon $x [expr $yt + $delta] $xl $yt \
$xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \
set t [$canv create polygon $x [expr {$yt + $delta}] $xl $yt \
$xr $yt $xr $yb $xl $yb $x [expr {$yb - $delta}] \
-width 1 -outline black -fill yellow -tags tag.$id]
$canv bind $t <1> [list showtag $tag 1]
set rowtextx($idline($id)) [expr {$xr + $linespc}]
@ -916,7 +912,7 @@ proc drawtags {id x xt y1} {
} else {
set col "#ddddff"
}
set xl [expr $xl - $delta/2]
set xl [expr {$xl - $delta/2}]
$canv create polygon $x $yt $xr $yt $xr $yb $x $yb \
-width 1 -outline black -fill $col -tags tag.$id
}
@ -1491,7 +1487,7 @@ proc drawgraph {} {
if {$displayorder == {}} return
set startmsecs [clock clicks -milliseconds]
set nextupdate [expr $startmsecs + 100]
set nextupdate [expr {$startmsecs + 100}]
set ncmupdate 1
initgraph
foreach id $displayorder {
@ -1520,7 +1516,7 @@ proc drawrest {} {
}
drawmore 0
set phase {}
set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs]
set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
#puts "overall $drawmsecs ms for $numcommits commits"
if {$redisplaying} {
if {$stopped == 0 && [info exists selectedline]} {
@ -1548,8 +1544,8 @@ proc findmatches {f} {
set matches {}
set i 0
while {[set j [string first $foundstring $str $i]] >= 0} {
lappend matches [list $j [expr $j+$foundstrlen-1]]
set i [expr $j + $foundstrlen]
lappend matches [list $j [expr {$j+$foundstrlen-1}]]
set i [expr {$j + $foundstrlen}]
}
}
return $matches
@ -1630,7 +1626,7 @@ proc findselectline {l} {
set matches [findmatches $f]
foreach match $matches {
set start [lindex $match 0]
set end [expr [lindex $match 1] + 1]
set end [expr {[lindex $match 1] + 1}]
$ctext tag add found "1.0 + $start c" "1.0 + $end c"
}
}
@ -1984,9 +1980,10 @@ proc markmatches {canv l str tag matches font} {
set start [lindex $match 0]
set end [lindex $match 1]
if {$start > $end} continue
set xoff [font measure $font [string range $str 0 [expr $start-1]]]
set xlen [font measure $font [string range $str 0 [expr $end]]]
set t [$canv create rect [expr $x0+$xoff] $y0 [expr $x0+$xlen+2] $y1 \
set xoff [font measure $font [string range $str 0 [expr {$start-1}]]]
set xlen [font measure $font [string range $str 0 [expr {$end}]]]
set t [$canv create rect [expr {$x0+$xoff}] $y0 \
[expr {$x0+$xlen+2}] $y1 \
-outline {} -tags matches -fill yellow]
$canv lower $t
}
@ -2078,8 +2075,8 @@ proc selectline {l isnew} {
set ytop [expr {$y - $linespc - 1}]
set ybot [expr {$y + $linespc + 1}]
set wnow [$canv yview]
set wtop [expr [lindex $wnow 0] * $ymax]
set wbot [expr [lindex $wnow 1] * $ymax]
set wtop [expr {[lindex $wnow 0] * $ymax}]
set wbot [expr {[lindex $wnow 1] * $ymax}]
set wh [expr {$wbot - $wtop}]
set newtop $wtop
if {$ytop < $wtop} {
@ -2105,7 +2102,7 @@ proc selectline {l isnew} {
if {$newtop < 0} {
set newtop 0
}
allcanvs yview moveto [expr $newtop * 1.0 / $ymax]
allcanvs yview moveto [expr {$newtop * 1.0 / $ymax}]
}
if {$isnew} {
@ -2164,7 +2161,7 @@ proc selectline {l isnew} {
$cflist delete 0 end
$cflist insert end "Comments"
if {$nparents($id) == 1} {
startdiff [concat $id $parents($id)]
startdiff $id
} elseif {$nparents($id) > 1} {
mergediff $id
}
@ -2173,7 +2170,7 @@ proc selectline {l isnew} {
proc selnextline {dir} {
global selectedline
if {![info exists selectedline]} return
set l [expr $selectedline + $dir]
set l [expr {$selectedline + $dir}]
unmarkmatches
selectline $l 1
}
@ -2273,12 +2270,12 @@ proc contmergediff {ids} {
# diff the child against each of the parents, and diff
# each of the parents against the GCA.
while 1 {
if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} {
set ids [list [lindex $ids 1] $diffmergegca]
if {[lindex $ids 1] == $diffmergeid && $diffmergegca ne {}} {
set ids [list $diffmergegca [lindex $ids 0]]
} else {
if {[incr diffpindex] >= $nparents($diffmergeid)} break
set p [lindex $parents($diffmergeid) $diffpindex]
set ids [list $diffmergeid $p]
set ids [list $p $diffmergeid]
}
if {![info exists treediffs($ids)]} {
set diffids $ids
@ -2296,8 +2293,8 @@ proc contmergediff {ids} {
if {$diffmergegca ne {}} {
set files {}
foreach p $parents($diffmergeid) {
set gcadiffs $treediffs([list $p $diffmergegca])
foreach f $treediffs([list $diffmergeid $p]) {
set gcadiffs $treediffs([list $diffmergegca $p])
foreach f $treediffs([list $p $diffmergeid]) {
if {[lsearch -exact $files $f] < 0
&& [lsearch -exact $gcadiffs $f] >= 0} {
lappend files $f
@ -2310,7 +2307,7 @@ proc contmergediff {ids} {
set files $treediffs([list $diffmergeid $p])
for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} {
set p [lindex $parents($diffmergeid) $i]
set df $treediffs([list $diffmergeid $p])
set df $treediffs([list $p $diffmergeid])
set nf {}
foreach f $files {
if {[lsearch -exact $df $f] >= 0} {
@ -2787,8 +2784,7 @@ proc gettreediffs {ids} {
global treediff parents treepending
set treepending $ids
set treediff {}
set id [lindex $ids 0]
if [catch {set gdtf [open "|git-diff-tree --no-commit-id -r $id" r]}] return
if [catch {set gdtf [open [concat | git-diff-tree --no-commit-id -r $ids] r]}] return
fconfigure $gdtf -blocking 0
fileevent $gdtf readable [list gettreediffline $gdtf $ids]
}
@ -2821,9 +2817,8 @@ proc getblobdiffs {ids} {
global diffopts blobdifffd diffids env curdifftag curtagstart
global difffilestart nextupdate diffinhdr treediffs
set id [lindex $ids 0]
set env(GIT_DIFF_OPTS) $diffopts
set cmd [list | git-diff-tree --no-commit-id -r -p -C $id]
set cmd [concat | git-diff-tree --no-commit-id -r -p -C $ids]
if {[catch {set bdf [open $cmd r]} err]} {
puts "error getting diffs: $err"
return
@ -2842,7 +2837,6 @@ proc getblobdiffline {bdf ids} {
global diffids blobdifffd ctext curdifftag curtagstart
global diffnexthead diffnextnote difffilestart
global nextupdate diffinhdr treediffs
global gaudydiff
set n [gets $bdf line]
if {$n < 0} {
@ -2891,26 +2885,14 @@ proc getblobdiffline {bdf ids} {
set diffinhdr 0
} elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
$line match f1l f1c f2l f2c rest]} {
if {$gaudydiff} {
$ctext insert end "\t" hunksep
$ctext insert end " $f1l " d0 " $f2l " d1
$ctext insert end " $rest \n" hunksep
} else {
$ctext insert end "$line\n" hunksep
}
$ctext insert end "$line\n" hunksep
set diffinhdr 0
} else {
set x [string range $line 0 0]
if {$x == "-" || $x == "+"} {
set tag [expr {$x == "+"}]
if {$gaudydiff} {
set line [string range $line 1 end]
}
$ctext insert end "$line\n" d$tag
} elseif {$x == " "} {
if {$gaudydiff} {
set line [string range $line 1 end]
}
$ctext insert end "$line\n"
} elseif {$diffinhdr || $x == "\\"} {
# e.g. "\ No newline at end of file"
@ -2966,8 +2948,8 @@ proc setcoords {} {
set linespc [font metrics $mainfont -linespace]
set charspc [font measure $mainfont "m"]
set canvy0 [expr 3 + 0.5 * $linespc]
set canvx0 [expr 3 + 0.5 * $linespc]
set canvy0 [expr {3 + 0.5 * $linespc}]
set canvx0 [expr {3 + 0.5 * $linespc}]
set lthickness [expr {int($linespc / 9) + 1}]
set xspc1(0) $linespc
set xspc2 $linespc
@ -3340,7 +3322,7 @@ proc doseldiff {oldid newid} {
$ctext conf -state disabled
$ctext tag delete Comments
$ctext tag remove found 1.0 end
startdiff [list $newid $oldid]
startdiff [list $oldid $newid]
}
proc mkpatch {} {
@ -3635,33 +3617,94 @@ proc doquit {} {
destroy .
}
proc formatdate {d} {
global hours nhours tfd fastdate
proc doprefs {} {
global maxwidth maxgraphpct diffopts findmergefiles
global oldprefs prefstop
if {!$fastdate} {
return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
set top .gitkprefs
set prefstop $top
if {[winfo exists $top]} {
raise $top
return
}
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
foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
set oldprefs($v) [set $v]
}
incr nhours($hr)
set minsec [format "%.2d:%.2d" [expr {$ms/60}] [expr {$ms%60}]]
return "$hours($hr):$minsec"
toplevel $top
wm title $top "Gitk preferences"
label $top.ldisp -text "Commit list display options"
grid $top.ldisp - -sticky w -pady 10
label $top.spacer -text " "
label $top.maxwidthl -text "Maximum graph width (lines)" \
-font optionfont
spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
label $top.maxpctl -text "Maximum graph width (% of pane)" \
-font optionfont
spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
grid x $top.maxpctl $top.maxpct -sticky w
checkbutton $top.findm -variable findmergefiles
label $top.findml -text "Include merges for \"Find\" in \"Files\"" \
-font optionfont
grid $top.findm $top.findml - -sticky w
label $top.ddisp -text "Diff display options"
grid $top.ddisp - -sticky w -pady 10
label $top.diffoptl -text "Options for diff program" \
-font optionfont
entry $top.diffopt -width 20 -textvariable diffopts
grid x $top.diffoptl $top.diffopt -sticky w
frame $top.buts
button $top.buts.ok -text "OK" -command prefsok
button $top.buts.can -text "Cancel" -command prefscan
grid $top.buts.ok $top.buts.can
grid columnconfigure $top.buts 0 -weight 1 -uniform a
grid columnconfigure $top.buts 1 -weight 1 -uniform a
grid $top.buts - - -pady 10 -sticky ew
}
proc prefscan {} {
global maxwidth maxgraphpct diffopts findmergefiles
global oldprefs prefstop
foreach v {maxwidth maxgraphpct diffopts findmergefiles} {
set $v $oldprefs($v)
}
catch {destroy $prefstop}
unset prefstop
}
proc prefsok {} {
global maxwidth maxgraphpct
global oldprefs prefstop
catch {destroy $prefstop}
unset prefstop
if {$maxwidth != $oldprefs(maxwidth)
|| $maxgraphpct != $oldprefs(maxgraphpct)} {
redisplay
}
}
proc formatdate {d} {
return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
}
# defaults...
set datemode 0
set boldnames 0
set diffopts "-U 5 -p"
set wrcomcmd "git-diff-tree --stdin -p --pretty"
set gitencoding ""
catch {
set gitencoding [exec git-repo-config --get i18n.commitencoding]
}
if {$gitencoding == ""} {
set gitencoding "utf-8"
}
set mainfont {Helvetica 9}
set textfont {Courier 9}
set findmergefiles 0
set gaudydiff 0
set maxgraphpct 50
set maxwidth 16
set revlistorder 0
@ -3672,15 +3715,13 @@ set colors {green red blue magenta darkgrey brown orange}
catch {source ~/.gitk}
set namefont $mainfont
if {$boldnames} {
lappend namefont bold
}
font create optionfont -family sans-serif -size -12
set revtreeargs {}
foreach arg $argv {
switch -regexp -- $arg {
"^$" { }
"^-b" { set boldnames 1 }
"^-d" { set datemode 1 }
"^-r" { set revlistorder 1 }
default {

Просмотреть файл

@ -29,6 +29,8 @@ int main(int argc, char **argv)
int i;
const char *type = "blob";
int write_object = 0;
const char *prefix = NULL;
int prefix_length = -1;
for (i = 1 ; i < argc; i++) {
if (!strcmp(argv[i], "-t")) {
@ -36,10 +38,20 @@ int main(int argc, char **argv)
die(hash_object_usage);
type = argv[i];
}
else if (!strcmp(argv[i], "-w"))
else if (!strcmp(argv[i], "-w")) {
if (prefix_length < 0) {
prefix = setup_git_directory();
prefix_length = prefix ? strlen(prefix) : 0;
}
write_object = 1;
else
hash_object(argv[i], type, write_object);
}
else {
const char *arg = argv[i];
if (0 <= prefix_length)
arg = prefix_filename(prefix, prefix_length,
arg);
hash_object(arg, type, write_object);
}
}
return 0;
}

Просмотреть файл

@ -922,6 +922,8 @@ int main(int argc, char **argv)
int arg = 1;
int rc = 0;
setup_git_directory();
while (arg < argc && argv[arg][0] == '-') {
if (argv[arg][1] == 't') {
get_tree = 1;

Просмотреть файл

@ -784,7 +784,7 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
strtol(ctx->cdata + 7, NULL, 10);
} else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
if (!strncmp(ctx->cdata, "opaquelocktoken:", 16)) {
lock->token = xmalloc(strlen(ctx->cdata - 15));
lock->token = xmalloc(strlen(ctx->cdata) - 15);
strcpy(lock->token, ctx->cdata + 16);
}
}
@ -1008,9 +1008,7 @@ static int unlock_remote(struct active_lock *lock)
if (lock->owner != NULL)
free(lock->owner);
free(lock->url);
/* Freeing the token causes a segfault...
free(lock->token);
*/
free(lock);
return rc;
@ -1239,6 +1237,7 @@ int main(int argc, char **argv)
int rc = 0;
int i;
setup_git_directory();
setup_ident();
remote = xmalloc(sizeof(*remote));
@ -1273,6 +1272,9 @@ int main(int argc, char **argv)
break;
}
if (!remote->url)
usage(http_push_usage);
memset(remote_dir_exists, 0, 256);
http_init();

Просмотреть файл

@ -132,6 +132,23 @@ static void copy_templates(const char *git_dir, int len, char *template_dir)
return;
}
/* Make sure that template is from the correct vintage */
strcpy(template_path + template_len, "config");
repository_format_version = 0;
git_config_from_file(check_repository_format_version,
template_path);
template_path[template_len] = 0;
if (repository_format_version &&
repository_format_version != GIT_REPO_VERSION) {
fprintf(stderr, "warning: not copying templates of "
"a wrong format version %d from '%s'\n",
repository_format_version,
template_dir);
closedir(dir);
return;
}
memcpy(path, git_dir, len);
path[len] = 0;
copy_templates_1(path, len,
@ -140,12 +157,13 @@ static void copy_templates(const char *git_dir, int len, char *template_dir)
closedir(dir);
}
static void create_default_files(const char *git_dir,
char *template_path)
static void create_default_files(const char *git_dir, char *template_path)
{
unsigned len = strlen(git_dir);
static char path[PATH_MAX];
unsigned char sha1[20];
struct stat st1;
char repo_version_string[10];
if (len > sizeof(path)-50)
die("insane git directory %s", git_dir);
@ -164,6 +182,15 @@ static void create_default_files(const char *git_dir,
strcpy(path + len, "refs/tags");
safe_create_dir(path);
/* First copy the templates -- we might have the default
* config file there, in which case we would want to read
* from it after installing.
*/
path[len] = 0;
copy_templates(path, len, template_path);
git_config(git_default_config);
/*
* Create the default symlink from ".git/HEAD" to the "master"
* branch, if it does not exist yet.
@ -173,44 +200,22 @@ static void create_default_files(const char *git_dir,
if (create_symref(path, "refs/heads/master") < 0)
exit(1);
}
/* This forces creation of new config file */
sprintf(repo_version_string, "%d", GIT_REPO_VERSION);
git_config_set("core.repositoryformatversion", repo_version_string);
path[len] = 0;
copy_templates(path, len, template_path);
/*
* Find out if we can trust the executable bit.
*/
safe_create_dir(path);
strcpy(path + len, "config");
if (access(path, R_OK) < 0) {
static const char contents[] =
"#\n"
"# This is the config file\n"
"#\n"
"\n"
"; core variables\n"
"[core]\n"
" ; Don't trust file modes\n"
" filemode = false\n"
"\n";
FILE *config = fopen(path, "w");
struct stat st;
if (!config)
die("Can not write to %s?", path);
fwrite(contents, sizeof(contents)-1, 1, config);
fclose(config);
if (!lstat(path, &st)) {
struct stat st2;
if (!chmod(path, st.st_mode ^ S_IXUSR) &&
!lstat(path, &st2) &&
st.st_mode != st2.st_mode)
unlink(path);
else
fprintf(stderr, "Ignoring file modes\n");
}
/* Check filemode trustability */
if (!lstat(path, &st1)) {
struct stat st2;
int filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&
!lstat(path, &st2) &&
st1.st_mode != st2.st_mode);
git_config_set("core.filemode",
filemode ? "true" : "false");
}
}
@ -249,6 +254,14 @@ int main(int argc, char **argv)
fprintf(stderr, "defaulting to local storage area\n");
}
safe_create_dir(git_dir);
/* Check to see if the repository version is right.
* Note that a newly created repository does not have
* config file, so this will not fail. What we are catching
* is an attempt to reinitialize new repository with an old tool.
*/
check_repository_format();
create_default_files(git_dir, template_dir);
/*

Просмотреть файл

@ -207,6 +207,8 @@ int main(int argc, char **argv)
char *commit_id;
int arg = 1;
setup_git_directory();
while (arg < argc && argv[arg][0] == '-') {
if (argv[arg][1] == 't')
get_tree = 1;

Просмотреть файл

@ -344,7 +344,7 @@ static void show_dir_entry(const char *tag, struct nond_on_fs *ent)
return;
fputs(tag, stdout);
write_name_quoted("", ent->name + offset, line_terminator, stdout);
write_name_quoted("", 0, ent->name + offset, line_terminator, stdout);
putchar(line_terminator);
}
@ -433,7 +433,8 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
if (!show_stage) {
fputs(tag, stdout);
write_name_quoted("", ce->name + offset, line_terminator, stdout);
write_name_quoted("", 0, ce->name + offset,
line_terminator, stdout);
putchar(line_terminator);
}
else {
@ -442,7 +443,8 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
ntohl(ce->ce_mode),
sha1_to_hex(ce->sha1),
ce_stage(ce));
write_name_quoted("", ce->name + offset, line_terminator, stdout);
write_name_quoted("", 0, ce->name + offset,
line_terminator, stdout);
putchar(line_terminator);
}
}

292
ls-tree.c
Просмотреть файл

@ -11,217 +11,75 @@
static int line_termination = '\n';
#define LS_RECURSIVE 1
#define LS_TREE_ONLY 2
#define LS_SHOW_TREES 4
#define LS_NAME_ONLY 8
static int ls_options = 0;
static struct tree_entry_list root_entry;
static void prepare_root(unsigned char *sha1)
{
unsigned char rsha[20];
unsigned long size;
void *buf;
struct tree *root_tree;
buf = read_object_with_reference(sha1, "tree", &size, rsha);
free(buf);
if (!buf)
die("Could not read %s", sha1_to_hex(sha1));
root_tree = lookup_tree(rsha);
if (!root_tree)
die("Could not read %s", sha1_to_hex(sha1));
/* Prepare a fake entry */
root_entry.directory = 1;
root_entry.executable = root_entry.symlink = 0;
root_entry.mode = S_IFDIR;
root_entry.name = "";
root_entry.item.tree = root_tree;
root_entry.parent = NULL;
}
static int prepare_children(struct tree_entry_list *elem)
{
if (!elem->directory)
return -1;
if (!elem->item.tree->object.parsed) {
struct tree_entry_list *e;
if (parse_tree(elem->item.tree))
return -1;
/* Set up the parent link */
for (e = elem->item.tree->entries; e; e = e->next)
e->parent = elem;
}
return 0;
}
static struct tree_entry_list *find_entry(const char *path, char *pathbuf)
{
const char *next, *slash;
int len;
struct tree_entry_list *elem = &root_entry, *oldelem = NULL;
*(pathbuf) = '\0';
/* Find tree element, descending from root, that
* corresponds to the named path, lazily expanding
* the tree if possible.
*/
while (path) {
/* The fact we still have path means that the caller
* wants us to make sure that elem at this point is a
* directory, and possibly descend into it. Even what
* is left is just trailing slashes, we loop back to
* here, and this call to prepare_children() will
* catch elem not being a tree. Nice.
*/
if (prepare_children(elem))
return NULL;
slash = strchr(path, '/');
if (!slash) {
len = strlen(path);
next = NULL;
}
else {
next = slash + 1;
len = slash - path;
}
if (len) {
if (oldelem) {
pathbuf += sprintf(pathbuf, "%s/", oldelem->name);
}
/* (len == 0) if the original path was "drivers/char/"
* and we have run already two rounds, having elem
* pointing at the drivers/char directory.
*/
elem = elem->item.tree->entries;
while (elem) {
if ((strlen(elem->name) == len) &&
!strncmp(elem->name, path, len)) {
/* found */
break;
}
elem = elem->next;
}
if (!elem)
return NULL;
oldelem = elem;
}
path = next;
}
return elem;
}
static const char *entry_type(struct tree_entry_list *e)
{
return (e->directory ? "tree" : "blob");
}
static const char *entry_hex(struct tree_entry_list *e)
{
return sha1_to_hex(e->directory
? e->item.tree->object.sha1
: e->item.blob->object.sha1);
}
/* forward declaration for mutually recursive routines */
static int show_entry(struct tree_entry_list *, int, char *pathbuf);
static int show_children(struct tree_entry_list *e, int level, char *pathbuf)
{
int oldlen = strlen(pathbuf);
if (e != &root_entry)
sprintf(pathbuf + oldlen, "%s/", e->name);
if (prepare_children(e))
die("internal error: ls-tree show_children called with non tree");
e = e->item.tree->entries;
while (e) {
show_entry(e, level, pathbuf);
e = e->next;
}
pathbuf[oldlen] = '\0';
return 0;
}
static int show_entry(struct tree_entry_list *e, int level, char *pathbuf)
{
int err = 0;
if (e != &root_entry) {
printf("%06o %s %s ",
e->mode, entry_type(e), entry_hex(e));
write_name_quoted(pathbuf, e->name, line_termination, stdout);
putchar(line_termination);
}
if (e->directory) {
/* If this is a directory, we have the following cases:
* (1) This is the top-level request (explicit path from the
* command line, or "root" if there is no command line).
* a. Without any flag. We show direct children. We do not
* recurse into them.
* b. With -r. We do recurse into children.
* c. With -d. We do not recurse into children.
* (2) We came here because our caller is either (1-a) or
* (1-b).
* a. Without any flag. We do not show our children (which
* are grandchildren for the original request).
* b. With -r. We continue to recurse into our children.
* c. With -d. We should not have come here to begin with.
*/
if (level == 0 && !(ls_options & LS_TREE_ONLY))
/* case (1)-a and (1)-b */
err = err | show_children(e, level+1, pathbuf);
else if (level && ls_options & LS_RECURSIVE)
/* case (2)-b */
err = err | show_children(e, level+1, pathbuf);
}
return err;
}
static int list_one(const char *path)
{
int err = 0;
char pathbuf[MAXPATHLEN + 1];
struct tree_entry_list *e = find_entry(path, pathbuf);
if (!e) {
/* traditionally ls-tree does not complain about
* missing path. We may change this later to match
* what "/bin/ls -a" does, which is to complain.
*/
return err;
}
err = err | show_entry(e, 0, pathbuf);
return err;
}
static int list(char **path)
{
int i;
int err = 0;
for (i = 0; path[i]; i++)
err = err | list_one(path[i]);
return err;
}
const char **pathspec;
static const char ls_tree_usage[] =
"git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
"git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] <tree-ish> [path...]";
int main(int argc, char **argv)
static int show_recursive(const char *base, int baselen, const char *pathname)
{
static char *path0[] = { "", NULL };
char **path;
unsigned char sha1[20];
const char **s;
if (ls_options & LS_RECURSIVE)
return 1;
s = pathspec;
if (!s)
return 0;
for (;;) {
const char *spec = *s++;
int len, speclen;
if (!spec)
return 0;
if (strncmp(base, spec, baselen))
continue;
len = strlen(pathname);
spec += baselen;
speclen = strlen(spec);
if (speclen <= len)
continue;
if (memcmp(pathname, spec, len))
continue;
return 1;
}
}
static int show_tree(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
{
int retval = 0;
const char *type = "blob";
if (S_ISDIR(mode)) {
if (show_recursive(base, baselen, pathname)) {
retval = READ_TREE_RECURSIVE;
if (!(ls_options & LS_SHOW_TREES))
return retval;
}
type = "tree";
}
else if (ls_options & LS_TREE_ONLY)
return 0;
if (!(ls_options & LS_NAME_ONLY))
printf("%06o %s %s\t", mode, type, sha1_to_hex(sha1));
write_name_quoted(base, baselen, pathname, line_termination, stdout);
putchar(line_termination);
return retval;
}
int main(int argc, const char **argv)
{
const char *prefix;
unsigned char sha1[20];
char *buf;
unsigned long size;
prefix = setup_git_directory();
while (1 < argc && argv[1][0] == '-') {
switch (argv[1][1]) {
case 'z':
@ -233,20 +91,36 @@ int main(int argc, char **argv)
case 'd':
ls_options |= LS_TREE_ONLY;
break;
case 't':
ls_options |= LS_SHOW_TREES;
break;
case '-':
if (!strcmp(argv[1]+2, "name-only") ||
!strcmp(argv[1]+2, "name-status")) {
ls_options |= LS_NAME_ONLY;
break;
}
/* otherwise fallthru */
default:
usage(ls_tree_usage);
}
argc--; argv++;
}
/* -d -r should imply -t, but -d by itself should not have to. */
if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
ls_options |= LS_SHOW_TREES;
if (argc < 2)
usage(ls_tree_usage);
if (get_sha1(argv[1], sha1) < 0)
usage(ls_tree_usage);
path = (argc == 2) ? path0 : (argv + 2);
prepare_root(sha1);
if (list(path) < 0)
die("list failed");
pathspec = get_pathspec(prefix, argv + 2);
buf = read_object_with_reference(sha1, "tree", &size, NULL);
if (!buf)
die("not a tree object");
read_tree_recursive(buf, size, "", 0, 0, pathspec, show_tree);
return 0;
}

Просмотреть файл

@ -8,6 +8,7 @@
#include <string.h>
#include <ctype.h>
#include <iconv.h>
#include "cache.h"
#ifdef NO_STRCASESTR
extern char *gitstrcasestr(const char *haystack, const char *needle);
@ -16,7 +17,7 @@ extern char *gitstrcasestr(const char *haystack, const char *needle);
static FILE *cmitmsg, *patchfile;
static int keep_subject = 0;
static int metainfo_utf8 = 0;
static char *metainfo_charset = NULL;
static char line[1000];
static char date[1000];
static char name[1000];
@ -441,29 +442,38 @@ static int decode_b_segment(char *in, char *ot, char *ep)
static void convert_to_utf8(char *line, char *charset)
{
if (*charset) {
char *in, *out;
size_t insize, outsize, nrc;
char outbuf[4096]; /* cheat */
iconv_t conv = iconv_open("utf-8", charset);
char *in, *out;
size_t insize, outsize, nrc;
char outbuf[4096]; /* cheat */
static char latin_one[] = "latin-1";
char *input_charset = *charset ? charset : latin_one;
iconv_t conv = iconv_open(metainfo_charset, input_charset);
if (conv == (iconv_t) -1) {
fprintf(stderr, "cannot convert from %s to utf-8\n",
charset);
if (conv == (iconv_t) -1) {
static int warned_latin1_once = 0;
if (input_charset != latin_one) {
fprintf(stderr, "cannot convert from %s to %s\n",
input_charset, metainfo_charset);
*charset = 0;
return;
}
in = line;
insize = strlen(in);
out = outbuf;
outsize = sizeof(outbuf);
nrc = iconv(conv, &in, &insize, &out, &outsize);
iconv_close(conv);
if (nrc == (size_t) -1)
return;
*out = 0;
strcpy(line, outbuf);
else if (!warned_latin1_once) {
warned_latin1_once = 1;
fprintf(stderr, "tried to convert from %s to %s, "
"but your iconv does not work with it.\n",
input_charset, metainfo_charset);
}
return;
}
in = line;
insize = strlen(in);
out = outbuf;
outsize = sizeof(outbuf);
nrc = iconv(conv, &in, &insize, &out, &outsize);
iconv_close(conv);
if (nrc == (size_t) -1)
return;
*out = 0;
strcpy(line, outbuf);
}
static void decode_header_bq(char *it)
@ -511,7 +521,7 @@ static void decode_header_bq(char *it)
}
if (sz < 0)
return;
if (metainfo_utf8)
if (metainfo_charset)
convert_to_utf8(piecebuf, charset_q);
strcpy(out, piecebuf);
out += strlen(out);
@ -590,7 +600,7 @@ static int handle_commit_msg(void)
* normalize the log message to UTF-8.
*/
decode_transfer_encoding(line);
if (metainfo_utf8)
if (metainfo_charset)
convert_to_utf8(line, charset);
fputs(line, cmitmsg);
} while (fgets(line, sizeof(line), stdin) != NULL);
@ -707,27 +717,29 @@ static void handle_body(void)
}
static const char mailinfo_usage[] =
"git-mailinfo [-k] [-u] msg patch <mail >info";
static void usage(void) {
fprintf(stderr, "%s\n", mailinfo_usage);
exit(1);
}
"git-mailinfo [-k] [-u | --encoding=<encoding>] msg patch <mail >info";
int main(int argc, char **argv)
{
/* NEEDSWORK: might want to do the optional .git/ directory
* discovery
*/
git_config(git_default_config);
while (1 < argc && argv[1][0] == '-') {
if (!strcmp(argv[1], "-k"))
keep_subject = 1;
else if (!strcmp(argv[1], "-u"))
metainfo_utf8 = 1;
metainfo_charset = git_commit_encoding;
else if (!strncmp(argv[1], "--encoding=", 11))
metainfo_charset = argv[1] + 11;
else
usage();
usage(mailinfo_usage);
argc--; argv++;
}
if (argc != 3)
usage();
usage(mailinfo_usage);
cmitmsg = fopen(argv[1], "w");
if (!cmitmsg) {
perror(argv[1]);

Просмотреть файл

@ -236,6 +236,8 @@ int main(int argc, char **argv)
struct commit *rev1, *rev2;
unsigned char rev1key[20], rev2key[20];
setup_git_directory();
while (1 < argc && argv[1][0] == '-') {
char *arg = argv[1];
if (!strcmp(arg, "-a") || !strcmp(arg, "--all"))

Просмотреть файл

@ -102,6 +102,7 @@ int main(int argc, char **argv)
if (argc < 3)
usage("git-merge-index [-o] [-q] <merge-program> (-a | <filename>*)");
setup_git_directory();
read_cache();
i = 1;

Просмотреть файл

@ -111,6 +111,8 @@ int main(int argc, char **argv)
if (argc != 1)
usage("cat <signaturefile> | git-mktag");
setup_git_directory();
// Read the signature
size = 0;
for (;;) {

Просмотреть файл

@ -21,7 +21,7 @@ static void name_rev(struct commit *commit,
{
struct rev_name *name = (struct rev_name *)commit->object.util;
struct commit_list *parents;
int parent_number = 0;
int parent_number = 1;
if (!commit->object.parsed)
parse_commit(commit);
@ -56,7 +56,7 @@ copy_data:
for (parents = commit->parents;
parents;
parents = parents->next, parent_number++) {
if (parent_number > 0) {
if (parent_number > 1) {
char *new_name = xmalloc(strlen(tip_name)+8);
if (generation > 0)
@ -217,10 +217,9 @@ int main(int argc, char **argv)
if (!strcmp(name, "undefined"))
continue;
fwrite(p_start, p - p_start, 1, stdout);
fputc('(', stdout);
fputs(name, stdout);
fputc(')', stdout);
fwrite(p_start, p - p_start + 1, 1,
stdout);
printf(" (%s)", name);
p_start = p + 1;
}
}

Просмотреть файл

@ -473,6 +473,8 @@ int main(int argc, char **argv)
struct object_entry **list;
int i;
setup_git_directory();
for (i = 1; i < argc; i++) {
const char *arg = argv[i];

Просмотреть файл

@ -600,6 +600,8 @@ int main(int argc, char **argv)
unsigned char *sha1;
char buf[42]; /* 40 byte sha1 + \n + \0 */
setup_git_directory();
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if(!strcmp(arg, "--")) {

166
path.c
Просмотреть файл

@ -131,75 +131,121 @@ int validate_symref(const char *path)
return -1;
}
static char *current_dir(void)
static char *user_path(char *buf, char *path, int sz)
{
return getcwd(pathname, sizeof(pathname));
}
struct passwd *pw;
char *slash;
int len, baselen;
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)
if (!path || path[0] != '~')
return NULL;
if (strict) {
if (chdir(path) < 0)
return NULL;
path++;
slash = strchr(path, '/');
if (path[0] == '/' || !path[0]) {
pw = getpwuid(getuid());
}
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 */
if (slash) {
*slash = 0;
pw = getpwnam(path);
*slash = '/';
}
else
return NULL;
(void)chdir(".git");
pw = getpwnam(path);
}
if (!pw || !pw->pw_dir || sz <= strlen(pw->pw_dir))
return NULL;
baselen = strlen(pw->pw_dir);
memcpy(buf, pw->pw_dir, baselen);
while ((1 < baselen) && (buf[baselen-1] == '/')) {
buf[baselen-1] = 0;
baselen--;
}
if (slash && slash[1]) {
len = strlen(slash);
if (sz <= baselen + len)
return NULL;
memcpy(buf + baselen, slash, len + 1);
}
return buf;
}
if(access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
validate_symref("HEAD") == 0) {
/*
* First, one directory to try is determined by the following algorithm.
*
* (0) If "strict" is given, the path is used as given and no DWIM is
* done. Otherwise:
* (1) "~/path" to mean path under the running user's home directory;
* (2) "~user/path" to mean path under named user's home directory;
* (3) "relative/path" to mean cwd relative directory; or
* (4) "/absolute/path" to mean absolute directory.
*
* Unless "strict" is given, we try access() for existence of "%s.git/.git",
* "%s/.git", "%s.git", "%s" in this order. The first one that exists is
* what we try.
*
* Second, we try chdir() to that. Upon failure, we return NULL.
*
* Then, we try if the current directory is a valid git repository.
* Upon failure, we return NULL.
*
* If all goes well, we return the directory we used to chdir() (but
* before ~user is expanded), avoiding getcwd() resolving symbolic
* links. User relative paths are also returned as they are given,
* except DWIM suffixing.
*/
char *enter_repo(char *path, int strict)
{
static char used_path[PATH_MAX];
static char validated_path[PATH_MAX];
if (!path)
return NULL;
if (!strict) {
static const char *suffix[] = {
".git/.git", "/.git", ".git", "", NULL,
};
int len = strlen(path);
int i;
while ((1 < len) && (path[len-1] == '/')) {
path[len-1] = 0;
len--;
}
if (PATH_MAX <= len)
return NULL;
if (path[0] == '~') {
if (!user_path(used_path, path, PATH_MAX))
return NULL;
strcpy(validated_path, path);
path = used_path;
}
else if (PATH_MAX - 10 < len)
return NULL;
else {
path = strcpy(used_path, path);
strcpy(validated_path, path);
}
len = strlen(path);
for (i = 0; suffix[i]; i++) {
strcpy(path + len, suffix[i]);
if (!access(path, F_OK)) {
strcat(validated_path, suffix[i]);
break;
}
}
if (!suffix[i] || chdir(path))
return NULL;
path = validated_path;
}
else if (chdir(path))
return NULL;
if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
validate_symref("HEAD") == 0) {
putenv("GIT_DIR=.");
return current_dir();
check_repository_format();
return path;
}
return NULL;

Просмотреть файл

@ -27,6 +27,9 @@ int main(int argc, char **argv)
char *dest = NULL;
int fd[2];
pid_t pid;
int nongit = 0;
setup_git_directory_gently(&nongit);
for (i = 1; i < argc; i++) {
char *arg = argv[i];

Просмотреть файл

@ -58,6 +58,8 @@ int main(int argc, char **argv)
{
int i;
setup_git_directory();
for (i = 1; i < argc; i++) {
const char *arg = argv[i];

29
quote.c
Просмотреть файл

@ -112,7 +112,8 @@ char *sq_dequote(char *arg)
* but not enclosed in double-quote pair. Return value is undefined.
*/
int quote_c_style(const char *name, char *outbuf, FILE *outfp, int no_dq)
static int quote_c_style_counted(const char *name, int namelen,
char *outbuf, FILE *outfp, int no_dq)
{
#undef EMIT
#define EMIT(c) \
@ -125,7 +126,7 @@ int quote_c_style(const char *name, char *outbuf, FILE *outfp, int no_dq)
if (!no_dq)
EMIT('"');
for (sp = name; (ch = *sp++); ) {
for (sp = name; (ch = *sp++) && (sp - name) <= namelen; ) {
if ((ch < ' ') || (ch == '"') || (ch == '\\') ||
(ch == 0177)) {
@ -162,6 +163,12 @@ int quote_c_style(const char *name, char *outbuf, FILE *outfp, int no_dq)
return needquote ? count : 0;
}
int quote_c_style(const char *name, char *outbuf, FILE *outfp, int no_dq)
{
int cnt = strlen(name);
return quote_c_style_counted(name, cnt, outbuf, outfp, no_dq);
}
/*
* C-style name unquoting.
*
@ -227,28 +234,30 @@ char *unquote_c_style(const char *quoted, const char **endp)
}
}
void write_name_quoted(const char *prefix, const char *name,
int quote, FILE *out)
void write_name_quoted(const char *prefix, int prefix_len,
const char *name, int quote, FILE *out)
{
int needquote;
if (!quote) {
no_quote:
if (prefix && prefix[0])
fputs(prefix, out);
if (prefix_len)
fprintf(out, "%.*s", prefix_len, prefix);
fputs(name, out);
return;
}
needquote = 0;
if (prefix && prefix[0])
needquote = quote_c_style(prefix, NULL, NULL, 0);
if (prefix_len)
needquote = quote_c_style_counted(prefix, prefix_len,
NULL, NULL, 0);
if (!needquote)
needquote = quote_c_style(name, NULL, NULL, 0);
if (needquote) {
fputc('"', out);
if (prefix && prefix[0])
quote_c_style(prefix, NULL, out, 1);
if (prefix_len)
quote_c_style_counted(prefix, prefix_len,
NULL, out, 1);
quote_c_style(name, NULL, out, 1);
fputc('"', out);
}

Просмотреть файл

@ -41,7 +41,7 @@ extern int quote_c_style(const char *name, char *outbuf, FILE *outfp,
int nodq);
extern char *unquote_c_style(const char *quoted, const char **endp);
extern void write_name_quoted(const char *prefix, const char *name,
int quote, FILE *out);
extern void write_name_quoted(const char *prefix, int prefix_len,
const char *name, int quote, FILE *out);
#endif

Просмотреть файл

@ -629,6 +629,8 @@ int main(int argc, char **argv)
unsigned char sha1[20];
merge_fn_t fn = NULL;
setup_git_directory();
newfd = hold_index_file_for_update(&cache_file, get_index_file());
if (newfd < 0)
die("unable to create new cachefile");

Просмотреть файл

@ -350,7 +350,8 @@ static int count_distance(struct commit_list *entry)
if (commit->object.flags & (UNINTERESTING | COUNTED))
break;
nr++;
if (!paths || (commit->object.flags & TREECHANGE))
nr++;
commit->object.flags |= COUNTED;
p = commit->parents;
entry = p;
@ -362,6 +363,7 @@ static int count_distance(struct commit_list *entry)
}
}
}
return nr;
}
@ -382,15 +384,20 @@ static struct commit_list *find_bisection(struct commit_list *list)
nr = 0;
p = list;
while (p) {
nr++;
if (!paths || (p->item->object.flags & TREECHANGE))
nr++;
p = p->next;
}
closest = 0;
best = list;
p = list;
while (p) {
int distance = count_distance(p);
for (p = list; p; p = p->next) {
int distance;
if (paths && !(p->item->object.flags & TREECHANGE))
continue;
distance = count_distance(p);
clear_distance(list);
if (nr - distance < distance)
distance = nr - distance;
@ -398,7 +405,6 @@ static struct commit_list *find_bisection(struct commit_list *list)
best = p;
closest = distance;
}
p = p->next;
}
if (best)
best->next = NULL;

Просмотреть файл

@ -273,6 +273,7 @@ int main(int argc, char **argv)
int fd[2], ret;
pid_t pid;
setup_git_directory();
argv++;
for (i = 1; i < argc; i++, argv++) {
char *arg = *argv;

47
setup.c
Просмотреть файл

@ -47,6 +47,21 @@ const char *prefix_path(const char *prefix, int len, const char *path)
return path;
}
/*
* Unlike prefix_path, this should be used if the named file does
* not have to interact with index entry; i.e. name of a random file
* on the filesystem.
*/
const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
{
static char path[PATH_MAX];
if (!pfx || !*pfx || arg[0] == '/')
return arg;
memcpy(path, pfx, pfx_len);
strcpy(path + pfx_len, arg);
return path;
}
const char **get_pathspec(const char *prefix, const char **pathspec)
{
const char *entry = *pathspec;
@ -92,7 +107,7 @@ static int is_toplevel_directory(void)
return 1;
}
static const char *setup_git_directory_1(void)
const char *setup_git_directory_gently(int *nongit_ok)
{
static char cwd[PATH_MAX+1];
int len, offset;
@ -116,7 +131,7 @@ static const char *setup_git_directory_1(void)
if (validate_symref(path))
goto bad_dir_environ;
if (getenv(DB_ENVIRONMENT)) {
if (access(DB_ENVIRONMENT, X_OK))
if (access(getenv(DB_ENVIRONMENT), X_OK))
goto bad_dir_environ;
}
else {
@ -139,8 +154,15 @@ static const char *setup_git_directory_1(void)
break;
chdir("..");
do {
if (!offset)
if (!offset) {
if (nongit_ok) {
if (chdir(cwd))
die("Cannot come back to cwd");
*nongit_ok = 1;
return NULL;
}
die("Not a git repository");
}
} while (cwd[--offset] != '/');
}
@ -154,8 +176,25 @@ static const char *setup_git_directory_1(void)
return cwd + offset;
}
int check_repository_format_version(const char *var, const char *value)
{
if (strcmp(var, "core.repositoryformatversion") == 0)
repository_format_version = git_config_int(var, value);
return 0;
}
int check_repository_format(void)
{
git_config(check_repository_format_version);
if (GIT_REPO_VERSION < repository_format_version)
die ("Expected git repo version <= %d, found %d",
GIT_REPO_VERSION, repository_format_version);
return 0;
}
const char *setup_git_directory(void)
{
const char *retval = setup_git_directory_1();
const char *retval = setup_git_directory_gently(NULL);
check_repository_format();
return retval;
}

Просмотреть файл

@ -5,8 +5,7 @@ static int do_generic_cmd(const char *me, char *arg)
{
const char *my_argv[4];
arg = sq_dequote(arg);
if (!arg)
if (!arg || !(arg = sq_dequote(arg)))
die("bad argument");
my_argv[0] = me;

Просмотреть файл

@ -131,6 +131,8 @@ int main(int argc, char **argv)
prog = getenv("GIT_SSH_PUSH");
if (!prog) prog = "git-ssh-upload";
setup_git_directory();
while (arg < argc && argv[arg][0] == '-') {
if (argv[arg][1] == 't') {
get_tree = 1;

Просмотреть файл

@ -121,6 +121,9 @@ int main(int argc, char **argv)
prog = getenv(COUNTERPART_ENV_NAME);
if (!prog) prog = COUNTERPART_PROGRAM_NAME;
setup_git_directory();
while (arg < argc && argv[arg][0] == '-') {
if (argv[arg][1] == 'w')
arg++;

Просмотреть файл

@ -126,19 +126,18 @@ test_expect_success \
'git-ls-tree output for a known tree.' \
'diff current expected'
# This changed in ls-tree pathspec change -- recursive does
# not show tree nodes anymore.
test_expect_success \
'showing tree with git-ls-tree -r' \
'git-ls-tree -r $tree >current'
cat >expected <<\EOF
100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0
120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym
040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2
100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2
120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym
040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3
100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3
120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym
040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3
100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3
120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym
EOF

Просмотреть файл

@ -54,6 +54,18 @@ test_expect_success \
cat >expected <<\EOF &&
100644 blob X path0
120000 blob X path1
100644 blob X path2/baz/b
120000 blob X path2/bazbo
100644 blob X path2/foo
EOF
test_output'
test_expect_success \
'ls-tree recursive with -t' \
'git-ls-tree -r -t $tree >current &&
cat >expected <<\EOF &&
100644 blob X path0
120000 blob X path1
040000 tree X path2
040000 tree X path2/baz
100644 blob X path2/baz/b
@ -62,6 +74,15 @@ test_expect_success \
EOF
test_output'
test_expect_success \
'ls-tree recursive with -d' \
'git-ls-tree -r -d $tree >current &&
cat >expected <<\EOF &&
040000 tree X path2
040000 tree X path2/baz
EOF
test_output'
test_expect_success \
'ls-tree filtered with path' \
'git-ls-tree $tree path >current &&
@ -70,12 +91,14 @@ EOF
test_output'
# it used to be path1 and then path0, but with pathspec semantics
# they are shown in canonical order.
test_expect_success \
'ls-tree filtered with path1 path0' \
'git-ls-tree $tree path1 path0 >current &&
cat >expected <<\EOF &&
120000 blob X path1
100644 blob X path0
120000 blob X path1
EOF
test_output'
@ -86,45 +109,49 @@ test_expect_success \
EOF
test_output'
# It used to show path2 and its immediate children but
# with pathspec semantics it shows only path2
test_expect_success \
'ls-tree filtered with path2' \
'git-ls-tree $tree path2 >current &&
cat >expected <<\EOF &&
040000 tree X path2
EOF
test_output'
# ... and path2/ shows the children.
test_expect_success \
'ls-tree filtered with path2/' \
'git-ls-tree $tree path2/ >current &&
cat >expected <<\EOF &&
040000 tree X path2/baz
120000 blob X path2/bazbo
100644 blob X path2/foo
EOF
test_output'
# The same change -- exact match does not show children of
# path2/baz
test_expect_success \
'ls-tree filtered with path2/baz' \
'git-ls-tree $tree path2/baz >current &&
cat >expected <<\EOF &&
040000 tree X path2/baz
100644 blob X path2/baz/b
EOF
test_output'
test_expect_success \
'ls-tree filtered with path2' \
'git-ls-tree $tree path2 >current &&
'ls-tree filtered with path2/bak' \
'git-ls-tree $tree path2/bak >current &&
cat >expected <<\EOF &&
040000 tree X path2
040000 tree X path2/baz
120000 blob X path2/bazbo
100644 blob X path2/foo
EOF
test_output'
test_expect_success \
'ls-tree filtered with path2/' \
'git-ls-tree $tree path2/ >current &&
'ls-tree -t filtered with path2/bak' \
'git-ls-tree -t $tree path2/bak >current &&
cat >expected <<\EOF &&
040000 tree X path2
040000 tree X path2/baz
120000 blob X path2/bazbo
100644 blob X path2/foo
EOF
test_output'

Просмотреть файл

@ -59,24 +59,16 @@ test_expect_success \
EOF
test_output'
# Recursive does not show tree nodes anymore...
test_expect_success \
'ls-tree recursive' \
'git-ls-tree -r $tree >current &&
cat >expected <<\EOF &&
100644 blob X 1.txt
100644 blob X 2.txt
040000 tree X path0
040000 tree X path0/a
040000 tree X path0/a/b
040000 tree X path0/a/b/c
100644 blob X path0/a/b/c/1.txt
040000 tree X path1
040000 tree X path1/b
040000 tree X path1/b/c
100644 blob X path1/b/c/1.txt
040000 tree X path2
100644 blob X path2/1.txt
040000 tree X path3
100644 blob X path3/1.txt
100644 blob X path3/2.txt
EOF
@ -110,41 +102,27 @@ test_expect_success \
EOF
test_output'
# I am not so sure about this one after ls-tree doing pathspec match.
# Having both path0/a and path0/a/b/c makes path0/a redundant, and
# it behaves as if path0/a/b/c, path1/b/c, path2 and path3 are specified.
test_expect_success \
'ls-tree filter directories' \
'git-ls-tree $tree path3 path2 path0/a/b/c path1/b/c path0/a >current &&
cat >expected <<\EOF &&
040000 tree X path3
100644 blob X path3/1.txt
100644 blob X path3/2.txt
040000 tree X path2
100644 blob X path2/1.txt
040000 tree X path0/a/b/c
100644 blob X path0/a/b/c/1.txt
040000 tree X path1/b/c
100644 blob X path1/b/c/1.txt
040000 tree X path0/a
040000 tree X path0/a/b
040000 tree X path2
040000 tree X path3
EOF
test_output'
# Again, duplicates are filtered away so this is equivalent to
# having 1.txt and path3
test_expect_success \
'ls-tree filter odd names' \
'git-ls-tree $tree 1.txt /1.txt //1.txt path3/1.txt /path3/1.txt //path3//1.txt path3 /path3/ path3// >current &&
cat >expected <<\EOF &&
100644 blob X 1.txt
100644 blob X 1.txt
100644 blob X 1.txt
100644 blob X path3/1.txt
100644 blob X path3/1.txt
100644 blob X path3/1.txt
040000 tree X path3
100644 blob X path3/1.txt
100644 blob X path3/2.txt
040000 tree X path3
100644 blob X path3/1.txt
100644 blob X path3/2.txt
040000 tree X path3
100644 blob X path3/1.txt
100644 blob X path3/2.txt
EOF

25
t/t6020-merge-df.sh Executable file
Просмотреть файл

@ -0,0 +1,25 @@
#!/bin/sh
#
# Copyright (c) 2005 Fredrik Kuivinen
#
test_description='Test merge with directory/file conflicts'
. ./test-lib.sh
test_expect_success 'prepare repository' \
'echo "Hello" > init &&
git add init &&
git commit -m "Initial commit" &&
git branch B &&
mkdir dir &&
echo "foo" > dir/foo &&
git add dir/foo &&
git commit -m "File: dir/foo" &&
git checkout B &&
echo "file dir" > dir &&
git add dir &&
git commit -m "File: dir"'
test_expect_code 1 'Merge with d/f conflicts' 'git merge "merge msg" B master'
test_done

92
t/t6021-merge-criss-cross.sh Executable file
Просмотреть файл

@ -0,0 +1,92 @@
#!/bin/sh
#
# Copyright (c) 2005 Fredrik Kuivinen
#
# See http://marc.theaimsgroup.com/?l=git&m=111463358500362&w=2 for a
# nice decription of what this is about.
test_description='Test criss-cross merge'
. ./test-lib.sh
test_expect_success 'prepare repository' \
'echo "1
2
3
4
5
6
7
8
9" > file &&
git add file &&
git commit -m "Initial commit" file &&
git branch A &&
git branch B &&
git checkout A &&
echo "1
2
3
4
5
6
7
8 changed in B8, branch A
9" > file &&
git commit -m "B8" file &&
git checkout B &&
echo "1
2
3 changed in C3, branch B
4
5
6
7
8
9
" > file &&
git commit -m "C3" file &&
git branch C3 &&
git merge "pre E3 merge" B A &&
echo "1
2
3 changed in E3, branch B. New file size
4
5
6
7
8 changed in B8, branch A
9
" > file &&
git commit -m "E3" file &&
git checkout A &&
git merge "pre D8 merge" A C3 &&
echo "1
2
3 changed in C3, branch B
4
5
6
7
8 changed in D8, branch A. New file size 2
9" > file &&
git commit -m D8 file'
test_expect_success 'Criss-cross merge' 'git merge "final merge" A B'
cat > file-expect <<EOF
1
2
3 changed in E3, branch B. New file size
4
5
6
7
8 changed in D8, branch A. New file size 2
9
EOF
test_expect_success 'Criss-cross merge result' 'cmp file file-expect'
test_done

27
t/t7001-mv.sh Executable file
Просмотреть файл

@ -0,0 +1,27 @@
#!/bin/sh
test_description='git-mv in subdirs'
. ./test-lib.sh
test_expect_success \
'prepare reference tree' \
'mkdir path0 path1 &&
cp ../../COPYING path0/COPYING &&
git-add path0/COPYING &&
git-commit -m add -a'
test_expect_success \
'moving the file' \
'cd path0 && git-mv COPYING ../path1/COPYING'
# in path0 currently
test_expect_success \
'commiting the change' \
'cd .. && git-commit -m move -a'
test_expect_success \
'checking the commit' \
'git-diff-tree -r -M --name-status HEAD^ HEAD | \
grep -E "^R100.+path0/COPYING.+path1/COPYING"'
test_done

Просмотреть файл

@ -133,6 +133,19 @@ test_expect_success () {
fi
}
test_expect_code () {
test "$#" = 3 ||
error "bug in the test script: not 3 parameters to test-expect-code"
say >&3 "expecting exit code $1: $3"
test_run_ "$3"
if [ "$?" = 0 -a "$eval_ret" = "$1" ]
then
test_ok_ "$2"
else
test_failure_ "$@"
fi
}
test_done () {
trap - exit
case "$test_failure" in

Просмотреть файл

@ -407,6 +407,8 @@ int main(int argc, char **argv)
void *buffer;
unsigned long size;
setup_git_directory();
switch (argc) {
case 3:
basedir = argv[2];

34
tree.c
Просмотреть файл

@ -9,9 +9,16 @@ const char *tree_type = "tree";
static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
{
int len = strlen(pathname);
unsigned int size = cache_entry_size(baselen + len);
struct cache_entry *ce = xmalloc(size);
int len;
unsigned int size;
struct cache_entry *ce;
if (S_ISDIR(mode))
return READ_TREE_RECURSIVE;
len = strlen(pathname);
size = cache_entry_size(baselen + len);
ce = xmalloc(size);
memset(ce, 0, size);
@ -67,9 +74,10 @@ static int match_tree_entry(const char *base, int baselen, const char *path, uns
return 0;
}
static int read_tree_recursive(void *buffer, unsigned long size,
const char *base, int baselen,
int stage, const char **match)
int read_tree_recursive(void *buffer, unsigned long size,
const char *base, int baselen,
int stage, const char **match,
read_tree_fn_t fn)
{
while (size) {
int len = strlen(buffer)+1;
@ -86,6 +94,14 @@ static int read_tree_recursive(void *buffer, unsigned long size,
if (!match_tree_entry(base, baselen, path, mode, match))
continue;
switch (fn(sha1, base, baselen, path, mode, stage)) {
case 0:
continue;
case READ_TREE_RECURSIVE:
break;;
default:
return -1;
}
if (S_ISDIR(mode)) {
int retval;
int pathlen = strlen(path);
@ -106,22 +122,20 @@ static int read_tree_recursive(void *buffer, unsigned long size,
retval = read_tree_recursive(eltbuf, eltsize,
newbase,
baselen + pathlen + 1,
stage, match);
stage, match, fn);
free(eltbuf);
free(newbase);
if (retval)
return -1;
continue;
}
if (read_one_entry(sha1, base, baselen, path, mode, stage) < 0)
return -1;
}
return 0;
}
int read_tree(void *buffer, unsigned long size, int stage, const char **match)
{
return read_tree_recursive(buffer, size, "", 0, stage, match);
return read_tree_recursive(buffer, size, "", 0, stage, match, read_one_entry);
}
struct tree *lookup_tree(const unsigned char *sha1)

9
tree.h
Просмотреть файл

@ -35,4 +35,13 @@ int parse_tree(struct tree *tree);
/* Parses and returns the tree in the given ent, chasing tags and commits. */
struct tree *parse_tree_indirect(const unsigned char *sha1);
#define READ_TREE_RECURSIVE 1
typedef int (*read_tree_fn_t)(unsigned char *, const char *, int, const char *, unsigned int, int);
extern int read_tree_recursive(void *buffer, unsigned long size,
const char *base, int baselen,
int stage, const char **match,
read_tree_fn_t fn);
#endif /* TREE_H */

Просмотреть файл

@ -29,6 +29,8 @@ int main(int argc, char **argv)
if (argc != 2 || get_sha1(argv[1], sha1))
usage("git-unpack-file <sha1>");
setup_git_directory();
puts(create_temp_file(sha1));
return 0;
}

Просмотреть файл

@ -269,6 +269,8 @@ int main(int argc, char **argv)
int i;
unsigned char sha1[20];
setup_git_directory();
for (i = 1 ; i < argc; i++) {
const char *arg = argv[i];

Просмотреть файл

@ -19,5 +19,7 @@ int main(int ac, char **av)
if (i != ac)
usage(update_server_info_usage);
setup_git_directory();
return !!update_server_info(force);
}

Просмотреть файл

@ -86,9 +86,12 @@ static int write_tree(struct cache_entry **cachep, int maxentries, const char *b
int main(int argc, char **argv)
{
int i, funny;
int entries = read_cache();
int entries;
unsigned char sha1[20];
setup_git_directory();
entries = read_cache();
if (argc == 2) {
if (!strcmp(argv[1], "--missing-ok"))
missing_ok = 1;