git-bisect
git-blame
git-branch
+git-bundle
git-cat-file
git-check-ref-format
git-checkout
git-write-tree
git-core-*/?*
gitweb/gitweb.cgi
+test-chmtime
test-date
test-delta
test-dump-cache-tree
DOC_REF = origin/man
-include ../config.mak.autogen
+-include ../config.mak
#
# Please note that there is a minor bug in asciidoc.
--- /dev/null
+GIT v1.5.0.2 Release Notes
+==========================
+
+Fixes since v1.5.0.1
+--------------------
+
+* Bugfixes
+
+ - Automated merge conflict handling when changes to symbolic
+ links conflicted were completely broken. The merge-resolve
+ strategy created a regular file with conflict markers in it
+ in place of the symbolic link. The default strategy,
+ merge-recursive was even more broken. It removed the path
+ that was pointed at by the symbolic link. Both of these
+ problems have been fixed.
+
+ - 'git diff maint master next' did not correctly give combined
+ diff across three trees.
+
+ - 'git fast-import' portability fix for Solaris.
+
+ - 'git show-ref --verify' without arguments did not error out
+ but segfaulted.
+
+ - 'git diff :tracked-file `pwd`/an-untracked-file' gave an extra
+ slashes after a/ and b/.
+
+ - 'git format-patch' produced too long filenames if the commit
+ message had too long line at the beginning.
+
+ - Running 'make all' and then without changing anything
+ running 'make install' still rebuilt some files. This
+ was inconvenient when building as yourself and then
+ installing as root (especially problematic when the source
+ directory is on NFS and root is mapped to nobody).
+
+ - 'git-rerere' failed to deal with two unconflicted paths that
+ sorted next to each other.
+
+ - 'git-rerere' attempted to open(2) a symlink and failed if
+ there was a conflict. Since a conflicting change to a
+ symlink would not benefit from rerere anyway, the command
+ now ignores conflicting changes to symlinks.
+
+ - 'git-repack' did not like to pass more than 64 arguments
+ internally to underlying 'rev-list' logic, which made it
+ impossible to repack after accumulating many (small) packs
+ in the repository.
+
+ - 'git-diff' to review the combined diff during a conflicted
+ merge were not reading the working tree version correctly
+ when changes to a symbolic link conflicted. It should have
+ read the data using readlink(2) but read from the regular
+ file the symbolic link pointed at.
+
+ - 'git-remote' did not like period in a remote's name.
+
+* Documentation updates
+
+ - added and clarified core.bare, core.legacyheaders configurations.
+
+ - updated "git-clone --depth" documentation.
+
+
+* Assorted git-gui fixes.
--- /dev/null
+GIT v1.5.0.2 Release Notes
+==========================
+
+Fixes since v1.5.0.2
+--------------------
+
+* Bugfixes
+
+ - 'git.el' honors the commit coding system from the configuration.
+
+ - 'blameview' in contrib/ correctly digs deeper when a line is
+ clicked.
+
+ - 'http-push' correctly makes sure the remote side has leading
+ path. Earlier it started in the middle of the path, and
+ incorrectly.
+
+ - 'cvsexportcommit' does not lose yet-to-be-used message file.
+
+ - int-vs-size_t typefix when running combined diff on files
+ over 2GB long.
+
+ - 'git apply --whitespace=strip' should not touch unmodified
+ lines.
+
+ - 'git-mailinfo' choke when a logical header line was too long.
+
+ - 'git show A..B' did not error out. Negative ref ("not A" in
+ this example) does not make sense for the purpose of the
+ command, so now it errors out.
+
+ - 'git fmt-merge-msg --file' without file parameter did not
+ correctly error out.
+
+ - 'git archimport' barfed upon encountering a commit without
+ summary.
+
+ - 'git index-pack' did not protect itself from getting a short
+ read out of pread(2).
+
+* Documentation updates
+
+ - options to 'git remote add' were described insufficiently.
+
+
+---
+exec >/var/tmp/1
+O=v1.5.0.2
+O=v1.5.0.2-16-gdb554bf
+echo O=`git describe maint`
+git shortlog --no-merges $O..maint
+
+# Local Variables:
+# mode: text
+# End:
git-bisect mainporcelain
git-blame ancillaryinterrogators
git-branch mainporcelain
+git-bundle mainporcelain
git-cat-file plumbinginterrogators
git-checkout-index plumbingmanipulators
git-checkout mainporcelain
The default program to execute on the remote side when fetching. See
option \--exec of gitlink:git-fetch-pack[1].
+remote.<name>.tagopt::
+ Setting this value to --no-tags disables automatic tag following when fetching
+ from remote <name>
+
remotes.<group>::
The list of remotes which are fetched by "git remote update
<group>". See gitlink:git-remote[1].
--- /dev/null
+git-bundle(1)
+=============
+
+NAME
+----
+git-bundle - Move objects and refs by archive
+
+
+SYNOPSIS
+--------
+'git-bundle' create <file> [git-rev-list args]
+'git-bundle' verify <file>
+'git-bundle' list-heads <file> [refname...]
+'git-bundle' unbundle <file> [refname...]
+
+DESCRIPTION
+-----------
+
+Some workflows require that one or more branches of development on one
+machine be replicated on another machine, but the two machines cannot
+be directly connected so the interactive git protocols (git, ssh,
+rsync, http) cannot be used. This command provides suport for
+git-fetch and git-pull to operate by packaging objects and references
+in an archive at the originating machine, then importing those into
+another repository using gitlink:git-fetch[1] and gitlink:git-pull[1]
+after moving the archive by some means (i.e., by sneakernet). As no
+direct connection between repositories exists, the user must specify a
+basis for the bundle that is held by the destination repository: the
+bundle assumes that all objects in the basis are already in the
+destination repository.
+
+OPTIONS
+-------
+
+create <file>::
+ Used to create a bundle named 'file'. This requires the
+ git-rev-list arguments to define the bundle contents.
+
+verify <file>::
+ Used to check that a bundle file is valid and will apply
+ cleanly to the current repository. This includes checks on the
+ bundle format itself as well as checking that the prerequisite
+ commits exist and are fully linked in the current repository.
+ git-bundle prints a list of missing commits, if any, and exits
+ with non-zero status.
+
+list-heads <file>::
+ Lists the references defined in the bundle. If followed by a
+ list of references, only references matching those given are
+ printed out.
+
+unbundle <file>::
+ Passes the objects in the bundle to gitlink:git-index-pack[1]
+ for storage in the repository, then prints the names of all
+ defined references. If a reflist is given, only references
+ matching those in the given list are printed. This command is
+ really plumbing, intended to be called only by
+ gitlink:git-fetch[1].
+
+[git-rev-list-args...]::
+ A list of arguments, accepatble to git-rev-parse and
+ git-rev-list, that specify the specific objects and references
+ to transport. For example, "master~10..master" causes the
+ current master reference to be packaged along with all objects
+ added since its 10th ancestor commit. There is no explicit
+ limit to the number of references and objects that may be
+ packaged.
+
+
+[refname...]::
+ A list of references used to limit the references reported as
+ available. This is principally of use to git-fetch, which
+ expects to recieve only those references asked for and not
+ necessarily everything in the pack (in this case, git-bundle is
+ acting like gitlink:git-fetch-pack[1]).
+
+SPECIFYING REFERENCES
+---------------------
+
+git-bundle will only package references that are shown by
+git-show-ref: this includes heads, tags, and remote heads. References
+such as master~1 cannot be packaged, but are perfectly suitable for
+defining the basis. More than one reference may be packaged, and more
+than one basis can be specified. The objects packaged are those not
+contained in the union of the given bases. Each basis can be
+specified explicitly (e.g., ^master~10), or implicitly (e.g.,
+master~10..master, master --since=10.days.ago).
+
+It is very important that the basis used be held by the destination.
+It is ok to err on the side of conservatism, causing the bundle file
+to contain objects already in the destination as these are ignored
+when unpacking at the destination.
+
+EXAMPLE
+-------
+
+Assume two repositories exist as R1 on machine A, and R2 on machine B.
+For whatever reason, direct connection between A and B is not allowed,
+but we can move data from A to B via some mechanism (CD, email, etc).
+We want to update R2 with developments made on branch master in R1.
+We set a tag in R1 (lastR2bundle) after the previous such transport,
+and move it afterwards to help build the bundle.
+
+in R1 on A:
+$ git-bundle create mybundle master ^lastR2bundle
+$ git tag -f lastR2bundle master
+
+(move mybundle from A to B by some mechanism)
+
+in R2 on B:
+$ git-bundle verify mybundle
+$ git-fetch mybundle refspec
+
+where refspec is refInBundle:localRef
+
+
+Also, with something like this in your config:
+
+[remote "bundle"]
+ url = /home/me/tmp/file.bdl
+ fetch = refs/heads/*:refs/remotes/origin/*
+
+You can first sneakernet the bundle file to ~/tmp/file.bdl and
+then these commands:
+
+$ git ls-remote bundle
+$ git fetch bundle
+$ git pull bundle
+
+would treat it as if it is talking with a remote side over the
+network.
+
+Author
+------
+Written by Mark Levedahl <mdl123@verizon.net>
+
+GIT
+---
+Part of the gitlink:git[7] suite
-s <subst>::
Substitute the character "/" in branch names with <subst>
--A <author-conv-file>::
- CVS by default uses the Unix username when writing its
- commit logs. Using this option and an author-conv-file
- in this format
-
-a::
Import all commits, including recent ones. cvsimport by default
skips commits that have a timestamp less than 10 minutes ago.
Limit the number of commits imported. Workaround for cases where
cvsimport leaks memory.
+-A <author-conv-file>::
+ CVS by default uses the Unix username when writing its
+ commit logs. Using this option and an author-conv-file
+ in this format
+
---------
exon=Andreas Ericsson <ae@op5.se>
SYNOPSIS
--------
-'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc] [<common diff options>] [<path>...]
+'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc|-n|--no-index] [<common diff options>] [<path>...]
DESCRIPTION
-----------
diff, similar to the way 'diff-tree' shows a merge
commit with these flags.
+\-n,\--no-index::
+ Compare the two given files / directories.
+
-q::
Remain silent even on nonexistent files
further add to the index but you still haven't. You can
stage these changes by using gitlink:git-add[1].
+ If exactly two paths are given, and at least one is untracked,
+ compare the two files / directories. This behavior can be
+ forced by --no-index.
+
'git-diff' [--options] --cached [<commit>] [--] [<path>...]::
This form is to view the changes you staged for the next
--------
[verse]
'git-remote'
-'git-remote' add <name> <url>
+'git-remote' add [-t <branch>] [-m <branch>] [-f] <name> <url>
'git-remote' show <name>
'git-remote' prune <name>
'git-remote' update [group]
Adds a remote named <name> for the repository at
<url>. The command `git fetch <name>` can then be used to create and
update remote-tracking branches <name>/<branch>.
++
+With `-f` option, `git fetch <name>` is run immediately after
+the remote information is set up.
++
+With `-t <branch>` option, instead of the default glob
+refspec for the remote to track all branches under
+`$GIT_DIR/remotes/<name>/`, a refspec to track only `<branch>`
+is created. You can give more than one `-t <branch>` to track
+multiple branche without grabbing all branches.
++
+With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
+up to point at remote's `<master>` branch instead of whatever
+branch the `HEAD` at the remote repository actually points at.
'show'::
Examples
--------
-Add a new remote, fetch, and check out a branch from it:
-
+* Add a new remote, fetch, and check out a branch from it
++
------------
$ git remote
origin
...
------------
+* Imitate 'git clone' but track only selected branches
++
+------------
+$ mkdir project.git
+$ cd project.git
+$ git init
+$ git remote add -f -t master -m master origin git://example.com/git.git/
+$ git merge origin
+------------
+
+
See Also
--------
gitlink:git-fetch[1]
Shows the tag `v1.0.0`, along with the object the tags
points at.
-git show v1.0.0^{tree}::
+git show v1.0.0^\{tree\}::
Shows the tree pointed to by the tag `v1.0.0`.
-git show next~10:Documentation/README
+git show next~10:Documentation/README::
Shows the contents of the file `Documentation/README` as
they were current in the 10th last commit of the branch
`next`.
-git show master:Makefile master:t/Makefile
+git show master:Makefile master:t/Makefile::
Concatenates the contents of said Makefiles in the head
of the branch `master`.
You are reading the documentation for the latest version of git.
Documentation for older releases are available here:
-* link:v1.5.0.1/git.html[documentation for release 1.5.0.1]
+* link:v1.5.0.2/git.html[documentation for release 1.5.0.2]
+
+* link:v1.5.0.2/RelNotes-1.5.0.2.txt[release notes for 1.5.0.2]
* link:v1.5.0.1/RelNotes-1.5.0.1.txt[release notes for 1.5.0.1]
_________________
This manual is designed to be readable by someone with basic unix
-commandline skills, but no previous knowledge of git.
+command-line skills, but no previous knowledge of git.
Chapter 1 gives a brief overview of git commands, without any
explanation; you may prefer to skip to chapter 2 on a first reading.
tip of the other branch, which is stored temporarily in MERGE_HEAD.
The diff above shows the differences between the working-tree version
-of file.txt and two previous version: one version from HEAD, and one
+of file.txt and two previous versions: one version from HEAD, and one
from MERGE_HEAD. So instead of preceding each line by a single "+"
or "-", it now uses two columns: the first column is used for
differences between the first parent and the working directory copy,
In some situations the reflog may not be able to save you. For
example, suppose you delete a branch, then realize you need the history
-it pointed you. The reflog is also deleted; however, if you have not
+it contained. The reflog is also deleted; however, if you have not
yet pruned the repository, then you may still be able to find
the lost commits; run git-fsck and watch for output that mentions
"dangling commits":
you get exactly the history reachable from that commit that is lost.
(And notice that it might not be just one commit: we only report the
"tip of the line" as being dangling, but there might be a whole deep
-and complex commit history that was gotten dropped.)
+and complex commit history that was dropped.)
If you decide you want the history back, you can always create a new
reference pointing to it, for example, a new branch:
(But note that no such commit will be created in the case of a
<<fast-forwards,fast forward>>; instead, your branch will just be
-updated to point to the latest commit from the upstream branch).
+updated to point to the latest commit from the upstream branch.)
The git-pull command can also be given "." as the "remote" repository,
in which case it just merges in a branch from the current repository; so
If you and maintainer both have accounts on the same machine, then
then you can just pull changes from each other's repositories
-directly; note that all of the command (gitlink:git-clone[1],
-git-fetch[1], git-pull[1], etc.) which accept a URL as an argument
+directly; note that all of the commands (gitlink:git-clone[1],
+git-fetch[1], git-pull[1], etc.) that accept a URL as an argument
will also accept a local file patch; so, for example, you can
use
correct, and understand why you made each change.
If you present all of your changes as a single patch (or commit), they
-may find it is too much to digest all at once.
+may find that it is too much to digest all at once.
If you present them with the entire history of your work, complete with
mistakes, corrections, and dead ends, they may be overwhelmed.
Keeping a patch series up to date using git-rebase
--------------------------------------------------
-Suppose you have a series of commits in a branch "mywork", which
-originally branched off from "origin".
-
-Suppose you create a branch "mywork" on a remote-tracking branch
-"origin", and created some commits on top of it:
+Suppose that you create a branch "mywork" on a remote-tracking branch
+"origin", and create some commits on top of it:
-------------------------------------------------
$ git checkout -b mywork origin
-----------
There are numerous other tools, such as stgit, which exist for the
-purpose of maintaining a patch series. These are out of the scope of
+purpose of maintaining a patch series. These are outside of the scope of
this manual.
Problems with rewriting history
$ git fetch git://example.com/proj.git +master:refs/remotes/example/master
-------------------------------------------------
-Note the addition of the "+" sign. Be aware that commits which the
+Note the addition of the "+" sign. Be aware that commits that the
old version of example/master pointed at may be lost, as we saw in
the previous section.
---------------------------
We saw above that "origin" is just a shortcut to refer to the
-repository which you originally cloned from. This information is
+repository that you originally cloned from. This information is
stored in git configuration variables, which you can see using
gitlink:git-config[1]:
associated with sufficient information about the trees involved that
you can create a three-way merge between them.'
-Those are the three ONLY things that the directory cache does. It's a
+Those are the ONLY three things that the directory cache does. It's a
cache, and the normal operation is to re-generate it completely from a
known tree object, or update/compare it with a live tree that is being
developed. If you blow the directory cache away entirely, you generally
builtin-archive.o \
builtin-blame.o \
builtin-branch.o \
+ builtin-bundle.o \
builtin-cat-file.o \
builtin-checkout-index.o \
builtin-check-ref-format.o \
export NO_SVN_TESTS
-test: all
+test: all test-chmtime$X
$(MAKE) -C t/ all
test-date$X: test-date.c date.o ctype.o
test-sha1$X: test-sha1.o $(GITLIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+test-chmtime$X: test-chmtime.c
+ $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $<
+
check-sha1:: test-sha1$X
./test-sha1.sh
static struct strbuf path;
int filenamelen = strlen(filename);
void *buffer;
- char type[20];
+ enum object_type type;
unsigned long size;
if (!path.alloc) {
buffer = NULL;
size = 0;
} else {
- buffer = read_sha1_file(sha1, type, &size);
+ buffer = read_sha1_file(sha1, &type, &size);
if (!buffer)
die("cannot read %s", sha1_to_hex(sha1));
}
int pathlen;
unsigned char *out;
char *path;
- char type[20];
+ enum object_type type;
void *buffer = NULL;
void *deflated = NULL;
if (S_ISREG(mode) && zlib_compression_level != 0)
method = 8;
result = 0;
- buffer = read_sha1_file(sha1, type, &size);
+ buffer = read_sha1_file(sha1, &type, &size);
if (!buffer)
die("cannot read %s", sha1_to_hex(sha1));
crc = crc32(crc, buffer, size);
int parse_blob(struct blob *item)
{
- char type[20];
+ enum object_type type;
void *buffer;
unsigned long size;
int ret;
if (item->object.parsed)
return 0;
- buffer = read_sha1_file(item->object.sha1, type, &size);
+ buffer = read_sha1_file(item->object.sha1, &type, &size);
if (!buffer)
return error("Could not read %s",
sha1_to_hex(item->object.sha1));
- if (strcmp(type, blob_type))
+ if (type != OBJ_BLOB)
return error("Object %s not a blob",
sha1_to_hex(item->object.sha1));
ret = parse_blob_buffer(item, buffer, size);
int need_fix_leading_space = 0;
char *buf;
- if ((new_whitespace != strip_whitespace) || !whitespace_error) {
+ if ((new_whitespace != strip_whitespace) || !whitespace_error ||
+ *patch != '+') {
memcpy(output, patch + 1, plen);
return plen;
}
if (has_sha1_file(sha1)) {
/* We already have the postimage */
- char type[10];
+ enum object_type type;
unsigned long size;
free(desc->buffer);
- desc->buffer = read_sha1_file(sha1, type, &size);
+ desc->buffer = read_sha1_file(sha1, &type, &size);
if (!desc->buffer)
return error("the necessary postimage %s for "
"'%s' cannot be read",
buf = NULL;
if (cached) {
if (ce) {
- char type[20];
- buf = read_sha1_file(ce->sha1, type, &size);
+ enum object_type type;
+ buf = read_sha1_file(ce->sha1, &type, &size);
if (!buf)
return error("read of %s failed",
patch->old_name);
static char *fill_origin_blob(struct origin *o, mmfile_t *file)
{
if (!o->file.ptr) {
- char type[10];
+ enum object_type type;
num_read_blob++;
- file->ptr = read_sha1_file(o->blob_sha1, type,
+ file->ptr = read_sha1_file(o->blob_sha1, &type,
(unsigned long *)(&(file->size)));
o->file = *file;
}
static int fill_blob_sha1(struct origin *origin)
{
unsigned mode;
- char type[10];
if (!is_null_sha1(origin->blob_sha1))
return 0;
origin->path,
origin->blob_sha1, &mode))
goto error_out;
- if (sha1_object_info(origin->blob_sha1, type, NULL) ||
- strcmp(type, blob_type))
+ if (sha1_object_info(origin->blob_sha1, NULL) != OBJ_BLOB)
goto error_out;
return 0;
error_out:
* we now need to populate them for output.
*/
if (!commit->buffer) {
- char type[20];
+ enum object_type type;
unsigned long size;
commit->buffer =
- read_sha1_file(commit->object.sha1, type, &size);
+ read_sha1_file(commit->object.sha1, &type, &size);
}
ret->author = author_buf;
get_ac_line(commit->buffer, "\nauthor ",
buf[fin_size] = 0;
origin->file.ptr = buf;
origin->file.size = fin_size;
- pretend_sha1_file(buf, fin_size, blob_type, origin->blob_sha1);
+ pretend_sha1_file(buf, fin_size, OBJ_BLOB, origin->blob_sha1);
commit->util = origin;
/*
int show_stats = 0;
const char *revs_file = NULL;
const char *final_commit_name = NULL;
- char type[10];
+ enum object_type type;
const char *bottomtop = NULL;
const char *contents_from = NULL;
if (fill_blob_sha1(o))
die("no such path %s in %s", path, final_commit_name);
- sb.final_buf = read_sha1_file(o->blob_sha1, type,
+ sb.final_buf = read_sha1_file(o->blob_sha1, &type,
&sb.final_buf_size);
}
num_read_blob++;
--- /dev/null
+#include "cache.h"
+#include "object.h"
+#include "commit.h"
+#include "diff.h"
+#include "revision.h"
+#include "list-objects.h"
+#include "exec_cmd.h"
+
+/*
+ * Basic handler for bundle files to connect repositories via sneakernet.
+ * Invocation must include action.
+ * This function can create a bundle or provide information on an existing
+ * bundle supporting git-fetch, git-pull, and git-ls-remote
+ */
+
+static const char *bundle_usage="git-bundle (create <bundle> <git-rev-list args> | verify <bundle> | list-heads <bundle> [refname]... | unbundle <bundle> [refname]... )";
+
+static const char bundle_signature[] = "# v2 git bundle\n";
+
+struct ref_list {
+ unsigned int nr, alloc;
+ struct ref_list_entry {
+ unsigned char sha1[20];
+ char *name;
+ } *list;
+};
+
+static void add_to_ref_list(const unsigned char *sha1, const char *name,
+ struct ref_list *list)
+{
+ if (list->nr + 1 >= list->alloc) {
+ list->alloc = alloc_nr(list->nr + 1);
+ list->list = xrealloc(list->list,
+ list->alloc * sizeof(list->list[0]));
+ }
+ memcpy(list->list[list->nr].sha1, sha1, 20);
+ list->list[list->nr].name = xstrdup(name);
+ list->nr++;
+}
+
+struct bundle_header {
+ struct ref_list prerequisites;
+ struct ref_list references;
+};
+
+/* this function returns the length of the string */
+static int read_string(int fd, char *buffer, int size)
+{
+ int i;
+ for (i = 0; i < size - 1; i++) {
+ int count = xread(fd, buffer + i, 1);
+ if (count < 0)
+ return error("Read error: %s", strerror(errno));
+ if (count == 0) {
+ i--;
+ break;
+ }
+ if (buffer[i] == '\n')
+ break;
+ }
+ buffer[i + 1] = '\0';
+ return i + 1;
+}
+
+/* returns an fd */
+static int read_header(const char *path, struct bundle_header *header) {
+ char buffer[1024];
+ int fd = open(path, O_RDONLY);
+
+ if (fd < 0)
+ return error("could not open '%s'", path);
+ if (read_string(fd, buffer, sizeof(buffer)) < 0 ||
+ strcmp(buffer, bundle_signature)) {
+ close(fd);
+ return error("'%s' does not look like a v2 bundle file", path);
+ }
+ while (read_string(fd, buffer, sizeof(buffer)) > 0
+ && buffer[0] != '\n') {
+ int is_prereq = buffer[0] == '-';
+ int offset = is_prereq ? 1 : 0;
+ int len = strlen(buffer);
+ unsigned char sha1[20];
+ struct ref_list *list = is_prereq ? &header->prerequisites
+ : &header->references;
+ char delim;
+
+ if (buffer[len - 1] == '\n')
+ buffer[len - 1] = '\0';
+ if (get_sha1_hex(buffer + offset, sha1)) {
+ warn("unrecognized header: %s", buffer);
+ continue;
+ }
+ delim = buffer[40 + offset];
+ if (!isspace(delim) && (delim != '\0' || !is_prereq))
+ die ("invalid header: %s", buffer);
+ add_to_ref_list(sha1, isspace(delim) ?
+ buffer + 41 + offset : "", list);
+ }
+ return fd;
+}
+
+/* if in && *in >= 0, take that as input file descriptor instead */
+static int fork_with_pipe(const char **argv, int *in, int *out)
+{
+ int needs_in, needs_out;
+ int fdin[2], fdout[2], pid;
+
+ needs_in = in && *in < 0;
+ if (needs_in) {
+ if (pipe(fdin) < 0)
+ return error("could not setup pipe");
+ *in = fdin[1];
+ }
+
+ needs_out = out && *out < 0;
+ if (needs_out) {
+ if (pipe(fdout) < 0)
+ return error("could not setup pipe");
+ *out = fdout[0];
+ }
+
+ if ((pid = fork()) < 0) {
+ if (needs_in) {
+ close(fdin[0]);
+ close(fdin[1]);
+ }
+ if (needs_out) {
+ close(fdout[0]);
+ close(fdout[1]);
+ }
+ return error("could not fork");
+ }
+ if (!pid) {
+ if (needs_in) {
+ dup2(fdin[0], 0);
+ close(fdin[0]);
+ close(fdin[1]);
+ } else if (in) {
+ dup2(*in, 0);
+ close(*in);
+ }
+ if (needs_out) {
+ dup2(fdout[1], 1);
+ close(fdout[0]);
+ close(fdout[1]);
+ } else if (out) {
+ dup2(*out, 1);
+ close(*out);
+ }
+ exit(execv_git_cmd(argv));
+ }
+ if (needs_in)
+ close(fdin[0]);
+ else if (in)
+ close(*in);
+ if (needs_out)
+ close(fdout[1]);
+ else if (out)
+ close(*out);
+ return pid;
+}
+
+static int verify_bundle(struct bundle_header *header)
+{
+ /*
+ * Do fast check, then if any prereqs are missing then go line by line
+ * to be verbose about the errors
+ */
+ struct ref_list *p = &header->prerequisites;
+ struct rev_info revs;
+ const char *argv[] = {NULL, "--all"};
+ struct object_array refs;
+ struct commit *commit;
+ int i, ret = 0, req_nr;
+ const char *message = "Repository lacks these prerequisite commits:";
+
+ init_revisions(&revs, NULL);
+ for (i = 0; i < p->nr; i++) {
+ struct ref_list_entry *e = p->list + i;
+ struct object *o = parse_object(e->sha1);
+ if (o) {
+ o->flags |= BOUNDARY_SHOW;
+ add_pending_object(&revs, o, e->name);
+ continue;
+ }
+ if (++ret == 1)
+ error(message);
+ error("%s %s", sha1_to_hex(e->sha1), e->name);
+ }
+ if (revs.pending.nr == 0)
+ return ret;
+ req_nr = revs.pending.nr;
+ setup_revisions(2, argv, &revs, NULL);
+
+ memset(&refs, 0, sizeof(struct object_array));
+ for (i = 0; i < revs.pending.nr; i++) {
+ struct object_array_entry *e = revs.pending.objects + i;
+ add_object_array(e->item, e->name, &refs);
+ }
+
+ prepare_revision_walk(&revs);
+
+ i = req_nr;
+ while (i && (commit = get_revision(&revs)))
+ if (commit->object.flags & BOUNDARY_SHOW)
+ i--;
+
+ for (i = 0; i < req_nr; i++)
+ if (!(refs.objects[i].item->flags & SHOWN)) {
+ if (++ret == 1)
+ error(message);
+ error("%s %s", sha1_to_hex(refs.objects[i].item->sha1),
+ refs.objects[i].name);
+ }
+
+ for (i = 0; i < refs.nr; i++)
+ clear_commit_marks((struct commit *)refs.objects[i].item, -1);
+
+ return ret;
+}
+
+static int list_heads(struct bundle_header *header, int argc, const char **argv)
+{
+ int i;
+ struct ref_list *r = &header->references;
+
+ for (i = 0; i < r->nr; i++) {
+ if (argc > 1) {
+ int j;
+ for (j = 1; j < argc; j++)
+ if (!strcmp(r->list[i].name, argv[j]))
+ break;
+ if (j == argc)
+ continue;
+ }
+ printf("%s %s\n", sha1_to_hex(r->list[i].sha1),
+ r->list[i].name);
+ }
+ return 0;
+}
+
+static void show_commit(struct commit *commit)
+{
+ write_or_die(1, sha1_to_hex(commit->object.sha1), 40);
+ write_or_die(1, "\n", 1);
+ if (commit->parents) {
+ free_commit_list(commit->parents);
+ commit->parents = NULL;
+ }
+}
+
+static void show_object(struct object_array_entry *p)
+{
+ /* An object with name "foo\n0000000..." can be used to
+ * confuse downstream git-pack-objects very badly.
+ */
+ const char *ep = strchr(p->name, '\n');
+ int len = ep ? ep - p->name : strlen(p->name);
+ write_or_die(1, sha1_to_hex(p->item->sha1), 40);
+ write_or_die(1, " ", 1);
+ if (len)
+ write_or_die(1, p->name, len);
+ write_or_die(1, "\n", 1);
+}
+
+static int create_bundle(struct bundle_header *header, const char *path,
+ int argc, const char **argv)
+{
+ int bundle_fd = -1;
+ const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *));
+ const char **argv_pack = xmalloc(4 * sizeof(const char *));
+ int pid, in, out, i, status;
+ char buffer[1024];
+ struct rev_info revs;
+
+ bundle_fd = (!strcmp(path, "-") ? 1 :
+ open(path, O_CREAT | O_WRONLY, 0666));
+ if (bundle_fd < 0)
+ return error("Could not write to '%s'", path);
+
+ /* write signature */
+ write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature));
+
+ /* write prerequisites */
+ memcpy(argv_boundary + 3, argv + 1, argc * sizeof(const char *));
+ argv_boundary[0] = "rev-list";
+ argv_boundary[1] = "--boundary";
+ argv_boundary[2] = "--pretty=oneline";
+ argv_boundary[argc + 2] = NULL;
+ out = -1;
+ pid = fork_with_pipe(argv_boundary, NULL, &out);
+ if (pid < 0)
+ return -1;
+ while ((i = read_string(out, buffer, sizeof(buffer))) > 0)
+ if (buffer[0] == '-')
+ write_or_die(bundle_fd, buffer, i);
+ while ((i = waitpid(pid, &status, 0)) < 0)
+ if (errno != EINTR)
+ return error("rev-list died");
+ if (!WIFEXITED(status) || WEXITSTATUS(status))
+ return error("rev-list died %d", WEXITSTATUS(status));
+
+ /* write references */
+ save_commit_buffer = 0;
+ init_revisions(&revs, NULL);
+ revs.tag_objects = 1;
+ revs.tree_objects = 1;
+ revs.blob_objects = 1;
+ argc = setup_revisions(argc, argv, &revs, NULL);
+ if (argc > 1)
+ return error("unrecognized argument: %s'", argv[1]);
+ for (i = 0; i < revs.pending.nr; i++) {
+ struct object_array_entry *e = revs.pending.objects + i;
+ if (!(e->item->flags & UNINTERESTING)) {
+ unsigned char sha1[20];
+ char *ref;
+ if (dwim_ref(e->name, strlen(e->name), sha1, &ref) != 1)
+ continue;
+ write_or_die(bundle_fd, sha1_to_hex(e->item->sha1), 40);
+ write_or_die(bundle_fd, " ", 1);
+ write_or_die(bundle_fd, ref, strlen(ref));
+ write_or_die(bundle_fd, "\n", 1);
+ free(ref);
+ }
+ }
+
+ /* end header */
+ write_or_die(bundle_fd, "\n", 1);
+
+ /* write pack */
+ argv_pack[0] = "pack-objects";
+ argv_pack[1] = "--all-progress";
+ argv_pack[2] = "--stdout";
+ argv_pack[3] = NULL;
+ in = -1;
+ out = bundle_fd;
+ pid = fork_with_pipe(argv_pack, &in, &out);
+ if (pid < 0)
+ return error("Could not spawn pack-objects");
+ close(1);
+ dup2(in, 1);
+ close(in);
+ prepare_revision_walk(&revs);
+ traverse_commit_list(&revs, show_commit, show_object);
+ close(1);
+ while (waitpid(pid, &status, 0) < 0)
+ if (errno != EINTR)
+ return -1;
+ if (!WIFEXITED(status) || WEXITSTATUS(status))
+ return error ("pack-objects died");
+ return 0;
+}
+
+static int unbundle(struct bundle_header *header, int bundle_fd,
+ int argc, const char **argv)
+{
+ const char *argv_index_pack[] = {"index-pack", "--stdin", NULL};
+ int pid, status, dev_null;
+
+ if (verify_bundle(header))
+ return -1;
+ dev_null = open("/dev/null", O_WRONLY);
+ pid = fork_with_pipe(argv_index_pack, &bundle_fd, &dev_null);
+ if (pid < 0)
+ return error("Could not spawn index-pack");
+ while (waitpid(pid, &status, 0) < 0)
+ if (errno != EINTR)
+ return error("index-pack died");
+ if (!WIFEXITED(status) || WEXITSTATUS(status))
+ return error("index-pack exited with status %d",
+ WEXITSTATUS(status));
+ return list_heads(header, argc, argv);
+}
+
+int cmd_bundle(int argc, const char **argv, const char *prefix)
+{
+ struct bundle_header header;
+ int nongit = 0;
+ const char *cmd, *bundle_file;
+ int bundle_fd = -1;
+ char buffer[PATH_MAX];
+
+ if (argc < 3)
+ usage(bundle_usage);
+
+ cmd = argv[1];
+ bundle_file = argv[2];
+ argc -= 2;
+ argv += 2;
+
+ prefix = setup_git_directory_gently(&nongit);
+ if (prefix && bundle_file[0] != '/') {
+ snprintf(buffer, sizeof(buffer), "%s/%s", prefix, bundle_file);
+ bundle_file = buffer;
+ }
+
+ memset(&header, 0, sizeof(header));
+ if (strcmp(cmd, "create") &&
+ !(bundle_fd = read_header(bundle_file, &header)))
+ return 1;
+
+ if (!strcmp(cmd, "verify")) {
+ close(bundle_fd);
+ if (verify_bundle(&header))
+ return 1;
+ fprintf(stderr, "%s is okay\n", bundle_file);
+ return 0;
+ }
+ if (!strcmp(cmd, "list-heads")) {
+ close(bundle_fd);
+ return !!list_heads(&header, argc, argv);
+ }
+ if (!strcmp(cmd, "create")) {
+ if (nongit)
+ die("Need a repository to create a bundle.");
+ return !!create_bundle(&header, bundle_file, argc, argv);
+ } else if (!strcmp(cmd, "unbundle")) {
+ if (nongit)
+ die("Need a repository to unbundle.");
+ return !!unbundle(&header, bundle_fd, argc, argv);
+ } else
+ usage(bundle_usage);
+}
+
int cmd_cat_file(int argc, const char **argv, const char *prefix)
{
unsigned char sha1[20];
- char type[20];
+ enum object_type type;
void *buf;
unsigned long size;
int opt;
buf = NULL;
switch (opt) {
case 't':
- if (!sha1_object_info(sha1, type, NULL)) {
- printf("%s\n", type);
+ type = sha1_object_info(sha1, NULL);
+ if (type > 0) {
+ printf("%s\n", typename(type));
return 0;
}
break;
case 's':
- if (!sha1_object_info(sha1, type, &size)) {
+ type = sha1_object_info(sha1, &size);
+ if (type > 0) {
printf("%lu\n", size);
return 0;
}
return !has_sha1_file(sha1);
case 'p':
- if (sha1_object_info(sha1, type, NULL))
+ type = sha1_object_info(sha1, NULL);
+ if (type < 0)
die("Not a valid object name %s", argv[2]);
/* custom pretty-print here */
- if (!strcmp(type, tree_type))
+ if (type == OBJ_TREE)
return cmd_ls_tree(2, argv + 1, NULL);
- buf = read_sha1_file(sha1, type, &size);
+ buf = read_sha1_file(sha1, &type, &size);
if (!buf)
die("Cannot read object %s", argv[2]);
- if (!strcmp(type, tag_type)) {
+ if (type == OBJ_TAG) {
pprint_tag(sha1, buf, size);
return 0;
}
memcpy(buf + size, one_line, len);
}
-static void check_valid(unsigned char *sha1, const char *expect)
+static void check_valid(unsigned char *sha1, enum object_type expect)
{
- char type[20];
-
- if (sha1_object_info(sha1, type, NULL))
+ enum object_type type = sha1_object_info(sha1, NULL);
+ if (type < 0)
die("%s is not a valid object", sha1_to_hex(sha1));
- if (expect && strcmp(type, expect))
+ if (type != expect)
die("%s is not a valid '%s' object", sha1_to_hex(sha1),
- expect);
+ typename(expect));
}
/*
if (get_sha1(argv[1], tree_sha1))
die("Not a valid object name %s", argv[1]);
- check_valid(tree_sha1, tree_type);
+ check_valid(tree_sha1, OBJ_TREE);
for (i = 2; i < argc; i += 2) {
const char *a, *b;
a = argv[i]; b = argv[i+1];
die("Too many parents (%d max)", MAXPARENT);
if (get_sha1(b, parent_sha1[parents]))
die("Not a valid object name %s", b);
- check_valid(parent_sha1[parents], commit_type);
+ check_valid(parent_sha1[parents], OBJ_COMMIT);
if (new_parent(parents))
parents++;
}
#include "builtin.h"
static const char diff_files_usage[] =
-"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
+"git-diff-files [-q] [-0/-1/2/3 |-c|--cc|-n|--no-index] [<common diff options>] [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
int cmd_diff_files(int argc, const char **argv, const char *prefix)
{
struct rev_info rev;
- int silent = 0;
+ int nongit = 0;
+ prefix = setup_git_directory_gently(&nongit);
init_revisions(&rev, prefix);
git_config(git_default_config); /* no "diff" UI options */
rev.abbrev = 0;
argc = setup_revisions(argc, argv, &rev, NULL);
- while (1 < argc && argv[1][0] == '-') {
- if (!strcmp(argv[1], "--base"))
- rev.max_count = 1;
- else if (!strcmp(argv[1], "--ours"))
- rev.max_count = 2;
- else if (!strcmp(argv[1], "--theirs"))
- rev.max_count = 3;
- else if (!strcmp(argv[1], "-q"))
- silent = 1;
- else
- usage(diff_files_usage);
- argv++; argc--;
- }
if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW;
-
- /*
- * Make sure there are NO revision (i.e. pending object) parameter,
- * rev.max_count is reasonable (0 <= n <= 3),
- * there is no other revision filtering parameters.
- */
- if (rev.pending.nr ||
- rev.min_age != -1 || rev.max_age != -1)
- usage(diff_files_usage);
- return run_diff_files(&rev, silent);
+ return run_diff_files_cmd(&rev, argc, argv);
}
if (rev.pending.nr != 1 ||
rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
usage(diff_cache_usage);
+ if (read_cache() < 0) {
+ perror("read_cache");
+ return -1;
+ }
return run_diff_index(&rev, cached);
}
static const char builtin_diff_usage[] =
"git-diff <options> <rev>{0,2} -- <path>*";
-static int builtin_diff_files(struct rev_info *revs,
- int argc, const char **argv)
-{
- int silent = 0;
- while (1 < argc) {
- const char *arg = argv[1];
- if (!strcmp(arg, "--base"))
- revs->max_count = 1;
- else if (!strcmp(arg, "--ours"))
- revs->max_count = 2;
- else if (!strcmp(arg, "--theirs"))
- revs->max_count = 3;
- else if (!strcmp(arg, "-q"))
- silent = 1;
- else
- usage(builtin_diff_usage);
- argv++; argc--;
- }
- /*
- * Make sure there are NO revision (i.e. pending object) parameter,
- * specified rev.max_count is reasonable (0 <= n <= 3), and
- * there is no other revision filtering parameter.
- */
- if (revs->pending.nr ||
- revs->min_age != -1 ||
- revs->max_age != -1 ||
- 3 < revs->max_count)
- usage(builtin_diff_usage);
- if (revs->max_count < 0 &&
- (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
- revs->combine_merges = revs->dense_combined_merges = 1;
- return run_diff_files(revs, silent);
-}
-
static void stuff_change(struct diff_options *opt,
unsigned old_mode, unsigned new_mode,
const unsigned char *old_sha1,
revs->max_count != -1 || revs->min_age != -1 ||
revs->max_age != -1)
usage(builtin_diff_usage);
+ if (read_cache() < 0) {
+ perror("read_cache");
+ return -1;
+ }
return run_diff_index(revs, cached);
}
int ents = 0, blobs = 0, paths = 0;
const char *path = NULL;
struct blobinfo blob[2];
+ int nongit = 0;
/*
* We could get N tree-ish in the rev.pending_objects list.
* Other cases are errors.
*/
+ prefix = setup_git_directory_gently(&nongit);
git_config(git_diff_ui_config);
init_revisions(&rev, prefix);
break;
else if (!strcmp(arg, "--cached")) {
add_head(&rev);
+ if (!rev.pending.nr)
+ die("No HEAD commit to compare with (yet)");
break;
}
}
if (!ents) {
switch (blobs) {
case 0:
- return builtin_diff_files(&rev, argc, argv);
+ return run_diff_files_cmd(&rev, argc, argv);
break;
case 1:
if (paths != 1)
else if (!strcmp(argv[1], "--no-summary"))
merge_summary = 0;
else if (!strcmp(argv[1], "-F") || !strcmp(argv[1], "--file")) {
- if (argc < 2)
+ if (argc < 3)
die ("Which file?");
if (!strcmp(argv[2], "-"))
in = stdin;
else {
fclose(in);
in = fopen(argv[2], "r");
+ if (!in)
+ die("cannot open %s", argv[2]);
}
argc--; argv++;
} else
*/
static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten)
{
- char type[20];
- void *buf = read_sha1_file(sha1, type, sz);
+ enum object_type type;
+ void *buf = read_sha1_file(sha1, &type, sz);
if (buf)
*obj = parse_object_buffer(sha1, type, *sz, buf, eaten);
if (deref)
name++;
if (!strcmp(name, "objecttype"))
- v->s = type_names[obj->type];
+ v->s = typename(obj->type);
else if (!strcmp(name, "objectsize")) {
char *s = xmalloc(40);
sprintf(s, "%lu", sz);
{
unsigned long size;
char *data;
- char type[20];
+ enum object_type type;
char *to_free = NULL;
int hit;
- data = read_sha1_file(sha1, type, &size);
+ data = read_sha1_file(sha1, &type, &size);
if (!data) {
error("'%s': unable to read %s", name, sha1_to_hex(sha1));
return 0;
else if (S_ISREG(entry.mode))
hit |= grep_sha1(opt, entry.sha1, path_buf, tn_len);
else if (S_ISDIR(entry.mode)) {
- char type[20];
+ enum object_type type;
struct tree_desc sub;
void *data;
- data = read_sha1_file(entry.sha1, type, &sub.size);
+ data = read_sha1_file(entry.sha1, &type, &sub.size);
if (!data)
die("unable to read tree (%s)",
sha1_to_hex(entry.sha1));
static int show_object(const unsigned char *sha1, int suppress_header)
{
unsigned long size;
- char type[20];
- char *buf = read_sha1_file(sha1, type, &size);
+ enum object_type type;
+ char *buf = read_sha1_file(sha1, &type, &size);
int offset = 0;
if (!buf)
*/
int ch;
char *cp = line;
+
+ /* Count mbox From headers as headers */
+ if (!memcmp(line, "From ", 5) || !memcmp(line, ">From ", 6))
+ return 1;
+
while ((ch = *cp++)) {
if (ch == ':')
return cp != line;
return 0;
}
+/*
+ * sz is size of 'line' buffer in bytes. Must be reasonably
+ * long enough to hold one physical real-world e-mail line.
+ */
static int read_one_header_line(char *line, int sz, FILE *in)
{
- int ofs = 0;
- while (ofs < sz) {
- int peek, len;
- if (fgets(line + ofs, sz - ofs, in) == NULL)
- break;
- len = eatspace(line + ofs);
- if ((len == 0) || !is_rfc2822_header(line)) {
- /* Re-add the newline */
- line[ofs + len] = '\n';
- line[ofs + len + 1] = '\0';
- break;
- }
- ofs += len;
- /* Yuck, 2822 header "folding" */
+ int len;
+
+ /*
+ * We will read at most (sz-1) bytes and then potentially
+ * re-add NUL after it. Accessing line[sz] after this is safe
+ * and we can allow len to grow up to and including sz.
+ */
+ sz--;
+
+ /* Get the first part of the line. */
+ if (!fgets(line, sz, in))
+ return 0;
+
+ /*
+ * Is it an empty line or not a valid rfc2822 header?
+ * If so, stop here, and return false ("not a header")
+ */
+ len = eatspace(line);
+ if (!len || !is_rfc2822_header(line)) {
+ /* Re-add the newline */
+ line[len] = '\n';
+ line[len + 1] = '\0';
+ return 0;
+ }
+
+ /*
+ * Now we need to eat all the continuation lines..
+ * Yuck, 2822 header "folding"
+ */
+ for (;;) {
+ int peek, addlen;
+ static char continuation[1000];
+
peek = fgetc(in); ungetc(peek, in);
if (peek != ' ' && peek != '\t')
break;
+ if (!fgets(continuation, sizeof(continuation), in))
+ break;
+ addlen = eatspace(continuation);
+ if (len < sz - 1) {
+ if (addlen >= sz - len)
+ addlen = sz - len - 1;
+ memcpy(line + len, continuation, addlen);
+ len += addlen;
+ }
}
- /* Count mbox From headers as headers */
- if (!ofs && (!memcmp(line, "From ", 5) || !memcmp(line, ">From ", 6)))
- ofs = 1;
- return ofs;
+ line[len] = 0;
+
+ return 1;
}
static int decode_q_segment(char *in, char *ot, char *ep, int rfc2047)
static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
{
unsigned long othersize, delta_size;
- char type[10];
- void *otherbuf = read_sha1_file(entry->delta->sha1, type, &othersize);
+ enum object_type type;
+ void *otherbuf = read_sha1_file(entry->delta->sha1, &type, &othersize);
void *delta_buf;
if (!otherbuf)
struct object_entry *entry)
{
unsigned long size;
- char type[10];
+ enum object_type type;
void *buf;
unsigned char header[10];
unsigned hdrlen, datalen;
}
if (!to_reuse) {
- buf = read_sha1_file(entry->sha1, type, &size);
+ buf = read_sha1_file(entry->sha1, &type, &size);
if (!buf)
die("unable to read %s", sha1_to_hex(entry->sha1));
if (size != entry->size)
struct pbase_tree_cache *ent, *nent;
void *data;
unsigned long size;
- char type[20];
+ enum object_type type;
int neigh;
int my_ix = pbase_tree_cache_ix(sha1);
int available_ix = -1;
/* Did not find one. Either we got a bogus request or
* we need to read and perhaps cache.
*/
- data = read_sha1_file(sha1, type, &size);
+ data = read_sha1_file(sha1, &type, &size);
if (!data)
return NULL;
- if (strcmp(type, tree_type)) {
+ if (type != OBJ_TREE) {
free(data);
return NULL;
}
while (tree_entry(tree,&entry)) {
unsigned long size;
- char type[20];
+ enum object_type type;
if (entry.pathlen != cmplen ||
memcmp(entry.path, name, cmplen) ||
!has_sha1_file(entry.sha1) ||
- sha1_object_info(entry.sha1, type, &size))
+ (type = sha1_object_info(entry.sha1, &size)) < 0)
continue;
if (name[cmplen] != '/') {
unsigned hash = name_hash(fullname);
add_object_entry(entry.sha1, hash, 1);
return;
}
- if (!strcmp(type, tree_type)) {
+ if (type == OBJ_TREE) {
struct tree_desc sub;
struct pbase_tree_cache *tree;
const char *down = name+cmplen+1;
static void check_object(struct object_entry *entry)
{
- char type[20];
-
if (entry->in_pack && !entry->preferred_base) {
struct packed_git *p = entry->in_pack;
struct pack_window *w_curs = NULL;
/* Otherwise we would do the usual */
}
- if (sha1_object_info(entry->sha1, type, &entry->size))
+ entry->type = sha1_object_info(entry->sha1, &entry->size);
+ if (entry->type < 0)
die("unable to get type of object %s",
sha1_to_hex(entry->sha1));
-
- if (!strcmp(type, commit_type)) {
- entry->type = OBJ_COMMIT;
- } else if (!strcmp(type, tree_type)) {
- entry->type = OBJ_TREE;
- } else if (!strcmp(type, blob_type)) {
- entry->type = OBJ_BLOB;
- } else if (!strcmp(type, tag_type)) {
- entry->type = OBJ_TAG;
- } else
- die("unable to pack object %s of type %s",
- sha1_to_hex(entry->sha1), type);
}
static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)
struct object_entry *trg_entry = trg->entry;
struct object_entry *src_entry = src->entry;
unsigned long trg_size, src_size, delta_size, sizediff, max_size, sz;
- char type[10];
+ enum object_type type;
void *delta_buf;
/* Don't bother doing diffs between different types */
/* Load data if not already done */
if (!trg->data) {
- trg->data = read_sha1_file(trg_entry->sha1, type, &sz);
+ trg->data = read_sha1_file(trg_entry->sha1, &type, &sz);
if (sz != trg_size)
die("object %s inconsistent object length (%lu vs %lu)",
sha1_to_hex(trg_entry->sha1), sz, trg_size);
}
if (!src->data) {
- src->data = read_sha1_file(src_entry->sha1, type, &sz);
+ src->data = read_sha1_file(src_entry->sha1, &type, &sz);
if (sz != src_size)
die("object %s inconsistent object length (%lu vs %lu)",
sha1_to_hex(src_entry->sha1), sz, src_size);
int use_internal_rev_list = 0;
int thin = 0;
int i;
- const char *rp_av[64];
+ const char **rp_av;
+ int rp_ac_alloc = 64;
int rp_ac;
+ rp_av = xcalloc(rp_ac_alloc, sizeof(*rp_av));
+
rp_av[0] = "pack-objects";
rp_av[1] = "--objects"; /* --thin will make it --objects-edge */
rp_ac = 2;
!strcmp("--reflog", arg) ||
!strcmp("--all", arg)) {
use_internal_rev_list = 1;
- if (ARRAY_SIZE(rp_av) - 1 <= rp_ac)
- die("too many internal rev-list options");
+ if (rp_ac >= rp_ac_alloc - 1) {
+ rp_ac_alloc = alloc_nr(rp_ac_alloc);
+ rp_av = xrealloc(rp_av,
+ rp_ac_alloc * sizeof(*rp_av));
+ }
rp_av[rp_ac++] = arg;
continue;
}
static int prune_object(char *path, const char *filename, const unsigned char *sha1)
{
- char buf[20];
- const char *type;
-
if (show_only) {
- if (sha1_object_info(sha1, buf, NULL))
- type = "unknown";
- else
- type = buf;
- printf("%s %s\n", sha1_to_hex(sha1), type);
+ enum object_type type = sha1_object_info(sha1, NULL);
+ printf("%s %s\n", sha1_to_hex(sha1),
+ (type > 0) ? typename(type) : "unknown");
return 0;
}
unlink(mkpath("%s/%s", path, filename));
desc.buf = tree->buffer;
desc.size = tree->size;
if (!desc.buf) {
- char type[20];
- void *data = read_sha1_file(sha1, type, &desc.size);
+ enum object_type type;
+ void *data = read_sha1_file(sha1, &type, &desc.size);
if (!data) {
tree->object.flags |= INCOMPLETE;
return 0;
return error("Could not read index");
for (i = 0; i + 2 < active_nr; i++) {
struct cache_entry *e1 = active_cache[i];
- struct cache_entry *e2 = active_cache[i + 1];
- struct cache_entry *e3 = active_cache[i + 2];
- if (ce_stage(e1) == 1 && ce_stage(e2) == 2 &&
- ce_stage(e3) == 3 && ce_same_name(e1, e2) &&
- ce_same_name(e1, e3)) {
+ struct cache_entry *e2 = active_cache[i+1];
+ struct cache_entry *e3 = active_cache[i+2];
+ if (ce_stage(e1) == 1 &&
+ ce_stage(e2) == 2 &&
+ ce_stage(e3) == 3 &&
+ ce_same_name(e1, e2) && ce_same_name(e1, e3) &&
+ S_ISREG(ntohl(e1->ce_mode)) &&
+ S_ISREG(ntohl(e2->ce_mode)) &&
+ S_ISREG(ntohl(e3->ce_mode))) {
path_list_insert((const char *)e1->name, conflict);
- i += 3;
+ i += 2;
}
}
return 0;
static struct obj_info *obj_list;
-static void added_object(unsigned nr, const char *type, void *data,
- unsigned long size);
+static void added_object(unsigned nr, enum object_type type,
+ void *data, unsigned long size);
-static void write_object(unsigned nr, void *buf, unsigned long size,
- const char *type)
+static void write_object(unsigned nr, enum object_type type,
+ void *buf, unsigned long size)
{
- if (write_sha1_file(buf, size, type, obj_list[nr].sha1) < 0)
+ if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
die("failed to write object");
added_object(nr, type, buf, size);
}
-static void resolve_delta(unsigned nr, const char *type,
+static void resolve_delta(unsigned nr, enum object_type type,
void *base, unsigned long base_size,
void *delta, unsigned long delta_size)
{
if (!result)
die("failed to apply delta");
free(delta);
- write_object(nr, result, result_size, type);
+ write_object(nr, type, result, result_size);
free(result);
}
-static void added_object(unsigned nr, const char *type, void *data,
- unsigned long size)
+static void added_object(unsigned nr, enum object_type type,
+ void *data, unsigned long size)
{
struct delta_info **p = &delta_list;
struct delta_info *info;
}
}
-static void unpack_non_delta_entry(enum object_type kind, unsigned long size,
+static void unpack_non_delta_entry(enum object_type type, unsigned long size,
unsigned nr)
{
void *buf = get_data(size);
- const char *type;
-
- switch (kind) {
- case OBJ_COMMIT: type = commit_type; break;
- case OBJ_TREE: type = tree_type; break;
- case OBJ_BLOB: type = blob_type; break;
- case OBJ_TAG: type = tag_type; break;
- default: die("bad type %d", kind);
- }
+
if (!dry_run && buf)
- write_object(nr, buf, size, type);
+ write_object(nr, type, buf, size);
free(buf);
}
-static void unpack_delta_entry(enum object_type kind, unsigned long delta_size,
+static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
unsigned nr)
{
void *delta_data, *base;
unsigned long base_size;
- char type[20];
unsigned char base_sha1[20];
- if (kind == OBJ_REF_DELTA) {
+ if (type == OBJ_REF_DELTA) {
hashcpy(base_sha1, fill(20));
use(20);
delta_data = get_data(delta_size);
}
}
- base = read_sha1_file(base_sha1, type, &base_size);
+ base = read_sha1_file(base_sha1, &type, &base_size);
if (!base) {
error("failed to read delta-pack base object %s",
sha1_to_hex(base_sha1));
int prefix_length = prefix ? strlen(prefix) : 0;
char set_executable_bit = 0;
unsigned int refresh_flags = 0;
+ int lock_error = 0;
struct lock_file *lock_file;
git_config(git_default_config);
/* We can't free this memory, it becomes part of a linked list parsed atexit() */
lock_file = xcalloc(1, sizeof(struct lock_file));
- newfd = hold_lock_file_for_update(lock_file, get_index_file(), 1);
+ newfd = hold_lock_file_for_update(lock_file, get_index_file(), 0);
+ if (newfd < 0)
+ lock_error = errno;
entries = read_cache();
if (entries < 0)
finish:
if (active_cache_changed) {
+ if (newfd < 0) {
+ if (refresh_flags & REFRESH_QUIET)
+ exit(128);
+ die("unable to create '%s.lock': %s",
+ get_index_file(), strerror(lock_error));
+ }
if (write_cache(newfd, active_cache, active_nr) ||
close(newfd) || commit_lock_file(lock_file))
die("Unable to write new index file");
extern int cmd_archive(int argc, const char **argv, const char *prefix);
extern int cmd_blame(int argc, const char **argv, const char *prefix);
extern int cmd_branch(int argc, const char **argv, const char *prefix);
+extern int cmd_bundle(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);
extern struct cache_tree *active_cache_tree;
extern int cache_errno;
+enum object_type {
+ OBJ_BAD = -1,
+ OBJ_NONE = 0,
+ OBJ_COMMIT = 1,
+ OBJ_TREE = 2,
+ OBJ_BLOB = 3,
+ OBJ_TAG = 4,
+ /* 5 for future expansion */
+ OBJ_OFS_DELTA = 6,
+ OBJ_REF_DELTA = 7,
+ OBJ_MAX,
+};
+
#define GIT_DIR_ENVIRONMENT "GIT_DIR"
#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
extern int ce_match_stat(struct cache_entry *ce, struct stat *st, int);
extern int ce_modified(struct cache_entry *ce, struct stat *st, int);
extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
-extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);
+extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
extern int read_pipe(int fd, char** return_buf, unsigned long* return_size);
extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
char *enter_repo(char *path, int strict);
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
-extern int sha1_object_info(const unsigned char *, char *, unsigned long *);
-extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
-extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
+extern int sha1_object_info(const unsigned char *, unsigned long *);
+extern void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size);
+extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size);
extern int hash_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *sha1);
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
-extern int pretend_sha1_file(void *, unsigned long, const char *, unsigned char *);
+extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
extern int has_pack_file(const unsigned char *sha1);
extern int has_pack_index(const unsigned char *sha1);
-enum object_type {
- OBJ_NONE = 0,
- OBJ_COMMIT = 1,
- OBJ_TREE = 2,
- OBJ_BLOB = 3,
- OBJ_TAG = 4,
- /* 5 for future expansion */
- OBJ_OFS_DELTA = 6,
- OBJ_REF_DELTA = 7,
- OBJ_BAD,
-};
-
extern signed char hexval_table[256];
static inline unsigned int hexval(unsigned int c)
{
extern int num_packed_objects(const struct packed_git *p);
extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
extern unsigned long find_pack_entry_one(const unsigned char *, struct packed_git *);
-extern void *unpack_entry(struct packed_git *, unsigned long, char *, unsigned long *);
+extern void *unpack_entry(struct packed_git *, unsigned long, enum object_type *, unsigned long *);
extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
-extern void packed_object_info_detail(struct packed_git *, unsigned long, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
+extern const char *packed_object_info_detail(struct packed_git *, unsigned long, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
/* Dumb servers support */
extern int update_server_info(int);
static char *grab_blob(const unsigned char *sha1, unsigned long *size)
{
char *blob;
- char type[20];
+ enum object_type type;
if (is_null_sha1(sha1)) {
/* deleted blob */
*size = 0;
return xcalloc(1, 1);
}
- blob = read_sha1_file(sha1, type, size);
- if (strcmp(type, blob_type))
+ blob = read_sha1_file(sha1, &type, size);
+ if (type != OBJ_BLOB)
die("object '%s' is not a blob!", sha1_to_hex(sha1));
return blob;
}
else {
/* Used by diff-tree to read from the working tree */
struct stat st;
- int fd;
- if (0 <= (fd = open(elem->path, O_RDONLY)) &&
- !fstat(fd, &st)) {
- int len = st.st_size;
- int sz = 0;
+ int fd = -1;
+
+ if (lstat(elem->path, &st) < 0)
+ goto deleted_file;
+
+ if (S_ISLNK(st.st_mode)) {
+ size_t len = st.st_size;
+ result_size = len;
+ result = xmalloc(len + 1);
+ if (result_size != readlink(elem->path, result, len)) {
+ error("readlink(%s): %s", elem->path,
+ strerror(errno));
+ return;
+ }
+ result[len] = 0;
+ elem->mode = canon_mode(st.st_mode);
+ }
+ else if (0 <= (fd = open(elem->path, O_RDONLY)) &&
+ !fstat(fd, &st)) {
+ size_t len = st.st_size;
+ size_t sz = 0;
elem->mode = canon_mode(st.st_mode);
result_size = len;
result[len] = 0;
}
else {
- /* deleted file */
+ deleted_file:
result_size = 0;
elem->mode = 0;
result = xcalloc(1, 1);
}
+
if (0 <= fd)
close(fd);
}
int parse_commit(struct commit *item)
{
- char type[20];
+ enum object_type type;
void *buffer;
unsigned long size;
int ret;
if (item->object.parsed)
return 0;
- buffer = read_sha1_file(item->object.sha1, type, &size);
+ buffer = read_sha1_file(item->object.sha1, &type, &size);
if (!buffer)
return error("Could not read %s",
sha1_to_hex(item->object.sha1));
- if (strcmp(type, commit_type)) {
+ if (type != OBJ_COMMIT) {
free(buffer);
return error("Object %s not a commit",
sha1_to_hex(item->object.sha1));
$fileview->signal_connect (row_activated => sub {
my ($sl, $path, $column) = @_;
my $row_ref = $sl->get_row_data_from_path ($path);
- system("blameview @$row_ref[0] $fn &");
+ system("blameview @$row_ref[0]~1 $fn &");
});
my $commitwindow = Gtk2::ScrolledWindow->new();
:type '(choice (const :tag "Default" nil)
(string :tag "Email")))
-(defcustom git-commits-coding-system 'utf-8
+(defcustom git-commits-coding-system nil
"Default coding system for the log message of git commits."
:group 'git
- :type 'coding-system)
+ :type '(choice (const :tag "From repository config" nil)
+ (coding-system)))
(defcustom git-append-signed-off-by nil
"Whether to append a Signed-off-by line to the commit message before editing."
(and (fboundp 'user-mail-address) (user-mail-address))
(and (boundp 'user-mail-address) user-mail-address)))
+(defun git-get-commits-coding-system ()
+ "Return the coding system to use for commits."
+ (let ((repo-config (git-config "i18n.commitencoding")))
+ (or git-commits-coding-system
+ (and repo-config
+ (fboundp 'locale-charset-to-coding-system)
+ (locale-charset-to-coding-system repo-config))
+ 'utf-8)))
+
(defun git-escape-file-name (name)
"Escape a file name if necessary."
(if (string-match "[\n\t\"\\]" name)
"Call git-commit-tree with buffer as input and return the resulting commit SHA1."
(let ((author-name (git-get-committer-name))
(author-email (git-get-committer-email))
- author-date log-start log-end args)
+ author-date log-start log-end args coding-system-for-write)
(when head
(push "-p" args)
(push head args))
(push "-p" args)
(push (match-string 1) args))))
(setq log-start (point-min)))
- (setq log-end (point-max)))
+ (setq log-end (point-max))
+ (setq coding-system-for-write buffer-file-coding-system))
(git-get-string-sha1
(with-output-to-string
(with-current-buffer standard-output
- (let ((coding-system-for-write git-commits-coding-system)
- (env `(("GIT_AUTHOR_NAME" . ,author-name)
+ (let ((env `(("GIT_AUTHOR_NAME" . ,author-name)
("GIT_AUTHOR_EMAIL" . ,author-email)
("GIT_COMMITTER_NAME" . ,(git-get-committer-name))
("GIT_COMMITTER_EMAIL" . ,(git-get-committer-email)))))
(let ((buffer (get-buffer-create "*git-commit*"))
(merge-heads (git-get-merge-heads))
(dir default-directory)
+ (coding-system (git-get-commits-coding-system))
(sign-off git-append-signed-off-by))
(with-current-buffer buffer
(when (eq 0 (buffer-size))
(git-get-committer-name) (git-get-committer-email)))))))
(log-edit #'git-do-commit nil #'git-log-edit-files buffer)
(setq font-lock-keywords (font-lock-compile-keywords git-log-edit-font-lock-keywords))
+ (setq buffer-file-coding-system coding-system)
(re-search-forward (regexp-quote (concat git-log-msg-separator "\n")) nil t)))
(defun git-find-file ()
static struct entry * convert_entry(unsigned char *sha1)
{
struct entry *entry = lookup_entry(sha1);
- char type[20];
+ enum object_type type;
void *buffer, *data;
unsigned long size;
if (entry->converted)
return entry;
- data = read_sha1_file(sha1, type, &size);
+ data = read_sha1_file(sha1, &type, &size);
if (!data)
die("unable to read object %s", sha1_to_hex(sha1));
buffer = xmalloc(size);
memcpy(buffer, data, size);
- if (!strcmp(type, blob_type)) {
+ if (type == OBJ_BLOB) {
write_sha1_file(buffer, size, blob_type, entry->new_sha1);
- } else if (!strcmp(type, tree_type))
+ } else if (type == OBJ_TREE)
convert_tree(buffer, size, entry->new_sha1);
- else if (!strcmp(type, commit_type))
+ else if (type == OBJ_COMMIT)
convert_commit(buffer, size, entry->new_sha1);
else
- die("unknown object type '%s' in %s", type, sha1_to_hex(sha1));
+ die("unknown object type %d in %s", type, sha1_to_hex(sha1));
entry->converted = 1;
free(buffer);
free(data);
#include "diffcore.h"
#include "revision.h"
#include "cache-tree.h"
+#include "path-list.h"
/*
* diff-files
*/
+static int read_directory(const char *path, struct path_list *list)
+{
+ DIR *dir;
+ struct dirent *e;
+
+ if (!(dir = opendir(path)))
+ return error("Could not open directory %s", path);
+
+ while ((e = readdir(dir)))
+ if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
+ path_list_insert(xstrdup(e->d_name), list);
+
+ closedir(dir);
+ return 0;
+}
+
+static int queue_diff(struct diff_options *o,
+ const char *name1, const char *name2)
+{
+ struct stat st;
+ int mode1 = 0, mode2 = 0;
+
+ if (name1) {
+ if (stat(name1, &st))
+ return error("Could not access '%s'", name1);
+ mode1 = st.st_mode;
+ }
+ if (name2) {
+ if (stat(name2, &st))
+ return error("Could not access '%s'", name2);
+ mode2 = st.st_mode;
+ }
+
+ if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
+ return error("file/directory conflict: %s, %s", name1, name2);
+
+ if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
+ char buffer1[PATH_MAX], buffer2[PATH_MAX];
+ struct path_list p1 = {NULL, 0, 0, 1}, p2 = {NULL, 0, 0, 1};
+ int len1 = 0, len2 = 0, i1, i2, ret = 0;
+
+ if (name1 && read_directory(name1, &p1))
+ return -1;
+ if (name2 && read_directory(name2, &p2)) {
+ path_list_clear(&p1, 0);
+ return -1;
+ }
+
+ if (name1) {
+ len1 = strlen(name1);
+ if (len1 > 0 && name1[len1 - 1] == '/')
+ len1--;
+ memcpy(buffer1, name1, len1);
+ buffer1[len1++] = '/';
+ }
+
+ if (name2) {
+ len2 = strlen(name2);
+ if (len2 > 0 && name2[len2 - 1] == '/')
+ len2--;
+ memcpy(buffer2, name2, len2);
+ buffer2[len2++] = '/';
+ }
+
+ for (i1 = i2 = 0; !ret && (i1 < p1.nr || i2 < p2.nr); ) {
+ const char *n1, *n2;
+ int comp;
+
+ if (i1 == p1.nr)
+ comp = 1;
+ else if (i2 == p2.nr)
+ comp = -1;
+ else
+ comp = strcmp(p1.items[i1].path,
+ p2.items[i2].path);
+
+ if (comp > 0)
+ n1 = NULL;
+ else {
+ n1 = buffer1;
+ strncpy(buffer1 + len1, p1.items[i1++].path,
+ PATH_MAX - len1);
+ }
+
+ if (comp < 0)
+ n2 = NULL;
+ else {
+ n2 = buffer2;
+ strncpy(buffer2 + len2, p2.items[i2++].path,
+ PATH_MAX - len2);
+ }
+
+ ret = queue_diff(o, n1, n2);
+ }
+ path_list_clear(&p1, 0);
+ path_list_clear(&p2, 0);
+
+ return ret;
+ } else {
+ struct diff_filespec *d1, *d2;
+
+ if (o->reverse_diff) {
+ unsigned tmp;
+ const char *tmp_c;
+ tmp = mode1; mode1 = mode2; mode2 = tmp;
+ tmp_c = name1; name1 = name2; name2 = tmp_c;
+ }
+
+ if (!name1)
+ name1 = "/dev/null";
+ if (!name2)
+ name2 = "/dev/null";
+ d1 = alloc_filespec(name1);
+ d2 = alloc_filespec(name2);
+ fill_filespec(d1, null_sha1, mode1);
+ fill_filespec(d2, null_sha1, mode2);
+
+ diff_queue(&diff_queued_diff, d1, d2);
+ return 0;
+ }
+}
+
+static int is_in_index(const char *path)
+{
+ int len = strlen(path);
+ int pos = cache_name_pos(path, len);
+ char c;
+
+ if (pos < 0)
+ return 0;
+ if (strncmp(active_cache[pos]->name, path, len))
+ return 0;
+ c = active_cache[pos]->name[len];
+ return c == '\0' || c == '/';
+}
+
+static int handle_diff_files_args(struct rev_info *revs,
+ int argc, const char **argv, int *silent)
+{
+ *silent = 0;
+
+ /* revs->max_count == -2 means --no-index */
+ while (1 < argc && argv[1][0] == '-') {
+ if (!strcmp(argv[1], "--base"))
+ revs->max_count = 1;
+ else if (!strcmp(argv[1], "--ours"))
+ revs->max_count = 2;
+ else if (!strcmp(argv[1], "--theirs"))
+ revs->max_count = 3;
+ else if (!strcmp(argv[1], "-n") ||
+ !strcmp(argv[1], "--no-index"))
+ revs->max_count = -2;
+ else if (!strcmp(argv[1], "-q"))
+ *silent = 1;
+ else
+ return error("invalid option: %s", argv[1]);
+ argv++; argc--;
+ }
+
+ if (revs->max_count == -1 && revs->diffopt.nr_paths == 2) {
+ /*
+ * If two files are specified, and at least one is untracked,
+ * default to no-index.
+ */
+ read_cache();
+ if (!is_in_index(revs->diffopt.paths[0]) ||
+ !is_in_index(revs->diffopt.paths[1]))
+ revs->max_count = -2;
+ }
+
+ /*
+ * Make sure there are NO revision (i.e. pending object) parameter,
+ * rev.max_count is reasonable (0 <= n <= 3),
+ * there is no other revision filtering parameters.
+ */
+ if (revs->pending.nr || revs->max_count > 3 ||
+ revs->min_age != -1 || revs->max_age != -1)
+ return error("no revision allowed with diff-files");
+
+ if (revs->max_count == -1 &&
+ (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
+ revs->combine_merges = revs->dense_combined_merges = 1;
+
+ return 0;
+}
+
+int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
+{
+ int silent_on_removed;
+
+ if (handle_diff_files_args(revs, argc, argv, &silent_on_removed))
+ return -1;
+
+ if (revs->max_count == -2) {
+ if (revs->diffopt.nr_paths != 2)
+ return error("need two files/directories with --no-index");
+ if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
+ revs->diffopt.paths[1]))
+ return -1;
+ diffcore_std(&revs->diffopt);
+ diff_flush(&revs->diffopt);
+ /*
+ * The return code for --no-index imitates diff(1):
+ * 0 = no changes, 1 = changes, else error
+ */
+ return revs->diffopt.found_changes;
+ }
+
+ if (read_cache() < 0) {
+ perror("read_cache");
+ return -1;
+ }
+ return run_diff_files(revs, silent_on_removed);
+}
+
int run_diff_files(struct rev_info *revs, int silent_on_removed)
{
int entries, i;
if (diff_unmerged_stage < 0)
diff_unmerged_stage = 2;
- entries = read_cache();
- if (entries < 0) {
- perror("read_cache");
- return -1;
- }
+ entries = active_nr;
for (i = 0; i < entries; i++) {
struct stat st;
unsigned int oldmode, newmode;
path_len = ce_namelen(ce);
- dpath = xmalloc (combine_diff_path_size (5, path_len));
+ dpath = xmalloc(combine_diff_path_size(5, path_len));
dpath->path = (char *) &(dpath->parent[5]);
dpath->next = NULL;
dpath->len = path_len;
memcpy(dpath->path, ce->name, path_len);
dpath->path[path_len] = '\0';
- dpath->mode = 0;
hashclr(dpath->sha1);
memset(&(dpath->parent[0]), 0,
- sizeof(struct combine_diff_parent)*5);
+ sizeof(struct combine_diff_parent)*5);
+
+ if (lstat(ce->name, &st) < 0) {
+ if (errno != ENOENT && errno != ENOTDIR) {
+ perror(ce->name);
+ continue;
+ }
+ if (silent_on_removed)
+ continue;
+ }
+ else
+ dpath->mode = canon_mode(st.st_mode);
while (i < entries) {
struct cache_entry *nce = active_cache[i];
if (!revs->ignore_merges)
match_missing = 1;
- if (read_cache() < 0) {
- perror("read_cache");
- return -1;
- }
mark_merge_entries();
ent = revs->pending.objects[0].item;
int nparents, color_diff;
const char **label_path;
struct diff_words_data *diff_words;
+ int *found_changesp;
};
static void free_diff_words_data(struct emit_callback *ecbdata)
const char *set = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
+ *(ecbdata->found_changesp) = 1;
+
if (ecbdata->label_path[0]) {
const char *name_a_tab, *name_b_tab;
if (complete_rewrite) {
emit_rewrite_diff(name_a, name_b, one, two,
o->color_diff);
+ o->found_changes = 1;
goto free_ab_and_return;
}
}
else
printf("Binary files %s and %s differ\n",
lbl[0], lbl[1]);
+ o->found_changes = 1;
}
else {
/* Crazy xdl interfaces.. */
memset(&ecbdata, 0, sizeof(ecbdata));
ecbdata.label_path = lbl;
ecbdata.color_diff = o->color_diff;
+ ecbdata.found_changesp = &o->found_changes;
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES;
}
}
else {
- char type[20];
+ enum object_type type;
struct sha1_size_cache *e;
if (size_only) {
s->size = e->size;
return 0;
}
- if (!sha1_object_info(s->sha1, type, &s->size))
+ type = sha1_object_info(s->sha1, &s->size);
+ if (type < 0)
locate_size_cache(s->sha1, 0, s->size);
}
else {
- s->data = read_sha1_file(s->sha1, type, &s->size);
+ s->data = read_sha1_file(s->sha1, &type, &s->size);
s->should_free = 1;
}
}
p->status = DIFF_STATUS_RENAMED;
}
else if (hashcmp(p->one->sha1, p->two->sha1) ||
- p->one->mode != p->two->mode)
+ p->one->mode != p->two->mode ||
+ is_null_sha1(p->one->sha1))
p->status = DIFF_STATUS_MODIFIED;
else {
/* This is a "no-change" entry and should not
int stat_width;
int stat_name_width;
+ /* this is set by diffcore for DIFF_FORMAT_PATCH */
+ int found_changes;
+
int nr_paths;
const char **paths;
int *pathlens;
extern const char *diff_unique_abbrev(const unsigned char *, int);
extern int run_diff_files(struct rev_info *revs, int silent_on_removed);
+extern int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv);
extern int run_diff_index(struct rev_info *revs, int cached);
void *new;
unsigned long size;
long wrote;
- char type[20];
+ enum object_type type;
- new = read_sha1_file(ce->sha1, type, &size);
- if (!new || strcmp(type, blob_type)) {
+ new = read_sha1_file(ce->sha1, &type, &size);
+ if (!new || type != OBJ_BLOB) {
if (new)
free(new);
return error("git-checkout-index: unable to read sha1 file of %s (%s)",
SHA_CTX c;
z_stream s;
- hdrlen = sprintf((char*)hdr,"%s %lu", type_names[type],
+ hdrlen = sprintf((char*)hdr,"%s %lu", typename(type),
(unsigned long)datlen) + 1;
SHA1_Init(&c);
SHA1_Update(&c, hdr, hdrlen);
struct object_entry *oe,
unsigned long *sizep)
{
- static char type[20];
+ enum object_type type;
struct packed_git *p = all_packs[oe->pack_id];
if (p == pack_data)
p->pack_size = pack_size + 20;
- return unpack_entry(p, oe->offset, type, sizep);
+ return unpack_entry(p, oe->offset, &type, sizep);
}
static const char *get_mode(const char *str, uint16_t *modep)
t->delta_depth = 0;
buf = gfi_unpack_entry(myoe, &size);
} else {
- char type[20];
- buf = read_sha1_file(sha1, type, &size);
- if (!buf || strcmp(type, tree_type))
+ enum object_type type;
+ buf = read_sha1_file(sha1, &type, &size);
+ if (!buf || type != OBJ_TREE)
die("Can't load tree %s", sha1_to_hex(sha1));
}
struct object_entry *oe = oe;
unsigned char sha1[20];
uint16_t mode, inline_data = 0;
- char type[20];
p = get_mode(p, &mode);
if (!p)
} else if (oe) {
if (oe->type != OBJ_BLOB)
die("Not a blob (actually a %s): %s",
- command_buf.buf, type_names[oe->type]);
+ command_buf.buf, typename(oe->type));
} else {
- if (sha1_object_info(sha1, type, NULL))
+ enum object_type type = sha1_object_info(sha1, NULL);
+ if (type < 0)
die("Blob not found: %s", command_buf.buf);
- if (strcmp(blob_type, type))
+ if (type != OBJ_BLOB)
die("Not a blob (actually a %s): %s",
- command_buf.buf, type);
+ typename(type), command_buf.buf);
}
tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode);
char *buf;
buf = read_object_with_reference(b->sha1,
- type_names[OBJ_COMMIT], &size, b->sha1);
+ commit_type, &size, b->sha1);
if (!buf || size < 46)
die("Not a valid commit: %s", from);
if (memcmp("tree ", buf, 5)
char *buf;
buf = read_object_with_reference(sha1,
- type_names[OBJ_COMMIT], &size, sha1);
+ commit_type, &size, sha1);
if (!buf || size < 46)
die("Not a valid commit: %s", from);
free(buf);
size_dbuf(&new_data, 67+strlen(t->name)+strlen(tagger)+msglen);
sp = new_data.buffer;
sp += sprintf(sp, "object %s\n", sha1_to_hex(sha1));
- sp += sprintf(sp, "type %s\n", type_names[OBJ_COMMIT]);
+ sp += sprintf(sp, "type %s\n", commit_type);
sp += sprintf(sp, "tag %s\n", t->name);
sp += sprintf(sp, "tagger %s\n", tagger);
*sp++ = '\n';
my $pid = open2(*READER, *WRITER,'git-commit-tree',$tree,@par)
or die $!;
- print WRITER $ps->{summary},"\n";
+ print WRITER $ps->{summary},"\n\n";
print WRITER $ps->{message},"\n";
# make it easy to backtrack and figure out which Arch revision this was:
$ps->{tag} = $1;
$key = undef;
} elsif (/^Summary:\s*(.*)$/ ) {
- # summary can be multiline as long as it has a leading space
+ # summary can be multiline as long as it has a leading space.
+ # we squeeze it onto a single line, though.
$ps->{summary} = [ $1 ];
$key = 'summary';
} elsif (/^Creator: (.*)\s*<([^\>]+)>/) {
}
}
- # post-processing:
- $ps->{summary} = join("\n",@{$ps->{summary}})."\n";
+ # drop leading empty lines from the log message
+ while (@$log && $log->[0] eq '') {
+ shift @$log;
+ }
+ if (exists $ps->{summary} && @{$ps->{summary}}) {
+ $ps->{summary} = join(' ', @{$ps->{summary}});
+ }
+ elsif (@$log == 0) {
+ $ps->{summary} = 'empty commit message';
+ } else {
+ $ps->{summary} = $log->[0] . '...';
+ }
$ps->{message} = join("\n",@$log);
# skip Arch control files, unescape pika-escaped files
case "$0" in
*status)
status_only=t
- unmerged_ok_if_status=--unmerged ;;
+ ;;
*commit)
status_only=
- unmerged_ok_if_status= ;;
+ ;;
esac
refuse_partial () {
USE_INDEX="$THIS_INDEX"
fi
-GIT_INDEX_FILE="$USE_INDEX" \
- git-update-index -q $unmerged_ok_if_status --refresh || exit
-
-################################################################
-# If the request is status, just show it and exit.
-
-case "$0" in
-*status)
+case "$status_only" in
+t)
+ # This will silently fail in a read-only repository, which is
+ # what we want.
+ GIT_INDEX_FILE="$USE_INDEX" git-update-index -q --unmerged --refresh
run_status
exit $?
+ ;;
+'')
+ GIT_INDEX_FILE="$USE_INDEX" git-update-index -q --refresh || exit
+ ;;
esac
################################################################
die "Exiting: The commit did not succeed";
}
print "Committed successfully to CVS\n";
+ # clean up
+ unlink(".msg");
} else {
print "Ready for you to commit, just run:\n\n $cmd\n";
}
# clean up
unlink(".cvsexportcommit.diff");
-unlink(".msg");
sub usage {
print STDERR <<END;
print "Checked-in $dirpart\n";
print "$filename\n";
- print "/$filepart/0///\n";
+ my $kopts = kopts_from_path($filepart);
+ print "/$filepart/0//$kopts/\n";
$addcount++;
}
print "Checked-in $dirpart\n";
print "$filename\n";
- print "/$filepart/-1.$wrev///\n";
+ my $kopts = kopts_from_path($filepart);
+ print "/$filepart/-1.$wrev//$kopts/\n";
$rmcount++;
}
print $state->{CVSROOT} . "/$module/" . ( defined ( $git->{dir} ) and $git->{dir} ne "./" ? $git->{dir} . "/" : "" ) . "$git->{name}\n";
# this is an "entries" line
- print "/$git->{name}/1.$git->{revision}///\n";
+ my $kopts = kopts_from_path($git->{name});
+ print "/$git->{name}/1.$git->{revision}//$kopts/\n";
# permissions
print "u=$git->{mode},g=$git->{mode},o=$git->{mode}\n";
print $state->{CVSROOT} . "/$state->{module}/$filename\n";
# this is an "entries" line
- $log->debug("/$filepart/1.$meta->{revision}///");
- print "/$filepart/1.$meta->{revision}///\n";
+ my $kopts = kopts_from_path($filepart);
+ $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
+ print "/$filepart/1.$meta->{revision}//$kopts/\n";
# permissions
$log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}");
print "Update-existing $dirpart\n";
$log->debug($state->{CVSROOT} . "/$state->{module}/$filename");
print $state->{CVSROOT} . "/$state->{module}/$filename\n";
- $log->debug("/$filepart/1.$meta->{revision}///");
- print "/$filepart/1.$meta->{revision}///\n";
+ my $kopts = kopts_from_path($filepart);
+ $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
+ print "/$filepart/1.$meta->{revision}//$kopts/\n";
}
}
elsif ( $return == 1 )
{
print "Update-existing $dirpart\n";
print $state->{CVSROOT} . "/$state->{module}/$filename\n";
- print "/$filepart/1.$meta->{revision}/+//\n";
+ my $kopts = kopts_from_path($filepart);
+ print "/$filepart/1.$meta->{revision}/+/$kopts/\n";
}
}
else
exit;
}
- my $lockfile = "$state->{CVSROOT}/refs/heads/$state->{module}.lock";
- unless ( sysopen(LOCKFILE,$lockfile,O_EXCL|O_CREAT|O_WRONLY) )
- {
- $log->warn("lockfile '$lockfile' already exists, please try again");
- print "error 1 Lock file '$lockfile' already exists, please try again\n";
- exit;
- }
-
# Grab a handle to the SQLite db and do any necessary updates
my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
$updater->update();
my $tmpdir = tempdir ( DIR => $TEMP_DIR );
my ( undef, $file_index ) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
- $log->info("Lock successful, basing commit on '$tmpdir', index file is '$file_index'");
+ $log->info("Lockless commit start, basing commit on '$tmpdir', index file is '$file_index'");
$ENV{GIT_DIR} = $state->{CVSROOT} . "/";
$ENV{GIT_INDEX_FILE} = $file_index;
+ # Remember where the head was at the beginning.
+ my $parenthash = `git show-ref -s refs/heads/$state->{module}`;
+ chomp $parenthash;
+ if ($parenthash !~ /^[0-9a-f]{40}$/) {
+ print "error 1 pserver cannot find the current HEAD of module";
+ exit;
+ }
+
chdir $tmpdir;
# populate the temporary index based
- system("git-read-tree", $state->{module});
+ system("git-read-tree", $parenthash);
unless ($? == 0)
{
die "Error running git-read-tree $state->{module} $file_index $!";
}
$log->info("Created index '$file_index' with for head $state->{module} - exit status $?");
-
my @committedfiles = ();
# foreach file specified on the command line ...
{
# fail everything if an up to date check fails
print "error 1 Up to date check failed for $filename\n";
- close LOCKFILE;
- unlink($lockfile);
chdir "/";
exit;
}
{
print "E No files to commit\n";
print "ok\n";
- close LOCKFILE;
- unlink($lockfile);
chdir "/";
return;
}
my $treehash = `git-write-tree`;
- my $parenthash = `cat $ENV{GIT_DIR}refs/heads/$state->{module}`;
chomp $treehash;
- chomp $parenthash;
$log->debug("Treehash : $treehash, Parenthash : $parenthash");
close $msg_fh;
my $commithash = `git-commit-tree $treehash -p $parenthash < $msg_filename`;
+ chomp($commithash);
$log->info("Commit hash : $commithash");
unless ( $commithash =~ /[a-zA-Z0-9]{40}/ )
{
$log->warn("Commit failed (Invalid commit hash)");
print "error 1 Commit failed (unknown reason)\n";
- close LOCKFILE;
- unlink($lockfile);
chdir "/";
exit;
}
{
$log->warn("Commit failed (update hook declined to update ref)");
print "error 1 Commit failed (update hook declined)\n";
- close LOCKFILE;
- unlink($lockfile);
chdir "/";
exit;
}
}
- print LOCKFILE $commithash;
+ if (system(qw(git update-ref -m), "cvsserver ci",
+ "refs/heads/$state->{module}", $commithash, $parenthash)) {
+ $log->warn("update-ref for $state->{module} failed.");
+ print "error 1 Cannot commit -- update first\n";
+ exit;
+ }
$updater->update();
} else {
print "Checked-in $dirpart\n";
print "$filename\n";
- print "/$filepart/1.$meta->{revision}///\n";
+ my $kopts = kopts_from_path($filepart);
+ print "/$filepart/1.$meta->{revision}//$kopts/\n";
}
}
- close LOCKFILE;
- my $reffile = "$ENV{GIT_DIR}refs/heads/$state->{module}";
- unlink($reffile);
- rename($lockfile, $reffile);
chdir "/";
-
print "ok\n";
}
return $filename;
}
+# Given a path, this function returns a string containing the kopts
+# that should go into that path's Entries line. For example, a binary
+# file should get -kb.
+sub kopts_from_path
+{
+ my ($path) = @_;
+
+ # Once it exists, the git attributes system should be used to look up
+ # what attributes apply to this path.
+
+ # Until then, take the setting from the config file
+ unless ( defined ( $cfg->{gitcvs}{allbinary} ) and $cfg->{gitcvs}{allbinary} =~ /^\s*(1|true|yes)\s*$/i )
+ {
+ # Return "" to give no special treatment to any path
+ return "";
+ } else {
+ # Alternatively, to have all files treated as if they are binary (which
+ # is more like git itself), always return the "-kb" option
+ return "-kb";
+ }
+}
+
package GITCVS::log;
####
( : subshell because we muck with IFS
IFS=" $LF"
(
+ if test -f "$remote" ; then
+ test -n "$shallow_depth" &&
+ die "shallow clone with bundle is not supported"
+ git-bundle unbundle "$remote" $rref ||
+ echo failed "$remote"
+ else
git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref ||
echo failed "$remote"
+ fi
) |
(
trap '
generate_credits ()
{
tip=$1 &&
- rm -f $CF &&
- git shortlog -n -s $tip | sed 's/: .*$//' >$CF || exit
+ rm -f "$2" &&
+ git shortlog -n -s $tip | sed 's/: .*$//' >"$2" || exit
}
# Always use the tarball credits file if found, just
# that fact.
#
+credits_tmp=/var/tmp/gitgui-credits-$$
+trap 'rm -f "$credits_tmp"' 0
+
+orig="$credits_tmp"
+
if test -f credits
then
- rm -f $CF &&
- cp credits $CF || exit
+ orig=credits
elif prefix="$(git rev-parse --show-prefix 2>/dev/null)" &&
test -n "$prefix" &&
head=$(git rev-list --max-count=1 HEAD -- . 2>/dev/null) &&
tip=$(tree_search $head $tree) &&
test -n "$tip"
then
- generate_credits $tip || exit
+ generate_credits $tip "$orig" || exit
elif tip="$(git rev-parse --verify HEAD 2>/dev/null)" &&
test -n "$tip"
then
- generate_credits $tip || exit
+ generate_credits $tip "$orig" || exit
else
echo "error: Cannot locate authorship information." >&2
exit 1
fi
+
+if test -f "$orig" && cmp -s "$orig" "$CF"
+then
+ : noop
+else
+ rm -f "$CF" &&
+ cat "$orig" >"$CF"
+fi
+
;;
* )
- git-peek-remote $exec "$peek_repo" ||
+ if test -f "$peek_repo" ; then
+ git bundle list-heads "$peek_repo" ||
echo "failed slurping"
+ else
+ git-peek-remote $exec "$peek_repo" ||
+ echo "failed slurping"
+ fi
;;
esac |
sort -t ' ' -k 2 |
}
package main;
+
+sub usage {
+ print <<EOT;
+git-send-email [options] <file | directory>...
+Options:
+ --from Specify the "From:" line of the email to be sent.
+
+ --to Specify the primary "To:" line of the email.
+
+ --cc Specify an initial "Cc:" list for the entire series
+ of emails.
+
+ --bcc Specify a list of email addresses that should be Bcc:
+ on all the emails.
+
+ --compose Use \$EDITOR to edit an introductory message for the
+ patch series.
+
+ --subject Specify the initial "Subject:" line.
+ Only necessary if --compose is also set. If --compose
+ is not set, this will be prompted for.
+
+ --in-reply-to Specify the first "In-Reply-To:" header line.
+ Only used if --compose is also set. If --compose is not
+ set, this will be prompted for.
+
+ --chain-reply-to If set, the replies will all be to the previous
+ email sent, rather than to the first email sent.
+ Defaults to on.
+
+ --no-signed-off-cc Suppress the automatic addition of email addresses
+ that appear in a Signed-off-by: line, to the cc: list.
+ Note: Using this option is not recommended.
+
+ --smtp-server If set, specifies the outgoing SMTP server to use.
+ Defaults to localhost.
+
+ --suppress-from Suppress sending emails to yourself if your address
+ appears in a From: line.
+
+ --quiet Make git-send-email less verbose. One line per email
+ should be all that is output.
+
+EOT
+ exit(1);
+}
+
# most mail servers generate the Date: header, but not all...
sub format_2822_time {
my ($time) = @_;
"dry-run" => \$dry_run,
);
+unless ($rc) {
+ usage();
+}
+
# Verify the user input
foreach my $entry (@to) {
print $_,"\n" for (@files);
}
} else {
- print <<EOT;
-git-send-email [options] <file | directory> [... file | directory ]
-Options:
- --from Specify the "From:" line of the email to be sent.
-
- --to Specify the primary "To:" line of the email.
-
- --cc Specify an initial "Cc:" list for the entire series
- of emails.
-
- --bcc Specify a list of email addresses that should be Bcc:
- on all the emails.
-
- --compose Use \$EDITOR to edit an introductory message for the
- patch series.
-
- --subject Specify the initial "Subject:" line.
- Only necessary if --compose is also set. If --compose
- is not set, this will be prompted for.
-
- --in-reply-to Specify the first "In-Reply-To:" header line.
- Only used if --compose is also set. If --compose is not
- set, this will be prompted for.
-
- --chain-reply-to If set, the replies will all be to the previous
- email sent, rather than to the first email sent.
- Defaults to on.
-
- --no-signed-off-cc Suppress the automatic addition of email addresses
- that appear in a Signed-off-by: line, to the cc: list.
- Note: Using this option is not recommended.
-
- --smtp-server If set, specifies the outgoing SMTP server to use.
- Defaults to localhost.
-
- --suppress-from Suppress sending emails to yourself if your address
- appears in a From: line.
-
- --quiet Make git-send-email less verbose. One line per email should be
- all that is output.
-
-Error: Please specify a file or a directory on the command line.
-EOT
- exit(1);
+ print STDERR "\nNo patch files specified!\n\n";
+ usage();
}
# Variables we set as part of the loop over files
{ "archive", cmd_archive },
{ "blame", cmd_blame, RUN_SETUP },
{ "branch", cmd_branch, RUN_SETUP },
+ { "bundle", cmd_bundle },
{ "cat-file", cmd_cat_file, RUN_SETUP },
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
{ "check-ref-format", cmd_check_ref_format },
{ "config", cmd_config },
{ "count-objects", cmd_count_objects, RUN_SETUP },
{ "describe", cmd_describe, RUN_SETUP },
- { "diff", cmd_diff, RUN_SETUP | USE_PAGER },
- { "diff-files", cmd_diff_files, RUN_SETUP },
+ { "diff", cmd_diff, USE_PAGER },
+ { "diff-files", cmd_diff_files },
{ "diff-index", cmd_diff_index, RUN_SETUP },
{ "diff-tree", cmd_diff_tree, RUN_SETUP },
{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
#include "cache.h"
#include "blob.h"
-static void hash_object(const char *path, const char *type, int write_object)
+static void hash_object(const char *path, enum object_type type, int write_object)
{
int fd;
struct stat st;
fd = open(path, O_RDONLY);
if (fd < 0 ||
fstat(fd, &st) < 0 ||
- index_fd(sha1, fd, &st, write_object, type))
+ index_fd(sha1, fd, &st, write_object, type, path))
die(write_object
? "Unable to add %s to database"
: "Unable to hash %s", path);
if (0 <= prefix_length)
arg = prefix_filename(prefix, prefix_length,
arg);
- hash_object(arg, type, write_object);
+ hash_object(arg, type_from_string(type), write_object);
no_more_flags = 1;
}
}
char *hex = sha1_to_hex(request->obj->sha1);
struct active_request_slot *slot;
char *posn;
- char type[20];
+ enum object_type type;
char hdr[50];
void *unpacked;
unsigned long len;
ssize_t size;
z_stream stream;
- unpacked = read_sha1_file(request->obj->sha1, type, &len);
- hdrlen = sprintf(hdr, "%s %lu", type, len) + 1;
+ unpacked = read_sha1_file(request->obj->sha1, &type, &len);
+ hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
/* Set it up */
memset(&stream, 0, sizeof(stream));
sprintf(url, "%s%s", remote->url, path);
/* Make sure leading directories exist for the remote ref */
- ep = strchr(url + strlen(remote->url) + 11, '/');
+ ep = strchr(url + strlen(remote->url) + 1, '/');
while (ep) {
*ep = 0;
slot = get_active_slot();
{
unsigned long from = obj[0].offset + obj[0].hdr_size;
unsigned long len = obj[1].offset - from;
+ unsigned long rdy = 0;
unsigned char *src, *data;
z_stream stream;
int st;
src = xmalloc(len);
- if (pread(pack_fd, src, len, from) != len)
- die("cannot pread pack file: %s", strerror(errno));
+ data = src;
+ do {
+ ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
+ if (n <= 0)
+ die("cannot pread pack file: %s", strerror(errno));
+ rdy += n;
+ } while (rdy < len);
data = xmalloc(obj->size);
memset(&stream, 0, sizeof(stream));
stream.next_out = data;
/* If input_fd is a file, we should have reached its end now. */
if (fstat(input_fd, &st))
die("cannot fstat packfile: %s", strerror(errno));
- if (S_ISREG(st.st_mode) && st.st_size != consumed_bytes)
+ if (S_ISREG(st.st_mode) &&
+ lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size)
die("pack has junk at the end");
if (!nr_deltas)
struct delta_entry *d = sorted_by_pos[i];
void *data;
unsigned long size;
- char type[10];
- enum object_type obj_type;
+ enum object_type type;
int j, first, last;
if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
continue;
- data = read_sha1_file(d->base.sha1, type, &size);
+ data = read_sha1_file(d->base.sha1, &type, &size);
if (!data)
continue;
- if (!strcmp(type, blob_type)) obj_type = OBJ_BLOB;
- else if (!strcmp(type, tree_type)) obj_type = OBJ_TREE;
- else if (!strcmp(type, commit_type)) obj_type = OBJ_COMMIT;
- else if (!strcmp(type, tag_type)) obj_type = OBJ_TAG;
- else die("base object %s is of type '%s'",
- sha1_to_hex(d->base.sha1), type);
find_delta_children(&d->base, &first, &last);
for (j = first; j <= last; j++) {
struct object_entry *child = objects + deltas[j].obj_no;
if (child->real_type == OBJ_REF_DELTA)
- resolve_delta(child, data, size, obj_type);
+ resolve_delta(child, data, size, type);
}
- append_obj_to_pack(data, size, obj_type);
+ append_obj_to_pack(data, size, type);
free(data);
if (verbose)
percent = display_progress(nr_resolved_deltas,
{
void *buf;
unsigned long size;
- char type[20];
+ enum object_type type;
- buf = read_sha1_file(obj->object.sha1, type, &size);
+ buf = read_sha1_file(obj->object.sha1, &type, &size);
if (!buf)
return -1;
- if (strcmp(type, blob_type))
+ if (type != OBJ_BLOB)
return -1;
f->ptr = buf;
f->size = size;
* modified in the other branch!
*/
if (!our || !their) {
- char type[20];
+ enum object_type type;
if (base)
return NULL;
if (!our)
our = their;
- return read_sha1_file(our->object.sha1, type, size);
+ return read_sha1_file(our->object.sha1, &type, size);
}
if (fill_mmfile_blob(&f1, our) < 0)
break;
found++;
strcpy(hexbuf[stage], sha1_to_hex(ce->sha1));
- sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode) & (~S_IFMT));
+ sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode));
arguments[stage] = hexbuf[stage];
arguments[stage + 4] = ownbuf[stage];
} while (++pos < active_nr);
update_wd = 0;
if (update_wd) {
- char type[20];
+ enum object_type type;
void *buf;
unsigned long size;
- buf = read_sha1_file(sha, type, &size);
+ buf = read_sha1_file(sha, &type, &size);
if (!buf)
die("cannot read object %s '%s'", sha1_to_hex(sha), path);
- if (strcmp(type, blob_type) != 0)
+ if (type != OBJ_BLOB)
die("blob expected for %s '%s'", sha1_to_hex(sha), path);
if (S_ISREG(mode)) {
memcpy(lnk, buf, size);
lnk[size] = '\0';
mkdir_p(path, 0777);
- unlink(lnk);
+ unlink(path);
symlink(lnk, path);
} else
die("do not know what to do with %06o %s '%s'",
static void fill_mm(const unsigned char *sha1, mmfile_t *mm)
{
unsigned long size;
- char type[20];
+ enum object_type type;
if (!hashcmp(sha1, null_sha1)) {
mm->ptr = xstrdup("");
return;
}
- mm->ptr = read_sha1_file(sha1, type, &size);
- if (!mm->ptr || strcmp(type, blob_type))
+ mm->ptr = read_sha1_file(sha1, &type, &size);
+ if (!mm->ptr || type != OBJ_BLOB)
die("unable to read blob object %s", sha1_to_hex(sha1));
mm->size = size;
}
tree->object.parsed = 1;
tree->object.type = OBJ_TREE;
- pretend_sha1_file(NULL, 0, tree_type, tree->object.sha1);
+ pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1);
merged_common_ancestors = make_virtual_commit(tree, "ancestor");
}
static void *result(struct merge_list *entry, unsigned long *size)
{
- char type[20];
+ enum object_type type;
struct blob *base, *our, *their;
if (!entry->stage)
- return read_sha1_file(entry->blob->object.sha1, type, size);
+ return read_sha1_file(entry->blob->object.sha1, &type, size);
base = NULL;
if (entry->stage == 1) {
base = entry->blob;
static void *origin(struct merge_list *entry, unsigned long *size)
{
- char type[20];
+ enum object_type type;
while (entry) {
if (entry->stage == 2)
- return read_sha1_file(entry->blob->object.sha1, type, size);
+ return read_sha1_file(entry->blob->object.sha1, &type, size);
entry = entry->link;
}
return NULL;
static int verify_object(unsigned char *sha1, const char *expected_type)
{
int ret = -1;
- char type[100];
+ enum object_type type;
unsigned long size;
- void *buffer = read_sha1_file(sha1, type, &size);
+ void *buffer = read_sha1_file(sha1, &type, &size);
if (buffer) {
- if (!strcmp(type, expected_type))
- ret = check_sha1_signature(sha1, buffer, size, type);
+ if (type == type_from_string(expected_type))
+ ret = check_sha1_signature(sha1, buffer, size, expected_type);
free(buffer);
}
return ret;
int len;
char *ptr, *ntr;
unsigned mode;
- char type[20];
+ enum object_type type;
char *path;
read_line(&sb, stdin, line_termination);
ntr[41] != '\t' ||
get_sha1_hex(ntr + 1, sha1))
die("input format error: %s", sb.buf);
- if (sha1_object_info(sha1, type, NULL))
+ type = sha1_object_info(sha1, NULL);
+ if (type < 0)
die("object %s unavailable", sha1_to_hex(sha1));
*ntr++ = 0; /* now at the beginning of SHA1 */
- if (strcmp(ptr, type))
- die("object type %s mismatch (%s)", ptr, type);
+ if (type != type_from_string(ptr))
+ die("object type %s mismatch (%s)", ptr, typename(type));
ntr += 41; /* at the beginning of name */
if (line_termination && ntr[0] == '"')
path = unquote_c_style(ntr, NULL);
return obj_hash[idx];
}
-const char *type_names[] = {
- "none", "commit", "tree", "blob", "tag",
- "bad type 5", "bad type 6", "delta", "bad",
+static const char *object_type_strings[] = {
+ NULL, /* OBJ_NONE = 0 */
+ "commit", /* OBJ_COMMIT = 1 */
+ "tree", /* OBJ_TREE = 2 */
+ "blob", /* OBJ_BLOB = 3 */
+ "tag", /* OBJ_TAG = 4 */
};
+const char *typename(unsigned int type)
+{
+ if (type >= ARRAY_SIZE(object_type_strings))
+ return NULL;
+ return object_type_strings[type];
+}
+
+int type_from_string(const char *str)
+{
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(object_type_strings); i++)
+ if (!strcmp(str, object_type_strings[i]))
+ return i;
+ die("invalid object type \"%s\"", str);
+}
+
static unsigned int hash_obj(struct object *obj, unsigned int n)
{
unsigned int hash = *(unsigned int *)obj->sha1;
nr_objs++;
}
-struct object *lookup_object_type(const unsigned char *sha1, const char *type)
-{
- if (!type) {
- return lookup_unknown_object(sha1);
- } else if (!strcmp(type, blob_type)) {
- return &lookup_blob(sha1)->object;
- } else if (!strcmp(type, tree_type)) {
- return &lookup_tree(sha1)->object;
- } else if (!strcmp(type, commit_type)) {
- return &lookup_commit(sha1)->object;
- } else if (!strcmp(type, tag_type)) {
- return &lookup_tag(sha1)->object;
- } else {
- error("Unknown type %s", type);
- return NULL;
- }
-}
-
union any_object {
struct object object;
struct commit commit;
return obj;
}
-struct object *parse_object_buffer(const unsigned char *sha1, const char *type, unsigned long size, void *buffer, int *eaten_p)
+struct object *parse_object_buffer(const unsigned char *sha1, enum object_type type, unsigned long size, void *buffer, int *eaten_p)
{
struct object *obj;
int eaten = 0;
- if (!strcmp(type, blob_type)) {
+ if (type == OBJ_BLOB) {
struct blob *blob = lookup_blob(sha1);
parse_blob_buffer(blob, buffer, size);
obj = &blob->object;
- } else if (!strcmp(type, tree_type)) {
+ } else if (type == OBJ_TREE) {
struct tree *tree = lookup_tree(sha1);
obj = &tree->object;
if (!tree->object.parsed) {
parse_tree_buffer(tree, buffer, size);
eaten = 1;
}
- } else if (!strcmp(type, commit_type)) {
+ } else if (type == OBJ_COMMIT) {
struct commit *commit = lookup_commit(sha1);
parse_commit_buffer(commit, buffer, size);
if (!commit->buffer) {
eaten = 1;
}
obj = &commit->object;
- } else if (!strcmp(type, tag_type)) {
+ } else if (type == OBJ_TAG) {
struct tag *tag = lookup_tag(sha1);
parse_tag_buffer(tag, buffer, size);
obj = &tag->object;
struct object *parse_object(const unsigned char *sha1)
{
unsigned long size;
- char type[20];
+ enum object_type type;
int eaten;
- void *buffer = read_sha1_file(sha1, type, &size);
+ void *buffer = read_sha1_file(sha1, &type, &size);
if (buffer) {
struct object *obj;
- if (check_sha1_signature(sha1, buffer, size, type) < 0)
+ if (check_sha1_signature(sha1, buffer, size, typename(type)) < 0)
printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
obj = parse_object_buffer(sha1, type, size, buffer, &eaten);
};
extern int track_object_refs;
-extern const char *type_names[9];
+
+extern const char *typename(unsigned int type);
+extern int type_from_string(const char *str);
extern unsigned int get_max_object_index(void);
extern struct object *get_indexed_object(unsigned int);
-
-static inline const char *typename(unsigned int type)
-{
- return type_names[type > OBJ_BAD ? OBJ_BAD : type];
-}
-
extern struct object_refs *lookup_object_refs(struct object *);
/** Internal only **/
struct object *lookup_object(const unsigned char *sha1);
-/** Returns the object, having looked it up as being the given type. **/
-struct object *lookup_object_type(const unsigned char *sha1, const char *type);
-
void created_object(const unsigned char *sha1, struct object *obj);
/** Returns the object, having parsed it to find out what it is. **/
* parsing it. eaten_p indicates if the object has a borrowed copy
* of buffer and the caller should not free() it.
*/
-struct object *parse_object_buffer(const unsigned char *sha1, const char *type, unsigned long size, void *buffer, int *eaten_p);
+struct object *parse_object_buffer(const unsigned char *sha1, enum object_type type, unsigned long size, void *buffer, int *eaten_p);
/** Returns the object, with potentially excess memory allocated. **/
struct object *lookup_unknown_object(const unsigned char *sha1);
for (i = err = 0; i < nr_objects; i++) {
unsigned char sha1[20];
void *data;
- char type[20];
+ enum object_type type;
unsigned long size, offset;
if (nth_packed_object_sha1(p, i, sha1))
offset = find_pack_entry_one(sha1, p);
if (!offset)
die("internal error pack-check find-pack-entry-one");
- data = unpack_entry(p, offset, type, &size);
+ data = unpack_entry(p, offset, &type, &size);
if (!data) {
err = error("cannot unpack %s from %s",
sha1_to_hex(sha1), p->pack_name);
continue;
}
- if (check_sha1_signature(sha1, data, size, type)) {
+ if (check_sha1_signature(sha1, data, size, typename(type))) {
err = error("packed %s from %s is corrupt",
sha1_to_hex(sha1), p->pack_name);
free(data);
for (i = 0; i < nr_objects; i++) {
unsigned char sha1[20], base_sha1[20];
- char type[20];
+ const char *type;
unsigned long size;
unsigned long store_size;
unsigned long offset;
if (!offset)
die("internal error pack-check find-pack-entry-one");
- packed_object_info_detail(p, offset, type, &size, &store_size,
- &delta_chain_length,
- base_sha1);
+ type = packed_object_info_detail(p, offset, &size, &store_size,
+ &delta_chain_length,
+ base_sha1);
printf("%s ", sha1_to_hex(sha1));
if (!delta_chain_length)
printf("%-6s %lu %lu\n", type, size, offset);
if (fd >= 0) {
unsigned char sha1[20];
- if (!index_fd(sha1, fd, st, 0, NULL))
+ if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name))
match = hashcmp(sha1, ce->sha1);
/* index_fd() closed the file descriptor already */
}
char *target;
void *buffer;
unsigned long size;
- char type[10];
+ enum object_type type;
int len;
target = xmalloc(expected_size);
free(target);
return -1;
}
- buffer = read_sha1_file(ce->sha1, type, &size);
+ buffer = read_sha1_file(ce->sha1, &type, &size);
if (!buffer) {
free(target);
return -1;
void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
{
+ if (revs->no_walk && (obj->flags & UNINTERESTING))
+ die("object ranges do not make sense when not walking revisions");
add_object_array(obj, name, &revs->pending);
if (revs->reflog_info && obj->type == OBJ_COMMIT)
add_reflog_for_walk(revs->reflog_info,
struct all_refs_cb *cb = cb_data;
struct object *object = get_reference(cb->all_revs, path, sha1,
cb->all_flags);
- add_pending_object(cb->all_revs, object, "");
+ add_pending_object(cb->all_revs, object, path);
return 0;
}
/* And generate the fake traditional header */
stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
- type_names[type], size);
+ typename(type), size);
return 0;
}
* too permissive for what we want to check. So do an anal
* object header parse by hand.
*/
-static int parse_sha1_header(char *hdr, char *type, unsigned long *sizep)
+static int parse_sha1_header(const char *hdr, unsigned long *sizep)
{
+ char type[10];
int i;
unsigned long size;
/*
* The type can be at most ten bytes (including the
* terminating '\0' that we add), and is followed by
- * a space.
+ * a space.
*/
- i = 10;
+ i = 0;
for (;;) {
char c = *hdr++;
if (c == ' ')
break;
- if (!--i)
+ type[i++] = c;
+ if (i >= sizeof(type))
return -1;
- *type++ = c;
}
- *type = 0;
+ type[i] = 0;
/*
* The length must follow immediately, and be in canonical
/*
* The length must be followed by a zero byte
*/
- return *hdr ? -1 : 0;
+ return *hdr ? -1 : type_from_string(type);
}
-void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size)
+void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size)
{
int ret;
z_stream stream;
char hdr[8192];
ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
- if (ret < Z_OK || parse_sha1_header(hdr, type, size) < 0)
+ if (ret < Z_OK || (*type = parse_sha1_header(hdr, size)) < 0)
return NULL;
return unpack_sha1_rest(&stream, hdr, *size);
static unsigned long get_delta_base(struct packed_git *p,
struct pack_window **w_curs,
- unsigned long offset,
- enum object_type kind,
- unsigned long delta_obj_offset,
- unsigned long *base_obj_offset)
+ unsigned long *curpos,
+ enum object_type type,
+ unsigned long delta_obj_offset)
{
- unsigned char *base_info = use_pack(p, w_curs, offset, NULL);
+ unsigned char *base_info = use_pack(p, w_curs, *curpos, NULL);
unsigned long base_offset;
/* use_pack() assured us we have [base_info, base_info + 20)
* that is assured. An OFS_DELTA longer than the hash size
* is stupid, as then a REF_DELTA would be smaller to store.
*/
- if (kind == OBJ_OFS_DELTA) {
+ if (type == OBJ_OFS_DELTA) {
unsigned used = 0;
unsigned char c = base_info[used++];
base_offset = c & 127;
base_offset = delta_obj_offset - base_offset;
if (base_offset >= delta_obj_offset)
die("delta base offset out of bound");
- offset += used;
- } else if (kind == OBJ_REF_DELTA) {
+ *curpos += used;
+ } else if (type == OBJ_REF_DELTA) {
/* The base entry _must_ be in the same pack */
base_offset = find_pack_entry_one(base_info, p);
if (!base_offset)
die("failed to find delta-pack base object %s",
sha1_to_hex(base_info));
- offset += 20;
+ *curpos += 20;
} else
die("I am totally screwed");
- *base_obj_offset = base_offset;
- return offset;
+ return base_offset;
}
/* forward declaration for a mutually recursive function */
static int packed_object_info(struct packed_git *p, unsigned long offset,
- char *type, unsigned long *sizep);
+ unsigned long *sizep);
static int packed_delta_info(struct packed_git *p,
struct pack_window **w_curs,
- unsigned long offset,
- enum object_type kind,
+ unsigned long curpos,
+ enum object_type type,
unsigned long obj_offset,
- char *type,
unsigned long *sizep)
{
unsigned long base_offset;
- offset = get_delta_base(p, w_curs, offset, kind,
- obj_offset, &base_offset);
+ base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset);
+ type = packed_object_info(p, base_offset, NULL);
/* We choose to only get the type of the base object and
* ignore potentially corrupt pack file that expects the delta
* based on a base with a wrong size. This saves tons of
* inflate() calls.
*/
- if (packed_object_info(p, base_offset, type, NULL))
- die("cannot get info for delta-pack base");
-
if (sizep) {
const unsigned char *data;
unsigned char delta_head[20], *in;
- unsigned long result_size;
z_stream stream;
int st;
inflateInit(&stream);
do {
- in = use_pack(p, w_curs, offset, &stream.avail_in);
+ in = use_pack(p, w_curs, curpos, &stream.avail_in);
stream.next_in = in;
st = inflate(&stream, Z_FINISH);
- offset += stream.next_in - in;
+ curpos += stream.next_in - in;
} while ((st == Z_OK || st == Z_BUF_ERROR)
&& stream.total_out < sizeof(delta_head));
inflateEnd(&stream);
get_delta_hdr_size(&data, delta_head+sizeof(delta_head));
/* Read the result size */
- result_size = get_delta_hdr_size(&data, delta_head+sizeof(delta_head));
- *sizep = result_size;
+ *sizep = get_delta_hdr_size(&data, delta_head+sizeof(delta_head));
}
- return 0;
+
+ return type;
}
-static unsigned long unpack_object_header(struct packed_git *p,
- struct pack_window **w_curs,
- unsigned long offset,
- enum object_type *type,
- unsigned long *sizep)
+static int unpack_object_header(struct packed_git *p,
+ struct pack_window **w_curs,
+ unsigned long *curpos,
+ unsigned long *sizep)
{
unsigned char *base;
unsigned int left;
unsigned long used;
+ enum object_type type;
/* use_pack() assures us we have [base, base + 20) available
* as a range that we can look at at. (Its actually the hash
* the maximum deflated object size is 2^137, which is just
* insane, so we know won't exceed what we have been given.
*/
- base = use_pack(p, w_curs, offset, &left);
- used = unpack_object_header_gently(base, left, type, sizep);
+ base = use_pack(p, w_curs, *curpos, &left);
+ used = unpack_object_header_gently(base, left, &type, sizep);
if (!used)
die("object offset outside of pack file");
+ *curpos += used;
- return offset + used;
+ return type;
}
-void packed_object_info_detail(struct packed_git *p,
- unsigned long offset,
- char *type,
- unsigned long *size,
- unsigned long *store_size,
- unsigned int *delta_chain_length,
- unsigned char *base_sha1)
+const char *packed_object_info_detail(struct packed_git *p,
+ unsigned long obj_offset,
+ unsigned long *size,
+ unsigned long *store_size,
+ unsigned int *delta_chain_length,
+ unsigned char *base_sha1)
{
struct pack_window *w_curs = NULL;
- unsigned long obj_offset, val;
+ unsigned long curpos, dummy;
unsigned char *next_sha1;
- enum object_type kind;
+ enum object_type type;
*delta_chain_length = 0;
- obj_offset = offset;
- offset = unpack_object_header(p, &w_curs, offset, &kind, size);
+ curpos = obj_offset;
+ type = unpack_object_header(p, &w_curs, &curpos, size);
for (;;) {
- switch (kind) {
+ switch (type) {
default:
die("pack %s contains unknown object type %d",
- p->pack_name, kind);
+ p->pack_name, type);
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
case OBJ_TAG:
- strcpy(type, type_names[kind]);
*store_size = 0; /* notyet */
unuse_pack(&w_curs);
- return;
+ return typename(type);
case OBJ_OFS_DELTA:
- get_delta_base(p, &w_curs, offset, kind,
- obj_offset, &offset);
+ obj_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
if (*delta_chain_length == 0) {
- /* TODO: find base_sha1 as pointed by offset */
+ /* TODO: find base_sha1 as pointed by curpos */
}
break;
case OBJ_REF_DELTA:
- next_sha1 = use_pack(p, &w_curs, offset, NULL);
+ next_sha1 = use_pack(p, &w_curs, curpos, NULL);
if (*delta_chain_length == 0)
hashcpy(base_sha1, next_sha1);
- offset = find_pack_entry_one(next_sha1, p);
+ obj_offset = find_pack_entry_one(next_sha1, p);
break;
}
- obj_offset = offset;
- offset = unpack_object_header(p, &w_curs, offset, &kind, &val);
(*delta_chain_length)++;
+ curpos = obj_offset;
+ type = unpack_object_header(p, &w_curs, &curpos, &dummy);
}
}
-static int packed_object_info(struct packed_git *p, unsigned long offset,
- char *type, unsigned long *sizep)
+static int packed_object_info(struct packed_git *p, unsigned long obj_offset,
+ unsigned long *sizep)
{
struct pack_window *w_curs = NULL;
- unsigned long size, obj_offset = offset;
- enum object_type kind;
- int r;
+ unsigned long size, curpos = obj_offset;
+ enum object_type type;
- offset = unpack_object_header(p, &w_curs, offset, &kind, &size);
+ type = unpack_object_header(p, &w_curs, &curpos, &size);
- switch (kind) {
+ switch (type) {
case OBJ_OFS_DELTA:
case OBJ_REF_DELTA:
- r = packed_delta_info(p, &w_curs, offset, kind,
- obj_offset, type, sizep);
- unuse_pack(&w_curs);
- return r;
+ type = packed_delta_info(p, &w_curs, curpos,
+ type, obj_offset, sizep);
+ break;
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
case OBJ_TAG:
- strcpy(type, type_names[kind]);
- unuse_pack(&w_curs);
+ if (sizep)
+ *sizep = size;
break;
default:
die("pack %s contains unknown object type %d",
- p->pack_name, kind);
+ p->pack_name, type);
}
- if (sizep)
- *sizep = size;
- return 0;
+ unuse_pack(&w_curs);
+ return type;
}
static void *unpack_compressed_entry(struct packed_git *p,
struct pack_window **w_curs,
- unsigned long offset,
+ unsigned long curpos,
unsigned long size)
{
int st;
inflateInit(&stream);
do {
- in = use_pack(p, w_curs, offset, &stream.avail_in);
+ in = use_pack(p, w_curs, curpos, &stream.avail_in);
stream.next_in = in;
st = inflate(&stream, Z_FINISH);
- offset += stream.next_in - in;
+ curpos += stream.next_in - in;
} while (st == Z_OK || st == Z_BUF_ERROR);
inflateEnd(&stream);
if ((st != Z_STREAM_END) || stream.total_out != size) {
static void *unpack_delta_entry(struct packed_git *p,
struct pack_window **w_curs,
- unsigned long offset,
+ unsigned long curpos,
unsigned long delta_size,
- enum object_type kind,
unsigned long obj_offset,
- char *type,
+ enum object_type *type,
unsigned long *sizep)
{
void *delta_data, *result, *base;
- unsigned long result_size, base_size, base_offset;
+ unsigned long base_size, base_offset;
- offset = get_delta_base(p, w_curs, offset, kind,
- obj_offset, &base_offset);
+ base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset);
base = unpack_entry(p, base_offset, type, &base_size);
if (!base)
die("failed to read delta base object at %lu from %s",
base_offset, p->pack_name);
- delta_data = unpack_compressed_entry(p, w_curs, offset, delta_size);
+ delta_data = unpack_compressed_entry(p, w_curs, curpos, delta_size);
result = patch_delta(base, base_size,
delta_data, delta_size,
- &result_size);
+ sizep);
if (!result)
die("failed to apply delta");
free(delta_data);
free(base);
- *sizep = result_size;
return result;
}
-void *unpack_entry(struct packed_git *p, unsigned long offset,
- char *type, unsigned long *sizep)
+void *unpack_entry(struct packed_git *p, unsigned long obj_offset,
+ enum object_type *type, unsigned long *sizep)
{
struct pack_window *w_curs = NULL;
- unsigned long size, obj_offset = offset;
- enum object_type kind;
- void *retval;
+ unsigned long curpos = obj_offset;
+ void *data;
- offset = unpack_object_header(p, &w_curs, offset, &kind, &size);
- switch (kind) {
+ *type = unpack_object_header(p, &w_curs, &curpos, sizep);
+ switch (*type) {
case OBJ_OFS_DELTA:
case OBJ_REF_DELTA:
- retval = unpack_delta_entry(p, &w_curs, offset, size,
- kind, obj_offset, type, sizep);
+ data = unpack_delta_entry(p, &w_curs, curpos, *sizep,
+ obj_offset, type, sizep);
break;
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
case OBJ_TAG:
- strcpy(type, type_names[kind]);
- *sizep = size;
- retval = unpack_compressed_entry(p, &w_curs, offset, size);
+ data = unpack_compressed_entry(p, &w_curs, curpos, *sizep);
break;
default:
- die("unknown object type %i in %s", kind, p->pack_name);
+ die("unknown object type %i in %s", *type, p->pack_name);
}
unuse_pack(&w_curs);
- return retval;
+ return data;
}
int num_packed_objects(const struct packed_git *p)
return p;
}
return NULL;
-
+
}
-static int sha1_loose_object_info(const unsigned char *sha1, char *type, unsigned long *sizep)
+static int sha1_loose_object_info(const unsigned char *sha1, unsigned long *sizep)
{
int status;
unsigned long mapsize, size;
void *map;
z_stream stream;
- char hdr[128];
+ char hdr[32];
map = map_sha1_file(sha1, &mapsize);
if (!map)
if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
status = error("unable to unpack %s header",
sha1_to_hex(sha1));
- if (parse_sha1_header(hdr, type, &size) < 0)
+ else if ((status = parse_sha1_header(hdr, &size)) < 0)
status = error("unable to parse %s header", sha1_to_hex(sha1));
- else {
- status = 0;
- if (sizep)
- *sizep = size;
- }
+ else if (sizep)
+ *sizep = size;
inflateEnd(&stream);
munmap(map, mapsize);
return status;
}
-int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep)
+int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
{
struct pack_entry e;
if (!find_pack_entry(sha1, &e, NULL)) {
reprepare_packed_git();
if (!find_pack_entry(sha1, &e, NULL))
- return sha1_loose_object_info(sha1, type, sizep);
+ return sha1_loose_object_info(sha1, sizep);
}
- return packed_object_info(e.p, e.offset, type, sizep);
+ return packed_object_info(e.p, e.offset, sizep);
}
-static void *read_packed_sha1(const unsigned char *sha1, char *type, unsigned long *size)
+static void *read_packed_sha1(const unsigned char *sha1,
+ enum object_type *type, unsigned long *size)
{
struct pack_entry e;
*/
static struct cached_object {
unsigned char sha1[20];
- const char *type;
+ enum object_type type;
void *buf;
unsigned long size;
} *cached_objects;
return NULL;
}
-int pretend_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *sha1)
+int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
+ unsigned char *sha1)
{
struct cached_object *co;
- hash_sha1_file(buf, len, type, sha1);
+ hash_sha1_file(buf, len, typename(type), sha1);
if (has_sha1_file(sha1) || find_cached_object(sha1))
return 0;
if (cached_object_alloc <= cached_object_nr) {
}
co = &cached_objects[cached_object_nr++];
co->size = len;
- co->type = strdup(type);
+ co->type = type;
co->buf = xmalloc(len);
memcpy(co->buf, buf, len);
hashcpy(co->sha1, sha1);
return 0;
}
-void *read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
+void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
+ unsigned long *size)
{
unsigned long mapsize;
void *map, *buf;
buf = xmalloc(co->size + 1);
memcpy(buf, co->buf, co->size);
((char*)buf)[co->size] = 0;
- strcpy(type, co->type);
+ *type = co->type;
*size = co->size;
return buf;
}
}
void *read_object_with_reference(const unsigned char *sha1,
- const char *required_type,
+ const char *required_type_name,
unsigned long *size,
unsigned char *actual_sha1_return)
{
- char type[20];
+ enum object_type type, required_type;
void *buffer;
unsigned long isize;
unsigned char actual_sha1[20];
+ required_type = type_from_string(required_type_name);
hashcpy(actual_sha1, sha1);
while (1) {
int ref_length = -1;
const char *ref_type = NULL;
- buffer = read_sha1_file(actual_sha1, type, &isize);
+ buffer = read_sha1_file(actual_sha1, &type, &isize);
if (!buffer)
return NULL;
- if (!strcmp(type, required_type)) {
+ if (type == required_type) {
*size = isize;
if (actual_sha1_return)
hashcpy(actual_sha1_return, actual_sha1);
return buffer;
}
/* Handle references */
- else if (!strcmp(type, commit_type))
+ else if (type == OBJ_COMMIT)
ref_type = "tree ";
- else if (!strcmp(type, tag_type))
+ else if (type == OBJ_TAG)
ref_type = "object ";
else {
free(buffer);
static void write_sha1_file_prepare(void *buf, unsigned long len,
const char *type, unsigned char *sha1,
- unsigned char *hdr, int *hdrlen)
+ char *hdr, int *hdrlen)
{
SHA_CTX c;
/* Generate the header */
- *hdrlen = sprintf((char *)hdr, "%s %lu", type, len)+1;
+ *hdrlen = sprintf(hdr, "%s %lu", type, len)+1;
/* Sha1.. */
SHA1_Init(&c);
static void setup_object_header(z_stream *stream, const char *type, unsigned long len)
{
- int obj_type, hdr;
+ int obj_type, hdrlen;
if (use_legacy_headers) {
while (deflate(stream, 0) == Z_OK)
/* nothing */;
return;
}
- if (!strcmp(type, blob_type))
- obj_type = OBJ_BLOB;
- else if (!strcmp(type, tree_type))
- obj_type = OBJ_TREE;
- else if (!strcmp(type, commit_type))
- obj_type = OBJ_COMMIT;
- else if (!strcmp(type, tag_type))
- obj_type = OBJ_TAG;
- else
- die("trying to generate bogus object of type '%s'", type);
- hdr = write_binary_header(stream->next_out, obj_type, len);
- stream->total_out = hdr;
- stream->next_out += hdr;
- stream->avail_out -= hdr;
+ obj_type = type_from_string(type);
+ hdrlen = write_binary_header(stream->next_out, obj_type, len);
+ stream->total_out = hdrlen;
+ stream->next_out += hdrlen;
+ stream->avail_out -= hdrlen;
}
int hash_sha1_file(void *buf, unsigned long len, const char *type,
unsigned char *sha1)
{
- unsigned char hdr[50];
+ char hdr[32];
int hdrlen;
write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
return 0;
unsigned char sha1[20];
char *filename;
static char tmpfile[PATH_MAX];
- unsigned char hdr[50];
+ char hdr[32];
int fd, hdrlen;
/* Normally if we have it in the pack then we do not bother writing
stream.avail_out = size;
/* First header.. */
- stream.next_in = hdr;
+ stream.next_in = (unsigned char *)hdr;
stream.avail_in = hdrlen;
setup_object_header(&stream, type, len);
z_stream stream;
unsigned char *unpacked;
unsigned long len;
- char type[20];
- char hdr[50];
+ enum object_type type;
+ char hdr[32];
int hdrlen;
void *buf;
/* need to unpack and recompress it by itself */
- unpacked = read_packed_sha1(sha1, type, &len);
+ unpacked = read_packed_sha1(sha1, &type, &len);
if (!unpacked)
error("cannot read sha1_file for %s", sha1_to_hex(sha1));
- hdrlen = sprintf(hdr, "%s %lu", type, len) + 1;
+ hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
/* Set it up */
memset(&stream, 0, sizeof(stream));
return ret;
}
-int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type)
+int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
+ enum object_type type, const char *path)
{
unsigned long size = st->st_size;
void *buf;
close(fd);
if (!type)
- type = blob_type;
+ type = OBJ_BLOB;
/*
* Convert blobs to git internal format
*/
- if (!strcmp(type, blob_type)) {
+ if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) {
unsigned long nsize = size;
char *nbuf = buf;
- if (convert_to_git(NULL, &nbuf, &nsize)) {
+ if (convert_to_git(path, &nbuf, &nsize)) {
if (size)
munmap(buf, size);
size = nsize;
}
if (write_object)
- ret = write_sha1_file(buf, size, type, sha1);
+ ret = write_sha1_file(buf, size, typename(type), sha1);
else
- ret = hash_sha1_file(buf, size, type, sha1);
+ ret = hash_sha1_file(buf, size, typename(type), sha1);
if (re_allocated) {
free(buf);
return ret;
if (fd < 0)
return error("open(\"%s\"): %s", path,
strerror(errno));
- if (index_fd(sha1, fd, st, write_object, NULL) < 0)
+ if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path) < 0)
return error("%s: failed to insert into database",
path);
break;
svnrepo="file://$svnrepo"
poke() {
- perl -e '@x = stat($ARGV[0]); utime($x[8], $x[9] + 1, $ARGV[0])' "$1"
+ test-chmtime +1 "$1"
}
mkdir $rr2
echo Hello > $rr2/preimage
-case "$(date -d @11111111 +%s 2>/dev/null)" in
-11111111)
- # 'date' must be able to take arbitrary input with @11111111 notation.
- # for this test to succeed. We should fix this part using more
- # portable script someday.
-
- now=$(date +%s)
- almost_15_days_ago=$(($now+60-15*86400))
- just_over_15_days_ago=$(($now-1-15*86400))
- almost_60_days_ago=$(($now+60-60*86400))
- just_over_60_days_ago=$(($now-1-60*86400))
- predate1="$(date -d "@$almost_60_days_ago" +%Y%m%d%H%M.%S)"
- predate2="$(date -d "@$almost_15_days_ago" +%Y%m%d%H%M.%S)"
- postdate1="$(date -d "@$just_over_60_days_ago" +%Y%m%d%H%M.%S)"
- postdate2="$(date -d "@$just_over_15_days_ago" +%Y%m%d%H%M.%S)"
-
- touch -m -t "$predate1" $rr/preimage
- touch -m -t "$predate2" $rr2/preimage
-
- test_expect_success 'garbage collection (part1)' 'git rerere gc'
-
- test_expect_success 'young records still live' \
- "test -f $rr/preimage -a -f $rr2/preimage"
-
- touch -m -t "$postdate1" $rr/preimage
- touch -m -t "$postdate2" $rr2/preimage
-
- test_expect_success 'garbage collection (part2)' 'git rerere gc'
-
- test_expect_success 'old records rest in peace' \
- "test ! -f $rr/preimage -a ! -f $rr2/preimage"
- ;;
-esac
+almost_15_days_ago=$((60-15*86400))
+just_over_15_days_ago=$((-1-15*86400))
+almost_60_days_ago=$((60-60*86400))
+just_over_60_days_ago=$((-1-60*86400))
+
+test-chmtime =$almost_60_days_ago $rr/preimage
+test-chmtime =$almost_15_days_ago $rr2/preimage
+
+test_expect_success 'garbage collection (part1)' 'git rerere gc'
+
+test_expect_success 'young records still live' \
+ "test -f $rr/preimage && test -f $rr2/preimage"
+
+test-chmtime =$just_over_60_days_ago $rr/preimage
+test-chmtime =$just_over_15_days_ago $rr2/preimage
+
+test_expect_success 'garbage collection (part2)' 'git rerere gc'
+
+test_expect_success 'old records rest in peace' \
+ "test ! -f $rr/preimage && test ! -f $rr2/preimage"
test_done
'git-mailsplit -o. ../t5100/sample.mbox >last &&
last=`cat last` &&
echo total is $last &&
- test `cat last` = 5'
+ test `cat last` = 6'
for mail in `echo 00*`
do
--- /dev/null
+Author: A U Thor
+Email: a.u.thor@example.com
+Subject: a commit.
+Date: Fri, 9 Jun 2006 00:44:16 -0700
+
--- /dev/null
+Here is a patch from A U Thor.
+
--- /dev/null
+---
+ foo | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/foo b/foo
+index 9123cdc..918dcf8 100644
+--- a/foo
++++ b/foo
+@@ -1 +1 @@
+-Fri Jun 9 00:44:04 PDT 2006
++Fri Jun 9 00:44:13 PDT 2006
+--
+1.4.0.g6f2b
+
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
+From nobody Mon Sep 17 00:00:00 2001
+From: A U Thor <a.u.thor@example.com>
+References: <Pine.LNX.4.640.0001@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0002@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0003@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0004@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0005@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0006@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0007@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0008@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0009@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0010@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0011@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0012@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0013@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0014@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0015@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0016@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0017@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0018@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0019@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0020@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0021@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0022@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0023@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0024@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0025@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0026@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0027@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0028@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0029@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0030@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0031@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0032@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0033@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0034@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0035@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0036@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0037@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0038@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0039@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0040@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0041@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0042@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0043@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0044@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0045@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0046@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0047@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0048@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0049@woody.linux-foundation.org>
+ <Pine.LNX.4.640.0050@woody.linux-foundation.org>
+Date: Fri, 9 Jun 2006 00:44:16 -0700
+Subject: [PATCH] a commit.
+
+Here is a patch from A U Thor.
+
+---
+ foo | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/foo b/foo
+index 9123cdc..918dcf8 100644
+--- a/foo
++++ b/foo
+@@ -1 +1 @@
+-Fri Jun 9 00:44:04 PDT 2006
++Fri Jun 9 00:44:13 PDT 2006
+--
+1.4.0.g6f2b
+
echo "URL: ../two/.git/"
echo "Pull: refs/heads/master:refs/heads/two"
echo "Pull: refs/heads/one:refs/heads/one"
- } >.git/remotes/two
+ } >.git/remotes/two &&
+ cd .. &&
+ git clone . bundle
'
test_expect_success "fetch test" '
'
+test_expect_success 'create bundle 1' '
+ cd "$D" &&
+ echo >file updated again by origin &&
+ git commit -a -m "tip" &&
+ git bundle create bundle1 master^..master
+'
+
+test_expect_success 'create bundle 2' '
+ cd "$D" &&
+ git bundle create bundle2 master~2..master
+'
+
+test_expect_failure 'unbundle 1' '
+ cd "$D/bundle" &&
+ git checkout -b some-branch &&
+ git fetch "$D/bundle1" master:master
+'
+
+test_expect_success 'unbundle 2' '
+ cd "$D/bundle" &&
+ git fetch ../bundle2 master:master &&
+ test "tip" = "$(git log -1 --pretty=oneline master | cut -b42-)"
+'
+
test_done
error "You haven't built things yet, have you?"
}
+if ! test -x ../test-chmtime; then
+ echo >&2 'You need to build test-chmtime:'
+ echo >&2 'Run "make test-chmtime" in the source (toplevel) directory'
+ exit 1
+fi
+
# Test repository
test=trash
rm -fr "$test"
#include "cache.h"
#include "tag.h"
+#include "commit.h"
+#include "tree.h"
+#include "blob.h"
const char *tag_type = "tag";
int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
{
int typelen, taglen;
- unsigned char object[20];
+ unsigned char sha1[20];
const char *type_line, *tag_line, *sig_line;
char type[20];
if (size < 64)
return -1;
- if (memcmp("object ", data, 7) || get_sha1_hex((char *) data + 7, object))
+ if (memcmp("object ", data, 7) || get_sha1_hex((char *) data + 7, sha1))
return -1;
type_line = (char *) data + 48;
memcpy(item->tag, tag_line + 4, taglen);
item->tag[taglen] = '\0';
- item->tagged = lookup_object_type(object, type);
+ if (!strcmp(type, blob_type)) {
+ item->tagged = &lookup_blob(sha1)->object;
+ } else if (!strcmp(type, tree_type)) {
+ item->tagged = &lookup_tree(sha1)->object;
+ } else if (!strcmp(type, commit_type)) {
+ item->tagged = &lookup_commit(sha1)->object;
+ } else if (!strcmp(type, tag_type)) {
+ item->tagged = &lookup_tag(sha1)->object;
+ } else {
+ error("Unknown type %s", type);
+ item->tagged = NULL;
+ }
+
if (item->tagged && track_object_refs) {
struct object_refs *refs = alloc_object_refs(1);
refs->ref[0] = item->tagged;
int parse_tag(struct tag *item)
{
- char type[20];
+ enum object_type type;
void *data;
unsigned long size;
int ret;
if (item->object.parsed)
return 0;
- data = read_sha1_file(item->object.sha1, type, &size);
+ data = read_sha1_file(item->object.sha1, &type, &size);
if (!data)
return error("Could not read %s",
sha1_to_hex(item->object.sha1));
- if (strcmp(type, tag_type)) {
+ if (type != OBJ_TAG) {
free(data);
return error("Object %s not a tag",
sha1_to_hex(item->object.sha1));
--- /dev/null
+#include "git-compat-util.h"
+#include <utime.h>
+
+static const char usage_str[] = "(+|=|=+|=-|-)<seconds> <file>...";
+
+int main(int argc, const char *argv[])
+{
+ int i;
+ int set_eq;
+ long int set_time;
+ char *test;
+ const char *timespec;
+
+ if (argc < 3)
+ goto usage;
+
+ timespec = argv[1];
+ set_eq = (*timespec == '=') ? 1 : 0;
+ if (set_eq) {
+ timespec++;
+ if (*timespec == '+') {
+ set_eq = 2; /* relative "in the future" */
+ timespec++;
+ }
+ }
+ set_time = strtol(timespec, &test, 10);
+ if (*test) {
+ fprintf(stderr, "Not a base-10 integer: %s\n", argv[1] + 1);
+ goto usage;
+ }
+ if ((set_eq && set_time < 0) || set_eq == 2) {
+ time_t now = time(NULL);
+ set_time += now;
+ }
+
+ for (i = 2; i < argc; i++) {
+ struct stat sb;
+ struct utimbuf utb;
+
+ if (stat(argv[i], &sb) < 0) {
+ fprintf(stderr, "Failed to stat %s: %s\n",
+ argv[i], strerror(errno));
+ return -1;
+ }
+
+ utb.actime = sb.st_atime;
+ utb.modtime = set_eq ? set_time : sb.st_mtime + set_time;
+
+ if (utime(argv[i], &utb) < 0) {
+ fprintf(stderr, "Failed to modify time on %s: %s\n",
+ argv[i], strerror(errno));
+ return -1;
+ }
+ }
+
+ return 0;
+
+usage:
+ fprintf(stderr, "Usage: %s %s\n", argv[0], usage_str);
+ return -1;
+}
const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);
if (opt->recursive && S_ISDIR(mode)) {
- char type[20];
+ enum object_type type;
char *newbase = malloc_base(base, path, strlen(path));
struct tree_desc inner;
void *tree;
- tree = read_sha1_file(sha1, type, &inner.size);
- if (!tree || strcmp(type, tree_type))
+ tree = read_sha1_file(sha1, &type, &inner.size);
+ if (!tree || type != OBJ_TREE)
die("corrupt tree sha %s", sha1_to_hex(sha1));
inner.buf = tree;
int parse_tree(struct tree *item)
{
- char type[20];
+ enum object_type type;
void *buffer;
unsigned long size;
if (item->object.parsed)
return 0;
- buffer = read_sha1_file(item->object.sha1, type, &size);
+ buffer = read_sha1_file(item->object.sha1, &type, &size);
if (!buffer)
return error("Could not read %s",
sha1_to_hex(item->object.sha1));
- if (strcmp(type, tree_type)) {
+ if (type != OBJ_TREE) {
free(buffer);
return error("Object %s not a tree",
sha1_to_hex(item->object.sha1));
{
static char path[50];
void *buf;
- char type[100];
+ enum object_type type;
unsigned long size;
int fd;
- buf = read_sha1_file(sha1, type, &size);
- if (!buf || strcmp(type, blob_type))
+ buf = read_sha1_file(sha1, &type, &size);
+ if (!buf || type != OBJ_BLOB)
die("unable to read blob object %s", sha1_to_hex(sha1));
strcpy(path, ".merge_file_XXXXXX");
wt_status_print_trailer();
}
+static void wt_read_cache(struct wt_status *s)
+{
+ discard_cache();
+ read_cache();
+}
+
void wt_status_print_initial(struct wt_status *s)
{
int i;
char buf[PATH_MAX];
- read_cache();
+ wt_read_cache(s);
if (active_nr) {
s->commitable = 1;
wt_status_print_cached_header(NULL);
rev.diffopt.format_callback = wt_status_print_updated_cb;
rev.diffopt.format_callback_data = s;
rev.diffopt.detect_rename = 1;
+ wt_read_cache(s);
run_diff_index(&rev, 1);
}
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = wt_status_print_changed_cb;
rev.diffopt.format_callback_data = s;
+ wt_read_cache(s);
run_diff_files(&rev, 0);
}
setup_revisions(0, NULL, &rev, s->reference);
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
rev.diffopt.detect_rename = 1;
+ wt_read_cache(s);
run_diff_index(&rev, 1);
}
}
else {
wt_status_print_updated(s);
- discard_cache();
}
wt_status_print_changed(s);