Merge branch 'lt/refs' into jc/lt-ref2-with-lt-refs
* lt/refs: (58 commits) git-pack-refs --prune pack-refs: do not pack symbolic refs. Tell between packed, unpacked and symbolic refs. Add callback data to for_each_ref() family. symbolit-ref: fix resolve_ref conversion. Fix broken sha1 locking fsck-objects: adjust to resolve_ref() clean-up. gitignore: git-pack-refs is a generated file. wt-status: use simplified resolve_ref to find current branch Fix t1400-update-ref test minimally Enable the packed refs file format Make ref resolution saner Add support for negative refs Start handling references internally as a sorted in-memory list gitweb fix validating pg (page) parameter git-repack(1): document --window and --depth git-apply(1): document --unidiff-zero gitweb: fix warnings in PATH_INFO code and add export_ok/strict_export upload-archive: monitor child communication even more carefully. gitweb: export options ...
This commit is contained in:
commit
eaf12a8c7d
4
.gitignore
vendored
4
.gitignore
vendored
@ -8,6 +8,7 @@ git-apply
|
||||
git-applymbox
|
||||
git-applypatch
|
||||
git-archimport
|
||||
git-archive
|
||||
git-bisect
|
||||
git-branch
|
||||
git-cat-file
|
||||
@ -72,6 +73,7 @@ git-name-rev
|
||||
git-mv
|
||||
git-pack-redundant
|
||||
git-pack-objects
|
||||
git-pack-refs
|
||||
git-parse-remote
|
||||
git-patch-id
|
||||
git-peek-remote
|
||||
@ -94,6 +96,7 @@ git-rev-list
|
||||
git-rev-parse
|
||||
git-revert
|
||||
git-rm
|
||||
git-runstatus
|
||||
git-send-email
|
||||
git-send-pack
|
||||
git-sh-setup
|
||||
@ -119,6 +122,7 @@ git-unpack-objects
|
||||
git-update-index
|
||||
git-update-ref
|
||||
git-update-server-info
|
||||
git-upload-archive
|
||||
git-upload-pack
|
||||
git-upload-tar
|
||||
git-var
|
||||
|
@ -225,6 +225,20 @@ showbranch.default::
|
||||
The default set of branches for gitlink:git-show-branch[1].
|
||||
See gitlink:git-show-branch[1].
|
||||
|
||||
status.color::
|
||||
A boolean to enable/disable color in the output of
|
||||
gitlink:git-status[1]. May be set to `true` (or `always`),
|
||||
`false` (or `never`) or `auto`, in which case colors are used
|
||||
only when the output is to a terminal. Defaults to false.
|
||||
|
||||
status.color.<slot>::
|
||||
Use customized color for status colorization. `<slot>` is
|
||||
one of `header` (the header text of the status message),
|
||||
`updated` (files which are updated but not committed),
|
||||
`changed` (files which are changed but not updated in the index),
|
||||
or `untracked` (files which are not tracked by git). The values of
|
||||
these variables may be specified as in diff.color.<slot>.
|
||||
|
||||
tar.umask::
|
||||
By default, gitlink:git-tar-tree[1] sets file and directories modes
|
||||
to 0666 or 0777. While this is both useful and acceptable for projects
|
||||
|
@ -95,6 +95,16 @@ OPTIONS
|
||||
context exist they all must match. By default no context is
|
||||
ever ignored.
|
||||
|
||||
--unidiff-zero::
|
||||
By default, gitlink:git-apply[1] expects that the patch being
|
||||
applied is a unified diff with at least one line of context.
|
||||
This provides good safety measures, but breaks down when
|
||||
applying a diff generated with --unified=0. To bypass these
|
||||
checks use '--unidiff-zero'.
|
||||
+
|
||||
Note, for the reasons stated above usage of context-free patches are
|
||||
discouraged.
|
||||
|
||||
--apply::
|
||||
If you use any of the options marked "Turns off
|
||||
'apply'" above, gitlink:git-apply[1] reads and outputs the
|
||||
|
100
Documentation/git-archive.txt
Normal file
100
Documentation/git-archive.txt
Normal file
@ -0,0 +1,100 @@
|
||||
git-archive(1)
|
||||
==============
|
||||
|
||||
NAME
|
||||
----
|
||||
git-archive - Creates a archive of the files in the named tree
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
|
||||
[--remote=<repo>] <tree-ish> [path...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Creates an archive of the specified format containing the tree
|
||||
structure for the named tree. If <prefix> is specified it is
|
||||
prepended to the filenames in the archive.
|
||||
|
||||
'git-archive' behaves differently when given a tree ID versus when
|
||||
given a commit ID or tag ID. In the first case the current time is
|
||||
used as modification time of each file in the archive. In the latter
|
||||
case the commit time as recorded in the referenced commit object is
|
||||
used instead. Additionally the commit ID is stored in a global
|
||||
extended pax header if the tar format is used; it can be extracted
|
||||
using 'git-get-tar-commit-id'. In ZIP files it is stored as a file
|
||||
comment.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
--format=<fmt>::
|
||||
Format of the resulting archive: 'tar', 'zip'...
|
||||
|
||||
--list::
|
||||
Show all available formats.
|
||||
|
||||
--prefix=<prefix>/::
|
||||
Prepend <prefix>/ to each filename in the archive.
|
||||
|
||||
<extra>::
|
||||
This can be any options that the archiver backend understand.
|
||||
|
||||
--remote=<repo>::
|
||||
Instead of making a tar archive from local repository,
|
||||
retrieve a tar archive from a remote repository.
|
||||
|
||||
<tree-ish>::
|
||||
The tree or commit to produce an archive for.
|
||||
|
||||
path::
|
||||
If one or more paths are specified, include only these in the
|
||||
archive, otherwise include all files and subdirectories.
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
By default, file and directories modes are set to 0666 or 0777 in tar
|
||||
archives. It is possible to change this by setting the "umask" variable
|
||||
in the repository configuration as follows :
|
||||
|
||||
[tar]
|
||||
umask = 002 ;# group friendly
|
||||
|
||||
The special umask value "user" indicates that the user's current umask
|
||||
will be used instead. The default value remains 0, which means world
|
||||
readable/writable files and directories.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -)::
|
||||
|
||||
Create a tar archive that contains the contents of the
|
||||
latest commit on the current branch, and extracts it in
|
||||
`/var/tmp/junk` directory.
|
||||
|
||||
git archive --format=tar --prefix=git-1.4.0/ v1.4.0 | gzip >git-1.4.0.tar.gz::
|
||||
|
||||
Create a compressed tarball for v1.4.0 release.
|
||||
|
||||
git archive --format=tar --prefix=git-1.4.0/ v1.4.0{caret}\{tree\} | gzip >git-1.4.0.tar.gz::
|
||||
|
||||
Create a compressed tarball for v1.4.0 release, but without a
|
||||
global extended pax header.
|
||||
|
||||
git archive --format=zip --prefix=git-docs/ HEAD:Documentation/ > git-1.4.0-docs.zip::
|
||||
|
||||
Put everything in the current head's Documentation/ directory
|
||||
into 'git-1.4.0-docs.zip', with the prefix 'git-docs/'.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Franck Bui-Huu and Rene Scharfe.
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
@ -11,7 +11,7 @@ SYNOPSIS
|
||||
[verse]
|
||||
'git-pack-objects' [-q] [--no-reuse-delta] [--non-empty]
|
||||
[--local] [--incremental] [--window=N] [--depth=N]
|
||||
{--stdout | base-name} < object-list
|
||||
[--revs [--unpacked | --all]*] [--stdout | base-name] < object-list
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@ -56,6 +56,24 @@ base-name::
|
||||
Write the pack contents (what would have been written to
|
||||
.pack file) out to the standard output.
|
||||
|
||||
--revs::
|
||||
Read the revision arguments from the standard input, instead of
|
||||
individual object names. The revision arguments are processed
|
||||
the same way as gitlink:git-rev-list[1] with `--objects` flag
|
||||
uses its `commit` arguments to build the list of objects it
|
||||
outputs. The objects on the resulting list are packed.
|
||||
|
||||
--unpacked::
|
||||
This implies `--revs`. When processing the list of
|
||||
revision arguments read from the standard input, limit
|
||||
the objects packed to those that are not already packed.
|
||||
|
||||
--all::
|
||||
This implies `--revs`. In addition to the list of
|
||||
revision arguments read from the standard input, pretend
|
||||
as if all refs under `$GIT_DIR/refs` are specifed to be
|
||||
included.
|
||||
|
||||
--window and --depth::
|
||||
These two options affects how the objects contained in
|
||||
the pack are stored using delta compression. The
|
||||
@ -103,6 +121,7 @@ Documentation by Junio C Hamano
|
||||
|
||||
See Also
|
||||
--------
|
||||
gitlink:git-rev-list[1]
|
||||
gitlink:git-repack[1]
|
||||
gitlink:git-prune-packed[1]
|
||||
|
||||
|
@ -9,7 +9,7 @@ objects into pack files.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-repack' [-a] [-d] [-f] [-l] [-n] [-q]
|
||||
'git-repack' [-a] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -56,6 +56,16 @@ OPTIONS
|
||||
Do not update the server information with
|
||||
`git update-server-info`.
|
||||
|
||||
--window=[N], --depth=[N]::
|
||||
These two options affects how the objects contained in the pack are
|
||||
stored using delta compression. The objects are first internally
|
||||
sorted by type, size and optionally names and compared against the
|
||||
other objects within `--window` to see if using delta compression saves
|
||||
space. `--depth` limits the maximum delta depth; making it too deep
|
||||
affects the performance on the unpacker side, because delta data needs
|
||||
to be applied that many times to get to the necessary object.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
37
Documentation/git-upload-archive.txt
Normal file
37
Documentation/git-upload-archive.txt
Normal file
@ -0,0 +1,37 @@
|
||||
git-upload-archive(1)
|
||||
====================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-upload-archive - Send archive
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-upload-archive' <directory>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Invoked by 'git-archive --remote' and sends a generated archive to the
|
||||
other end over the git protocol.
|
||||
|
||||
This command is usually not invoked directly by the end user. The UI
|
||||
for the protocol is on the 'git-archive' side, and the program pair
|
||||
is meant to be used to get an archive from a remote repository.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
<directory>::
|
||||
The repository to get a tar archive from.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Franck Bui-Huu.
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
21
Makefile
21
Makefile
@ -126,6 +126,8 @@ GITWEB_CONFIG = gitweb_config.perl
|
||||
GITWEB_HOME_LINK_STR = projects
|
||||
GITWEB_SITENAME =
|
||||
GITWEB_PROJECTROOT = /pub/git
|
||||
GITWEB_EXPORT_OK =
|
||||
GITWEB_STRICT_EXPORT =
|
||||
GITWEB_BASE_URL =
|
||||
GITWEB_LIST =
|
||||
GITWEB_HOMETEXT = indextext.html
|
||||
@ -232,8 +234,8 @@ LIB_FILE=libgit.a
|
||||
XDIFF_LIB=xdiff/lib.a
|
||||
|
||||
LIB_H = \
|
||||
blob.h cache.h commit.h csum-file.h delta.h \
|
||||
diff.h object.h pack.h pkt-line.h quote.h refs.h \
|
||||
archive.h blob.h cache.h commit.h csum-file.h delta.h \
|
||||
diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
|
||||
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
|
||||
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h
|
||||
|
||||
@ -245,17 +247,19 @@ DIFF_OBJS = \
|
||||
LIB_OBJS = \
|
||||
blob.o commit.o connect.o csum-file.o cache-tree.o base85.o \
|
||||
date.o diff-delta.o entry.o exec_cmd.o ident.o lockfile.o \
|
||||
object.o pack-check.o patch-delta.o path.o pkt-line.o \
|
||||
object.o pack-check.o patch-delta.o path.o pkt-line.o sideband.o \
|
||||
quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
|
||||
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
|
||||
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
|
||||
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
|
||||
write_or_die.o trace.o \
|
||||
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS)
|
||||
write_or_die.o trace.o list-objects.o \
|
||||
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
|
||||
color.o wt-status.o
|
||||
|
||||
BUILTIN_OBJS = \
|
||||
builtin-add.o \
|
||||
builtin-apply.o \
|
||||
builtin-archive.o \
|
||||
builtin-cat-file.o \
|
||||
builtin-checkout-index.o \
|
||||
builtin-check-ref-format.o \
|
||||
@ -285,6 +289,7 @@ BUILTIN_OBJS = \
|
||||
builtin-rev-list.o \
|
||||
builtin-rev-parse.o \
|
||||
builtin-rm.o \
|
||||
builtin-runstatus.o \
|
||||
builtin-show-branch.o \
|
||||
builtin-stripspace.o \
|
||||
builtin-symbolic-ref.o \
|
||||
@ -292,11 +297,13 @@ BUILTIN_OBJS = \
|
||||
builtin-unpack-objects.o \
|
||||
builtin-update-index.o \
|
||||
builtin-update-ref.o \
|
||||
builtin-upload-archive.o \
|
||||
builtin-upload-tar.o \
|
||||
builtin-verify-pack.o \
|
||||
builtin-write-tree.o \
|
||||
builtin-zip-tree.o \
|
||||
builtin-show-ref.o
|
||||
builtin-show-ref.o \
|
||||
builtin-pack-refs.o
|
||||
|
||||
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
|
||||
LIBS = $(GITLIBS) -lz
|
||||
@ -632,6 +639,8 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl
|
||||
-e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
|
||||
-e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
|
||||
-e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
|
||||
-e 's|++GITWEB_EXPORT_OK++|$(GITWEB_EXPORT_OK)|g' \
|
||||
-e 's|++GITWEB_STRICT_EXPORT++|$(GITWEB_STRICT_EXPORT)|g' \
|
||||
-e 's|++GITWEB_BASE_URL++|$(GITWEB_BASE_URL)|g' \
|
||||
-e 's|++GITWEB_LIST++|$(GITWEB_LIST)|g' \
|
||||
-e 's|++GITWEB_HOMETEXT++|$(GITWEB_HOMETEXT)|g' \
|
||||
|
47
archive.h
Normal file
47
archive.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef ARCHIVE_H
|
||||
#define ARCHIVE_H
|
||||
|
||||
#define MAX_EXTRA_ARGS 32
|
||||
#define MAX_ARGS (MAX_EXTRA_ARGS + 32)
|
||||
|
||||
struct archiver_args {
|
||||
const char *base;
|
||||
struct tree *tree;
|
||||
const unsigned char *commit_sha1;
|
||||
time_t time;
|
||||
const char **pathspec;
|
||||
unsigned int verbose : 1;
|
||||
void *extra;
|
||||
};
|
||||
|
||||
typedef int (*write_archive_fn_t)(struct archiver_args *);
|
||||
|
||||
typedef void *(*parse_extra_args_fn_t)(int argc, const char **argv);
|
||||
|
||||
struct archiver {
|
||||
const char *name;
|
||||
struct archiver_args args;
|
||||
write_archive_fn_t write_archive;
|
||||
parse_extra_args_fn_t parse_extra;
|
||||
};
|
||||
|
||||
extern struct archiver archivers[];
|
||||
|
||||
extern int parse_archive_args(int argc,
|
||||
const char **argv,
|
||||
struct archiver *ar);
|
||||
|
||||
extern void parse_treeish_arg(const char **treeish,
|
||||
struct archiver_args *ar_args,
|
||||
const char *prefix);
|
||||
|
||||
extern void parse_pathspec_arg(const char **pathspec,
|
||||
struct archiver_args *args);
|
||||
/*
|
||||
* Archive-format specific backends.
|
||||
*/
|
||||
extern int write_tar_archive(struct archiver_args *);
|
||||
extern int write_zip_archive(struct archiver_args *);
|
||||
extern void *parse_extra_zip_args(int argc, const char **argv);
|
||||
|
||||
#endif /* ARCHIVE_H */
|
108
builtin-apply.c
108
builtin-apply.c
@ -27,6 +27,7 @@ static const char *prefix;
|
||||
static int prefix_length = -1;
|
||||
static int newfd = -1;
|
||||
|
||||
static int unidiff_zero;
|
||||
static int p_value = 1;
|
||||
static int check_index;
|
||||
static int write_index;
|
||||
@ -854,11 +855,10 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a unified diff. Note that this really needs
|
||||
* to parse each fragment separately, since the only
|
||||
* way to know the difference between a "---" that is
|
||||
* part of a patch, and a "---" that starts the next
|
||||
* patch is to look at the line counts..
|
||||
* Parse a unified diff. Note that this really needs to parse each
|
||||
* fragment separately, since the only way to know the difference
|
||||
* between a "---" that is part of a patch, and a "---" that starts
|
||||
* the next patch is to look at the line counts..
|
||||
*/
|
||||
static int parse_fragment(char *line, unsigned long size, struct patch *patch, struct fragment *fragment)
|
||||
{
|
||||
@ -875,31 +875,14 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
|
||||
leading = 0;
|
||||
trailing = 0;
|
||||
|
||||
if (patch->is_new < 0) {
|
||||
patch->is_new = !oldlines;
|
||||
if (!oldlines)
|
||||
patch->old_name = NULL;
|
||||
}
|
||||
if (patch->is_delete < 0) {
|
||||
patch->is_delete = !newlines;
|
||||
if (!newlines)
|
||||
patch->new_name = NULL;
|
||||
}
|
||||
|
||||
if (patch->is_new && oldlines)
|
||||
return error("new file depends on old contents");
|
||||
if (patch->is_delete != !newlines) {
|
||||
if (newlines)
|
||||
return error("deleted file still has contents");
|
||||
fprintf(stderr, "** warning: file %s becomes empty but is not deleted\n", patch->new_name);
|
||||
}
|
||||
|
||||
/* Parse the thing.. */
|
||||
line += len;
|
||||
size -= len;
|
||||
linenr++;
|
||||
added = deleted = 0;
|
||||
for (offset = len; size > 0; offset += len, size -= len, line += len, linenr++) {
|
||||
for (offset = len;
|
||||
0 < size;
|
||||
offset += len, size -= len, line += len, linenr++) {
|
||||
if (!oldlines && !newlines)
|
||||
break;
|
||||
len = linelen(line, size);
|
||||
@ -972,12 +955,18 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
|
||||
|
||||
patch->lines_added += added;
|
||||
patch->lines_deleted += deleted;
|
||||
|
||||
if (0 < patch->is_new && oldlines)
|
||||
return error("new file depends on old contents");
|
||||
if (0 < patch->is_delete && newlines)
|
||||
return error("deleted file still has contents");
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int parse_single_patch(char *line, unsigned long size, struct patch *patch)
|
||||
{
|
||||
unsigned long offset = 0;
|
||||
unsigned long oldlines = 0, newlines = 0, context = 0;
|
||||
struct fragment **fragp = &patch->fragments;
|
||||
|
||||
while (size > 4 && !memcmp(line, "@@ -", 4)) {
|
||||
@ -988,9 +977,11 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc
|
||||
len = parse_fragment(line, size, patch, fragment);
|
||||
if (len <= 0)
|
||||
die("corrupt patch at line %d", linenr);
|
||||
|
||||
fragment->patch = line;
|
||||
fragment->size = len;
|
||||
oldlines += fragment->oldlines;
|
||||
newlines += fragment->newlines;
|
||||
context += fragment->leading + fragment->trailing;
|
||||
|
||||
*fragp = fragment;
|
||||
fragp = &fragment->next;
|
||||
@ -999,6 +990,46 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc
|
||||
line += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
/*
|
||||
* If something was removed (i.e. we have old-lines) it cannot
|
||||
* be creation, and if something was added it cannot be
|
||||
* deletion. However, the reverse is not true; --unified=0
|
||||
* patches that only add are not necessarily creation even
|
||||
* though they do not have any old lines, and ones that only
|
||||
* delete are not necessarily deletion.
|
||||
*
|
||||
* Unfortunately, a real creation/deletion patch do _not_ have
|
||||
* any context line by definition, so we cannot safely tell it
|
||||
* apart with --unified=0 insanity. At least if the patch has
|
||||
* more than one hunk it is not creation or deletion.
|
||||
*/
|
||||
if (patch->is_new < 0 &&
|
||||
(oldlines || (patch->fragments && patch->fragments->next)))
|
||||
patch->is_new = 0;
|
||||
if (patch->is_delete < 0 &&
|
||||
(newlines || (patch->fragments && patch->fragments->next)))
|
||||
patch->is_delete = 0;
|
||||
if (!unidiff_zero || context) {
|
||||
/* If the user says the patch is not generated with
|
||||
* --unified=0, or if we have seen context lines,
|
||||
* then not having oldlines means the patch is creation,
|
||||
* and not having newlines means the patch is deletion.
|
||||
*/
|
||||
if (patch->is_new < 0 && !oldlines)
|
||||
patch->is_new = 1;
|
||||
if (patch->is_delete < 0 && !newlines)
|
||||
patch->is_delete = 1;
|
||||
}
|
||||
|
||||
if (0 < patch->is_new && oldlines)
|
||||
die("new file %s depends on old contents", patch->new_name);
|
||||
if (0 < patch->is_delete && newlines)
|
||||
die("deleted file %s still has contents", patch->old_name);
|
||||
if (!patch->is_delete && !newlines && context)
|
||||
fprintf(stderr, "** warning: file %s becomes empty but "
|
||||
"is not deleted\n", patch->new_name);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
@ -1556,9 +1587,19 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
|
||||
/*
|
||||
* If we don't have any leading/trailing data in the patch,
|
||||
* we want it to match at the beginning/end of the file.
|
||||
*
|
||||
* But that would break if the patch is generated with
|
||||
* --unified=0; sane people wouldn't do that to cause us
|
||||
* trouble, but we try to please not so sane ones as well.
|
||||
*/
|
||||
if (unidiff_zero) {
|
||||
match_beginning = (!leading && !frag->oldpos);
|
||||
match_end = 0;
|
||||
}
|
||||
else {
|
||||
match_beginning = !leading && (frag->oldpos == 1);
|
||||
match_end = !trailing;
|
||||
}
|
||||
|
||||
lines = 0;
|
||||
pos = frag->newpos;
|
||||
@ -1804,7 +1845,7 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
|
||||
patch->result = desc.buffer;
|
||||
patch->resultsize = desc.size;
|
||||
|
||||
if (patch->is_delete && patch->resultsize)
|
||||
if (0 < patch->is_delete && patch->resultsize)
|
||||
return error("removal patch leaves file contents");
|
||||
|
||||
return 0;
|
||||
@ -1876,7 +1917,7 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
|
||||
old_name, st_mode, patch->old_mode);
|
||||
}
|
||||
|
||||
if (new_name && prev_patch && prev_patch->is_delete &&
|
||||
if (new_name && prev_patch && 0 < prev_patch->is_delete &&
|
||||
!strcmp(prev_patch->old_name, new_name))
|
||||
/* A type-change diff is always split into a patch to
|
||||
* delete old, immediately followed by a patch to
|
||||
@ -1889,7 +1930,8 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
|
||||
else
|
||||
ok_if_exists = 0;
|
||||
|
||||
if (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) {
|
||||
if (new_name &&
|
||||
((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) {
|
||||
if (check_index &&
|
||||
cache_name_pos(new_name, strlen(new_name)) >= 0 &&
|
||||
!ok_if_exists)
|
||||
@ -1906,7 +1948,7 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
|
||||
return error("%s: %s", new_name, strerror(errno));
|
||||
}
|
||||
if (!patch->new_mode) {
|
||||
if (patch->is_new)
|
||||
if (0 < patch->is_new)
|
||||
patch->new_mode = S_IFREG | 0644;
|
||||
else
|
||||
patch->new_mode = patch->old_mode;
|
||||
@ -1957,7 +1999,7 @@ static void show_index_list(struct patch *list)
|
||||
const char *name;
|
||||
|
||||
name = patch->old_name ? patch->old_name : patch->new_name;
|
||||
if (patch->is_new)
|
||||
if (0 < patch->is_new)
|
||||
sha1_ptr = null_sha1;
|
||||
else if (get_sha1(patch->old_sha1_prefix, sha1))
|
||||
die("sha1 information is lacking or useless (%s).",
|
||||
@ -2543,6 +2585,10 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
|
||||
apply_in_reverse = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--unidiff-zero")) {
|
||||
unidiff_zero = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--reject")) {
|
||||
apply = apply_with_reject = apply_verbosely = 1;
|
||||
continue;
|
||||
|
263
builtin-archive.c
Normal file
263
builtin-archive.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Franck Bui-Huu
|
||||
* Copyright (c) 2006 Rene Scharfe
|
||||
*/
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "archive.h"
|
||||
#include "commit.h"
|
||||
#include "tree-walk.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
|
||||
static const char archive_usage[] = \
|
||||
"git-archive --format=<fmt> [--prefix=<prefix>/] [--verbose] [<extra>] <tree-ish> [path...]";
|
||||
|
||||
struct archiver archivers[] = {
|
||||
{
|
||||
.name = "tar",
|
||||
.write_archive = write_tar_archive,
|
||||
},
|
||||
{
|
||||
.name = "zip",
|
||||
.write_archive = write_zip_archive,
|
||||
.parse_extra = parse_extra_zip_args,
|
||||
},
|
||||
};
|
||||
|
||||
static int run_remote_archiver(const char *remote, int argc,
|
||||
const char **argv)
|
||||
{
|
||||
char *url, buf[LARGE_PACKET_MAX];
|
||||
int fd[2], i, len, rv;
|
||||
pid_t pid;
|
||||
const char *exec = "git-upload-archive";
|
||||
int exec_at = 0;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strncmp("--exec=", arg, 7)) {
|
||||
if (exec_at)
|
||||
die("multiple --exec specified");
|
||||
exec = arg + 7;
|
||||
exec_at = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
url = xstrdup(remote);
|
||||
pid = git_connect(fd, url, exec);
|
||||
if (pid < 0)
|
||||
return pid;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (i == exec_at)
|
||||
continue;
|
||||
packet_write(fd[1], "argument %s\n", argv[i]);
|
||||
}
|
||||
packet_flush(fd[1]);
|
||||
|
||||
len = packet_read_line(fd[0], buf, sizeof(buf));
|
||||
if (!len)
|
||||
die("git-archive: expected ACK/NAK, got EOF");
|
||||
if (buf[len-1] == '\n')
|
||||
buf[--len] = 0;
|
||||
if (strcmp(buf, "ACK")) {
|
||||
if (len > 5 && !strncmp(buf, "NACK ", 5))
|
||||
die("git-archive: NACK %s", buf + 5);
|
||||
die("git-archive: protocol error");
|
||||
}
|
||||
|
||||
len = packet_read_line(fd[0], buf, sizeof(buf));
|
||||
if (len)
|
||||
die("git-archive: expected a flush");
|
||||
|
||||
/* Now, start reading from fd[0] and spit it out to stdout */
|
||||
rv = recv_sideband("archive", fd[0], 1, 2, buf, sizeof(buf));
|
||||
close(fd[0]);
|
||||
rv |= finish_connect(pid);
|
||||
|
||||
return !!rv;
|
||||
}
|
||||
|
||||
static int init_archiver(const char *name, struct archiver *ar)
|
||||
{
|
||||
int rv = -1, i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(archivers); i++) {
|
||||
if (!strcmp(name, archivers[i].name)) {
|
||||
memcpy(ar, &archivers[i], sizeof(struct archiver));
|
||||
rv = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void parse_pathspec_arg(const char **pathspec, struct archiver_args *ar_args)
|
||||
{
|
||||
ar_args->pathspec = get_pathspec(ar_args->base, pathspec);
|
||||
}
|
||||
|
||||
void parse_treeish_arg(const char **argv, struct archiver_args *ar_args,
|
||||
const char *prefix)
|
||||
{
|
||||
const char *name = argv[0];
|
||||
const unsigned char *commit_sha1;
|
||||
time_t archive_time;
|
||||
struct tree *tree;
|
||||
struct commit *commit;
|
||||
unsigned char sha1[20];
|
||||
|
||||
if (get_sha1(name, sha1))
|
||||
die("Not a valid object name");
|
||||
|
||||
commit = lookup_commit_reference_gently(sha1, 1);
|
||||
if (commit) {
|
||||
commit_sha1 = commit->object.sha1;
|
||||
archive_time = commit->date;
|
||||
} else {
|
||||
commit_sha1 = NULL;
|
||||
archive_time = time(NULL);
|
||||
}
|
||||
|
||||
tree = parse_tree_indirect(sha1);
|
||||
if (tree == NULL)
|
||||
die("not a tree object");
|
||||
|
||||
if (prefix) {
|
||||
unsigned char tree_sha1[20];
|
||||
unsigned int mode;
|
||||
int err;
|
||||
|
||||
err = get_tree_entry(tree->object.sha1, prefix,
|
||||
tree_sha1, &mode);
|
||||
if (err || !S_ISDIR(mode))
|
||||
die("current working directory is untracked");
|
||||
|
||||
free(tree);
|
||||
tree = parse_tree_indirect(tree_sha1);
|
||||
}
|
||||
ar_args->tree = tree;
|
||||
ar_args->commit_sha1 = commit_sha1;
|
||||
ar_args->time = archive_time;
|
||||
}
|
||||
|
||||
int parse_archive_args(int argc, const char **argv, struct archiver *ar)
|
||||
{
|
||||
const char *extra_argv[MAX_EXTRA_ARGS];
|
||||
int extra_argc = 0;
|
||||
const char *format = NULL; /* might want to default to "tar" */
|
||||
const char *base = "";
|
||||
int verbose = 0;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (!strcmp(arg, "--list") || !strcmp(arg, "-l")) {
|
||||
for (i = 0; i < ARRAY_SIZE(archivers); i++)
|
||||
printf("%s\n", archivers[i].name);
|
||||
exit(0);
|
||||
}
|
||||
if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) {
|
||||
verbose = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--format=", 9)) {
|
||||
format = arg + 9;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--prefix=", 9)) {
|
||||
base = arg + 9;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--")) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (arg[0] == '-') {
|
||||
if (extra_argc > MAX_EXTRA_ARGS - 1)
|
||||
die("Too many extra options");
|
||||
extra_argv[extra_argc++] = arg;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* We need at least one parameter -- tree-ish */
|
||||
if (argc - 1 < i)
|
||||
usage(archive_usage);
|
||||
if (!format)
|
||||
die("You must specify an archive format");
|
||||
if (init_archiver(format, ar) < 0)
|
||||
die("Unknown archive format '%s'", format);
|
||||
|
||||
if (extra_argc) {
|
||||
if (!ar->parse_extra)
|
||||
die("'%s' format does not handle %s",
|
||||
ar->name, extra_argv[0]);
|
||||
ar->args.extra = ar->parse_extra(extra_argc, extra_argv);
|
||||
}
|
||||
ar->args.verbose = verbose;
|
||||
ar->args.base = base;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static const char *extract_remote_arg(int *ac, const char **av)
|
||||
{
|
||||
int ix, iy, cnt = *ac;
|
||||
int no_more_options = 0;
|
||||
const char *remote = NULL;
|
||||
|
||||
for (ix = iy = 1; ix < cnt; ix++) {
|
||||
const char *arg = av[ix];
|
||||
if (!strcmp(arg, "--"))
|
||||
no_more_options = 1;
|
||||
if (!no_more_options) {
|
||||
if (!strncmp(arg, "--remote=", 9)) {
|
||||
if (remote)
|
||||
die("Multiple --remote specified");
|
||||
remote = arg + 9;
|
||||
continue;
|
||||
}
|
||||
if (arg[0] != '-')
|
||||
no_more_options = 1;
|
||||
}
|
||||
if (ix != iy)
|
||||
av[iy] = arg;
|
||||
iy++;
|
||||
}
|
||||
if (remote) {
|
||||
av[--cnt] = NULL;
|
||||
*ac = cnt;
|
||||
}
|
||||
return remote;
|
||||
}
|
||||
|
||||
int cmd_archive(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct archiver ar;
|
||||
int tree_idx;
|
||||
const char *remote = NULL;
|
||||
|
||||
remote = extract_remote_arg(&argc, argv);
|
||||
if (remote)
|
||||
return run_remote_archiver(remote, argc, argv);
|
||||
|
||||
setlinebuf(stderr);
|
||||
|
||||
memset(&ar, 0, sizeof(ar));
|
||||
tree_idx = parse_archive_args(argc, argv, &ar);
|
||||
if (prefix == NULL)
|
||||
prefix = setup_git_directory();
|
||||
|
||||
argv += tree_idx;
|
||||
parse_treeish_arg(argv, &ar.args, prefix);
|
||||
parse_pathspec_arg(argv + 1, &ar.args);
|
||||
|
||||
return ar.write_archive(&ar.args);
|
||||
}
|
@ -62,7 +62,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
|
||||
hex[40] = 0;
|
||||
if (get_sha1_hex(hex, sha1))
|
||||
die("internal error");
|
||||
if (has_sha1_pack(sha1))
|
||||
if (has_sha1_pack(sha1, NULL))
|
||||
(*packed_loose)++;
|
||||
}
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
|
||||
FILE *in = stdin;
|
||||
const char *sep = "";
|
||||
unsigned char head_sha1[20];
|
||||
const char *head, *current_branch;
|
||||
const char *current_branch;
|
||||
|
||||
git_config(fmt_merge_msg_config);
|
||||
|
||||
@ -277,10 +277,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
|
||||
usage(fmt_merge_msg_usage);
|
||||
|
||||
/* get current branch */
|
||||
head = xstrdup(git_path("HEAD"));
|
||||
current_branch = resolve_ref(head, head_sha1, 1);
|
||||
current_branch += strlen(head) - 4;
|
||||
free((char *)head);
|
||||
current_branch = resolve_ref("HEAD", head_sha1, 1, NULL);
|
||||
if (!strncmp(current_branch, "refs/heads/", 11))
|
||||
current_branch += 11;
|
||||
|
||||
|
@ -218,8 +218,8 @@ static void create_default_files(const char *git_dir, const char *template_path)
|
||||
* branch, if it does not exist yet.
|
||||
*/
|
||||
strcpy(path + len, "HEAD");
|
||||
if (read_ref(path, sha1) < 0) {
|
||||
if (create_symref(path, "refs/heads/master") < 0)
|
||||
if (read_ref("HEAD", sha1) < 0) {
|
||||
if (create_symref("HEAD", "refs/heads/master") < 0)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -75,11 +75,10 @@ copy_data:
|
||||
}
|
||||
}
|
||||
|
||||
static int tags_only;
|
||||
|
||||
static int name_ref(const char *path, const unsigned char *sha1)
|
||||
static int name_ref(const char *path, const unsigned char *sha1, int flags, void *cb_data)
|
||||
{
|
||||
struct object *o = parse_object(sha1);
|
||||
int tags_only = *(int*)cb_data;
|
||||
int deref = 0;
|
||||
|
||||
if (tags_only && strncmp(path, "refs/tags/", 10))
|
||||
@ -131,6 +130,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct object_array revs = { 0, 0, NULL };
|
||||
int as_is = 0, all = 0, transform_stdin = 0;
|
||||
int tags_only = 0;
|
||||
|
||||
git_config(git_default_config);
|
||||
|
||||
@ -186,7 +186,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
|
||||
add_object_array((struct object *)commit, *argv, &revs);
|
||||
}
|
||||
|
||||
for_each_ref(name_ref);
|
||||
for_each_ref(name_ref, &tags_only);
|
||||
|
||||
if (transform_stdin) {
|
||||
char buffer[2048];
|
||||
|
@ -9,10 +9,13 @@
|
||||
#include "pack.h"
|
||||
#include "csum-file.h"
|
||||
#include "tree-walk.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "list-objects.h"
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
|
||||
static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
|
||||
static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] [--revs [--unpacked | --all]*] [--stdout | base-name] <ref-list | <object-list]";
|
||||
|
||||
struct object_entry {
|
||||
unsigned char sha1[20];
|
||||
@ -66,6 +69,7 @@ static int progress = 1;
|
||||
static volatile sig_atomic_t progress_update;
|
||||
static int window = 10;
|
||||
static int pack_to_stdout;
|
||||
static int num_preferred_base;
|
||||
|
||||
/*
|
||||
* The object names in objects array are hashed with this hashtable,
|
||||
@ -838,7 +842,7 @@ static int check_pbase_path(unsigned hash)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_preferred_base_object(char *name, unsigned hash)
|
||||
static void add_preferred_base_object(const char *name, unsigned hash)
|
||||
{
|
||||
struct pbase_tree *it;
|
||||
int cmplen = name_cmp_len(name);
|
||||
@ -867,6 +871,9 @@ static void add_preferred_base(unsigned char *sha1)
|
||||
unsigned long size;
|
||||
unsigned char tree_sha1[20];
|
||||
|
||||
if (window <= num_preferred_base++)
|
||||
return;
|
||||
|
||||
data = read_object_with_reference(sha1, tree_type, &size, tree_sha1);
|
||||
if (!data)
|
||||
return;
|
||||
@ -1326,14 +1333,105 @@ static int git_pack_config(const char *k, const char *v)
|
||||
return git_default_config(k, v);
|
||||
}
|
||||
|
||||
static void read_object_list_from_stdin(void)
|
||||
{
|
||||
char line[40 + 1 + PATH_MAX + 2];
|
||||
unsigned char sha1[20];
|
||||
unsigned hash;
|
||||
|
||||
for (;;) {
|
||||
if (!fgets(line, sizeof(line), stdin)) {
|
||||
if (feof(stdin))
|
||||
break;
|
||||
if (!ferror(stdin))
|
||||
die("fgets returned NULL, not EOF, not error!");
|
||||
if (errno != EINTR)
|
||||
die("fgets: %s", strerror(errno));
|
||||
clearerr(stdin);
|
||||
continue;
|
||||
}
|
||||
if (line[0] == '-') {
|
||||
if (get_sha1_hex(line+1, sha1))
|
||||
die("expected edge sha1, got garbage:\n %s",
|
||||
line);
|
||||
add_preferred_base(sha1);
|
||||
continue;
|
||||
}
|
||||
if (get_sha1_hex(line, sha1))
|
||||
die("expected sha1, got garbage:\n %s", line);
|
||||
|
||||
hash = name_hash(line+41);
|
||||
add_preferred_base_object(line+41, hash);
|
||||
add_object_entry(sha1, hash, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void show_commit(struct commit *commit)
|
||||
{
|
||||
unsigned hash = name_hash("");
|
||||
add_preferred_base_object("", hash);
|
||||
add_object_entry(commit->object.sha1, hash, 0);
|
||||
}
|
||||
|
||||
static void show_object(struct object_array_entry *p)
|
||||
{
|
||||
unsigned hash = name_hash(p->name);
|
||||
add_preferred_base_object(p->name, hash);
|
||||
add_object_entry(p->item->sha1, hash, 0);
|
||||
}
|
||||
|
||||
static void show_edge(struct commit *commit)
|
||||
{
|
||||
add_preferred_base(commit->object.sha1);
|
||||
}
|
||||
|
||||
static void get_object_list(int ac, const char **av)
|
||||
{
|
||||
struct rev_info revs;
|
||||
char line[1000];
|
||||
int flags = 0;
|
||||
|
||||
init_revisions(&revs, NULL);
|
||||
save_commit_buffer = 0;
|
||||
track_object_refs = 0;
|
||||
setup_revisions(ac, av, &revs, NULL);
|
||||
|
||||
while (fgets(line, sizeof(line), stdin) != NULL) {
|
||||
int len = strlen(line);
|
||||
if (line[len - 1] == '\n')
|
||||
line[--len] = 0;
|
||||
if (!len)
|
||||
break;
|
||||
if (*line == '-') {
|
||||
if (!strcmp(line, "--not")) {
|
||||
flags ^= UNINTERESTING;
|
||||
continue;
|
||||
}
|
||||
die("not a rev '%s'", line);
|
||||
}
|
||||
if (handle_revision_arg(line, &revs, flags, 1))
|
||||
die("bad revision '%s'", line);
|
||||
}
|
||||
|
||||
prepare_revision_walk(&revs);
|
||||
mark_edges_uninteresting(revs.commits, &revs, show_edge);
|
||||
traverse_commit_list(&revs, show_commit, show_object);
|
||||
}
|
||||
|
||||
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
SHA_CTX ctx;
|
||||
char line[40 + 1 + PATH_MAX + 2];
|
||||
int depth = 10;
|
||||
struct object_entry **list;
|
||||
int num_preferred_base = 0;
|
||||
int use_internal_rev_list = 0;
|
||||
int thin = 0;
|
||||
int i;
|
||||
const char *rp_av[64];
|
||||
int rp_ac;
|
||||
|
||||
rp_av[0] = "pack-objects";
|
||||
rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
|
||||
rp_ac = 2;
|
||||
|
||||
git_config(git_pack_config);
|
||||
|
||||
@ -1341,7 +1439,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
if (*arg == '-') {
|
||||
if (*arg != '-')
|
||||
break;
|
||||
|
||||
if (!strcmp("--non-empty", arg)) {
|
||||
non_empty = 1;
|
||||
continue;
|
||||
@ -1388,16 +1488,50 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
pack_to_stdout = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--revs", arg)) {
|
||||
use_internal_rev_list = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--unpacked", arg) ||
|
||||
!strncmp("--unpacked=", arg, 11) ||
|
||||
!strcmp("--all", arg)) {
|
||||
use_internal_rev_list = 1;
|
||||
if (ARRAY_SIZE(rp_av) - 1 <= rp_ac)
|
||||
die("too many internal rev-list options");
|
||||
rp_av[rp_ac++] = arg;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--thin", arg)) {
|
||||
use_internal_rev_list = 1;
|
||||
thin = 1;
|
||||
rp_av[1] = "--objects-edge";
|
||||
continue;
|
||||
}
|
||||
usage(pack_usage);
|
||||
}
|
||||
if (base_name)
|
||||
usage(pack_usage);
|
||||
base_name = arg;
|
||||
}
|
||||
|
||||
/* Traditionally "pack-objects [options] base extra" failed;
|
||||
* we would however want to take refs parameter that would
|
||||
* have been given to upstream rev-list ourselves, which means
|
||||
* we somehow want to say what the base name is. So the
|
||||
* syntax would be:
|
||||
*
|
||||
* pack-objects [options] base <refs...>
|
||||
*
|
||||
* in other words, we would treat the first non-option as the
|
||||
* base_name and send everything else to the internal revision
|
||||
* walker.
|
||||
*/
|
||||
|
||||
if (!pack_to_stdout)
|
||||
base_name = argv[i++];
|
||||
|
||||
if (pack_to_stdout != !base_name)
|
||||
usage(pack_usage);
|
||||
|
||||
if (!pack_to_stdout && thin)
|
||||
die("--thin cannot be used to build an indexable pack.");
|
||||
|
||||
prepare_packed_git();
|
||||
|
||||
if (progress) {
|
||||
@ -1405,35 +1539,13 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
setup_progress_signal();
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
unsigned char sha1[20];
|
||||
unsigned hash;
|
||||
|
||||
if (!fgets(line, sizeof(line), stdin)) {
|
||||
if (feof(stdin))
|
||||
break;
|
||||
if (!ferror(stdin))
|
||||
die("fgets returned NULL, not EOF, not error!");
|
||||
if (errno != EINTR)
|
||||
die("fgets: %s", strerror(errno));
|
||||
clearerr(stdin);
|
||||
continue;
|
||||
if (!use_internal_rev_list)
|
||||
read_object_list_from_stdin();
|
||||
else {
|
||||
rp_av[rp_ac] = NULL;
|
||||
get_object_list(rp_ac, rp_av);
|
||||
}
|
||||
|
||||
if (line[0] == '-') {
|
||||
if (get_sha1_hex(line+1, sha1))
|
||||
die("expected edge sha1, got garbage:\n %s",
|
||||
line+1);
|
||||
if (num_preferred_base++ < window)
|
||||
add_preferred_base(sha1);
|
||||
continue;
|
||||
}
|
||||
if (get_sha1_hex(line, sha1))
|
||||
die("expected sha1, got garbage:\n %s", line);
|
||||
hash = name_hash(line+41);
|
||||
add_preferred_base_object(line+41, hash);
|
||||
add_object_entry(sha1, hash, 0);
|
||||
}
|
||||
if (progress)
|
||||
fprintf(stderr, "Done counting %d objects.\n", nr_objects);
|
||||
sorted_by_sha = create_final_object_list();
|
||||
|
112
builtin-pack-refs.c
Normal file
112
builtin-pack-refs.c
Normal file
@ -0,0 +1,112 @@
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
|
||||
static const char *result_path, *lock_path;
|
||||
static const char builtin_pack_refs_usage[] =
|
||||
"git-pack-refs [--prune]";
|
||||
|
||||
struct ref_to_prune {
|
||||
struct ref_to_prune *next;
|
||||
unsigned char sha1[20];
|
||||
char name[FLEX_ARRAY];
|
||||
};
|
||||
|
||||
struct pack_refs_cb_data {
|
||||
int prune;
|
||||
struct ref_to_prune *ref_to_prune;
|
||||
FILE *refs_file;
|
||||
};
|
||||
|
||||
static void remove_lock_file(void)
|
||||
{
|
||||
if (lock_path)
|
||||
unlink(lock_path);
|
||||
}
|
||||
|
||||
static int do_not_prune(int flags)
|
||||
{
|
||||
/* If it is already packed or if it is a symref,
|
||||
* do not prune it.
|
||||
*/
|
||||
return (flags & (REF_ISSYMREF|REF_ISPACKED));
|
||||
}
|
||||
|
||||
static int handle_one_ref(const char *path, const unsigned char *sha1,
|
||||
int flags, void *cb_data)
|
||||
{
|
||||
struct pack_refs_cb_data *cb = cb_data;
|
||||
|
||||
/* Do not pack the symbolic refs */
|
||||
if (!(flags & REF_ISSYMREF))
|
||||
fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
|
||||
if (cb->prune && !do_not_prune(flags)) {
|
||||
int namelen = strlen(path) + 1;
|
||||
struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
|
||||
hashcpy(n->sha1, sha1);
|
||||
strcpy(n->name, path);
|
||||
n->next = cb->ref_to_prune;
|
||||
cb->ref_to_prune = n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* make sure nobody touched the ref, and unlink */
|
||||
static void prune_ref(struct ref_to_prune *r)
|
||||
{
|
||||
struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1, 1);
|
||||
|
||||
if (lock) {
|
||||
unlink(git_path(r->name));
|
||||
unlock_ref(lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void prune_refs(struct ref_to_prune *r)
|
||||
{
|
||||
while (r) {
|
||||
prune_ref(r);
|
||||
r = r->next;
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int fd, i;
|
||||
struct pack_refs_cb_data cbdata;
|
||||
|
||||
memset(&cbdata, 0, sizeof(cbdata));
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "--prune")) {
|
||||
cbdata.prune = 1;
|
||||
continue;
|
||||
}
|
||||
/* perhaps other parameters later... */
|
||||
break;
|
||||
}
|
||||
if (i != argc)
|
||||
usage(builtin_pack_refs_usage);
|
||||
|
||||
result_path = xstrdup(git_path("packed-refs"));
|
||||
lock_path = xstrdup(mkpath("%s.lock", result_path));
|
||||
|
||||
fd = open(lock_path, O_CREAT | O_EXCL | O_WRONLY, 0666);
|
||||
if (fd < 0)
|
||||
die("unable to create new ref-pack file (%s)", strerror(errno));
|
||||
atexit(remove_lock_file);
|
||||
|
||||
cbdata.refs_file = fdopen(fd, "w");
|
||||
if (!cbdata.refs_file)
|
||||
die("unable to create ref-pack file structure (%s)",
|
||||
strerror(errno));
|
||||
for_each_ref(handle_one_ref, &cbdata);
|
||||
fsync(fd);
|
||||
fclose(cbdata.refs_file);
|
||||
if (rename(lock_path, result_path) < 0)
|
||||
die("unable to overwrite old ref-pack file (%s)", strerror(errno));
|
||||
lock_path = NULL;
|
||||
if (cbdata.prune)
|
||||
prune_refs(cbdata.ref_to_prune);
|
||||
return 0;
|
||||
}
|
@ -19,7 +19,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len)
|
||||
memcpy(hex+2, de->d_name, 38);
|
||||
if (get_sha1_hex(hex, sha1))
|
||||
continue;
|
||||
if (!has_sha1_pack(sha1))
|
||||
if (!has_sha1_pack(sha1, NULL))
|
||||
continue;
|
||||
memcpy(pathname + len, de->d_name, 38);
|
||||
if (dryrun)
|
||||
|
@ -174,7 +174,7 @@ static void walk_commit_list(struct rev_info *revs)
|
||||
}
|
||||
}
|
||||
|
||||
static int add_one_ref(const char *path, const unsigned char *sha1)
|
||||
static int add_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct object *object = parse_object(sha1);
|
||||
if (!object)
|
||||
@ -240,7 +240,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
revs.tree_objects = 1;
|
||||
|
||||
/* Add all external refs */
|
||||
for_each_ref(add_one_ref);
|
||||
for_each_ref(add_one_ref, NULL);
|
||||
|
||||
/* Add all refs from the index file */
|
||||
add_cache_refs();
|
||||
|
@ -27,7 +27,7 @@ static void add_refspec(const char *ref)
|
||||
refspec_nr = nr;
|
||||
}
|
||||
|
||||
static int expand_one_ref(const char *ref, const unsigned char *sha1)
|
||||
static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
/* Ignore the "refs/" at the beginning of the refname */
|
||||
ref += 5;
|
||||
@ -51,7 +51,7 @@ static void expand_refspecs(void)
|
||||
}
|
||||
if (!tags)
|
||||
return;
|
||||
for_each_ref(expand_one_ref);
|
||||
for_each_ref(expand_one_ref, NULL);
|
||||
}
|
||||
|
||||
static void set_refspecs(const char **refs, int nr)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "tree-walk.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "list-objects.h"
|
||||
#include "builtin.h"
|
||||
|
||||
/* bits #0-15 in revision.h */
|
||||
@ -98,92 +99,8 @@ static void show_commit(struct commit *commit)
|
||||
commit->buffer = NULL;
|
||||
}
|
||||
|
||||
static void process_blob(struct blob *blob,
|
||||
struct object_array *p,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
static void show_object(struct object_array_entry *p)
|
||||
{
|
||||
struct object *obj = &blob->object;
|
||||
|
||||
if (!revs.blob_objects)
|
||||
return;
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
return;
|
||||
obj->flags |= SEEN;
|
||||
name = xstrdup(name);
|
||||
add_object(obj, p, path, name);
|
||||
}
|
||||
|
||||
static void process_tree(struct tree *tree,
|
||||
struct object_array *p,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
{
|
||||
struct object *obj = &tree->object;
|
||||
struct tree_desc desc;
|
||||
struct name_entry entry;
|
||||
struct name_path me;
|
||||
|
||||
if (!revs.tree_objects)
|
||||
return;
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
return;
|
||||
if (parse_tree(tree) < 0)
|
||||
die("bad tree object %s", sha1_to_hex(obj->sha1));
|
||||
obj->flags |= SEEN;
|
||||
name = xstrdup(name);
|
||||
add_object(obj, p, path, name);
|
||||
me.up = path;
|
||||
me.elem = name;
|
||||
me.elem_len = strlen(name);
|
||||
|
||||
desc.buf = tree->buffer;
|
||||
desc.size = tree->size;
|
||||
|
||||
while (tree_entry(&desc, &entry)) {
|
||||
if (S_ISDIR(entry.mode))
|
||||
process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
|
||||
else
|
||||
process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
|
||||
}
|
||||
free(tree->buffer);
|
||||
tree->buffer = NULL;
|
||||
}
|
||||
|
||||
static void show_commit_list(struct rev_info *revs)
|
||||
{
|
||||
int i;
|
||||
struct commit *commit;
|
||||
struct object_array objects = { 0, 0, NULL };
|
||||
|
||||
while ((commit = get_revision(revs)) != NULL) {
|
||||
process_tree(commit->tree, &objects, NULL, "");
|
||||
show_commit(commit);
|
||||
}
|
||||
for (i = 0; i < revs->pending.nr; i++) {
|
||||
struct object_array_entry *pending = revs->pending.objects + i;
|
||||
struct object *obj = pending->item;
|
||||
const char *name = pending->name;
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
continue;
|
||||
if (obj->type == OBJ_TAG) {
|
||||
obj->flags |= SEEN;
|
||||
add_object_array(obj, name, &objects);
|
||||
continue;
|
||||
}
|
||||
if (obj->type == OBJ_TREE) {
|
||||
process_tree((struct tree *)obj, &objects, NULL, name);
|
||||
continue;
|
||||
}
|
||||
if (obj->type == OBJ_BLOB) {
|
||||
process_blob((struct blob *)obj, &objects, NULL, name);
|
||||
continue;
|
||||
}
|
||||
die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
|
||||
}
|
||||
for (i = 0; i < objects.nr; i++) {
|
||||
struct object_array_entry *p = objects.objects + i;
|
||||
|
||||
/* An object with name "foo\n0000000..." can be used to
|
||||
* confuse downstream git-pack-objects very badly.
|
||||
*/
|
||||
@ -196,6 +113,10 @@ static void show_commit_list(struct rev_info *revs)
|
||||
else
|
||||
printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
|
||||
}
|
||||
|
||||
static void show_edge(struct commit *commit)
|
||||
{
|
||||
printf("-%s\n", sha1_to_hex(commit->object.sha1));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -276,35 +197,6 @@ static struct commit_list *find_bisection(struct commit_list *list)
|
||||
return best;
|
||||
}
|
||||
|
||||
static void mark_edge_parents_uninteresting(struct commit *commit)
|
||||
{
|
||||
struct commit_list *parents;
|
||||
|
||||
for (parents = commit->parents; parents; parents = parents->next) {
|
||||
struct commit *parent = parents->item;
|
||||
if (!(parent->object.flags & UNINTERESTING))
|
||||
continue;
|
||||
mark_tree_uninteresting(parent->tree);
|
||||
if (revs.edge_hint && !(parent->object.flags & SHOWN)) {
|
||||
parent->object.flags |= SHOWN;
|
||||
printf("-%s\n", sha1_to_hex(parent->object.sha1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_edges_uninteresting(struct commit_list *list)
|
||||
{
|
||||
for ( ; list; list = list->next) {
|
||||
struct commit *commit = list->item;
|
||||
|
||||
if (commit->object.flags & UNINTERESTING) {
|
||||
mark_tree_uninteresting(commit->tree);
|
||||
continue;
|
||||
}
|
||||
mark_edge_parents_uninteresting(commit);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_revisions_from_stdin(struct rev_info *revs)
|
||||
{
|
||||
char line[1000];
|
||||
@ -384,12 +276,12 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||
|
||||
prepare_revision_walk(&revs);
|
||||
if (revs.tree_objects)
|
||||
mark_edges_uninteresting(revs.commits);
|
||||
mark_edges_uninteresting(revs.commits, &revs, show_edge);
|
||||
|
||||
if (bisect_list)
|
||||
revs.commits = find_bisection(revs.commits);
|
||||
|
||||
show_commit_list(&revs);
|
||||
traverse_commit_list(&revs, show_commit, show_object);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ static void show_default(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int show_reference(const char *refname, const unsigned char *sha1)
|
||||
static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
show_rev(NORMAL, sha1, refname);
|
||||
return 0;
|
||||
@ -299,19 +299,19 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--all")) {
|
||||
for_each_ref(show_reference);
|
||||
for_each_ref(show_reference, NULL);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--branches")) {
|
||||
for_each_branch_ref(show_reference);
|
||||
for_each_branch_ref(show_reference, NULL);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--tags")) {
|
||||
for_each_tag_ref(show_reference);
|
||||
for_each_tag_ref(show_reference, NULL);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--remotes")) {
|
||||
for_each_remote_ref(show_reference);
|
||||
for_each_remote_ref(show_reference, NULL);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--show-prefix")) {
|
||||
|
36
builtin-runstatus.c
Normal file
36
builtin-runstatus.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include "wt-status.h"
|
||||
#include "cache.h"
|
||||
|
||||
extern int wt_status_use_color;
|
||||
|
||||
static const char runstatus_usage[] =
|
||||
"git-runstatus [--color|--nocolor] [--amend] [--verbose]";
|
||||
|
||||
int cmd_runstatus(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct wt_status s;
|
||||
int i;
|
||||
|
||||
git_config(git_status_config);
|
||||
wt_status_prepare(&s);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--color"))
|
||||
wt_status_use_color = 1;
|
||||
else if (!strcmp(argv[i], "--nocolor"))
|
||||
wt_status_use_color = 0;
|
||||
else if (!strcmp(argv[i], "--amend")) {
|
||||
s.amend = 1;
|
||||
s.reference = "HEAD^1";
|
||||
}
|
||||
else if (!strcmp(argv[i], "--verbose"))
|
||||
s.verbose = 1;
|
||||
else if (!strcmp(argv[i], "--untracked"))
|
||||
s.untracked = 1;
|
||||
else
|
||||
usage(runstatus_usage);
|
||||
}
|
||||
|
||||
wt_status_print(&s);
|
||||
return s.commitable ? 0 : 1;
|
||||
}
|
@ -346,7 +346,7 @@ static void sort_ref_range(int bottom, int top)
|
||||
compare_ref_name);
|
||||
}
|
||||
|
||||
static int append_ref(const char *refname, const unsigned char *sha1)
|
||||
static int append_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct commit *commit = lookup_commit_reference_gently(sha1, 1);
|
||||
int i;
|
||||
@ -369,7 +369,7 @@ static int append_ref(const char *refname, const unsigned char *sha1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_head_ref(const char *refname, const unsigned char *sha1)
|
||||
static int append_head_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
unsigned char tmp[20];
|
||||
int ofs = 11;
|
||||
@ -380,14 +380,14 @@ static int append_head_ref(const char *refname, const unsigned char *sha1)
|
||||
*/
|
||||
if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
|
||||
ofs = 5;
|
||||
return append_ref(refname + ofs, sha1);
|
||||
return append_ref(refname + ofs, sha1, flag, cb_data);
|
||||
}
|
||||
|
||||
static int append_tag_ref(const char *refname, const unsigned char *sha1)
|
||||
static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
if (strncmp(refname, "refs/tags/", 10))
|
||||
return 0;
|
||||
return append_ref(refname + 5, sha1);
|
||||
return append_ref(refname + 5, sha1, flag, cb_data);
|
||||
}
|
||||
|
||||
static const char *match_ref_pattern = NULL;
|
||||
@ -401,7 +401,7 @@ static int count_slash(const char *s)
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int append_matching_ref(const char *refname, const unsigned char *sha1)
|
||||
static int append_matching_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
/* we want to allow pattern hold/<asterisk> to show all
|
||||
* branches under refs/heads/hold/, and v0.99.9? to show
|
||||
@ -417,41 +417,33 @@ static int append_matching_ref(const char *refname, const unsigned char *sha1)
|
||||
if (fnmatch(match_ref_pattern, tail, 0))
|
||||
return 0;
|
||||
if (!strncmp("refs/heads/", refname, 11))
|
||||
return append_head_ref(refname, sha1);
|
||||
return append_head_ref(refname, sha1, flag, cb_data);
|
||||
if (!strncmp("refs/tags/", refname, 10))
|
||||
return append_tag_ref(refname, sha1);
|
||||
return append_ref(refname, sha1);
|
||||
return append_tag_ref(refname, sha1, flag, cb_data);
|
||||
return append_ref(refname, sha1, flag, cb_data);
|
||||
}
|
||||
|
||||
static void snarf_refs(int head, int tag)
|
||||
{
|
||||
if (head) {
|
||||
int orig_cnt = ref_name_cnt;
|
||||
for_each_ref(append_head_ref);
|
||||
for_each_ref(append_head_ref, NULL);
|
||||
sort_ref_range(orig_cnt, ref_name_cnt);
|
||||
}
|
||||
if (tag) {
|
||||
int orig_cnt = ref_name_cnt;
|
||||
for_each_ref(append_tag_ref);
|
||||
for_each_ref(append_tag_ref, NULL);
|
||||
sort_ref_range(orig_cnt, ref_name_cnt);
|
||||
}
|
||||
}
|
||||
|
||||
static int rev_is_head(char *head_path, int headlen, char *name,
|
||||
static int rev_is_head(char *head, int headlen, char *name,
|
||||
unsigned char *head_sha1, unsigned char *sha1)
|
||||
{
|
||||
int namelen;
|
||||
if ((!head_path[0]) ||
|
||||
if ((!head[0]) ||
|
||||
(head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
|
||||
return 0;
|
||||
namelen = strlen(name);
|
||||
if ((headlen < namelen) ||
|
||||
memcmp(head_path + headlen - namelen, name, namelen))
|
||||
return 0;
|
||||
if (headlen == namelen ||
|
||||
head_path[headlen - namelen - 1] == '/')
|
||||
return 1;
|
||||
return 0;
|
||||
return !strcmp(head, name);
|
||||
}
|
||||
|
||||
static int show_merge_base(struct commit_list *seen, int num_rev)
|
||||
@ -495,7 +487,7 @@ static void append_one_rev(const char *av)
|
||||
{
|
||||
unsigned char revkey[20];
|
||||
if (!get_sha1(av, revkey)) {
|
||||
append_ref(av, revkey);
|
||||
append_ref(av, revkey, 0, NULL);
|
||||
return;
|
||||
}
|
||||
if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
|
||||
@ -503,7 +495,7 @@ static void append_one_rev(const char *av)
|
||||
int saved_matches = ref_name_cnt;
|
||||
match_ref_pattern = av;
|
||||
match_ref_slash = count_slash(av);
|
||||
for_each_ref(append_matching_ref);
|
||||
for_each_ref(append_matching_ref, NULL);
|
||||
if (saved_matches == ref_name_cnt &&
|
||||
ref_name_cnt < MAX_REVS)
|
||||
error("no matching refs with %s", av);
|
||||
@ -559,9 +551,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
int all_heads = 0, all_tags = 0;
|
||||
int all_mask, all_revs;
|
||||
int lifo = 1;
|
||||
char head_path[128];
|
||||
const char *head_path_p;
|
||||
int head_path_len;
|
||||
char head[128];
|
||||
const char *head_p;
|
||||
int head_len;
|
||||
unsigned char head_sha1[20];
|
||||
int merge_base = 0;
|
||||
int independent = 0;
|
||||
@ -638,31 +630,31 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
ac--; av++;
|
||||
}
|
||||
|
||||
head_path_p = resolve_ref(git_path("HEAD"), head_sha1, 1);
|
||||
if (head_path_p) {
|
||||
head_path_len = strlen(head_path_p);
|
||||
memcpy(head_path, head_path_p, head_path_len + 1);
|
||||
head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
|
||||
if (head_p) {
|
||||
head_len = strlen(head_p);
|
||||
memcpy(head, head_p, head_len + 1);
|
||||
}
|
||||
else {
|
||||
head_path_len = 0;
|
||||
head_path[0] = 0;
|
||||
head_len = 0;
|
||||
head[0] = 0;
|
||||
}
|
||||
|
||||
if (with_current_branch && head_path_p) {
|
||||
if (with_current_branch && head_p) {
|
||||
int has_head = 0;
|
||||
for (i = 0; !has_head && i < ref_name_cnt; i++) {
|
||||
/* We are only interested in adding the branch
|
||||
* HEAD points at.
|
||||
*/
|
||||
if (rev_is_head(head_path,
|
||||
head_path_len,
|
||||
if (rev_is_head(head,
|
||||
head_len,
|
||||
ref_name[i],
|
||||
head_sha1, NULL))
|
||||
has_head++;
|
||||
}
|
||||
if (!has_head) {
|
||||
int pfxlen = strlen(git_path("refs/heads/"));
|
||||
append_one_rev(head_path + pfxlen);
|
||||
int pfxlen = strlen("refs/heads/");
|
||||
append_one_rev(head + pfxlen);
|
||||
}
|
||||
}
|
||||
|
||||
@ -713,8 +705,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
if (1 < num_rev || extra < 0) {
|
||||
for (i = 0; i < num_rev; i++) {
|
||||
int j;
|
||||
int is_head = rev_is_head(head_path,
|
||||
head_path_len,
|
||||
int is_head = rev_is_head(head,
|
||||
head_len,
|
||||
ref_name[i],
|
||||
head_sha1,
|
||||
rev[i]->object.sha1);
|
||||
|
@ -9,7 +9,7 @@ static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0,
|
||||
found_match = 0, verify = 0, quiet = 0, hash_only = 0;
|
||||
static const char **pattern;
|
||||
|
||||
static int show_ref(const char *refname, const unsigned char *sha1)
|
||||
static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
|
||||
{
|
||||
struct object *obj;
|
||||
|
||||
@ -109,8 +109,8 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
||||
usage(show_ref_usage);
|
||||
}
|
||||
if (show_head)
|
||||
head_ref(show_ref);
|
||||
for_each_ref(show_ref);
|
||||
head_ref(show_ref, NULL);
|
||||
for_each_ref(show_ref, NULL);
|
||||
if (!found_match) {
|
||||
if (verify && !quiet)
|
||||
die("No match");
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
|
||||
static const char git_symbolic_ref_usage[] =
|
||||
"git-symbolic-ref name [ref]";
|
||||
@ -7,15 +8,14 @@ static const char git_symbolic_ref_usage[] =
|
||||
static void check_symref(const char *HEAD)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
const char *git_HEAD = xstrdup(git_path("%s", HEAD));
|
||||
const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 0);
|
||||
if (git_refs_heads_master) {
|
||||
/* we want to strip the .git/ part */
|
||||
int pfxlen = strlen(git_HEAD) - strlen(HEAD);
|
||||
puts(git_refs_heads_master + pfxlen);
|
||||
}
|
||||
else
|
||||
int flag;
|
||||
const char *refs_heads_master = resolve_ref(HEAD, sha1, 0, &flag);
|
||||
|
||||
if (!refs_heads_master)
|
||||
die("No such ref: %s", HEAD);
|
||||
else if (!(flag & REF_ISSYMREF))
|
||||
die("ref %s is not a symbolic ref", HEAD);
|
||||
puts(refs_heads_master);
|
||||
}
|
||||
|
||||
int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
|
||||
@ -26,7 +26,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
|
||||
check_symref(argv[1]);
|
||||
break;
|
||||
case 3:
|
||||
create_symref(xstrdup(git_path("%s", argv[1])), argv[2]);
|
||||
create_symref(argv[1], argv[2]);
|
||||
break;
|
||||
default:
|
||||
usage(git_symbolic_ref_usage);
|
||||
|
@ -3,12 +3,12 @@
|
||||
*/
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "tree-walk.h"
|
||||
#include "commit.h"
|
||||
#include "strbuf.h"
|
||||
#include "tar.h"
|
||||
#include "builtin.h"
|
||||
#include "pkt-line.h"
|
||||
#include "archive.h"
|
||||
|
||||
#define RECORDSIZE (512)
|
||||
#define BLOCKSIZE (RECORDSIZE * 20)
|
||||
@ -21,6 +21,7 @@ static unsigned long offset;
|
||||
|
||||
static time_t archive_time;
|
||||
static int tar_umask;
|
||||
static int verbose;
|
||||
|
||||
/* writes out the whole block, but only if it is full */
|
||||
static void write_if_needed(void)
|
||||
@ -168,6 +169,8 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
|
||||
mode = 0100666;
|
||||
sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
|
||||
} else {
|
||||
if (verbose)
|
||||
fprintf(stderr, "%.*s\n", path->len, path->buf);
|
||||
if (S_ISDIR(mode)) {
|
||||
*header.typeflag = TYPEFLAG_DIR;
|
||||
mode = (mode | 0777) & ~tar_umask;
|
||||
@ -244,37 +247,6 @@ static void write_global_extended_header(const unsigned char *sha1)
|
||||
free(ext_header.buf);
|
||||
}
|
||||
|
||||
static void traverse_tree(struct tree_desc *tree, struct strbuf *path)
|
||||
{
|
||||
int pathlen = path->len;
|
||||
struct name_entry entry;
|
||||
|
||||
while (tree_entry(tree, &entry)) {
|
||||
void *eltbuf;
|
||||
char elttype[20];
|
||||
unsigned long eltsize;
|
||||
|
||||
eltbuf = read_sha1_file(entry.sha1, elttype, &eltsize);
|
||||
if (!eltbuf)
|
||||
die("cannot read %s", sha1_to_hex(entry.sha1));
|
||||
|
||||
path->len = pathlen;
|
||||
strbuf_append_string(path, entry.path);
|
||||
if (S_ISDIR(entry.mode))
|
||||
strbuf_append_string(path, "/");
|
||||
|
||||
write_entry(entry.sha1, path, entry.mode, eltbuf, eltsize);
|
||||
|
||||
if (S_ISDIR(entry.mode)) {
|
||||
struct tree_desc subtree;
|
||||
subtree.buf = eltbuf;
|
||||
subtree.size = eltsize;
|
||||
traverse_tree(&subtree, path);
|
||||
}
|
||||
free(eltbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static int git_tar_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "tar.umask")) {
|
||||
@ -291,50 +263,95 @@ static int git_tar_config(const char *var, const char *value)
|
||||
|
||||
static int generate_tar(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
unsigned char sha1[20], tree_sha1[20];
|
||||
struct commit *commit;
|
||||
struct tree_desc tree;
|
||||
struct strbuf current_path;
|
||||
void *buffer;
|
||||
|
||||
current_path.buf = xmalloc(PATH_MAX);
|
||||
current_path.alloc = PATH_MAX;
|
||||
current_path.len = current_path.eof = 0;
|
||||
struct archiver_args args;
|
||||
int result;
|
||||
char *base = NULL;
|
||||
|
||||
git_config(git_tar_config);
|
||||
|
||||
switch (argc) {
|
||||
case 3:
|
||||
strbuf_append_string(¤t_path, argv[2]);
|
||||
strbuf_append_string(¤t_path, "/");
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
if (get_sha1(argv[1], sha1))
|
||||
die("Not a valid object name %s", argv[1]);
|
||||
break;
|
||||
default:
|
||||
memset(&args, 0, sizeof(args));
|
||||
if (argc != 2 && argc != 3)
|
||||
usage(tar_tree_usage);
|
||||
if (argc == 3) {
|
||||
int baselen = strlen(argv[2]);
|
||||
base = xmalloc(baselen + 2);
|
||||
memcpy(base, argv[2], baselen);
|
||||
base[baselen] = '/';
|
||||
base[baselen + 1] = '\0';
|
||||
}
|
||||
args.base = base;
|
||||
parse_treeish_arg(argv + 1, &args, NULL);
|
||||
|
||||
result = write_tar_archive(&args);
|
||||
free(base);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
commit = lookup_commit_reference_gently(sha1, 1);
|
||||
if (commit) {
|
||||
write_global_extended_header(commit->object.sha1);
|
||||
archive_time = commit->date;
|
||||
} else
|
||||
archive_time = time(NULL);
|
||||
static int write_tar_entry(const unsigned char *sha1,
|
||||
const char *base, int baselen,
|
||||
const char *filename, unsigned mode, int stage)
|
||||
{
|
||||
static struct strbuf path;
|
||||
int filenamelen = strlen(filename);
|
||||
void *buffer;
|
||||
char type[20];
|
||||
unsigned long size;
|
||||
|
||||
tree.buf = buffer = read_object_with_reference(sha1, tree_type,
|
||||
&tree.size, tree_sha1);
|
||||
if (!tree.buf)
|
||||
die("not a reference to a tag, commit or tree object: %s",
|
||||
sha1_to_hex(sha1));
|
||||
if (!path.alloc) {
|
||||
path.buf = xmalloc(PATH_MAX);
|
||||
path.alloc = PATH_MAX;
|
||||
path.len = path.eof = 0;
|
||||
}
|
||||
if (path.alloc < baselen + filenamelen) {
|
||||
free(path.buf);
|
||||
path.buf = xmalloc(baselen + filenamelen);
|
||||
path.alloc = baselen + filenamelen;
|
||||
}
|
||||
memcpy(path.buf, base, baselen);
|
||||
memcpy(path.buf + baselen, filename, filenamelen);
|
||||
path.len = baselen + filenamelen;
|
||||
if (S_ISDIR(mode)) {
|
||||
strbuf_append_string(&path, "/");
|
||||
buffer = NULL;
|
||||
size = 0;
|
||||
} else {
|
||||
buffer = read_sha1_file(sha1, type, &size);
|
||||
if (!buffer)
|
||||
die("cannot read %s", sha1_to_hex(sha1));
|
||||
}
|
||||
|
||||
if (current_path.len > 0)
|
||||
write_entry(tree_sha1, ¤t_path, 040777, NULL, 0);
|
||||
traverse_tree(&tree, ¤t_path);
|
||||
write_trailer();
|
||||
write_entry(sha1, &path, mode, buffer, size);
|
||||
free(buffer);
|
||||
free(current_path.buf);
|
||||
|
||||
return READ_TREE_RECURSIVE;
|
||||
}
|
||||
|
||||
int write_tar_archive(struct archiver_args *args)
|
||||
{
|
||||
int plen = args->base ? strlen(args->base) : 0;
|
||||
|
||||
git_config(git_tar_config);
|
||||
|
||||
archive_time = args->time;
|
||||
verbose = args->verbose;
|
||||
|
||||
if (args->commit_sha1)
|
||||
write_global_extended_header(args->commit_sha1);
|
||||
|
||||
if (args->base && plen > 0 && args->base[plen - 1] == '/') {
|
||||
char *base = xstrdup(args->base);
|
||||
int baselen = strlen(base);
|
||||
|
||||
while (baselen > 0 && base[baselen - 1] == '/')
|
||||
base[--baselen] = '\0';
|
||||
write_tar_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
|
||||
free(base);
|
||||
}
|
||||
read_tree_recursive(args->tree, args->base, plen, 0,
|
||||
args->pathspec, write_tar_entry);
|
||||
write_trailer();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
175
builtin-upload-archive.c
Normal file
175
builtin-upload-archive.c
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Franck Bui-Huu
|
||||
*/
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "archive.h"
|
||||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
#include <sys/wait.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
static const char upload_archive_usage[] =
|
||||
"git-upload-archive <repo>";
|
||||
|
||||
static const char deadchild[] =
|
||||
"git-upload-archive: archiver died with error";
|
||||
|
||||
static const char lostchild[] =
|
||||
"git-upload-archive: archiver process was lost";
|
||||
|
||||
|
||||
static int run_upload_archive(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct archiver ar;
|
||||
const char *sent_argv[MAX_ARGS];
|
||||
const char *arg_cmd = "argument ";
|
||||
char *p, buf[4096];
|
||||
int treeish_idx;
|
||||
int sent_argc;
|
||||
int len;
|
||||
|
||||
if (argc != 2)
|
||||
usage(upload_archive_usage);
|
||||
|
||||
if (strlen(argv[1]) > sizeof(buf))
|
||||
die("insanely long repository name");
|
||||
|
||||
strcpy(buf, argv[1]); /* enter-repo smudges its argument */
|
||||
|
||||
if (!enter_repo(buf, 0))
|
||||
die("not a git archive");
|
||||
|
||||
/* put received options in sent_argv[] */
|
||||
sent_argc = 1;
|
||||
sent_argv[0] = "git-upload-archive";
|
||||
for (p = buf;;) {
|
||||
/* This will die if not enough free space in buf */
|
||||
len = packet_read_line(0, p, (buf + sizeof buf) - p);
|
||||
if (len == 0)
|
||||
break; /* got a flush */
|
||||
if (sent_argc > MAX_ARGS - 2)
|
||||
die("Too many options (>29)");
|
||||
|
||||
if (p[len-1] == '\n') {
|
||||
p[--len] = 0;
|
||||
}
|
||||
if (len < strlen(arg_cmd) ||
|
||||
strncmp(arg_cmd, p, strlen(arg_cmd)))
|
||||
die("'argument' token or flush expected");
|
||||
|
||||
len -= strlen(arg_cmd);
|
||||
memmove(p, p + strlen(arg_cmd), len);
|
||||
sent_argv[sent_argc++] = p;
|
||||
p += len;
|
||||
*p++ = 0;
|
||||
}
|
||||
sent_argv[sent_argc] = NULL;
|
||||
|
||||
/* parse all options sent by the client */
|
||||
treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar);
|
||||
|
||||
parse_treeish_arg(sent_argv + treeish_idx, &ar.args, prefix);
|
||||
parse_pathspec_arg(sent_argv + treeish_idx + 1, &ar.args);
|
||||
|
||||
return ar.write_archive(&ar.args);
|
||||
}
|
||||
|
||||
static void error_clnt(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list params;
|
||||
int len;
|
||||
|
||||
va_start(params, fmt);
|
||||
len = vsprintf(buf, fmt, params);
|
||||
va_end(params);
|
||||
send_sideband(1, 3, buf, len, LARGE_PACKET_MAX);
|
||||
die("sent error to the client: %s", buf);
|
||||
}
|
||||
|
||||
static void process_input(int child_fd, int band)
|
||||
{
|
||||
char buf[16384];
|
||||
ssize_t sz = read(child_fd, buf, sizeof(buf));
|
||||
if (sz < 0) {
|
||||
if (errno != EINTR)
|
||||
error_clnt("read error: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
send_sideband(1, band, buf, sz, LARGE_PACKET_MAX);
|
||||
}
|
||||
|
||||
int cmd_upload_archive(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
pid_t writer;
|
||||
int fd1[2], fd2[2];
|
||||
/*
|
||||
* Set up sideband subprocess.
|
||||
*
|
||||
* We (parent) monitor and read from child, sending its fd#1 and fd#2
|
||||
* multiplexed out to our fd#1. If the child dies, we tell the other
|
||||
* end over channel #3.
|
||||
*/
|
||||
if (pipe(fd1) < 0 || pipe(fd2) < 0) {
|
||||
int err = errno;
|
||||
packet_write(1, "NACK pipe failed on the remote side\n");
|
||||
die("upload-archive: %s", strerror(err));
|
||||
}
|
||||
writer = fork();
|
||||
if (writer < 0) {
|
||||
int err = errno;
|
||||
packet_write(1, "NACK fork failed on the remote side\n");
|
||||
die("upload-archive: %s", strerror(err));
|
||||
}
|
||||
if (!writer) {
|
||||
/* child - connect fd#1 and fd#2 to the pipe */
|
||||
dup2(fd1[1], 1);
|
||||
dup2(fd2[1], 2);
|
||||
close(fd1[1]); close(fd2[1]);
|
||||
close(fd1[0]); close(fd2[0]); /* we do not read from pipe */
|
||||
|
||||
exit(run_upload_archive(argc, argv, prefix));
|
||||
}
|
||||
|
||||
/* parent - read from child, multiplex and send out to fd#1 */
|
||||
close(fd1[1]); close(fd2[1]); /* we do not write to pipe */
|
||||
packet_write(1, "ACK\n");
|
||||
packet_flush(1);
|
||||
|
||||
while (1) {
|
||||
struct pollfd pfd[2];
|
||||
int status;
|
||||
|
||||
pfd[0].fd = fd1[0];
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = fd2[0];
|
||||
pfd[1].events = POLLIN;
|
||||
if (poll(pfd, 2, -1) < 0) {
|
||||
if (errno != EINTR) {
|
||||
error("poll failed resuming: %s",
|
||||
strerror(errno));
|
||||
sleep(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (pfd[0].revents & POLLIN)
|
||||
/* Data stream ready */
|
||||
process_input(pfd[0].fd, 1);
|
||||
if (pfd[1].revents & POLLIN)
|
||||
/* Status stream ready */
|
||||
process_input(pfd[1].fd, 2);
|
||||
/* Always finish to read data when available */
|
||||
if ((pfd[0].revents | pfd[1].revents) & POLLIN)
|
||||
continue;
|
||||
|
||||
if (waitpid(writer, &status, 0) < 0)
|
||||
error_clnt("%s", lostchild);
|
||||
else if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
|
||||
error_clnt("%s", deadchild);
|
||||
packet_flush(1);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -8,10 +8,12 @@
|
||||
#include "tree.h"
|
||||
#include "quote.h"
|
||||
#include "builtin.h"
|
||||
#include "archive.h"
|
||||
|
||||
static const char zip_tree_usage[] =
|
||||
"git-zip-tree [-0|...|-9] <tree-ish> [ <base> ]";
|
||||
|
||||
static int verbose;
|
||||
static int zip_date;
|
||||
static int zip_time;
|
||||
|
||||
@ -163,6 +165,8 @@ static int write_zip_entry(const unsigned char *sha1,
|
||||
crc = crc32(0, Z_NULL, 0);
|
||||
|
||||
path = construct_path(base, baselen, filename, S_ISDIR(mode), &pathlen);
|
||||
if (verbose)
|
||||
fprintf(stderr, "%s\n", path);
|
||||
if (pathlen > 0xffff) {
|
||||
error("path too long (%d chars, SHA1: %s): %s", pathlen,
|
||||
sha1_to_hex(sha1), path);
|
||||
@ -351,3 +355,44 @@ int cmd_zip_tree(int argc, const char **argv, const char *prefix)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_zip_archive(struct archiver_args *args)
|
||||
{
|
||||
int plen = strlen(args->base);
|
||||
|
||||
dos_time(&args->time, &zip_date, &zip_time);
|
||||
|
||||
zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
|
||||
zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
|
||||
verbose = args->verbose;
|
||||
|
||||
if (args->base && plen > 0 && args->base[plen - 1] == '/') {
|
||||
char *base = xstrdup(args->base);
|
||||
int baselen = strlen(base);
|
||||
|
||||
while (baselen > 0 && base[baselen - 1] == '/')
|
||||
base[--baselen] = '\0';
|
||||
write_zip_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
|
||||
free(base);
|
||||
}
|
||||
read_tree_recursive(args->tree, args->base, plen, 0,
|
||||
args->pathspec, write_zip_entry);
|
||||
write_zip_trailer(args->commit_sha1);
|
||||
|
||||
free(zip_dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *parse_extra_zip_args(int argc, const char **argv)
|
||||
{
|
||||
for (; argc > 0; argc--, argv++) {
|
||||
const char *arg = argv[0];
|
||||
|
||||
if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0')
|
||||
zlib_compression_level = arg[1] - '0';
|
||||
else
|
||||
die("Unknown argument for zip format: %s", arg);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
|
||||
|
||||
extern int cmd_add(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_apply(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_archive(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
|
||||
@ -46,6 +47,7 @@ extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_rm(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_show(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
|
||||
@ -55,11 +57,13 @@ extern int cmd_zip_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_update_index(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_upload_archive(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_version(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_show_ref(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);
|
||||
|
||||
#endif
|
||||
|
8
cache.h
8
cache.h
@ -259,7 +259,7 @@ extern int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
|
||||
extern int write_sha1_to_fd(int fd, const unsigned char *sha1);
|
||||
extern int move_temp_to_file(const char *tmpfile, const char *filename);
|
||||
|
||||
extern int has_sha1_pack(const unsigned char *sha1);
|
||||
extern int has_sha1_pack(const unsigned char *sha1, const char **ignore);
|
||||
extern int has_sha1_file(const unsigned char *sha1);
|
||||
extern void *map_sha1_file(const unsigned char *sha1, unsigned long *);
|
||||
extern int legacy_loose_object(unsigned char *);
|
||||
@ -286,9 +286,9 @@ extern int get_sha1(const char *str, unsigned char *sha1);
|
||||
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
|
||||
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
||||
extern int read_ref(const char *filename, unsigned char *sha1);
|
||||
extern const char *resolve_ref(const char *path, unsigned char *sha1, int);
|
||||
extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
|
||||
extern int validate_symref(const char *git_HEAD);
|
||||
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
|
||||
extern int create_symref(const char *ref, const char *refs_heads_master);
|
||||
extern int validate_symref(const char *ref);
|
||||
|
||||
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
|
||||
extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
|
||||
|
176
color.c
Normal file
176
color.c
Normal file
@ -0,0 +1,176 @@
|
||||
#include "color.h"
|
||||
#include "cache.h"
|
||||
#include "git-compat-util.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define COLOR_RESET "\033[m"
|
||||
|
||||
static int parse_color(const char *name, int len)
|
||||
{
|
||||
static const char * const color_names[] = {
|
||||
"normal", "black", "red", "green", "yellow",
|
||||
"blue", "magenta", "cyan", "white"
|
||||
};
|
||||
char *end;
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(color_names); i++) {
|
||||
const char *str = color_names[i];
|
||||
if (!strncasecmp(name, str, len) && !str[len])
|
||||
return i - 1;
|
||||
}
|
||||
i = strtol(name, &end, 10);
|
||||
if (*name && !*end && i >= -1 && i <= 255)
|
||||
return i;
|
||||
return -2;
|
||||
}
|
||||
|
||||
static int parse_attr(const char *name, int len)
|
||||
{
|
||||
static const int attr_values[] = { 1, 2, 4, 5, 7 };
|
||||
static const char * const attr_names[] = {
|
||||
"bold", "dim", "ul", "blink", "reverse"
|
||||
};
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
|
||||
const char *str = attr_names[i];
|
||||
if (!strncasecmp(name, str, len) && !str[len])
|
||||
return attr_values[i];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void color_parse(const char *value, const char *var, char *dst)
|
||||
{
|
||||
const char *ptr = value;
|
||||
int attr = -1;
|
||||
int fg = -2;
|
||||
int bg = -2;
|
||||
|
||||
if (!strcasecmp(value, "reset")) {
|
||||
strcpy(dst, "\033[m");
|
||||
return;
|
||||
}
|
||||
|
||||
/* [fg [bg]] [attr] */
|
||||
while (*ptr) {
|
||||
const char *word = ptr;
|
||||
int val, len = 0;
|
||||
|
||||
while (word[len] && !isspace(word[len]))
|
||||
len++;
|
||||
|
||||
ptr = word + len;
|
||||
while (*ptr && isspace(*ptr))
|
||||
ptr++;
|
||||
|
||||
val = parse_color(word, len);
|
||||
if (val >= -1) {
|
||||
if (fg == -2) {
|
||||
fg = val;
|
||||
continue;
|
||||
}
|
||||
if (bg == -2) {
|
||||
bg = val;
|
||||
continue;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
val = parse_attr(word, len);
|
||||
if (val < 0 || attr != -1)
|
||||
goto bad;
|
||||
attr = val;
|
||||
}
|
||||
|
||||
if (attr >= 0 || fg >= 0 || bg >= 0) {
|
||||
int sep = 0;
|
||||
|
||||
*dst++ = '\033';
|
||||
*dst++ = '[';
|
||||
if (attr >= 0) {
|
||||
*dst++ = '0' + attr;
|
||||
sep++;
|
||||
}
|
||||
if (fg >= 0) {
|
||||
if (sep++)
|
||||
*dst++ = ';';
|
||||
if (fg < 8) {
|
||||
*dst++ = '3';
|
||||
*dst++ = '0' + fg;
|
||||
} else {
|
||||
dst += sprintf(dst, "38;5;%d", fg);
|
||||
}
|
||||
}
|
||||
if (bg >= 0) {
|
||||
if (sep++)
|
||||
*dst++ = ';';
|
||||
if (bg < 8) {
|
||||
*dst++ = '4';
|
||||
*dst++ = '0' + bg;
|
||||
} else {
|
||||
dst += sprintf(dst, "48;5;%d", bg);
|
||||
}
|
||||
}
|
||||
*dst++ = 'm';
|
||||
}
|
||||
*dst = 0;
|
||||
return;
|
||||
bad:
|
||||
die("bad config value '%s' for variable '%s'", value, var);
|
||||
}
|
||||
|
||||
int git_config_colorbool(const char *var, const char *value)
|
||||
{
|
||||
if (!value)
|
||||
return 1;
|
||||
if (!strcasecmp(value, "auto")) {
|
||||
if (isatty(1) || (pager_in_use && pager_use_color)) {
|
||||
char *term = getenv("TERM");
|
||||
if (term && strcmp(term, "dumb"))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (!strcasecmp(value, "never"))
|
||||
return 0;
|
||||
if (!strcasecmp(value, "always"))
|
||||
return 1;
|
||||
return git_config_bool(var, value);
|
||||
}
|
||||
|
||||
static int color_vprintf(const char *color, const char *fmt,
|
||||
va_list args, const char *trail)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (*color)
|
||||
r += printf("%s", color);
|
||||
r += vprintf(fmt, args);
|
||||
if (*color)
|
||||
r += printf("%s", COLOR_RESET);
|
||||
if (trail)
|
||||
r += printf("%s", trail);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int color_printf(const char *color, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int r;
|
||||
va_start(args, fmt);
|
||||
r = color_vprintf(color, fmt, args, NULL);
|
||||
va_end(args);
|
||||
return r;
|
||||
}
|
||||
|
||||
int color_printf_ln(const char *color, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int r;
|
||||
va_start(args, fmt);
|
||||
r = color_vprintf(color, fmt, args, "\n");
|
||||
va_end(args);
|
||||
return r;
|
||||
}
|
12
color.h
Normal file
12
color.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef COLOR_H
|
||||
#define COLOR_H
|
||||
|
||||
/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
|
||||
#define COLOR_MAXLEN 24
|
||||
|
||||
int git_config_colorbool(const char *var, const char *value);
|
||||
void color_parse(const char *var, const char *value, char *dst);
|
||||
int color_printf(const char *color, const char *fmt, ...);
|
||||
int color_printf_ln(const char *color, const char *fmt, ...);
|
||||
|
||||
#endif /* COLOR_H */
|
7
daemon.c
7
daemon.c
@ -325,7 +325,14 @@ static int upload_pack(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int upload_archive(void)
|
||||
{
|
||||
execl_git_cmd("upload-archive", ".", NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct daemon_service daemon_service[] = {
|
||||
{ "upload-archive", "uploadarch", upload_archive, 0, 1 },
|
||||
{ "upload-pack", "uploadpack", upload_pack, 1, 1 },
|
||||
};
|
||||
|
||||
|
@ -53,7 +53,7 @@ static void add_to_known_names(const char *path,
|
||||
names = ++idx;
|
||||
}
|
||||
|
||||
static int get_name(const char *path, const unsigned char *sha1)
|
||||
static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct commit *commit = lookup_commit_reference_gently(sha1, 1);
|
||||
struct object *object;
|
||||
@ -113,7 +113,7 @@ static void describe(const char *arg, int last_one)
|
||||
|
||||
if (!initialized) {
|
||||
initialized = 1;
|
||||
for_each_ref(get_name);
|
||||
for_each_ref(get_name, NULL);
|
||||
qsort(name_array, names, sizeof(*name_array), compare_names);
|
||||
}
|
||||
|
||||
|
139
diff.c
139
diff.c
@ -10,6 +10,7 @@
|
||||
#include "diffcore.h"
|
||||
#include "delta.h"
|
||||
#include "xdiff-interface.h"
|
||||
#include "color.h"
|
||||
|
||||
static int use_size_cache;
|
||||
|
||||
@ -17,8 +18,7 @@ static int diff_detect_rename_default;
|
||||
static int diff_rename_limit_default = -1;
|
||||
static int diff_use_color_default;
|
||||
|
||||
/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
|
||||
static char diff_colors[][24] = {
|
||||
static char diff_colors[][COLOR_MAXLEN] = {
|
||||
"\033[m", /* reset */
|
||||
"", /* normal */
|
||||
"\033[1m", /* bold */
|
||||
@ -45,119 +45,6 @@ static int parse_diff_color_slot(const char *var, int ofs)
|
||||
die("bad config variable '%s'", var);
|
||||
}
|
||||
|
||||
static int parse_color(const char *name, int len)
|
||||
{
|
||||
static const char * const color_names[] = {
|
||||
"normal", "black", "red", "green", "yellow",
|
||||
"blue", "magenta", "cyan", "white"
|
||||
};
|
||||
char *end;
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(color_names); i++) {
|
||||
const char *str = color_names[i];
|
||||
if (!strncasecmp(name, str, len) && !str[len])
|
||||
return i - 1;
|
||||
}
|
||||
i = strtol(name, &end, 10);
|
||||
if (*name && !*end && i >= -1 && i <= 255)
|
||||
return i;
|
||||
return -2;
|
||||
}
|
||||
|
||||
static int parse_attr(const char *name, int len)
|
||||
{
|
||||
static const int attr_values[] = { 1, 2, 4, 5, 7 };
|
||||
static const char * const attr_names[] = {
|
||||
"bold", "dim", "ul", "blink", "reverse"
|
||||
};
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
|
||||
const char *str = attr_names[i];
|
||||
if (!strncasecmp(name, str, len) && !str[len])
|
||||
return attr_values[i];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void parse_diff_color_value(const char *value, const char *var, char *dst)
|
||||
{
|
||||
const char *ptr = value;
|
||||
int attr = -1;
|
||||
int fg = -2;
|
||||
int bg = -2;
|
||||
|
||||
if (!strcasecmp(value, "reset")) {
|
||||
strcpy(dst, "\033[m");
|
||||
return;
|
||||
}
|
||||
|
||||
/* [fg [bg]] [attr] */
|
||||
while (*ptr) {
|
||||
const char *word = ptr;
|
||||
int val, len = 0;
|
||||
|
||||
while (word[len] && !isspace(word[len]))
|
||||
len++;
|
||||
|
||||
ptr = word + len;
|
||||
while (*ptr && isspace(*ptr))
|
||||
ptr++;
|
||||
|
||||
val = parse_color(word, len);
|
||||
if (val >= -1) {
|
||||
if (fg == -2) {
|
||||
fg = val;
|
||||
continue;
|
||||
}
|
||||
if (bg == -2) {
|
||||
bg = val;
|
||||
continue;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
val = parse_attr(word, len);
|
||||
if (val < 0 || attr != -1)
|
||||
goto bad;
|
||||
attr = val;
|
||||
}
|
||||
|
||||
if (attr >= 0 || fg >= 0 || bg >= 0) {
|
||||
int sep = 0;
|
||||
|
||||
*dst++ = '\033';
|
||||
*dst++ = '[';
|
||||
if (attr >= 0) {
|
||||
*dst++ = '0' + attr;
|
||||
sep++;
|
||||
}
|
||||
if (fg >= 0) {
|
||||
if (sep++)
|
||||
*dst++ = ';';
|
||||
if (fg < 8) {
|
||||
*dst++ = '3';
|
||||
*dst++ = '0' + fg;
|
||||
} else {
|
||||
dst += sprintf(dst, "38;5;%d", fg);
|
||||
}
|
||||
}
|
||||
if (bg >= 0) {
|
||||
if (sep++)
|
||||
*dst++ = ';';
|
||||
if (bg < 8) {
|
||||
*dst++ = '4';
|
||||
*dst++ = '0' + bg;
|
||||
} else {
|
||||
dst += sprintf(dst, "48;5;%d", bg);
|
||||
}
|
||||
}
|
||||
*dst++ = 'm';
|
||||
}
|
||||
*dst = 0;
|
||||
return;
|
||||
bad:
|
||||
die("bad config value '%s' for variable '%s'", value, var);
|
||||
}
|
||||
|
||||
/*
|
||||
* These are to give UI layer defaults.
|
||||
* The core-level commands such as git-diff-files should
|
||||
@ -171,22 +58,7 @@ int git_diff_ui_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "diff.color")) {
|
||||
if (!value)
|
||||
diff_use_color_default = 1; /* bool */
|
||||
else if (!strcasecmp(value, "auto")) {
|
||||
diff_use_color_default = 0;
|
||||
if (isatty(1) || (pager_in_use && pager_use_color)) {
|
||||
char *term = getenv("TERM");
|
||||
if (term && strcmp(term, "dumb"))
|
||||
diff_use_color_default = 1;
|
||||
}
|
||||
}
|
||||
else if (!strcasecmp(value, "never"))
|
||||
diff_use_color_default = 0;
|
||||
else if (!strcasecmp(value, "always"))
|
||||
diff_use_color_default = 1;
|
||||
else
|
||||
diff_use_color_default = git_config_bool(var, value);
|
||||
diff_use_color_default = git_config_colorbool(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "diff.renames")) {
|
||||
@ -201,7 +73,7 @@ int git_diff_ui_config(const char *var, const char *value)
|
||||
}
|
||||
if (!strncmp(var, "diff.color.", 11)) {
|
||||
int slot = parse_diff_color_slot(var, 11);
|
||||
parse_diff_color_value(value, var, diff_colors[slot]);
|
||||
color_parse(value, var, diff_colors[slot]);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
@ -2593,6 +2465,9 @@ void diff_flush(struct diff_options *options)
|
||||
}
|
||||
}
|
||||
|
||||
if (output_format & DIFF_FORMAT_CALLBACK)
|
||||
options->format_callback(q, options, options->format_callback_data);
|
||||
|
||||
for (i = 0; i < q->nr; i++)
|
||||
diff_free_filepair(q->queue[i]);
|
||||
free_queue:
|
||||
|
8
diff.h
8
diff.h
@ -8,6 +8,7 @@
|
||||
|
||||
struct rev_info;
|
||||
struct diff_options;
|
||||
struct diff_queue_struct;
|
||||
|
||||
typedef void (*change_fn_t)(struct diff_options *options,
|
||||
unsigned old_mode, unsigned new_mode,
|
||||
@ -20,6 +21,9 @@ typedef void (*add_remove_fn_t)(struct diff_options *options,
|
||||
const unsigned char *sha1,
|
||||
const char *base, const char *path);
|
||||
|
||||
typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
|
||||
struct diff_options *options, void *data);
|
||||
|
||||
#define DIFF_FORMAT_RAW 0x0001
|
||||
#define DIFF_FORMAT_DIFFSTAT 0x0002
|
||||
#define DIFF_FORMAT_SUMMARY 0x0004
|
||||
@ -35,6 +39,8 @@ typedef void (*add_remove_fn_t)(struct diff_options *options,
|
||||
*/
|
||||
#define DIFF_FORMAT_NO_OUTPUT 0x0080
|
||||
|
||||
#define DIFF_FORMAT_CALLBACK 0x0100
|
||||
|
||||
struct diff_options {
|
||||
const char *filter;
|
||||
const char *orderfile;
|
||||
@ -68,6 +74,8 @@ struct diff_options {
|
||||
int *pathlens;
|
||||
change_fn_t change;
|
||||
add_remove_fn_t add_remove;
|
||||
diff_format_fn_t format_callback;
|
||||
void *format_callback_data;
|
||||
};
|
||||
|
||||
enum color_diff {
|
||||
|
7
dir.c
7
dir.c
@ -397,3 +397,10 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
|
||||
qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
|
||||
return dir->nr;
|
||||
}
|
||||
|
||||
int
|
||||
file_exists(const char *f)
|
||||
{
|
||||
struct stat sb;
|
||||
return stat(f, &sb) == 0;
|
||||
}
|
||||
|
1
dir.h
1
dir.h
@ -47,5 +47,6 @@ extern int excluded(struct dir_struct *, const char *);
|
||||
extern void add_excludes_from_file(struct dir_struct *, const char *fname);
|
||||
extern void add_exclude(const char *string, const char *base,
|
||||
int baselen, struct exclude_list *which);
|
||||
extern int file_exists(const char *);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "cache.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
@ -114,36 +115,13 @@ static pid_t setup_sideband(int sideband, const char *me, int fd[2], int xd[2])
|
||||
die("%s: unable to fork off sideband demultiplexer", me);
|
||||
if (!side_pid) {
|
||||
/* subprocess */
|
||||
char buf[LARGE_PACKET_MAX];
|
||||
|
||||
close(fd[0]);
|
||||
if (xd[0] != xd[1])
|
||||
close(xd[1]);
|
||||
while (1) {
|
||||
char buf[1024];
|
||||
int len = packet_read_line(xd[0], buf, sizeof(buf));
|
||||
if (len == 0)
|
||||
break;
|
||||
if (len < 1)
|
||||
die("%s: protocol error: no band designator",
|
||||
me);
|
||||
len--;
|
||||
switch (buf[0] & 0xFF) {
|
||||
case 3:
|
||||
safe_write(2, "remote: ", 8);
|
||||
safe_write(2, buf+1, len);
|
||||
safe_write(2, "\n", 1);
|
||||
if (recv_sideband(me, xd[0], fd[1], 2, buf, sizeof(buf)))
|
||||
exit(1);
|
||||
case 2:
|
||||
safe_write(2, "remote: ", 8);
|
||||
safe_write(2, buf+1, len);
|
||||
continue;
|
||||
case 1:
|
||||
safe_write(fd[1], buf+1, len);
|
||||
continue;
|
||||
default:
|
||||
die("%s: protocol error: bad band #%d",
|
||||
me, (buf[0] & 0xFF));
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
close(xd[0]);
|
||||
|
20
fetch-pack.c
20
fetch-pack.c
@ -42,7 +42,7 @@ static void rev_list_push(struct commit *commit, int mark)
|
||||
}
|
||||
}
|
||||
|
||||
static int rev_list_insert_ref(const char *path, const unsigned char *sha1)
|
||||
static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct object *o = deref_tag(parse_object(sha1), path, 0);
|
||||
|
||||
@ -143,7 +143,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
|
||||
unsigned in_vain = 0;
|
||||
int got_continue = 0;
|
||||
|
||||
for_each_ref(rev_list_insert_ref);
|
||||
for_each_ref(rev_list_insert_ref, NULL);
|
||||
|
||||
fetching = 0;
|
||||
for ( ; refs ; refs = refs->next) {
|
||||
@ -166,10 +166,11 @@ static int find_common(int fd[2], unsigned char *result_sha1,
|
||||
}
|
||||
|
||||
if (!fetching)
|
||||
packet_write(fd[1], "want %s%s%s%s\n",
|
||||
packet_write(fd[1], "want %s%s%s%s%s\n",
|
||||
sha1_to_hex(remote),
|
||||
(multi_ack ? " multi_ack" : ""),
|
||||
(use_sideband ? " side-band" : ""),
|
||||
(use_sideband == 2 ? " side-band-64k" : ""),
|
||||
(use_sideband == 1 ? " side-band" : ""),
|
||||
(use_thin_pack ? " thin-pack" : ""));
|
||||
else
|
||||
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
|
||||
@ -252,7 +253,7 @@ done:
|
||||
|
||||
static struct commit_list *complete;
|
||||
|
||||
static int mark_complete(const char *path, const unsigned char *sha1)
|
||||
static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct object *o = parse_object(sha1);
|
||||
|
||||
@ -364,7 +365,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
|
||||
}
|
||||
}
|
||||
|
||||
for_each_ref(mark_complete);
|
||||
for_each_ref(mark_complete, NULL);
|
||||
if (cutoff)
|
||||
mark_recent_complete_commits(cutoff);
|
||||
|
||||
@ -426,7 +427,12 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
|
||||
fprintf(stderr, "Server supports multi_ack\n");
|
||||
multi_ack = 1;
|
||||
}
|
||||
if (server_supports("side-band")) {
|
||||
if (server_supports("side-band-64k")) {
|
||||
if (verbose)
|
||||
fprintf(stderr, "Server supports side-band-64k\n");
|
||||
use_sideband = 2;
|
||||
}
|
||||
else if (server_supports("side-band")) {
|
||||
if (verbose)
|
||||
fprintf(stderr, "Server supports side-band\n");
|
||||
use_sideband = 1;
|
||||
|
4
fetch.c
4
fetch.c
@ -201,7 +201,7 @@ static int interpret_target(char *target, unsigned char *sha1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mark_complete(const char *path, const unsigned char *sha1)
|
||||
static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct commit *commit = lookup_commit_reference_gently(sha1, 1);
|
||||
if (commit) {
|
||||
@ -274,7 +274,7 @@ int pull(int targets, char **target, const char **write_ref,
|
||||
}
|
||||
|
||||
if (!get_recover)
|
||||
for_each_ref(mark_complete);
|
||||
for_each_ref(mark_complete, NULL);
|
||||
|
||||
for (i = 0; i < targets; i++) {
|
||||
if (interpret_target(target[i], &sha1[20 * i])) {
|
||||
|
@ -402,7 +402,7 @@ static void fsck_dir(int i, char *path)
|
||||
|
||||
static int default_refs;
|
||||
|
||||
static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
|
||||
static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct object *obj;
|
||||
|
||||
@ -424,7 +424,7 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
|
||||
|
||||
static void get_default_heads(void)
|
||||
{
|
||||
for_each_ref(fsck_handle_ref);
|
||||
for_each_ref(fsck_handle_ref, NULL);
|
||||
|
||||
/*
|
||||
* Not having any default heads isn't really fatal, but
|
||||
@ -458,15 +458,14 @@ static void fsck_object_dir(const char *path)
|
||||
static int fsck_head_link(void)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
const char *git_HEAD = xstrdup(git_path("HEAD"));
|
||||
const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 1);
|
||||
int pfxlen = strlen(git_HEAD) - 4; /* strip .../.git/ part */
|
||||
int flag;
|
||||
const char *head_points_at = resolve_ref("HEAD", sha1, 1, &flag);
|
||||
|
||||
if (!git_refs_heads_master)
|
||||
if (!head_points_at || !(flag & REF_ISSYMREF))
|
||||
return error("HEAD is not a symbolic ref");
|
||||
if (strncmp(git_refs_heads_master + pfxlen, "refs/heads/", 11))
|
||||
if (strncmp(head_points_at, "refs/heads/", 11))
|
||||
return error("HEAD points to something strange (%s)",
|
||||
git_refs_heads_master + pfxlen);
|
||||
head_points_at);
|
||||
if (is_null_sha1(sha1))
|
||||
return error("HEAD: not a valid git pointer");
|
||||
return 0;
|
||||
|
@ -12,6 +12,7 @@ struct cmdname_help common_cmds[] = {"
|
||||
sort <<\EOF |
|
||||
add
|
||||
apply
|
||||
archive
|
||||
bisect
|
||||
branch
|
||||
checkout
|
||||
|
21
git-am.sh
21
git-am.sh
@ -166,10 +166,25 @@ fi
|
||||
|
||||
if test -d "$dotest"
|
||||
then
|
||||
if test ",$#," != ",0," || ! tty -s
|
||||
then
|
||||
case "$#,$skip$resolved" in
|
||||
0,*t*)
|
||||
# Explicit resume command and we do not have file, so
|
||||
# we are happy.
|
||||
: ;;
|
||||
0,)
|
||||
# No file input but without resume parameters; catch
|
||||
# user error to feed us a patch from standard input
|
||||
# when there is already .dotest. This is somewhat
|
||||
# unreliable -- stdin could be /dev/null for example
|
||||
# and the caller did not intend to feed us a patch but
|
||||
# wanted to continue unattended.
|
||||
tty -s
|
||||
;;
|
||||
*)
|
||||
false
|
||||
;;
|
||||
esac ||
|
||||
die "previous dotest directory $dotest still exists but mbox given."
|
||||
fi
|
||||
resume=yes
|
||||
else
|
||||
# Make sure we are not given --skip nor --resolved
|
||||
|
105
git-commit.sh
105
git-commit.sh
@ -60,26 +60,6 @@ report () {
|
||||
}
|
||||
|
||||
run_status () {
|
||||
(
|
||||
# We always show status for the whole tree.
|
||||
cd "$TOP"
|
||||
|
||||
IS_INITIAL="$initial_commit"
|
||||
REFERENCE=HEAD
|
||||
case "$amend" in
|
||||
t)
|
||||
# If we are amending the initial commit, there
|
||||
# is no HEAD^1.
|
||||
if git-rev-parse --verify "HEAD^1" >/dev/null 2>&1
|
||||
then
|
||||
REFERENCE="HEAD^1"
|
||||
IS_INITIAL=
|
||||
else
|
||||
IS_INITIAL=t
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# If TMP_INDEX is defined, that means we are doing
|
||||
# "--only" partial commit, and that index file is used
|
||||
# to build the tree for the commit. Otherwise, if
|
||||
@ -96,85 +76,14 @@ run_status () {
|
||||
export GIT_INDEX_FILE
|
||||
fi
|
||||
|
||||
case "$branch" in
|
||||
refs/heads/master) ;;
|
||||
*) echo "# On branch $branch" ;;
|
||||
case "$status_only" in
|
||||
t) color= ;;
|
||||
*) color=--nocolor ;;
|
||||
esac
|
||||
|
||||
if test -z "$IS_INITIAL"
|
||||
then
|
||||
git-diff-index -M --cached --name-status \
|
||||
--diff-filter=MDTCRA $REFERENCE |
|
||||
sed -e '
|
||||
s/\\/\\\\/g
|
||||
s/ /\\ /g
|
||||
' |
|
||||
report "Updated but not checked in" "will commit"
|
||||
committable="$?"
|
||||
else
|
||||
echo '#
|
||||
# Initial commit
|
||||
#'
|
||||
git-ls-files |
|
||||
sed -e '
|
||||
s/\\/\\\\/g
|
||||
s/ /\\ /g
|
||||
s/^/A /
|
||||
' |
|
||||
report "Updated but not checked in" "will commit"
|
||||
|
||||
committable="$?"
|
||||
fi
|
||||
|
||||
git-diff-files --name-status |
|
||||
sed -e '
|
||||
s/\\/\\\\/g
|
||||
s/ /\\ /g
|
||||
' |
|
||||
report "Changed but not updated" \
|
||||
"use git-update-index to mark for commit"
|
||||
|
||||
option=""
|
||||
if test -z "$untracked_files"; then
|
||||
option="--directory --no-empty-directory"
|
||||
fi
|
||||
hdr_shown=
|
||||
if test -f "$GIT_DIR/info/exclude"
|
||||
then
|
||||
git-ls-files --others $option \
|
||||
--exclude-from="$GIT_DIR/info/exclude" \
|
||||
--exclude-per-directory=.gitignore
|
||||
else
|
||||
git-ls-files --others $option \
|
||||
--exclude-per-directory=.gitignore
|
||||
fi |
|
||||
while read line; do
|
||||
if [ -z "$hdr_shown" ]; then
|
||||
echo '#'
|
||||
echo '# Untracked files:'
|
||||
echo '# (use "git add" to add to commit)'
|
||||
echo '#'
|
||||
hdr_shown=1
|
||||
fi
|
||||
echo "# $line"
|
||||
done
|
||||
|
||||
if test -n "$verbose" -a -z "$IS_INITIAL"
|
||||
then
|
||||
git-diff-index --cached -M -p --diff-filter=MDTCRA $REFERENCE
|
||||
fi
|
||||
case "$committable" in
|
||||
0)
|
||||
case "$amend" in
|
||||
t)
|
||||
echo "# No changes" ;;
|
||||
*)
|
||||
echo "nothing to commit" ;;
|
||||
esac
|
||||
exit 1 ;;
|
||||
esac
|
||||
exit 0
|
||||
)
|
||||
git-runstatus ${color} \
|
||||
${verbose:+--verbose} \
|
||||
${amend:+--amend} \
|
||||
${untracked_files:+--untracked}
|
||||
}
|
||||
|
||||
trap '
|
||||
|
4
git.c
4
git.c
@ -220,6 +220,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||
} commands[] = {
|
||||
{ "add", cmd_add, RUN_SETUP },
|
||||
{ "apply", cmd_apply },
|
||||
{ "archive", cmd_archive },
|
||||
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
||||
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
||||
{ "check-ref-format", cmd_check_ref_format },
|
||||
@ -252,6 +253,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||
{ "rev-list", cmd_rev_list, RUN_SETUP },
|
||||
{ "rev-parse", cmd_rev_parse, RUN_SETUP },
|
||||
{ "rm", cmd_rm, RUN_SETUP },
|
||||
{ "runstatus", cmd_runstatus, RUN_SETUP },
|
||||
{ "show-branch", cmd_show_branch, RUN_SETUP },
|
||||
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
|
||||
{ "stripspace", cmd_stripspace },
|
||||
@ -261,12 +263,14 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||
{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
|
||||
{ "update-index", cmd_update_index, RUN_SETUP },
|
||||
{ "update-ref", cmd_update_ref, RUN_SETUP },
|
||||
{ "upload-archive", cmd_upload_archive },
|
||||
{ "upload-tar", cmd_upload_tar },
|
||||
{ "version", cmd_version },
|
||||
{ "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
|
||||
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
||||
{ "verify-pack", cmd_verify_pack },
|
||||
{ "show-ref", cmd_show_ref, RUN_SETUP },
|
||||
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
|
||||
};
|
||||
int i;
|
||||
|
||||
|
@ -54,6 +54,13 @@ our $favicon = "++GITWEB_FAVICON++";
|
||||
# source of projects list
|
||||
our $projects_list = "++GITWEB_LIST++";
|
||||
|
||||
# show repository only if this file exists
|
||||
# (only effective if this variable evaluates to true)
|
||||
our $export_ok = "++GITWEB_EXPORT_OK++";
|
||||
|
||||
# only allow viewing of repositories also shown on the overview page
|
||||
our $strict_export = "++GITWEB_STRICT_EXPORT++";
|
||||
|
||||
# list of git base URLs used for URL to where fetch project from,
|
||||
# i.e. full URL is "$git_base_url/$project"
|
||||
our @git_base_url_list = ("++GITWEB_BASE_URL++");
|
||||
@ -182,9 +189,6 @@ do $GITWEB_CONFIG if -e $GITWEB_CONFIG;
|
||||
# version of the core git binary
|
||||
our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
|
||||
|
||||
# path to the current git repository
|
||||
our $git_dir;
|
||||
|
||||
$projects_list ||= $projectroot;
|
||||
|
||||
# ======================================================================
|
||||
@ -196,23 +200,16 @@ if (defined $action) {
|
||||
}
|
||||
}
|
||||
|
||||
our $project = ($cgi->param('p') || $ENV{'PATH_INFO'});
|
||||
our $project = $cgi->param('p');
|
||||
if (defined $project) {
|
||||
$project =~ s|^/||;
|
||||
$project =~ s|/$||;
|
||||
$project = undef unless $project;
|
||||
}
|
||||
if (defined $project) {
|
||||
if (!validate_input($project)) {
|
||||
die_error(undef, "Invalid project parameter");
|
||||
}
|
||||
if (!(-d "$projectroot/$project")) {
|
||||
die_error(undef, "No such directory");
|
||||
}
|
||||
if (!(-e "$projectroot/$project/HEAD")) {
|
||||
if (!validate_input($project) ||
|
||||
!(-d "$projectroot/$project") ||
|
||||
!(-e "$projectroot/$project/HEAD") ||
|
||||
($export_ok && !(-e "$projectroot/$project/$export_ok")) ||
|
||||
($strict_export && !project_in_list($project))) {
|
||||
undef $project;
|
||||
die_error(undef, "No such project");
|
||||
}
|
||||
$git_dir = "$projectroot/$project";
|
||||
}
|
||||
|
||||
our $file_name = $cgi->param('f');
|
||||
@ -259,7 +256,7 @@ if (defined $hash_parent_base) {
|
||||
|
||||
our $page = $cgi->param('pg');
|
||||
if (defined $page) {
|
||||
if ($page =~ m/[^0-9]$/) {
|
||||
if ($page =~ m/[^0-9]/) {
|
||||
die_error(undef, "Invalid page parameter");
|
||||
}
|
||||
}
|
||||
@ -272,6 +269,43 @@ if (defined $searchtext) {
|
||||
$searchtext = quotemeta $searchtext;
|
||||
}
|
||||
|
||||
# now read PATH_INFO and use it as alternative to parameters
|
||||
sub evaluate_path_info {
|
||||
return if defined $project;
|
||||
my $path_info = $ENV{"PATH_INFO"};
|
||||
return if !$path_info;
|
||||
$path_info =~ s,(^/|/$),,gs;
|
||||
$path_info = validate_input($path_info);
|
||||
return if !$path_info;
|
||||
$project = $path_info;
|
||||
while ($project && !-e "$projectroot/$project/HEAD") {
|
||||
$project =~ s,/*[^/]*$,,;
|
||||
}
|
||||
if (!$project ||
|
||||
($export_ok && !-e "$projectroot/$project/$export_ok") ||
|
||||
($strict_export && !project_in_list($project))) {
|
||||
undef $project;
|
||||
return;
|
||||
}
|
||||
# do not change any parameters if an action is given using the query string
|
||||
return if $action;
|
||||
if ($path_info =~ m,^$project/([^/]+)/(.+)$,) {
|
||||
# we got "project.git/branch/filename"
|
||||
$action ||= "blob_plain";
|
||||
$hash_base ||= validate_input($1);
|
||||
$file_name ||= validate_input($2);
|
||||
} elsif ($path_info =~ m,^$project/([^/]+)$,) {
|
||||
# we got "project.git/branch"
|
||||
$action ||= "shortlog";
|
||||
$hash ||= validate_input($1);
|
||||
}
|
||||
}
|
||||
evaluate_path_info();
|
||||
|
||||
# path to the current git repository
|
||||
our $git_dir;
|
||||
$git_dir = "$projectroot/$project" if $project;
|
||||
|
||||
# dispatch
|
||||
my %actions = (
|
||||
"blame" => \&git_blame2,
|
||||
@ -405,6 +439,12 @@ sub untabify {
|
||||
return $line;
|
||||
}
|
||||
|
||||
sub project_in_list {
|
||||
my $project = shift;
|
||||
my @list = git_get_projects_list();
|
||||
return @list && scalar(grep { $_->{'path'} eq $project } @list);
|
||||
}
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
## HTML aware string manipulation
|
||||
|
||||
@ -717,7 +757,8 @@ sub git_get_projects_list {
|
||||
|
||||
my $subdir = substr($File::Find::name, $pfxlen + 1);
|
||||
# we check related file in $projectroot
|
||||
if (-e "$projectroot/$subdir/HEAD") {
|
||||
if (-e "$projectroot/$subdir/HEAD" && (!$export_ok ||
|
||||
-e "$projectroot/$subdir/$export_ok")) {
|
||||
push @list, { path => $subdir };
|
||||
$File::Find::prune = 1;
|
||||
}
|
||||
@ -738,7 +779,8 @@ sub git_get_projects_list {
|
||||
if (!defined $path) {
|
||||
next;
|
||||
}
|
||||
if (-e "$projectroot/$path/HEAD") {
|
||||
if (-e "$projectroot/$path/HEAD" && (!$export_ok ||
|
||||
-e "$projectroot/$path/$export_ok")) {
|
||||
my $pr = {
|
||||
path => $path,
|
||||
owner => decode("utf8", $owner, Encode::FB_DEFAULT),
|
||||
@ -2527,11 +2569,7 @@ sub git_heads {
|
||||
}
|
||||
|
||||
sub git_blob_plain {
|
||||
# blobs defined by non-textual hash id's can be cached
|
||||
my $expires;
|
||||
if ($hash =~ m/^[0-9a-fA-F]{40}$/) {
|
||||
$expires = "+1d";
|
||||
}
|
||||
|
||||
if (!defined $hash) {
|
||||
if (defined $file_name) {
|
||||
@ -2541,7 +2579,11 @@ sub git_blob_plain {
|
||||
} else {
|
||||
die_error(undef, "No file name defined");
|
||||
}
|
||||
} elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) {
|
||||
# blobs defined by non-textual hash id's can be cached
|
||||
$expires = "+1d";
|
||||
}
|
||||
|
||||
my $type = shift;
|
||||
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
|
||||
or die_error(undef, "Couldn't cat $file_name, $hash");
|
||||
@ -2569,11 +2611,7 @@ sub git_blob_plain {
|
||||
}
|
||||
|
||||
sub git_blob {
|
||||
# blobs defined by non-textual hash id's can be cached
|
||||
my $expires;
|
||||
if ($hash =~ m/^[0-9a-fA-F]{40}$/) {
|
||||
$expires = "+1d";
|
||||
}
|
||||
|
||||
if (!defined $hash) {
|
||||
if (defined $file_name) {
|
||||
@ -2583,7 +2621,11 @@ sub git_blob {
|
||||
} else {
|
||||
die_error(undef, "No file name defined");
|
||||
}
|
||||
} elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) {
|
||||
# blobs defined by non-textual hash id's can be cached
|
||||
$expires = "+1d";
|
||||
}
|
||||
|
||||
my ($have_blame) = gitweb_check_feature('blame');
|
||||
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
|
||||
or die_error(undef, "Couldn't cat $file_name, $hash");
|
||||
|
25
http-fetch.c
25
http-fetch.c
@ -144,6 +144,19 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
|
||||
return size;
|
||||
}
|
||||
|
||||
static int missing__target(int code, int result)
|
||||
{
|
||||
return /* file:// URL -- do we ever use one??? */
|
||||
(result == CURLE_FILE_COULDNT_READ_FILE) ||
|
||||
/* http:// and https:// URL */
|
||||
(code == 404 && result == CURLE_HTTP_RETURNED_ERROR) ||
|
||||
/* ftp:// URL */
|
||||
(code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE)
|
||||
;
|
||||
}
|
||||
|
||||
#define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
|
||||
|
||||
static void fetch_alternates(const char *base);
|
||||
|
||||
static void process_object_response(void *callback_data);
|
||||
@ -323,8 +336,7 @@ static void process_object_response(void *callback_data)
|
||||
obj_req->state = COMPLETE;
|
||||
|
||||
/* Use alternates if necessary */
|
||||
if (obj_req->http_code == 404 ||
|
||||
obj_req->curl_result == CURLE_FILE_COULDNT_READ_FILE) {
|
||||
if (missing_target(obj_req)) {
|
||||
fetch_alternates(alt->base);
|
||||
if (obj_req->repo->next != NULL) {
|
||||
obj_req->repo =
|
||||
@ -537,8 +549,7 @@ static void process_alternates_response(void *callback_data)
|
||||
return;
|
||||
}
|
||||
} else if (slot->curl_result != CURLE_OK) {
|
||||
if (slot->http_code != 404 &&
|
||||
slot->curl_result != CURLE_FILE_COULDNT_READ_FILE) {
|
||||
if (!missing_target(slot)) {
|
||||
got_alternates = -1;
|
||||
return;
|
||||
}
|
||||
@ -941,8 +952,7 @@ static int fetch_indices(struct alt_base *repo)
|
||||
if (start_active_slot(slot)) {
|
||||
run_active_slot(slot);
|
||||
if (results.curl_result != CURLE_OK) {
|
||||
if (results.http_code == 404 ||
|
||||
results.curl_result == CURLE_FILE_COULDNT_READ_FILE) {
|
||||
if (missing_target(&results)) {
|
||||
repo->got_indices = 1;
|
||||
free(buffer.buffer);
|
||||
return 0;
|
||||
@ -1123,8 +1133,7 @@ static int fetch_object(struct alt_base *repo, unsigned char *sha1)
|
||||
ret = error("Request for %s aborted", hex);
|
||||
} else if (obj_req->curl_result != CURLE_OK &&
|
||||
obj_req->http_code != 416) {
|
||||
if (obj_req->http_code == 404 ||
|
||||
obj_req->curl_result == CURLE_FILE_COULDNT_READ_FILE)
|
||||
if (missing_target(obj_req))
|
||||
ret = -1; /* Be silent, it is probably in a pack. */
|
||||
else
|
||||
ret = error("%s (curl_result = %d, http_code = %ld, sha1 = %s)",
|
||||
|
@ -1864,7 +1864,7 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
|
||||
static struct ref *local_refs, **local_tail;
|
||||
static struct ref *remote_refs, **remote_tail;
|
||||
|
||||
static int one_local_ref(const char *refname, const unsigned char *sha1)
|
||||
static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct ref *ref;
|
||||
int len = strlen(refname) + 1;
|
||||
@ -1913,7 +1913,7 @@ static void one_remote_ref(char *refname)
|
||||
static void get_local_heads(void)
|
||||
{
|
||||
local_tail = &local_refs;
|
||||
for_each_ref(one_local_ref);
|
||||
for_each_ref(one_local_ref, NULL);
|
||||
}
|
||||
|
||||
static void get_dav_remote_heads(void)
|
||||
|
140
list-objects.c
Normal file
140
list-objects.c
Normal file
@ -0,0 +1,140 @@
|
||||
#include "cache.h"
|
||||
#include "tag.h"
|
||||
#include "commit.h"
|
||||
#include "tree.h"
|
||||
#include "blob.h"
|
||||
#include "diff.h"
|
||||
#include "tree-walk.h"
|
||||
#include "revision.h"
|
||||
#include "list-objects.h"
|
||||
|
||||
static void process_blob(struct rev_info *revs,
|
||||
struct blob *blob,
|
||||
struct object_array *p,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
{
|
||||
struct object *obj = &blob->object;
|
||||
|
||||
if (!revs->blob_objects)
|
||||
return;
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
return;
|
||||
obj->flags |= SEEN;
|
||||
name = xstrdup(name);
|
||||
add_object(obj, p, path, name);
|
||||
}
|
||||
|
||||
static void process_tree(struct rev_info *revs,
|
||||
struct tree *tree,
|
||||
struct object_array *p,
|
||||
struct name_path *path,
|
||||
const char *name)
|
||||
{
|
||||
struct object *obj = &tree->object;
|
||||
struct tree_desc desc;
|
||||
struct name_entry entry;
|
||||
struct name_path me;
|
||||
|
||||
if (!revs->tree_objects)
|
||||
return;
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
return;
|
||||
if (parse_tree(tree) < 0)
|
||||
die("bad tree object %s", sha1_to_hex(obj->sha1));
|
||||
obj->flags |= SEEN;
|
||||
name = xstrdup(name);
|
||||
add_object(obj, p, path, name);
|
||||
me.up = path;
|
||||
me.elem = name;
|
||||
me.elem_len = strlen(name);
|
||||
|
||||
desc.buf = tree->buffer;
|
||||
desc.size = tree->size;
|
||||
|
||||
while (tree_entry(&desc, &entry)) {
|
||||
if (S_ISDIR(entry.mode))
|
||||
process_tree(revs,
|
||||
lookup_tree(entry.sha1),
|
||||
p, &me, entry.path);
|
||||
else
|
||||
process_blob(revs,
|
||||
lookup_blob(entry.sha1),
|
||||
p, &me, entry.path);
|
||||
}
|
||||
free(tree->buffer);
|
||||
tree->buffer = NULL;
|
||||
}
|
||||
|
||||
static void mark_edge_parents_uninteresting(struct commit *commit,
|
||||
struct rev_info *revs,
|
||||
show_edge_fn show_edge)
|
||||
{
|
||||
struct commit_list *parents;
|
||||
|
||||
for (parents = commit->parents; parents; parents = parents->next) {
|
||||
struct commit *parent = parents->item;
|
||||
if (!(parent->object.flags & UNINTERESTING))
|
||||
continue;
|
||||
mark_tree_uninteresting(parent->tree);
|
||||
if (revs->edge_hint && !(parent->object.flags & SHOWN)) {
|
||||
parent->object.flags |= SHOWN;
|
||||
show_edge(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mark_edges_uninteresting(struct commit_list *list,
|
||||
struct rev_info *revs,
|
||||
show_edge_fn show_edge)
|
||||
{
|
||||
for ( ; list; list = list->next) {
|
||||
struct commit *commit = list->item;
|
||||
|
||||
if (commit->object.flags & UNINTERESTING) {
|
||||
mark_tree_uninteresting(commit->tree);
|
||||
continue;
|
||||
}
|
||||
mark_edge_parents_uninteresting(commit, revs, show_edge);
|
||||
}
|
||||
}
|
||||
|
||||
void traverse_commit_list(struct rev_info *revs,
|
||||
void (*show_commit)(struct commit *),
|
||||
void (*show_object)(struct object_array_entry *))
|
||||
{
|
||||
int i;
|
||||
struct commit *commit;
|
||||
struct object_array objects = { 0, 0, NULL };
|
||||
|
||||
while ((commit = get_revision(revs)) != NULL) {
|
||||
process_tree(revs, commit->tree, &objects, NULL, "");
|
||||
show_commit(commit);
|
||||
}
|
||||
for (i = 0; i < revs->pending.nr; i++) {
|
||||
struct object_array_entry *pending = revs->pending.objects + i;
|
||||
struct object *obj = pending->item;
|
||||
const char *name = pending->name;
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
continue;
|
||||
if (obj->type == OBJ_TAG) {
|
||||
obj->flags |= SEEN;
|
||||
add_object_array(obj, name, &objects);
|
||||
continue;
|
||||
}
|
||||
if (obj->type == OBJ_TREE) {
|
||||
process_tree(revs, (struct tree *)obj, &objects,
|
||||
NULL, name);
|
||||
continue;
|
||||
}
|
||||
if (obj->type == OBJ_BLOB) {
|
||||
process_blob(revs, (struct blob *)obj, &objects,
|
||||
NULL, name);
|
||||
continue;
|
||||
}
|
||||
die("unknown pending object %s (%s)",
|
||||
sha1_to_hex(obj->sha1), name);
|
||||
}
|
||||
for (i = 0; i < objects.nr; i++)
|
||||
show_object(&objects.objects[i]);
|
||||
}
|
12
list-objects.h
Normal file
12
list-objects.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef LIST_OBJECTS_H
|
||||
#define LIST_OBJECTS_H
|
||||
|
||||
typedef void (*show_commit_fn)(struct commit *);
|
||||
typedef void (*show_object_fn)(struct object_array_entry *);
|
||||
typedef void (*show_edge_fn)(struct commit *);
|
||||
|
||||
void traverse_commit_list(struct rev_info *revs, show_commit_fn, show_object_fn);
|
||||
|
||||
void mark_edges_uninteresting(struct commit_list *, struct rev_info *, show_edge_fn);
|
||||
|
||||
#endif
|
@ -12,7 +12,7 @@ static int report_status;
|
||||
static char capabilities[] = "report-status";
|
||||
static int capabilities_sent;
|
||||
|
||||
static int show_ref(const char *path, const unsigned char *sha1)
|
||||
static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
if (capabilities_sent)
|
||||
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
|
||||
@ -25,9 +25,9 @@ static int show_ref(const char *path, const unsigned char *sha1)
|
||||
|
||||
static void write_head_info(void)
|
||||
{
|
||||
for_each_ref(show_ref);
|
||||
for_each_ref(show_ref, NULL);
|
||||
if (!capabilities_sent)
|
||||
show_ref("capabilities^{}", null_sha1);
|
||||
show_ref("capabilities^{}", null_sha1, 0, NULL);
|
||||
|
||||
}
|
||||
|
||||
|
361
refs.c
361
refs.c
@ -3,15 +3,165 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
struct ref_list {
|
||||
struct ref_list *next;
|
||||
unsigned char flag; /* ISSYMREF? ISPACKED? */
|
||||
unsigned char sha1[20];
|
||||
char name[FLEX_ARRAY];
|
||||
};
|
||||
|
||||
static const char *parse_ref_line(char *line, unsigned char *sha1)
|
||||
{
|
||||
/*
|
||||
* 42: the answer to everything.
|
||||
*
|
||||
* In this case, it happens to be the answer to
|
||||
* 40 (length of sha1 hex representation)
|
||||
* +1 (space in between hex and name)
|
||||
* +1 (newline at the end of the line)
|
||||
*/
|
||||
int len = strlen(line) - 42;
|
||||
|
||||
if (len <= 0)
|
||||
return NULL;
|
||||
if (get_sha1_hex(line, sha1) < 0)
|
||||
return NULL;
|
||||
if (!isspace(line[40]))
|
||||
return NULL;
|
||||
line += 41;
|
||||
if (isspace(*line))
|
||||
return NULL;
|
||||
if (line[len] != '\n')
|
||||
return NULL;
|
||||
line[len] = 0;
|
||||
return line;
|
||||
}
|
||||
|
||||
static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
|
||||
int flag, struct ref_list *list)
|
||||
{
|
||||
int len;
|
||||
struct ref_list **p = &list, *entry;
|
||||
|
||||
/* Find the place to insert the ref into.. */
|
||||
while ((entry = *p) != NULL) {
|
||||
int cmp = strcmp(entry->name, name);
|
||||
if (cmp > 0)
|
||||
break;
|
||||
|
||||
/* Same as existing entry? */
|
||||
if (!cmp)
|
||||
return list;
|
||||
p = &entry->next;
|
||||
}
|
||||
|
||||
/* Allocate it and add it in.. */
|
||||
len = strlen(name) + 1;
|
||||
entry = xmalloc(sizeof(struct ref_list) + len);
|
||||
hashcpy(entry->sha1, sha1);
|
||||
memcpy(entry->name, name, len);
|
||||
entry->flag = flag;
|
||||
entry->next = *p;
|
||||
*p = entry;
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct ref_list *get_packed_refs(void)
|
||||
{
|
||||
static int did_refs = 0;
|
||||
static struct ref_list *refs = NULL;
|
||||
|
||||
if (!did_refs) {
|
||||
FILE *f = fopen(git_path("packed-refs"), "r");
|
||||
if (f) {
|
||||
struct ref_list *list = NULL;
|
||||
char refline[PATH_MAX];
|
||||
while (fgets(refline, sizeof(refline), f)) {
|
||||
unsigned char sha1[20];
|
||||
const char *name = parse_ref_line(refline, sha1);
|
||||
if (!name)
|
||||
continue;
|
||||
list = add_ref(name, sha1, REF_ISPACKED, list);
|
||||
}
|
||||
fclose(f);
|
||||
refs = list;
|
||||
}
|
||||
did_refs = 1;
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
|
||||
{
|
||||
DIR *dir = opendir(git_path("%s", base));
|
||||
|
||||
if (dir) {
|
||||
struct dirent *de;
|
||||
int baselen = strlen(base);
|
||||
char *ref = xmalloc(baselen + 257);
|
||||
|
||||
memcpy(ref, base, baselen);
|
||||
if (baselen && base[baselen-1] != '/')
|
||||
ref[baselen++] = '/';
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
unsigned char sha1[20];
|
||||
struct stat st;
|
||||
int flag;
|
||||
int namelen;
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
namelen = strlen(de->d_name);
|
||||
if (namelen > 255)
|
||||
continue;
|
||||
if (has_extension(de->d_name, ".lock"))
|
||||
continue;
|
||||
memcpy(ref + baselen, de->d_name, namelen+1);
|
||||
if (stat(git_path("%s", ref), &st) < 0)
|
||||
continue;
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
list = get_ref_dir(ref, list);
|
||||
continue;
|
||||
}
|
||||
if (!resolve_ref(ref, sha1, 1, &flag)) {
|
||||
error("%s points nowhere!", ref);
|
||||
continue;
|
||||
}
|
||||
list = add_ref(ref, sha1, flag, list);
|
||||
}
|
||||
free(ref);
|
||||
closedir(dir);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct ref_list *get_loose_refs(void)
|
||||
{
|
||||
static int did_refs = 0;
|
||||
static struct ref_list *refs = NULL;
|
||||
|
||||
if (!did_refs) {
|
||||
refs = get_ref_dir("refs", NULL);
|
||||
did_refs = 1;
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
/* We allow "recursive" symbolic refs. Only within reason, though */
|
||||
#define MAXDEPTH 5
|
||||
|
||||
const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
||||
const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
|
||||
{
|
||||
int depth = MAXDEPTH, len;
|
||||
char buffer[256];
|
||||
static char ref_buffer[256];
|
||||
|
||||
if (flag)
|
||||
*flag = 0;
|
||||
|
||||
for (;;) {
|
||||
const char *path = git_path("%s", ref);
|
||||
struct stat st;
|
||||
char *buf;
|
||||
int fd;
|
||||
@ -27,17 +177,31 @@ const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
||||
* reading.
|
||||
*/
|
||||
if (lstat(path, &st) < 0) {
|
||||
struct ref_list *list = get_packed_refs();
|
||||
while (list) {
|
||||
if (!strcmp(ref, list->name)) {
|
||||
hashcpy(sha1, list->sha1);
|
||||
if (flag)
|
||||
*flag |= REF_ISPACKED;
|
||||
return ref;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
if (reading || errno != ENOENT)
|
||||
return NULL;
|
||||
hashclr(sha1);
|
||||
return path;
|
||||
return ref;
|
||||
}
|
||||
|
||||
/* Follow "normalized" - ie "refs/.." symlinks by hand */
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
len = readlink(path, buffer, sizeof(buffer)-1);
|
||||
if (len >= 5 && !memcmp("refs/", buffer, 5)) {
|
||||
path = git_path("%.*s", len, buffer);
|
||||
buffer[len] = 0;
|
||||
strcpy(ref_buffer, buffer);
|
||||
ref = ref_buffer;
|
||||
if (flag)
|
||||
*flag |= REF_ISSYMREF;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -62,19 +226,24 @@ const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
||||
while (len && isspace(*buf))
|
||||
buf++, len--;
|
||||
while (len && isspace(buf[len-1]))
|
||||
buf[--len] = 0;
|
||||
path = git_path("%.*s", len, buf);
|
||||
len--;
|
||||
buf[len] = 0;
|
||||
memcpy(ref_buffer, buf, len + 1);
|
||||
ref = ref_buffer;
|
||||
if (flag)
|
||||
*flag |= REF_ISSYMREF;
|
||||
}
|
||||
if (len < 40 || get_sha1_hex(buffer, sha1))
|
||||
return NULL;
|
||||
return path;
|
||||
return ref;
|
||||
}
|
||||
|
||||
int create_symref(const char *git_HEAD, const char *refs_heads_master)
|
||||
int create_symref(const char *ref_target, const char *refs_heads_master)
|
||||
{
|
||||
const char *lockpath;
|
||||
char ref[1000];
|
||||
int fd, len, written;
|
||||
const char *git_HEAD = git_path("%s", ref_target);
|
||||
|
||||
#ifndef NO_SYMLINK_HEAD
|
||||
if (prefer_symlink_refs) {
|
||||
@ -112,104 +281,101 @@ int create_symref(const char *git_HEAD, const char *refs_heads_master)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_ref(const char *filename, unsigned char *sha1)
|
||||
int read_ref(const char *ref, unsigned char *sha1)
|
||||
{
|
||||
if (resolve_ref(filename, sha1, 1))
|
||||
if (resolve_ref(ref, sha1, 1, NULL))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1), int trim)
|
||||
static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
|
||||
void *cb_data)
|
||||
{
|
||||
int retval = 0;
|
||||
DIR *dir = opendir(git_path("%s", base));
|
||||
int retval;
|
||||
struct ref_list *packed = get_packed_refs();
|
||||
struct ref_list *loose = get_loose_refs();
|
||||
|
||||
if (dir) {
|
||||
struct dirent *de;
|
||||
int baselen = strlen(base);
|
||||
char *path = xmalloc(baselen + 257);
|
||||
|
||||
if (!strncmp(base, "./", 2)) {
|
||||
base += 2;
|
||||
baselen -= 2;
|
||||
while (packed && loose) {
|
||||
struct ref_list *entry;
|
||||
int cmp = strcmp(packed->name, loose->name);
|
||||
if (!cmp) {
|
||||
packed = packed->next;
|
||||
continue;
|
||||
}
|
||||
memcpy(path, base, baselen);
|
||||
if (baselen && base[baselen-1] != '/')
|
||||
path[baselen++] = '/';
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
unsigned char sha1[20];
|
||||
struct stat st;
|
||||
int namelen;
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
if (cmp > 0) {
|
||||
entry = loose;
|
||||
loose = loose->next;
|
||||
} else {
|
||||
entry = packed;
|
||||
packed = packed->next;
|
||||
}
|
||||
if (strncmp(base, entry->name, trim))
|
||||
continue;
|
||||
namelen = strlen(de->d_name);
|
||||
if (namelen > 255)
|
||||
if (is_null_sha1(entry->sha1))
|
||||
continue;
|
||||
if (has_extension(de->d_name, ".lock"))
|
||||
if (!has_sha1_file(entry->sha1)) {
|
||||
error("%s does not point to a valid object!", entry->name);
|
||||
continue;
|
||||
memcpy(path + baselen, de->d_name, namelen+1);
|
||||
if (stat(git_path("%s", path), &st) < 0)
|
||||
continue;
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
retval = do_for_each_ref(path, fn, trim);
|
||||
}
|
||||
retval = fn(entry->name + trim, entry->sha1,
|
||||
entry->flag, cb_data);
|
||||
if (retval)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (read_ref(git_path("%s", path), sha1) < 0) {
|
||||
error("%s points nowhere!", path);
|
||||
continue;
|
||||
}
|
||||
if (!has_sha1_file(sha1)) {
|
||||
error("%s does not point to a valid "
|
||||
"commit object!", path);
|
||||
continue;
|
||||
}
|
||||
retval = fn(path + trim, sha1);
|
||||
if (retval)
|
||||
break;
|
||||
}
|
||||
free(path);
|
||||
closedir(dir);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int head_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
if (!read_ref(git_path("HEAD"), sha1))
|
||||
return fn("HEAD", sha1);
|
||||
packed = packed ? packed : loose;
|
||||
while (packed) {
|
||||
if (!strncmp(base, packed->name, trim)) {
|
||||
retval = fn(packed->name + trim, packed->sha1,
|
||||
packed->flag, cb_data);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
packed = packed->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
||||
int head_ref(each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
return do_for_each_ref("refs", fn, 0);
|
||||
unsigned char sha1[20];
|
||||
int flag;
|
||||
|
||||
if (resolve_ref("HEAD", sha1, 1, &flag))
|
||||
return fn("HEAD", sha1, flag, cb_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
||||
int for_each_ref(each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
return do_for_each_ref("refs/tags", fn, 10);
|
||||
return do_for_each_ref("refs/", fn, 0, cb_data);
|
||||
}
|
||||
|
||||
int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
||||
int for_each_tag_ref(each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
return do_for_each_ref("refs/heads", fn, 11);
|
||||
return do_for_each_ref("refs/tags/", fn, 10, cb_data);
|
||||
}
|
||||
|
||||
int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
||||
int for_each_branch_ref(each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
return do_for_each_ref("refs/remotes", fn, 13);
|
||||
return do_for_each_ref("refs/heads/", fn, 11, cb_data);
|
||||
}
|
||||
|
||||
int for_each_remote_ref(each_ref_fn fn, void *cb_data)
|
||||
{
|
||||
return do_for_each_ref("refs/remotes/", fn, 13, cb_data);
|
||||
}
|
||||
|
||||
/* NEEDSWORK: This is only used by ssh-upload and it should go; the
|
||||
* caller should do resolve_ref or read_ref like everybody else. Or
|
||||
* maybe everybody else should use get_ref_sha1() instead of doing
|
||||
* read_ref().
|
||||
*/
|
||||
int get_ref_sha1(const char *ref, unsigned char *sha1)
|
||||
{
|
||||
if (check_ref_format(ref))
|
||||
return -1;
|
||||
return read_ref(git_path("refs/%s", ref), sha1);
|
||||
return read_ref(mkpath("refs/%s", ref), sha1);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -267,22 +433,13 @@ int check_ref_format(const char *ref)
|
||||
static struct ref_lock *verify_lock(struct ref_lock *lock,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
{
|
||||
char buf[40];
|
||||
int nr, fd = open(lock->ref_file, O_RDONLY);
|
||||
if (fd < 0 && (mustexist || errno != ENOENT)) {
|
||||
error("Can't verify ref %s", lock->ref_file);
|
||||
unlock_ref(lock);
|
||||
return NULL;
|
||||
}
|
||||
nr = read(fd, buf, 40);
|
||||
close(fd);
|
||||
if (nr != 40 || get_sha1_hex(buf, lock->old_sha1) < 0) {
|
||||
error("Can't verify ref %s", lock->ref_file);
|
||||
if (!resolve_ref(lock->ref_name, lock->old_sha1, mustexist, NULL)) {
|
||||
error("Can't verify ref %s", lock->ref_name);
|
||||
unlock_ref(lock);
|
||||
return NULL;
|
||||
}
|
||||
if (hashcmp(lock->old_sha1, old_sha1)) {
|
||||
error("Ref %s is at %s but expected %s", lock->ref_file,
|
||||
error("Ref %s is at %s but expected %s", lock->ref_name,
|
||||
sha1_to_hex(lock->old_sha1), sha1_to_hex(old_sha1));
|
||||
unlock_ref(lock);
|
||||
return NULL;
|
||||
@ -290,36 +447,37 @@ static struct ref_lock *verify_lock(struct ref_lock *lock,
|
||||
return lock;
|
||||
}
|
||||
|
||||
static struct ref_lock *lock_ref_sha1_basic(const char *path,
|
||||
static struct ref_lock *lock_ref_sha1_basic(const char *ref,
|
||||
int plen,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
{
|
||||
const char *orig_path = path;
|
||||
char *ref_file;
|
||||
const char *orig_ref = ref;
|
||||
struct ref_lock *lock;
|
||||
struct stat st;
|
||||
|
||||
lock = xcalloc(1, sizeof(struct ref_lock));
|
||||
lock->lock_fd = -1;
|
||||
|
||||
plen = strlen(path) - plen;
|
||||
path = resolve_ref(path, lock->old_sha1, mustexist);
|
||||
if (!path) {
|
||||
ref = resolve_ref(ref, lock->old_sha1, mustexist, NULL);
|
||||
if (!ref) {
|
||||
int last_errno = errno;
|
||||
error("unable to resolve reference %s: %s",
|
||||
orig_path, strerror(errno));
|
||||
orig_ref, strerror(errno));
|
||||
unlock_ref(lock);
|
||||
errno = last_errno;
|
||||
return NULL;
|
||||
}
|
||||
lock->lk = xcalloc(1, sizeof(struct lock_file));
|
||||
|
||||
lock->ref_file = xstrdup(path);
|
||||
lock->log_file = xstrdup(git_path("logs/%s", lock->ref_file + plen));
|
||||
lock->force_write = lstat(lock->ref_file, &st) && errno == ENOENT;
|
||||
lock->ref_name = xstrdup(ref);
|
||||
lock->log_file = xstrdup(git_path("logs/%s", ref));
|
||||
ref_file = git_path(ref);
|
||||
lock->force_write = lstat(ref_file, &st) && errno == ENOENT;
|
||||
|
||||
if (safe_create_leading_directories(lock->ref_file))
|
||||
die("unable to create directory for %s", lock->ref_file);
|
||||
lock->lock_fd = hold_lock_file_for_update(lock->lk, lock->ref_file, 1);
|
||||
if (safe_create_leading_directories(ref_file))
|
||||
die("unable to create directory for %s", ref_file);
|
||||
lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, 1);
|
||||
|
||||
return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
|
||||
}
|
||||
@ -327,17 +485,18 @@ static struct ref_lock *lock_ref_sha1_basic(const char *path,
|
||||
struct ref_lock *lock_ref_sha1(const char *ref,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
{
|
||||
char refpath[PATH_MAX];
|
||||
if (check_ref_format(ref))
|
||||
return NULL;
|
||||
return lock_ref_sha1_basic(git_path("refs/%s", ref),
|
||||
5 + strlen(ref), old_sha1, mustexist);
|
||||
strcpy(refpath, mkpath("refs/%s", ref));
|
||||
return lock_ref_sha1_basic(refpath, strlen(refpath),
|
||||
old_sha1, mustexist);
|
||||
}
|
||||
|
||||
struct ref_lock *lock_any_ref_for_update(const char *ref,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
{
|
||||
return lock_ref_sha1_basic(git_path("%s", ref),
|
||||
strlen(ref), old_sha1, mustexist);
|
||||
return lock_ref_sha1_basic(ref, strlen(ref), old_sha1, mustexist);
|
||||
}
|
||||
|
||||
void unlock_ref(struct ref_lock *lock)
|
||||
@ -348,7 +507,7 @@ void unlock_ref(struct ref_lock *lock)
|
||||
if (lock->lk)
|
||||
rollback_lock_file(lock->lk);
|
||||
}
|
||||
free(lock->ref_file);
|
||||
free(lock->ref_name);
|
||||
free(lock->log_file);
|
||||
free(lock);
|
||||
}
|
||||
@ -425,7 +584,7 @@ int write_ref_sha1(struct ref_lock *lock,
|
||||
return -1;
|
||||
}
|
||||
if (commit_lock_file(lock->lk)) {
|
||||
error("Couldn't set %s", lock->ref_file);
|
||||
error("Couldn't set %s", lock->ref_name);
|
||||
unlock_ref(lock);
|
||||
return -1;
|
||||
}
|
||||
|
15
refs.h
15
refs.h
@ -2,7 +2,7 @@
|
||||
#define REFS_H
|
||||
|
||||
struct ref_lock {
|
||||
char *ref_file;
|
||||
char *ref_name;
|
||||
char *log_file;
|
||||
struct lock_file *lk;
|
||||
unsigned char old_sha1[20];
|
||||
@ -14,11 +14,14 @@ struct ref_lock {
|
||||
* Calls the specified function for each ref file until it returns nonzero,
|
||||
* and returns the value
|
||||
*/
|
||||
extern int head_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
||||
extern int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
||||
extern int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
||||
extern int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
||||
extern int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
||||
#define REF_ISSYMREF 01
|
||||
#define REF_ISPACKED 02
|
||||
typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data);
|
||||
extern int head_ref(each_ref_fn, void *);
|
||||
extern int for_each_ref(each_ref_fn, void *);
|
||||
extern int for_each_tag_ref(each_ref_fn, void *);
|
||||
extern int for_each_branch_ref(each_ref_fn, void *);
|
||||
extern int for_each_remote_ref(each_ref_fn, void *);
|
||||
|
||||
/** Reads the refs file specified into sha1 **/
|
||||
extern int get_ref_sha1(const char *ref, unsigned char *sha1);
|
||||
|
28
revision.c
28
revision.c
@ -416,7 +416,8 @@ static void limit_list(struct rev_info *revs)
|
||||
|
||||
if (revs->max_age != -1 && (commit->date < revs->max_age))
|
||||
obj->flags |= UNINTERESTING;
|
||||
if (revs->unpacked && has_sha1_pack(obj->sha1))
|
||||
if (revs->unpacked &&
|
||||
has_sha1_pack(obj->sha1, revs->ignore_packed))
|
||||
obj->flags |= UNINTERESTING;
|
||||
add_parents_to_list(revs, commit, &list);
|
||||
if (obj->flags & UNINTERESTING) {
|
||||
@ -465,7 +466,7 @@ static void limit_list(struct rev_info *revs)
|
||||
static int all_flags;
|
||||
static struct rev_info *all_revs;
|
||||
|
||||
static int handle_one_ref(const char *path, const unsigned char *sha1)
|
||||
static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct object *object = get_reference(all_revs, path, sha1, all_flags);
|
||||
add_pending_object(all_revs, object, "");
|
||||
@ -476,7 +477,7 @@ static void handle_all(struct rev_info *revs, unsigned flags)
|
||||
{
|
||||
all_revs = revs;
|
||||
all_flags = flags;
|
||||
for_each_ref(handle_one_ref);
|
||||
for_each_ref(handle_one_ref, NULL);
|
||||
}
|
||||
|
||||
static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
|
||||
@ -671,6 +672,16 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_ignore_packed(struct rev_info *revs, const char *name)
|
||||
{
|
||||
int num = ++revs->num_ignore_packed;
|
||||
|
||||
revs->ignore_packed = xrealloc(revs->ignore_packed,
|
||||
sizeof(const char **) * (num + 1));
|
||||
revs->ignore_packed[num-1] = name;
|
||||
revs->ignore_packed[num] = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse revision information, filling in the "rev_info" structure,
|
||||
* and removing the used arguments from the argument list.
|
||||
@ -811,6 +822,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
}
|
||||
if (!strcmp(arg, "--unpacked")) {
|
||||
revs->unpacked = 1;
|
||||
free(revs->ignore_packed);
|
||||
revs->ignore_packed = NULL;
|
||||
revs->num_ignore_packed = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--unpacked=", 11)) {
|
||||
revs->unpacked = 1;
|
||||
add_ignore_packed(revs, arg+11);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-r")) {
|
||||
@ -1057,7 +1076,8 @@ struct commit *get_revision(struct rev_info *revs)
|
||||
*/
|
||||
if (!revs->limited) {
|
||||
if ((revs->unpacked &&
|
||||
has_sha1_pack(commit->object.sha1)) ||
|
||||
has_sha1_pack(commit->object.sha1,
|
||||
revs->ignore_packed)) ||
|
||||
(revs->max_age != -1 &&
|
||||
(commit->date < revs->max_age)))
|
||||
continue;
|
||||
|
@ -38,7 +38,7 @@ struct rev_info {
|
||||
blob_objects:1,
|
||||
edge_hint:1,
|
||||
limited:1,
|
||||
unpacked:1,
|
||||
unpacked:1, /* see also ignore_packed below */
|
||||
boundary:1,
|
||||
parents:1;
|
||||
|
||||
@ -57,6 +57,10 @@ struct rev_info {
|
||||
unsigned int shown_one:1,
|
||||
abbrev_commit:1,
|
||||
relative_date:1;
|
||||
|
||||
const char **ignore_packed; /* pretend objects in these are unpacked */
|
||||
int num_ignore_packed;
|
||||
|
||||
unsigned int abbrev;
|
||||
enum cmit_fmt commit_format;
|
||||
struct log_info *loginfo;
|
||||
|
@ -215,7 +215,7 @@ static int ref_newer(const unsigned char *new_sha1,
|
||||
static struct ref *local_refs, **local_tail;
|
||||
static struct ref *remote_refs, **remote_tail;
|
||||
|
||||
static int one_local_ref(const char *refname, const unsigned char *sha1)
|
||||
static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct ref *ref;
|
||||
int len = strlen(refname) + 1;
|
||||
@ -230,7 +230,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1)
|
||||
static void get_local_heads(void)
|
||||
{
|
||||
local_tail = &local_refs;
|
||||
for_each_ref(one_local_ref);
|
||||
for_each_ref(one_local_ref, NULL);
|
||||
}
|
||||
|
||||
static int receive_status(int in)
|
||||
|
@ -7,7 +7,7 @@
|
||||
/* refs */
|
||||
static FILE *info_ref_fp;
|
||||
|
||||
static int add_info_ref(const char *path, const unsigned char *sha1)
|
||||
static int add_info_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct object *o = parse_object(sha1);
|
||||
|
||||
@ -34,7 +34,7 @@ static int update_info_refs(int force)
|
||||
info_ref_fp = fopen(path1, "w");
|
||||
if (!info_ref_fp)
|
||||
return error("unable to update %s", path0);
|
||||
for_each_ref(add_info_ref);
|
||||
for_each_ref(add_info_ref, NULL);
|
||||
fclose(info_ref_fp);
|
||||
rename(path1, path0);
|
||||
free(path0);
|
||||
|
26
sha1_file.c
26
sha1_file.c
@ -1217,12 +1217,20 @@ int find_pack_entry_one(const unsigned char *sha1,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
|
||||
static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed)
|
||||
{
|
||||
struct packed_git *p;
|
||||
prepare_packed_git();
|
||||
|
||||
for (p = packed_git; p; p = p->next) {
|
||||
if (ignore_packed) {
|
||||
const char **ig;
|
||||
for (ig = ignore_packed; *ig; ig++)
|
||||
if (!strcmp(p->pack_name, *ig))
|
||||
break;
|
||||
if (*ig)
|
||||
continue;
|
||||
}
|
||||
if (find_pack_entry_one(sha1, e, p))
|
||||
return 1;
|
||||
}
|
||||
@ -1255,10 +1263,10 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep
|
||||
if (!map) {
|
||||
struct pack_entry e;
|
||||
|
||||
if (find_pack_entry(sha1, &e))
|
||||
if (find_pack_entry(sha1, &e, NULL))
|
||||
return packed_object_info(&e, type, sizep);
|
||||
reprepare_packed_git();
|
||||
if (find_pack_entry(sha1, &e))
|
||||
if (find_pack_entry(sha1, &e, NULL))
|
||||
return packed_object_info(&e, type, sizep);
|
||||
return error("unable to find %s", sha1_to_hex(sha1));
|
||||
}
|
||||
@ -1281,7 +1289,7 @@ static void *read_packed_sha1(const unsigned char *sha1, char *type, unsigned lo
|
||||
{
|
||||
struct pack_entry e;
|
||||
|
||||
if (!find_pack_entry(sha1, &e)) {
|
||||
if (!find_pack_entry(sha1, &e, NULL)) {
|
||||
error("cannot read sha1_file for %s", sha1_to_hex(sha1));
|
||||
return NULL;
|
||||
}
|
||||
@ -1294,7 +1302,7 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size
|
||||
void *map, *buf;
|
||||
struct pack_entry e;
|
||||
|
||||
if (find_pack_entry(sha1, &e))
|
||||
if (find_pack_entry(sha1, &e, NULL))
|
||||
return read_packed_sha1(sha1, type, size);
|
||||
map = map_sha1_file(sha1, &mapsize);
|
||||
if (map) {
|
||||
@ -1303,7 +1311,7 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size
|
||||
return buf;
|
||||
}
|
||||
reprepare_packed_git();
|
||||
if (find_pack_entry(sha1, &e))
|
||||
if (find_pack_entry(sha1, &e, NULL))
|
||||
return read_packed_sha1(sha1, type, size);
|
||||
return NULL;
|
||||
}
|
||||
@ -1735,10 +1743,10 @@ int has_pack_file(const unsigned char *sha1)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int has_sha1_pack(const unsigned char *sha1)
|
||||
int has_sha1_pack(const unsigned char *sha1, const char **ignore_packed)
|
||||
{
|
||||
struct pack_entry e;
|
||||
return find_pack_entry(sha1, &e);
|
||||
return find_pack_entry(sha1, &e, ignore_packed);
|
||||
}
|
||||
|
||||
int has_sha1_file(const unsigned char *sha1)
|
||||
@ -1746,7 +1754,7 @@ int has_sha1_file(const unsigned char *sha1)
|
||||
struct stat st;
|
||||
struct pack_entry e;
|
||||
|
||||
if (find_pack_entry(sha1, &e))
|
||||
if (find_pack_entry(sha1, &e, NULL))
|
||||
return 1;
|
||||
return find_sha1_file(sha1, &st) ? 1 : 0;
|
||||
}
|
||||
|
14
sha1_name.c
14
sha1_name.c
@ -247,8 +247,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
||||
NULL
|
||||
};
|
||||
static const char *warning = "warning: refname '%.*s' is ambiguous.\n";
|
||||
const char **p, *pathname;
|
||||
char *real_path = NULL;
|
||||
const char **p, *ref;
|
||||
char *real_ref = NULL;
|
||||
int refs_found = 0, am;
|
||||
unsigned long at_time = (unsigned long)-1;
|
||||
unsigned char *this_result;
|
||||
@ -276,10 +276,10 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
||||
|
||||
for (p = fmt; *p; p++) {
|
||||
this_result = refs_found ? sha1_from_ref : sha1;
|
||||
pathname = resolve_ref(git_path(*p, len, str), this_result, 1);
|
||||
if (pathname) {
|
||||
ref = resolve_ref(mkpath(*p, len, str), this_result, 1, NULL);
|
||||
if (ref) {
|
||||
if (!refs_found++)
|
||||
real_path = xstrdup(pathname);
|
||||
real_ref = xstrdup(ref);
|
||||
if (!warn_ambiguous_refs)
|
||||
break;
|
||||
}
|
||||
@ -293,12 +293,12 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
||||
|
||||
if (at_time != (unsigned long)-1) {
|
||||
read_ref_at(
|
||||
real_path + strlen(git_path(".")) - 1,
|
||||
real_ref,
|
||||
at_time,
|
||||
sha1);
|
||||
}
|
||||
|
||||
free(real_path);
|
||||
free(real_ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
74
sideband.c
Normal file
74
sideband.c
Normal file
@ -0,0 +1,74 @@
|
||||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
|
||||
/*
|
||||
* Receive multiplexed output stream over git native protocol.
|
||||
* in_stream is the input stream from the remote, which carries data
|
||||
* in pkt_line format with band designator. Demultiplex it into out
|
||||
* and err and return error appropriately. Band #1 carries the
|
||||
* primary payload. Things coming over band #2 is not necessarily
|
||||
* error; they are usually informative message on the standard error
|
||||
* stream, aka "verbose"). A message over band #3 is a signal that
|
||||
* the remote died unexpectedly. A flush() concludes the stream.
|
||||
*/
|
||||
int recv_sideband(const char *me, int in_stream, int out, int err, char *buf, int bufsz)
|
||||
{
|
||||
while (1) {
|
||||
int len = packet_read_line(in_stream, buf, bufsz);
|
||||
if (len == 0)
|
||||
break;
|
||||
if (len < 1) {
|
||||
len = sprintf(buf, "%s: protocol error: no band designator\n", me);
|
||||
safe_write(err, buf, len);
|
||||
return SIDEBAND_PROTOCOL_ERROR;
|
||||
}
|
||||
len--;
|
||||
switch (buf[0] & 0xFF) {
|
||||
case 3:
|
||||
safe_write(err, "remote: ", 8);
|
||||
safe_write(err, buf+1, len);
|
||||
safe_write(err, "\n", 1);
|
||||
return SIDEBAND_REMOTE_ERROR;
|
||||
case 2:
|
||||
safe_write(err, "remote: ", 8);
|
||||
safe_write(err, buf+1, len);
|
||||
continue;
|
||||
case 1:
|
||||
safe_write(out, buf+1, len);
|
||||
continue;
|
||||
default:
|
||||
len = sprintf(buf + 1,
|
||||
"%s: protocol error: bad band #%d\n",
|
||||
me, buf[0] & 0xFF);
|
||||
safe_write(err, buf+1, len);
|
||||
return SIDEBAND_PROTOCOL_ERROR;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fd is connected to the remote side; send the sideband data
|
||||
* over multiplexed packet stream.
|
||||
*/
|
||||
ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max)
|
||||
{
|
||||
ssize_t ssz = sz;
|
||||
const char *p = data;
|
||||
|
||||
while (sz) {
|
||||
unsigned n;
|
||||
char hdr[5];
|
||||
|
||||
n = sz;
|
||||
if (packet_max - 5 < n)
|
||||
n = packet_max - 5;
|
||||
sprintf(hdr, "%04x", n + 5);
|
||||
hdr[4] = band;
|
||||
safe_write(fd, hdr, 5);
|
||||
safe_write(fd, p, n);
|
||||
p += n;
|
||||
sz -= n;
|
||||
}
|
||||
return ssz;
|
||||
}
|
13
sideband.h
Normal file
13
sideband.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef SIDEBAND_H
|
||||
#define SIDEBAND_H
|
||||
|
||||
#define SIDEBAND_PROTOCOL_ERROR -2
|
||||
#define SIDEBAND_REMOTE_ERROR -1
|
||||
|
||||
#define DEFAULT_PACKET_MAX 1000
|
||||
#define LARGE_PACKET_MAX 65520
|
||||
|
||||
int recv_sideband(const char *me, int in_stream, int out, int err, char *, int);
|
||||
ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max);
|
||||
|
||||
#endif
|
@ -19,51 +19,48 @@ n=$n_dir/fixes
|
||||
|
||||
test_expect_success \
|
||||
"create $m" \
|
||||
'git-update-ref $m $A &&
|
||||
test $A = $(cat .git/$m)'
|
||||
"git-update-ref $m $A &&
|
||||
test $A"' = $(cat .git/'"$m"')'
|
||||
test_expect_success \
|
||||
"create $m" \
|
||||
'git-update-ref $m $B $A &&
|
||||
test $B = $(cat .git/$m)'
|
||||
"git-update-ref $m $B $A &&
|
||||
test $B"' = $(cat .git/'"$m"')'
|
||||
rm -f .git/$m
|
||||
|
||||
test_expect_success \
|
||||
"fail to create $n" \
|
||||
'touch .git/$n_dir
|
||||
git-update-ref $n $A >out 2>err
|
||||
test $? = 1 &&
|
||||
test "" = "$(cat out)" &&
|
||||
grep "error: unable to resolve reference" err &&
|
||||
grep $n err'
|
||||
"touch .git/$n_dir
|
||||
git-update-ref $n $A >out 2>err"'
|
||||
test $? != 0'
|
||||
rm -f .git/$n_dir out err
|
||||
|
||||
test_expect_success \
|
||||
"create $m (by HEAD)" \
|
||||
'git-update-ref HEAD $A &&
|
||||
test $A = $(cat .git/$m)'
|
||||
"git-update-ref HEAD $A &&
|
||||
test $A"' = $(cat .git/'"$m"')'
|
||||
test_expect_success \
|
||||
"create $m (by HEAD)" \
|
||||
'git-update-ref HEAD $B $A &&
|
||||
test $B = $(cat .git/$m)'
|
||||
"git-update-ref HEAD $B $A &&
|
||||
test $B"' = $(cat .git/'"$m"')'
|
||||
rm -f .git/$m
|
||||
|
||||
test_expect_failure \
|
||||
'(not) create HEAD with old sha1' \
|
||||
'git-update-ref HEAD $A $B'
|
||||
"git-update-ref HEAD $A $B"
|
||||
test_expect_failure \
|
||||
"(not) prior created .git/$m" \
|
||||
'test -f .git/$m'
|
||||
"test -f .git/$m"
|
||||
rm -f .git/$m
|
||||
|
||||
test_expect_success \
|
||||
"create HEAD" \
|
||||
'git-update-ref HEAD $A'
|
||||
"git-update-ref HEAD $A"
|
||||
test_expect_failure \
|
||||
'(not) change HEAD with wrong SHA1' \
|
||||
'git-update-ref HEAD $B $Z'
|
||||
"git-update-ref HEAD $B $Z"
|
||||
test_expect_failure \
|
||||
"(not) changed .git/$m" \
|
||||
'test $B = $(cat .git/$m)'
|
||||
"test $B"' = $(cat .git/'"$m"')'
|
||||
rm -f .git/$m
|
||||
|
||||
mkdir -p .git/logs/refs/heads
|
||||
@ -71,18 +68,18 @@ touch .git/logs/refs/heads/master
|
||||
test_expect_success \
|
||||
"create $m (logged by touch)" \
|
||||
'GIT_COMMITTER_DATE="2005-05-26 23:30" \
|
||||
git-update-ref HEAD $A -m "Initial Creation" &&
|
||||
test $A = $(cat .git/$m)'
|
||||
git-update-ref HEAD '"$A"' -m "Initial Creation" &&
|
||||
test '"$A"' = $(cat .git/'"$m"')'
|
||||
test_expect_success \
|
||||
"update $m (logged by touch)" \
|
||||
'GIT_COMMITTER_DATE="2005-05-26 23:31" \
|
||||
git-update-ref HEAD $B $A -m "Switch" &&
|
||||
test $B = $(cat .git/$m)'
|
||||
git-update-ref HEAD'" $B $A "'-m "Switch" &&
|
||||
test '"$B"' = $(cat .git/'"$m"')'
|
||||
test_expect_success \
|
||||
"set $m (logged by touch)" \
|
||||
'GIT_COMMITTER_DATE="2005-05-26 23:41" \
|
||||
git-update-ref HEAD $A &&
|
||||
test $A = $(cat .git/$m)'
|
||||
git-update-ref HEAD'" $A &&
|
||||
test $A"' = $(cat .git/'"$m"')'
|
||||
|
||||
cat >expect <<EOF
|
||||
$Z $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 Initial Creation
|
||||
@ -91,7 +88,7 @@ $B $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150860 +0000
|
||||
EOF
|
||||
test_expect_success \
|
||||
"verifying $m's log" \
|
||||
'diff expect .git/logs/$m'
|
||||
"diff expect .git/logs/$m"
|
||||
rm -rf .git/$m .git/logs expect
|
||||
|
||||
test_expect_success \
|
||||
@ -102,18 +99,18 @@ test_expect_success \
|
||||
test_expect_success \
|
||||
"create $m (logged by config)" \
|
||||
'GIT_COMMITTER_DATE="2005-05-26 23:32" \
|
||||
git-update-ref HEAD $A -m "Initial Creation" &&
|
||||
test $A = $(cat .git/$m)'
|
||||
git-update-ref HEAD'" $A "'-m "Initial Creation" &&
|
||||
test '"$A"' = $(cat .git/'"$m"')'
|
||||
test_expect_success \
|
||||
"update $m (logged by config)" \
|
||||
'GIT_COMMITTER_DATE="2005-05-26 23:33" \
|
||||
git-update-ref HEAD $B $A -m "Switch" &&
|
||||
test $B = $(cat .git/$m)'
|
||||
git-update-ref HEAD'" $B $A "'-m "Switch" &&
|
||||
test '"$B"' = $(cat .git/'"$m"')'
|
||||
test_expect_success \
|
||||
"set $m (logged by config)" \
|
||||
'GIT_COMMITTER_DATE="2005-05-26 23:43" \
|
||||
git-update-ref HEAD $A &&
|
||||
test $A = $(cat .git/$m)'
|
||||
git-update-ref HEAD '"$A &&
|
||||
test $A"' = $(cat .git/'"$m"')'
|
||||
|
||||
cat >expect <<EOF
|
||||
$Z $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 +0000 Initial Creation
|
||||
@ -140,50 +137,50 @@ test_expect_success \
|
||||
'Query "master@{May 25 2005}" (before history)' \
|
||||
'rm -f o e
|
||||
git-rev-parse --verify "master@{May 25 2005}" >o 2>e &&
|
||||
test $C = $(cat o) &&
|
||||
test "warning: Log .git/logs/$m only goes back to $ed." = "$(cat e)"'
|
||||
test '"$C"' = $(cat o) &&
|
||||
test "warning: Log .git/logs/'"$m only goes back to $ed"'." = "$(cat e)"'
|
||||
test_expect_success \
|
||||
"Query master@{2005-05-25} (before history)" \
|
||||
'rm -f o e
|
||||
git-rev-parse --verify master@{2005-05-25} >o 2>e &&
|
||||
test $C = $(cat o) &&
|
||||
echo test "warning: Log .git/logs/$m only goes back to $ed." = "$(cat e)"'
|
||||
test '"$C"' = $(cat o) &&
|
||||
echo test "warning: Log .git/logs/'"$m only goes back to $ed"'." = "$(cat e)"'
|
||||
test_expect_success \
|
||||
'Query "master@{May 26 2005 23:31:59}" (1 second before history)' \
|
||||
'rm -f o e
|
||||
git-rev-parse --verify "master@{May 26 2005 23:31:59}" >o 2>e &&
|
||||
test $C = $(cat o) &&
|
||||
test "warning: Log .git/logs/$m only goes back to $ed." = "$(cat e)"'
|
||||
test '"$C"' = $(cat o) &&
|
||||
test "warning: Log .git/logs/'"$m only goes back to $ed"'." = "$(cat e)"'
|
||||
test_expect_success \
|
||||
'Query "master@{May 26 2005 23:32:00}" (exactly history start)' \
|
||||
'rm -f o e
|
||||
git-rev-parse --verify "master@{May 26 2005 23:32:00}" >o 2>e &&
|
||||
test $A = $(cat o) &&
|
||||
test '"$A"' = $(cat o) &&
|
||||
test "" = "$(cat e)"'
|
||||
test_expect_success \
|
||||
'Query "master@{2005-05-26 23:33:01}" (middle of history with gap)' \
|
||||
'rm -f o e
|
||||
git-rev-parse --verify "master@{2005-05-26 23:33:01}" >o 2>e &&
|
||||
test $B = $(cat o) &&
|
||||
test "warning: Log .git/logs/$m has gap after $gd." = "$(cat e)"'
|
||||
test '"$B"' = $(cat o) &&
|
||||
test "warning: Log .git/logs/'"$m has gap after $gd"'." = "$(cat e)"'
|
||||
test_expect_success \
|
||||
'Query "master@{2005-05-26 23:38:00}" (middle of history)' \
|
||||
'rm -f o e
|
||||
git-rev-parse --verify "master@{2005-05-26 23:38:00}" >o 2>e &&
|
||||
test $Z = $(cat o) &&
|
||||
test '"$Z"' = $(cat o) &&
|
||||
test "" = "$(cat e)"'
|
||||
test_expect_success \
|
||||
'Query "master@{2005-05-26 23:43:00}" (exact end of history)' \
|
||||
'rm -f o e
|
||||
git-rev-parse --verify "master@{2005-05-26 23:43:00}" >o 2>e &&
|
||||
test $E = $(cat o) &&
|
||||
test '"$E"' = $(cat o) &&
|
||||
test "" = "$(cat e)"'
|
||||
test_expect_success \
|
||||
'Query "master@{2005-05-28}" (past end of history)' \
|
||||
'rm -f o e
|
||||
git-rev-parse --verify "master@{2005-05-28}" >o 2>e &&
|
||||
test $D = $(cat o) &&
|
||||
test "warning: Log .git/logs/$m unexpectedly ended on $ld." = "$(cat e)"'
|
||||
test '"$D"' = $(cat o) &&
|
||||
test "warning: Log .git/logs/'"$m unexpectedly ended on $ld"'." = "$(cat e)"'
|
||||
|
||||
|
||||
rm -f .git/$m .git/logs/$m expect
|
||||
@ -221,7 +218,7 @@ $h_FIXED $h_MERGED $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117151100 +0000 c
|
||||
EOF
|
||||
test_expect_success \
|
||||
'git-commit logged updates' \
|
||||
'diff expect .git/logs/$m'
|
||||
"diff expect .git/logs/$m"
|
||||
unset h_TEST h_OTHER h_FIXED h_MERGED
|
||||
|
||||
test_expect_success \
|
||||
|
@ -37,7 +37,9 @@ test_expect_success setup '
|
||||
git branch skip-merge skip-reference
|
||||
'
|
||||
|
||||
test_expect_failure 'rebase with git am -3 (default)' 'git rebase master'
|
||||
test_expect_failure 'rebase with git am -3 (default)' '
|
||||
git rebase master
|
||||
'
|
||||
|
||||
test_expect_success 'rebase --skip with am -3' '
|
||||
git reset --hard HEAD &&
|
||||
|
115
t/t4104-apply-boundary.sh
Executable file
115
t/t4104-apply-boundary.sh
Executable file
@ -0,0 +1,115 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2005 Junio C Hamano
|
||||
#
|
||||
|
||||
test_description='git-apply boundary tests
|
||||
|
||||
'
|
||||
. ./test-lib.sh
|
||||
|
||||
L="c d e f g h i j k l m n o p q r s t u v w x"
|
||||
|
||||
test_expect_success setup '
|
||||
for i in b '"$L"' y
|
||||
do
|
||||
echo $i
|
||||
done >victim &&
|
||||
cat victim >original &&
|
||||
git update-index --add victim &&
|
||||
|
||||
: add to the head
|
||||
for i in a b '"$L"' y
|
||||
do
|
||||
echo $i
|
||||
done >victim &&
|
||||
cat victim >add-a-expect &&
|
||||
git diff victim >add-a-patch.with &&
|
||||
git diff --unified=0 >add-a-patch.without &&
|
||||
|
||||
: modify at the head
|
||||
for i in a '"$L"' y
|
||||
do
|
||||
echo $i
|
||||
done >victim &&
|
||||
cat victim >mod-a-expect &&
|
||||
git diff victim >mod-a-patch.with &&
|
||||
git diff --unified=0 >mod-a-patch.without &&
|
||||
|
||||
: remove from the head
|
||||
for i in '"$L"' y
|
||||
do
|
||||
echo $i
|
||||
done >victim &&
|
||||
cat victim >del-a-expect &&
|
||||
git diff victim >del-a-patch.with
|
||||
git diff --unified=0 >del-a-patch.without &&
|
||||
|
||||
: add to the tail
|
||||
for i in b '"$L"' y z
|
||||
do
|
||||
echo $i
|
||||
done >victim &&
|
||||
cat victim >add-z-expect &&
|
||||
git diff victim >add-z-patch.with &&
|
||||
git diff --unified=0 >add-z-patch.without &&
|
||||
|
||||
: modify at the tail
|
||||
for i in a '"$L"' y
|
||||
do
|
||||
echo $i
|
||||
done >victim &&
|
||||
cat victim >mod-z-expect &&
|
||||
git diff victim >mod-z-patch.with &&
|
||||
git diff --unified=0 >mod-z-patch.without &&
|
||||
|
||||
: remove from the tail
|
||||
for i in b '"$L"'
|
||||
do
|
||||
echo $i
|
||||
done >victim &&
|
||||
cat victim >del-z-expect &&
|
||||
git diff victim >del-z-patch.with
|
||||
git diff --unified=0 >del-z-patch.without &&
|
||||
|
||||
: done
|
||||
'
|
||||
|
||||
for with in with without
|
||||
do
|
||||
case "$with" in
|
||||
with) u= ;;
|
||||
without) u='--unidiff-zero ' ;;
|
||||
esac
|
||||
for kind in add-a add-z mod-a mod-z del-a del-z
|
||||
do
|
||||
test_expect_success "apply $kind-patch $with context" '
|
||||
cat original >victim &&
|
||||
git update-index victim &&
|
||||
git apply --index '"$u$kind-patch.$with"' || {
|
||||
cat '"$kind-patch.$with"'
|
||||
(exit 1)
|
||||
} &&
|
||||
diff -u '"$kind"'-expect victim
|
||||
'
|
||||
done
|
||||
done
|
||||
|
||||
for kind in add-a add-z mod-a mod-z del-a del-z
|
||||
do
|
||||
rm -f $kind-ng.without
|
||||
sed -e "s/^diff --git /diff /" \
|
||||
-e '/^index /d' \
|
||||
<$kind-patch.without >$kind-ng.without
|
||||
test_expect_success "apply non-git $kind-patch without context" '
|
||||
cat original >victim &&
|
||||
git update-index victim &&
|
||||
git apply --unidiff-zero --index '"$kind-ng.without"' || {
|
||||
cat '"$kind-ng.without"'
|
||||
(exit 1)
|
||||
} &&
|
||||
diff -u '"$kind"'-expect victim
|
||||
'
|
||||
done
|
||||
|
||||
test_done
|
@ -4,6 +4,7 @@
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
#include "tag.h"
|
||||
#include "object.h"
|
||||
#include "commit.h"
|
||||
@ -19,6 +20,9 @@ static int use_thin_pack;
|
||||
static struct object_array have_obj;
|
||||
static struct object_array want_obj;
|
||||
static unsigned int timeout;
|
||||
/* 0 for no sideband,
|
||||
* otherwise maximum packet size (up to 65520 bytes).
|
||||
*/
|
||||
static int use_sideband;
|
||||
|
||||
static void reset_timeout(void)
|
||||
@ -33,19 +37,10 @@ static int strip(char *line, int len)
|
||||
return len;
|
||||
}
|
||||
|
||||
#define PACKET_MAX 1000
|
||||
static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
|
||||
{
|
||||
ssize_t ssz;
|
||||
const char *p;
|
||||
|
||||
if (!data) {
|
||||
if (!use_sideband)
|
||||
return 0;
|
||||
packet_flush(1);
|
||||
}
|
||||
|
||||
if (!use_sideband) {
|
||||
if (use_sideband)
|
||||
return send_sideband(1, fd, data, sz, use_sideband);
|
||||
if (fd == 3)
|
||||
/* emergency quit */
|
||||
fd = 2;
|
||||
@ -55,24 +50,6 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
|
||||
}
|
||||
return safe_write(fd, data, sz);
|
||||
}
|
||||
p = data;
|
||||
ssz = sz;
|
||||
while (sz) {
|
||||
unsigned n;
|
||||
char hdr[5];
|
||||
|
||||
n = sz;
|
||||
if (PACKET_MAX - 5 < n)
|
||||
n = PACKET_MAX - 5;
|
||||
sprintf(hdr, "%04x", n + 5);
|
||||
hdr[4] = fd;
|
||||
safe_write(1, hdr, 5);
|
||||
safe_write(1, p, n);
|
||||
p += n;
|
||||
sz -= n;
|
||||
}
|
||||
return ssz;
|
||||
}
|
||||
|
||||
static void create_pack_file(void)
|
||||
{
|
||||
@ -308,7 +285,8 @@ static void create_pack_file(void)
|
||||
goto fail;
|
||||
fprintf(stderr, "flushed.\n");
|
||||
}
|
||||
send_client_data(1, NULL, 0);
|
||||
if (use_sideband)
|
||||
packet_flush(1);
|
||||
return;
|
||||
}
|
||||
fail:
|
||||
@ -351,7 +329,8 @@ static int got_sha1(char *hex, unsigned char *sha1)
|
||||
static int get_common_commits(void)
|
||||
{
|
||||
static char line[1000];
|
||||
unsigned char sha1[20], last_sha1[20];
|
||||
unsigned char sha1[20];
|
||||
char hex[41], last_hex[41];
|
||||
int len;
|
||||
|
||||
track_object_refs = 0;
|
||||
@ -368,21 +347,22 @@ static int get_common_commits(void)
|
||||
}
|
||||
len = strip(line, len);
|
||||
if (!strncmp(line, "have ", 5)) {
|
||||
if (got_sha1(line+5, sha1) &&
|
||||
(multi_ack || have_obj.nr == 1)) {
|
||||
packet_write(1, "ACK %s%s\n",
|
||||
sha1_to_hex(sha1),
|
||||
multi_ack ? " continue" : "");
|
||||
if (multi_ack)
|
||||
hashcpy(last_sha1, sha1);
|
||||
if (got_sha1(line+5, sha1)) {
|
||||
memcpy(hex, sha1_to_hex(sha1), 41);
|
||||
if (multi_ack) {
|
||||
const char *msg = "ACK %s continue\n";
|
||||
packet_write(1, msg, hex);
|
||||
memcpy(last_hex, hex, 41);
|
||||
}
|
||||
else if (have_obj.nr == 1)
|
||||
packet_write(1, "ACK %s\n", hex);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(line, "done")) {
|
||||
if (have_obj.nr > 0) {
|
||||
if (multi_ack)
|
||||
packet_write(1, "ACK %s\n",
|
||||
sha1_to_hex(last_sha1));
|
||||
packet_write(1, "ACK %s\n", last_hex);
|
||||
return 0;
|
||||
}
|
||||
packet_write(1, "NAK\n");
|
||||
@ -413,8 +393,10 @@ static void receive_needs(void)
|
||||
multi_ack = 1;
|
||||
if (strstr(line+45, "thin-pack"))
|
||||
use_thin_pack = 1;
|
||||
if (strstr(line+45, "side-band"))
|
||||
use_sideband = 1;
|
||||
if (strstr(line+45, "side-band-64k"))
|
||||
use_sideband = LARGE_PACKET_MAX;
|
||||
else if (strstr(line+45, "side-band"))
|
||||
use_sideband = DEFAULT_PACKET_MAX;
|
||||
|
||||
/* We have sent all our refs already, and the other end
|
||||
* should have chosen out of them; otherwise they are
|
||||
@ -434,9 +416,9 @@ static void receive_needs(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int send_ref(const char *refname, const unsigned char *sha1)
|
||||
static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
static const char *capabilities = "multi_ack thin-pack side-band";
|
||||
static const char *capabilities = "multi_ack thin-pack side-band side-band-64k";
|
||||
struct object *o = parse_object(sha1);
|
||||
|
||||
if (!o)
|
||||
@ -462,8 +444,8 @@ static int send_ref(const char *refname, const unsigned char *sha1)
|
||||
static void upload_pack(void)
|
||||
{
|
||||
reset_timeout();
|
||||
head_ref(send_ref);
|
||||
for_each_ref(send_ref);
|
||||
head_ref(send_ref, NULL);
|
||||
for_each_ref(send_ref, NULL);
|
||||
packet_flush(1);
|
||||
receive_needs();
|
||||
if (want_obj.nr) {
|
||||
|
274
wt-status.c
Normal file
274
wt-status.c
Normal file
@ -0,0 +1,274 @@
|
||||
#include "wt-status.h"
|
||||
#include "color.h"
|
||||
#include "cache.h"
|
||||
#include "object.h"
|
||||
#include "dir.h"
|
||||
#include "commit.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "diffcore.h"
|
||||
|
||||
int wt_status_use_color = 0;
|
||||
static char wt_status_colors[][COLOR_MAXLEN] = {
|
||||
"", /* WT_STATUS_HEADER: normal */
|
||||
"\033[32m", /* WT_STATUS_UPDATED: green */
|
||||
"\033[31m", /* WT_STATUS_CHANGED: red */
|
||||
"\033[31m", /* WT_STATUS_UNTRACKED: red */
|
||||
};
|
||||
|
||||
static int parse_status_slot(const char *var, int offset)
|
||||
{
|
||||
if (!strcasecmp(var+offset, "header"))
|
||||
return WT_STATUS_HEADER;
|
||||
if (!strcasecmp(var+offset, "updated"))
|
||||
return WT_STATUS_UPDATED;
|
||||
if (!strcasecmp(var+offset, "changed"))
|
||||
return WT_STATUS_CHANGED;
|
||||
if (!strcasecmp(var+offset, "untracked"))
|
||||
return WT_STATUS_UNTRACKED;
|
||||
die("bad config variable '%s'", var);
|
||||
}
|
||||
|
||||
static const char* color(int slot)
|
||||
{
|
||||
return wt_status_use_color ? wt_status_colors[slot] : "";
|
||||
}
|
||||
|
||||
void wt_status_prepare(struct wt_status *s)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
const char *head;
|
||||
|
||||
s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0;
|
||||
|
||||
head = resolve_ref("HEAD", sha1, 0, NULL);
|
||||
s->branch = head ? xstrdup(head) : NULL;
|
||||
|
||||
s->reference = "HEAD";
|
||||
s->amend = 0;
|
||||
s->verbose = 0;
|
||||
s->commitable = 0;
|
||||
s->untracked = 0;
|
||||
}
|
||||
|
||||
static void wt_status_print_header(const char *main, const char *sub)
|
||||
{
|
||||
const char *c = color(WT_STATUS_HEADER);
|
||||
color_printf_ln(c, "# %s:", main);
|
||||
color_printf_ln(c, "# (%s)", sub);
|
||||
color_printf_ln(c, "#");
|
||||
}
|
||||
|
||||
static void wt_status_print_trailer(void)
|
||||
{
|
||||
color_printf_ln(color(WT_STATUS_HEADER), "#");
|
||||
}
|
||||
|
||||
static void wt_status_print_filepair(int t, struct diff_filepair *p)
|
||||
{
|
||||
const char *c = color(t);
|
||||
color_printf(color(WT_STATUS_HEADER), "#\t");
|
||||
switch (p->status) {
|
||||
case DIFF_STATUS_ADDED:
|
||||
color_printf(c, "new file: %s", p->one->path); break;
|
||||
case DIFF_STATUS_COPIED:
|
||||
color_printf(c, "copied: %s -> %s",
|
||||
p->one->path, p->two->path);
|
||||
break;
|
||||
case DIFF_STATUS_DELETED:
|
||||
color_printf(c, "deleted: %s", p->one->path); break;
|
||||
case DIFF_STATUS_MODIFIED:
|
||||
color_printf(c, "modified: %s", p->one->path); break;
|
||||
case DIFF_STATUS_RENAMED:
|
||||
color_printf(c, "renamed: %s -> %s",
|
||||
p->one->path, p->two->path);
|
||||
break;
|
||||
case DIFF_STATUS_TYPE_CHANGED:
|
||||
color_printf(c, "typechange: %s", p->one->path); break;
|
||||
case DIFF_STATUS_UNKNOWN:
|
||||
color_printf(c, "unknown: %s", p->one->path); break;
|
||||
case DIFF_STATUS_UNMERGED:
|
||||
color_printf(c, "unmerged: %s", p->one->path); break;
|
||||
default:
|
||||
die("bug: unhandled diff status %c", p->status);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void wt_status_print_updated_cb(struct diff_queue_struct *q,
|
||||
struct diff_options *options,
|
||||
void *data)
|
||||
{
|
||||
struct wt_status *s = data;
|
||||
int shown_header = 0;
|
||||
int i;
|
||||
if (q->nr) {
|
||||
}
|
||||
for (i = 0; i < q->nr; i++) {
|
||||
if (q->queue[i]->status == 'U')
|
||||
continue;
|
||||
if (!shown_header) {
|
||||
wt_status_print_header("Updated but not checked in",
|
||||
"will commit");
|
||||
s->commitable = 1;
|
||||
shown_header = 1;
|
||||
}
|
||||
wt_status_print_filepair(WT_STATUS_UPDATED, q->queue[i]);
|
||||
}
|
||||
if (shown_header)
|
||||
wt_status_print_trailer();
|
||||
}
|
||||
|
||||
static void wt_status_print_changed_cb(struct diff_queue_struct *q,
|
||||
struct diff_options *options,
|
||||
void *data)
|
||||
{
|
||||
int i;
|
||||
if (q->nr)
|
||||
wt_status_print_header("Changed but not updated",
|
||||
"use git-update-index to mark for commit");
|
||||
for (i = 0; i < q->nr; i++)
|
||||
wt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);
|
||||
if (q->nr)
|
||||
wt_status_print_trailer();
|
||||
}
|
||||
|
||||
void wt_status_print_initial(struct wt_status *s)
|
||||
{
|
||||
int i;
|
||||
read_cache();
|
||||
if (active_nr) {
|
||||
s->commitable = 1;
|
||||
wt_status_print_header("Updated but not checked in",
|
||||
"will commit");
|
||||
}
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
color_printf(color(WT_STATUS_HEADER), "#\t");
|
||||
color_printf_ln(color(WT_STATUS_UPDATED), "new file: %s",
|
||||
active_cache[i]->name);
|
||||
}
|
||||
if (active_nr)
|
||||
wt_status_print_trailer();
|
||||
}
|
||||
|
||||
static void wt_status_print_updated(struct wt_status *s)
|
||||
{
|
||||
struct rev_info rev;
|
||||
const char *argv[] = { NULL, NULL, NULL };
|
||||
argv[1] = s->reference;
|
||||
init_revisions(&rev, NULL);
|
||||
setup_revisions(2, argv, &rev, NULL);
|
||||
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
|
||||
rev.diffopt.format_callback = wt_status_print_updated_cb;
|
||||
rev.diffopt.format_callback_data = s;
|
||||
rev.diffopt.detect_rename = 1;
|
||||
run_diff_index(&rev, 1);
|
||||
}
|
||||
|
||||
static void wt_status_print_changed(struct wt_status *s)
|
||||
{
|
||||
struct rev_info rev;
|
||||
const char *argv[] = { NULL, NULL };
|
||||
init_revisions(&rev, "");
|
||||
setup_revisions(1, argv, &rev, NULL);
|
||||
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
|
||||
rev.diffopt.format_callback = wt_status_print_changed_cb;
|
||||
rev.diffopt.format_callback_data = s;
|
||||
run_diff_files(&rev, 0);
|
||||
}
|
||||
|
||||
static void wt_status_print_untracked(const struct wt_status *s)
|
||||
{
|
||||
struct dir_struct dir;
|
||||
const char *x;
|
||||
int i;
|
||||
int shown_header = 0;
|
||||
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
|
||||
dir.exclude_per_dir = ".gitignore";
|
||||
if (!s->untracked) {
|
||||
dir.show_other_directories = 1;
|
||||
dir.hide_empty_directories = 1;
|
||||
}
|
||||
x = git_path("info/exclude");
|
||||
if (file_exists(x))
|
||||
add_excludes_from_file(&dir, x);
|
||||
|
||||
read_directory(&dir, ".", "", 0);
|
||||
for(i = 0; i < dir.nr; i++) {
|
||||
/* check for matching entry, which is unmerged; lifted from
|
||||
* builtin-ls-files:show_other_files */
|
||||
struct dir_entry *ent = dir.entries[i];
|
||||
int pos = cache_name_pos(ent->name, ent->len);
|
||||
struct cache_entry *ce;
|
||||
if (0 <= pos)
|
||||
die("bug in wt_status_print_untracked");
|
||||
pos = -pos - 1;
|
||||
if (pos < active_nr) {
|
||||
ce = active_cache[pos];
|
||||
if (ce_namelen(ce) == ent->len &&
|
||||
!memcmp(ce->name, ent->name, ent->len))
|
||||
continue;
|
||||
}
|
||||
if (!shown_header) {
|
||||
wt_status_print_header("Untracked files",
|
||||
"use \"git add\" to add to commit");
|
||||
shown_header = 1;
|
||||
}
|
||||
color_printf(color(WT_STATUS_HEADER), "#\t");
|
||||
color_printf_ln(color(WT_STATUS_UNTRACKED), "%.*s",
|
||||
ent->len, ent->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void wt_status_print_verbose(struct wt_status *s)
|
||||
{
|
||||
struct rev_info rev;
|
||||
const char *argv[] = { NULL, NULL, NULL };
|
||||
argv[1] = s->reference;
|
||||
init_revisions(&rev, NULL);
|
||||
setup_revisions(2, argv, &rev, NULL);
|
||||
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
|
||||
rev.diffopt.detect_rename = 1;
|
||||
run_diff_index(&rev, 1);
|
||||
}
|
||||
|
||||
void wt_status_print(struct wt_status *s)
|
||||
{
|
||||
if (s->branch && strcmp(s->branch, "refs/heads/master"))
|
||||
color_printf_ln(color(WT_STATUS_HEADER),
|
||||
"# On branch %s", s->branch);
|
||||
|
||||
if (s->is_initial) {
|
||||
color_printf_ln(color(WT_STATUS_HEADER), "#");
|
||||
color_printf_ln(color(WT_STATUS_HEADER), "# Initial commit");
|
||||
color_printf_ln(color(WT_STATUS_HEADER), "#");
|
||||
wt_status_print_initial(s);
|
||||
}
|
||||
else {
|
||||
wt_status_print_updated(s);
|
||||
discard_cache();
|
||||
}
|
||||
|
||||
wt_status_print_changed(s);
|
||||
wt_status_print_untracked(s);
|
||||
|
||||
if (s->verbose && !s->is_initial)
|
||||
wt_status_print_verbose(s);
|
||||
if (!s->commitable)
|
||||
printf("%s\n", s->amend ? "# No changes" : "nothing to commit");
|
||||
}
|
||||
|
||||
int git_status_config(const char *k, const char *v)
|
||||
{
|
||||
if (!strcmp(k, "status.color")) {
|
||||
wt_status_use_color = git_config_colorbool(k, v);
|
||||
return 0;
|
||||
}
|
||||
if (!strncmp(k, "status.color.", 13)) {
|
||||
int slot = parse_status_slot(k, 13);
|
||||
color_parse(v, k, wt_status_colors[slot]);
|
||||
}
|
||||
return git_default_config(k, v);
|
||||
}
|
25
wt-status.h
Normal file
25
wt-status.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef STATUS_H
|
||||
#define STATUS_H
|
||||
|
||||
enum color_wt_status {
|
||||
WT_STATUS_HEADER,
|
||||
WT_STATUS_UPDATED,
|
||||
WT_STATUS_CHANGED,
|
||||
WT_STATUS_UNTRACKED,
|
||||
};
|
||||
|
||||
struct wt_status {
|
||||
int is_initial;
|
||||
char *branch;
|
||||
const char *reference;
|
||||
int commitable;
|
||||
int verbose;
|
||||
int amend;
|
||||
int untracked;
|
||||
};
|
||||
|
||||
int git_status_config(const char *var, const char *value);
|
||||
void wt_status_prepare(struct wt_status *s);
|
||||
void wt_status_print(struct wt_status *s);
|
||||
|
||||
#endif /* STATUS_H */
|
Loading…
Reference in New Issue
Block a user